arch/arm64/kernel/head.S
421 __primary_switched:
422 mov x28, lr // preserve LR
423 adr_l x8, vectors // load VBAR_EL1 with virtual
424 msr vbar_el1, x8 // vector table address
425 isb
426
427 // Clear BSS
428 adr_l x0, __bss_start
429 mov x1, xzr
430 adr_l x2, __bss_stop
431 sub x2, x2, x0
432 bl __pi_memset
433 dsb ishst // Make zero page visible to PTW
434
435 adr_l sp, initial_sp, x4
436 mov x4, sp
437 and x4, x4, #~(THREAD_SIZE - 1)
438 msr sp_el0, x4 // Save thread_info
439 str_l x21, __fdt_pointer, x5 // Save FDT pointer
440
441 ldr_l x4, kimage_vaddr // Save the offset between
442 sub x4, x4, x24 // the kernel virtual and
443 str_l x4, kimage_voffset, x5 // physical mappings
保存uboot 传递过来的fdt的地址到__fdt_pointer中.
arch/arm64/kernel/setup.c
229 void __init setup_arch(char **cmdline_p)
230 {
231 pr_info("Boot CPU: AArch64 Processor [%08x]\n", read_cpuid_id());
232
233 sprintf(init_utsname()->machine, ELF_PLATFORM);
234 init_mm.start_code = (unsigned long) _text;
235 init_mm.end_code = (unsigned long) _etext;
236 init_mm.end_data = (unsigned long) _edata;
237 init_mm.brk = (unsigned long) _end;
238
239 *cmdline_p = boot_command_line;
240
241 early_fixmap_init();
242 early_ioremap_init();
243
244 setup_machine_fdt(__fdt_pointer);
调用setup_machine_fdt来解析device tree
arch/arm64/kernel/setup.c
181 static void __init setup_machine_fdt(phys_addr_t dt_phys)
182 {
183 void *dt_virt = fixmap_remap_fdt(dt_phys);
184
185 if (!dt_virt || !early_init_dt_scan(dt_virt)) {
186 pr_crit("\n"
187 "Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n"
188 "The dtb must be 8-byte aligned and must not exceed 2 MB in size\n"
189 "\nPlease check your bootloader.",
190 &dt_phys, dt_virt);
191
192 while (true)
193 cpu_relax();
194 }
195
196 dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name());
197 }
调用fixmap_remap_fdt将uboot传递的物理地址转成虚拟地址,交给early_init_dt_scan来解析
/drivers/of/fdt.c
1204 bool __init early_init_dt_scan(void *params)
1205 {
1206 bool status;
1207
1208 status = early_init_dt_verify(params);
1209 if (!status)
1210 return false;
1211
1212 early_init_dt_scan_nodes();
1213 return true;
1214 }
early_init_dt_scan 中early_init_dt_verify 由于check 是否包含fdt的header。early_init_dt_scan_nodes()来做实际的解析.
1192 void __init early_init_dt_scan_nodes(void)
1193 {
1194 /* Retrieve various information from the /chosen node */
1195 of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
1196
1197 /* Initialize {size,address}-cells info */
1198 of_scan_flat_dt(early_init_dt_scan_root, NULL);
1199
1200 /* Setup memory, calling early_init_dt_add_memory_arch */
1201 of_scan_flat_dt(early_init_dt_scan_memory, NULL);
1202 }
这个函数会解析uboot 传递的bootcmd,和memory node。我们主要看memory node的解析early_init_dt_scan_memory.
1001 int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
1002 int depth, void *data)
1003 {
1004 const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
1005 const __be32 *reg, *endp;
1006 int l;
1007
1008 /* We are scanning "memory" nodes only */
1009 if (type == NULL) {
1010 /*
1011 * The longtrail doesn't have a device_type on the
1012 * /memory node, so look for the node called /memory@0.
1013 */
1014 if (!IS_ENABLED(CONFIG_PPC32) || depth != 1 || strcmp(uname, "memory@0") != 0)
1015 return 0;
1016 } else if (strcmp(type, "memory") != 0)
1017 return 0;
1018
1019 reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
1020 if (reg == NULL)
1021 reg = of_get_flat_dt_prop(node, "reg", &l);
1022 if (reg == NULL)
1023 return 0;
1024
1025 endp = reg + (l / sizeof(__be32));
1026
1027 pr_debug("memory scan node %s, reg size %d,\n", uname, l);
1028
1029 while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
1030 u64 base, size;
1031
1032 base = dt_mem_next_cell(dt_root_addr_cells, ®);
1033 size = dt_mem_next_cell(dt_root_size_cells, ®);
1034
1035 if (size == 0)
1036 continue;
1037 pr_debug(" - %llx , %llx\n", (unsigned long long)base,
1038 (unsigned long long)size);
1039
1040 early_init_dt_add_memory_arch(base, size);
1041 }
1042
1043 return 0;
1044 }
在实际使用中linux,usable-memory node 一般为空。走1029行的early_init_dt_add_memory_arch 来添加memory bank
1097 void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
1098 {
1099 const u64 phys_offset = MIN_MEMBLOCK_ADDR;
1100
1101 if (!PAGE_ALIGNED(base)) {
1102 if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
1103 pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
1104 base, base + size);
1105 return;
1106 }
1107 size -= PAGE_SIZE - (base & ~PAGE_MASK);
1108 base = PAGE_ALIGN(base);
1109 }
1110 size &= PAGE_MASK;
1111
1112 if (base > MAX_MEMBLOCK_ADDR) {
1113 pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
1114 base, base + size);
1115 return;
1116 }
1117
1118 if (base + size - 1 > MAX_MEMBLOCK_ADDR) {
1119 pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
1120 ((u64)MAX_MEMBLOCK_ADDR) + 1, base + size);
1121 size = MAX_MEMBLOCK_ADDR - base + 1;
1122 }
1123
1124 if (base + size < phys_offset) {
1125 pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
1126 base, base + size);
1127 return;
1128 }
1129 if (base < phys_offset) {
1130 pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
1131 base, phys_offset);
1132 size -= phys_offset - base;
1133 base = phys_offset;
1134 }
1135 memblock_add(base, size);
1136 }
可以看到底1135 行通过memblcok_add 来添加memory。到此为止uboot 传递给kernel的memory 信息已经转变成用memblock来描述了.