arm64 memory node的解析

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来描述了.

你可能感兴趣的:(Linux,源码分析)