On Wed, Mar 19, 2025 at 18:55:47 -0700, Changyuan Lyu <changyu...@google.com> wrote: > From: Alexander Graf <g...@amazon.com> > [...] > +/** > + * early_init_dt_check_kho - Decode info required for kexec handover from DT > + */ > +static void __init early_init_dt_check_kho(void) > +{ > + unsigned long node = chosen_node_offset; > + u64 kho_start, scratch_start, scratch_size; > + const __be32 *p; > + int l; > + > + if (!IS_ENABLED(CONFIG_KEXEC_HANDOVER) || (long)node < 0) > + return; > + > + p = of_get_flat_dt_prop(node, "linux,kho-fdt", &l); > + if (l != (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32)) > + return; > + > + kho_start = dt_mem_next_cell(dt_root_addr_cells, &p); > + > + p = of_get_flat_dt_prop(node, "linux,kho-scratch", &l); > + if (l != (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32)) > + return; > + > + scratch_start = dt_mem_next_cell(dt_root_addr_cells, &p); > + scratch_size = dt_mem_next_cell(dt_root_addr_cells, &p); > + > + kho_populate(kho_start, scratch_start, scratch_size); > +} > [...] > +static int kho_add_chosen(const struct kimage *image, void *fdt, int > chosen_node) > +{ > + int ret = 0; > +#ifdef CONFIG_KEXEC_HANDOVER > + phys_addr_t dt_mem = 0; > + phys_addr_t dt_len = 0; > + phys_addr_t scratch_mem = 0; > + phys_addr_t scratch_len = 0; > + > + if (!image->kho.fdt || !image->kho.scratch) > + return 0; > + > + dt_mem = image->kho.fdt->mem; > + dt_len = image->kho.fdt->memsz; > + > + scratch_mem = image->kho.scratch->mem; > + scratch_len = image->kho.scratch->bufsz; > + > + pr_debug("Adding kho metadata to DT"); > + > + ret = fdt_appendprop_addrrange(fdt, 0, chosen_node, "linux,kho-fdt", > + dt_mem, dt_len); > + if (ret) > + return ret; > + > + ret = fdt_appendprop_addrrange(fdt, 0, chosen_node, "linux,kho-scratch", > + scratch_mem, scratch_len);
While testing on ARM64 today, I realized that calling "fdt_appendprop_addrrange" here intercedes a bug that prevents consecutive KHO-enabled kexecs. Suppose we do KHO kexec from kernel 1 to kernel 2 and then from kernel 2 to kernel 3. The firmware DT got by kernel 2 from kernel 1 already has "linux,kho-fdt" and "linux,kho-scratch" in the "chosen" node. And when KHO kexec-ing to kernel 3 from kernel 2, kernel 2 will __append__ the its KHO FDT address to the "linux,kho-fdt". Thus the "linux,kho-fdt" received by kernel 3 contains 2 address ranges. Kernel 3 would fail at early_init_dt_check_kho() above. I will fix this bug in v6. > + > +#endif /* CONFIG_KEXEC_HANDOVER */ > + return ret; > +} > [...] Best, Changyuan