1start_kernel
start_kernel是kernel起始的地方,由bootloader拉起来。具体的调用在汇编里面,截取部分代码如下:
__mmap_switched:
// Clear BSS
adr_l x0, __bss_start
mov x1, xzr
adr_l x2, __bss_stop
sub x2, x2, x0
bl __pi_memset
adr_l sp, initial_sp, x4
mov x4, sp
and x4, x4, #~(THREAD_SIZE - 1)
msr sp_el0, x4 // Save thread_info
//将x21寄存器保存的fdt的地址赋值给__fdt_pointer
str_l x21, __fdt_pointer, x5 // Save FDT pointer
str_l x24, memstart_addr, x6 // Save PHYS_OFFSET
mov x29, #0
#ifdef CONFIG_KASAN
bl kasan_early_init
#endif
//跳转到start_kernel函数地址
b start_kernel
ENDPROC(__mmap_switched)
2.setup_arch
void __init setup_arch(char **cmdline_p)
{
pr_info("Boot CPU: AArch64 Processor [%08x]\n", read_cpuid_id());
...
*cmdline_p = boot_command_line;
early_fixmap_init();
early_ioremap_init();
//这里的__fdt_pointer已经在上面汇编.S文件里面赋值了
setup_machine_fdt(__fdt_pointer);
...
if (acpi_disabled) {
unflatten_device_tree();
psci_dt_init();
} else {
psci_acpi_init();
}
...
3.setup_machine_fdt
static void __init setup_machine_fdt(phys_addr_t dt_phys)
{
//获取fdt结构体的头部地址
void *dt_virt = fixmap_remap_fdt(dt_phys);
if (!dt_virt || !early_init_dt_scan(dt_virt)) {
pr_crit("\n"
"Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n"
"The dtb must be 8-byte aligned and must not exceed 2 MB in size\n"
"\nPlease check your bootloader.",
&dt_phys, dt_virt);
while (true)
cpu_relax();
}
dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name());
}
上面这个函数大体作用如下:
1.获取dts的头部地址
2.调用fdt函数进行下一步的扫描
4.early_init_dt_scan
bool __init early_init_dt_scan(void *params)
{
bool status;
//检查这个地址是否是合法地址,就是其魔法数据是否一致。检测通过后将这个地址赋值给全局变量,后面扫描node都是通过这个地址来的
status = early_init_dt_verify(params);
if (!status)
return false;
//进行早期扫描
early_init_dt_scan_nodes();
return true;
}
5.early_init_dt_scan_nodes
void __init early_init_dt_scan_nodes(void)
{
/* Retrieve various information from the /chosen node */
of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
/* Initialize {size,address}-cells info */
of_scan_flat_dt(early_init_dt_scan_root, NULL);
/* Setup memory, calling early_init_dt_add_memory_arch */
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
}
通过上面的代码可以看出,这个函数里面明显有回调。接下来看其实现
int __init of_scan_flat_dt(int (*it)(unsigned long node,
const char *uname, int depth,
void *data),
void *data)
{
//这个initial_boot_params就是检查通过后赋给的头地址
const void *blob = initial_boot_params;
const char *pathp;
int offset, rc = 0, depth = -1;
//扫描所有节点
for (offset = fdt_next_node(blob, -1, &depth);
offset >= 0 && depth >= 0 && !rc;
offset = fdt_next_node(blob, offset, &depth)) {
pathp = fdt_get_name(blob, offset, NULL);
if (*pathp == '/')
pathp = kbasename(pathp);
//调用回调函数处理扫描后得到的数据
rc = it(offset, pathp, depth