Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

of/fdt: add dt_phys arg to early_init_dt_scan and early_init_dt_verify

__pa() is only intended to be used for linear map addresses and using
it for initial_boot_params which is in fixmap for arm64 will give an
incorrect value. Hence save the physical address when it is known at
boot time when calling early_init_dt_scan for arm64 and use it at kexec
time instead of converting the virtual address using __pa().

Note that arm64 doesn't need the FDT region reserved in the DT as the
kernel explicitly reserves the passed in FDT. Therefore, only a debug
warning is fixed with this change.

Reported-by: Breno Leitao <leitao@debian.org>
Suggested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Usama Arif <usamaarif642@gmail.com>
Fixes: ac10be5cdbfa ("arm64: Use common of_kexec_alloc_and_setup_fdt()")
Link: https://lore.kernel.org/r/20241023171426.452688-1-usamaarif642@gmail.com
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>

authored by

Usama Arif and committed by
Rob Herring (Arm)
b2473a35 f9759e2b

+36 -29
+1 -1
arch/arc/kernel/devtree.c
··· 62 62 const struct machine_desc *mdesc; 63 63 unsigned long dt_root; 64 64 65 - if (!early_init_dt_scan(dt)) 65 + if (!early_init_dt_scan(dt, __pa(dt))) 66 66 return NULL; 67 67 68 68 mdesc = of_flat_dt_match_machine(NULL, arch_get_next_mach);
+1 -1
arch/arm/kernel/devtree.c
··· 200 200 201 201 mdesc_best = &__mach_desc_GENERIC_DT; 202 202 203 - if (!dt_virt || !early_init_dt_verify(dt_virt)) 203 + if (!dt_virt || !early_init_dt_verify(dt_virt, __pa(dt_virt))) 204 204 return NULL; 205 205 206 206 mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach);
+5 -1
arch/arm64/kernel/setup.c
··· 175 175 if (dt_virt) 176 176 memblock_reserve(dt_phys, size); 177 177 178 - if (!dt_virt || !early_init_dt_scan(dt_virt)) { 178 + /* 179 + * dt_virt is a fixmap address, hence __pa(dt_virt) can't be used. 180 + * Pass dt_phys directly. 181 + */ 182 + if (!early_init_dt_scan(dt_virt, dt_phys)) { 179 183 pr_crit("\n" 180 184 "Error: invalid device tree blob at physical address %pa (virtual address 0x%px)\n" 181 185 "The dtb must be 8-byte aligned and must not exceed 2 MB in size\n"
+2 -2
arch/csky/kernel/setup.c
··· 112 112 pre_trap_init(); 113 113 114 114 if (dtb_start == NULL) 115 - early_init_dt_scan(__dtb_start); 115 + early_init_dt_scan(__dtb_start, __pa(dtb_start)); 116 116 else 117 - early_init_dt_scan(dtb_start); 117 + early_init_dt_scan(dtb_start, __pa(dtb_start)); 118 118 119 119 start_kernel(); 120 120
+1 -1
arch/loongarch/kernel/setup.c
··· 290 290 if (!fdt_pointer || fdt_check_header(fdt_pointer)) 291 291 return; 292 292 293 - early_init_dt_scan(fdt_pointer); 293 + early_init_dt_scan(fdt_pointer, __pa(fdt_pointer)); 294 294 early_init_fdt_reserve_self(); 295 295 296 296 max_low_pfn = PFN_PHYS(memblock_end_of_DRAM());
+1 -1
arch/microblaze/kernel/prom.c
··· 18 18 { 19 19 pr_debug(" -> early_init_devtree(%p)\n", params); 20 20 21 - early_init_dt_scan(params); 21 + early_init_dt_scan(params, __pa(params)); 22 22 if (!strlen(boot_command_line)) 23 23 strscpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); 24 24
+1 -1
arch/mips/kernel/prom.c
··· 41 41 42 42 void __init __dt_setup_arch(void *bph) 43 43 { 44 - if (!early_init_dt_scan(bph)) 44 + if (!early_init_dt_scan(bph, __pa(bph))) 45 45 return; 46 46 47 47 mips_set_machine_name(of_flat_dt_get_machine_name());
+1 -1
arch/mips/kernel/relocate.c
··· 337 337 #if defined(CONFIG_USE_OF) 338 338 /* Deal with the device tree */ 339 339 fdt = plat_get_fdt(); 340 - early_init_dt_scan(fdt); 340 + early_init_dt_scan(fdt, __pa(fdt)); 341 341 if (boot_command_line[0]) { 342 342 /* Boot command line was passed in device tree */ 343 343 strscpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+2 -2
arch/nios2/kernel/prom.c
··· 27 27 if (be32_to_cpup((__be32 *)CONFIG_NIOS2_DTB_PHYS_ADDR) == 28 28 OF_DT_HEADER) { 29 29 params = (void *)CONFIG_NIOS2_DTB_PHYS_ADDR; 30 - early_init_dt_scan(params); 30 + early_init_dt_scan(params, __pa(params)); 31 31 return; 32 32 } 33 33 #endif ··· 37 37 params = (void *)__dtb_start; 38 38 #endif 39 39 40 - early_init_dt_scan(params); 40 + early_init_dt_scan(params, __pa(params)); 41 41 }
+1 -1
arch/openrisc/kernel/prom.c
··· 22 22 23 23 void __init early_init_devtree(void *params) 24 24 { 25 - early_init_dt_scan(params); 25 + early_init_dt_scan(params, __pa(params)); 26 26 memblock_allow_resize(); 27 27 }
+1 -1
arch/powerpc/kernel/dt_cpu_ftrs.c
··· 867 867 using_dt_cpu_ftrs = false; 868 868 869 869 /* Setup and verify the FDT, if it fails we just bail */ 870 - if (!early_init_dt_verify(fdt)) 870 + if (!early_init_dt_verify(fdt, __pa(fdt))) 871 871 return false; 872 872 873 873 if (!of_scan_flat_dt(fdt_find_cpu_features, NULL))
+1 -1
arch/powerpc/kernel/prom.c
··· 791 791 DBG(" -> early_init_devtree(%px)\n", params); 792 792 793 793 /* Too early to BUG_ON(), do it by hand */ 794 - if (!early_init_dt_verify(params)) 794 + if (!early_init_dt_verify(params, __pa(params))) 795 795 panic("BUG: Failed verifying flat device tree, bad version?"); 796 796 797 797 of_scan_flat_dt(early_init_dt_scan_model, NULL);
+1 -1
arch/powerpc/platforms/pseries/plpks.c
··· 683 683 out: 684 684 fdt_nop_property(fdt, chosen_node, "ibm,plpks-pw"); 685 685 // Since we've cleared the password, we must update the FDT checksum 686 - early_init_dt_verify(fdt); 686 + early_init_dt_verify(fdt, __pa(fdt)); 687 687 } 688 688 689 689 static __init int pseries_plpks_init(void)
+1 -1
arch/riscv/kernel/setup.c
··· 227 227 static void __init parse_dtb(void) 228 228 { 229 229 /* Early scan of device tree from init memory */ 230 - if (early_init_dt_scan(dtb_early_va)) { 230 + if (early_init_dt_scan(dtb_early_va, __pa(dtb_early_va))) { 231 231 const char *name = of_flat_dt_get_machine_name(); 232 232 233 233 if (name) {
+1 -1
arch/sh/kernel/setup.c
··· 255 255 dt_virt = phys_to_virt(dt_phys); 256 256 #endif 257 257 258 - if (!dt_virt || !early_init_dt_scan(dt_virt)) { 258 + if (!dt_virt || !early_init_dt_scan(dt_virt, __pa(dt_virt))) { 259 259 pr_crit("Error: invalid device tree blob" 260 260 " at physical address %p\n", (void *)dt_phys); 261 261
+1 -1
arch/um/kernel/dtb.c
··· 17 17 18 18 area = uml_load_file(dtb, &size); 19 19 if (area) { 20 - if (!early_init_dt_scan(area)) { 20 + if (!early_init_dt_scan(area, __pa(area))) { 21 21 pr_err("invalid DTB %s\n", dtb); 22 22 memblock_free(area, size); 23 23 return;
+1 -1
arch/x86/kernel/devicetree.c
··· 305 305 map_len = size; 306 306 } 307 307 308 - early_init_dt_verify(dt); 308 + early_init_dt_verify(dt, __pa(dt)); 309 309 } 310 310 311 311 unflatten_and_copy_device_tree();
+1 -1
arch/xtensa/kernel/setup.c
··· 216 216 217 217 void __init early_init_devtree(void *params) 218 218 { 219 - early_init_dt_scan(params); 219 + early_init_dt_scan(params, __pa(params)); 220 220 of_scan_flat_dt(xtensa_dt_io_area, NULL); 221 221 222 222 if (!command_line[0])
+8 -6
drivers/of/fdt.c
··· 457 457 int __initdata dt_root_size_cells; 458 458 459 459 void *initial_boot_params __ro_after_init; 460 + phys_addr_t initial_boot_params_pa __ro_after_init; 460 461 461 462 #ifdef CONFIG_OF_EARLY_FLATTREE 462 463 ··· 1135 1134 return ptr; 1136 1135 } 1137 1136 1138 - bool __init early_init_dt_verify(void *params) 1137 + bool __init early_init_dt_verify(void *dt_virt, phys_addr_t dt_phys) 1139 1138 { 1140 - if (!params) 1139 + if (!dt_virt) 1141 1140 return false; 1142 1141 1143 1142 /* check device tree validity */ 1144 - if (fdt_check_header(params)) 1143 + if (fdt_check_header(dt_virt)) 1145 1144 return false; 1146 1145 1147 1146 /* Setup flat device-tree pointer */ 1148 - initial_boot_params = params; 1147 + initial_boot_params = dt_virt; 1148 + initial_boot_params_pa = dt_phys; 1149 1149 of_fdt_crc32 = crc32_be(~0, initial_boot_params, 1150 1150 fdt_totalsize(initial_boot_params)); 1151 1151 ··· 1173 1171 early_init_dt_check_for_usable_mem_range(); 1174 1172 } 1175 1173 1176 - bool __init early_init_dt_scan(void *params) 1174 + bool __init early_init_dt_scan(void *dt_virt, phys_addr_t dt_phys) 1177 1175 { 1178 1176 bool status; 1179 1177 1180 - status = early_init_dt_verify(params); 1178 + status = early_init_dt_verify(dt_virt, dt_phys); 1181 1179 if (!status) 1182 1180 return false; 1183 1181
+1 -1
drivers/of/kexec.c
··· 301 301 } 302 302 303 303 /* Remove memory reservation for the current device tree. */ 304 - ret = fdt_find_and_del_mem_rsv(fdt, __pa(initial_boot_params), 304 + ret = fdt_find_and_del_mem_rsv(fdt, initial_boot_params_pa, 305 305 fdt_totalsize(initial_boot_params)); 306 306 if (ret == -EINVAL) { 307 307 pr_err("Error removing memory reservation.\n");
+3 -2
include/linux/of_fdt.h
··· 31 31 extern int __initdata dt_root_addr_cells; 32 32 extern int __initdata dt_root_size_cells; 33 33 extern void *initial_boot_params; 34 + extern phys_addr_t initial_boot_params_pa; 34 35 35 36 extern char __dtb_start[]; 36 37 extern char __dtb_end[]; ··· 71 70 /* Early flat tree scan hooks */ 72 71 extern int early_init_dt_scan_root(void); 73 72 74 - extern bool early_init_dt_scan(void *params); 75 - extern bool early_init_dt_verify(void *params); 73 + extern bool early_init_dt_scan(void *dt_virt, phys_addr_t dt_phys); 74 + extern bool early_init_dt_verify(void *dt_virt, phys_addr_t dt_phys); 76 75 extern void early_init_dt_scan_nodes(void); 77 76 78 77 extern const char *of_flat_dt_get_machine_name(void);