1 uboot将Linux DTB二进制文件传递给Linux kernel, Linux kernel在启动过程中,会将DTB二进制文件加载进内存,并将device tree展开,通过深度遍历整棵树,填充每个节点和属性, 调用过程start_kernel() -> setup_arch() -> unflatten_device_tree()
asmlinkage __visible void __init __no_sanitize_address start_kernel(void) // init/main.c
void __init __no_sanitize_address setup_arch(char **cmdline_p) //arch/arm64/kernel/setup.c
if (acpi_disabled)
unflatten_device_tree(); //drivers/of/fdt.c
__unflatten_device_tree(initial_boot_params, NULL, &of_root,
early_init_dt_alloc_memory_arch, false);
size = unflatten_dt_nodes(blob, NULL, dad, NULL);·
ret = unflatten_dt_nodes(blob, mem, dad, mynodes);
ret = populate_node(blob, offset, &mem, nps[depth],&nps[depth+1], dryrun);
populate_properties(blob, offset, mem, np, pathp, dryrun);
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
of_alias_scan(early_init_dt_alloc_memory_arch);
unittest_unflatten_overlay_base();
2 通过device_node, 创建/sys/firmware/devicetree/base,
root@Linux:~ >ls -al /proc/device-tree
lrwxrwxrwx 1 root root 29 Mar 1 07:54 /proc/device-tree -> /sys/firmware/devicetree/base
root@Linux:~ >
通过反编译devicetree,可以得到整个板子的final Device tree
dtc -I fs -O dts /sys/firmware/devicetree/base/ -o linux_board.dts
调用过程如下:
start_kernel()
arch_call_rest_init();
rest_init();
pid = user_mode_thread(kernel_init, NULL, CLONE_FS);
kernel_init_freeable();
do_basic_setup();
cpuset_init_smp();
driver_init();
/* These are the core pieces */
bdi_init(&noop_backing_dev_info);
devtmpfs_init();
devices_init();
buses_init();
classes_init();
firmware_init();
hypervisor_init();
/* These are also core pieces, but must come after the
* core core pieces.
*/
of_core_init();
proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
platform_bus_init();
auxiliary_bus_init();
cpu_dev_init();
memory_dev_init();
node_dev_init();
container_dev_init();
init_irq_proc();
do_ctors();
do_initcalls();
3 do_initcalls是Linux内核初始化过程的一个重要部分,负责调用内核启动时需要执行的一系列初始化函数。这些函数被称为"initcalls",它们按照指定的顺序依次执行,以初始化内核各个部分的数据结构、驱动程序和服务。module_platform_driver() 和 module_i2c_driver等函数会在do_initcalls()中被调用。platform driver在加载过程中会选择性的将device node 创建成device。
static void __init do_initcalls(void)
{
int level;
size_t len = strlen(saved_command_line) + 1;
char *command_line;
command_line = kzalloc(len, GFP_KERNEL);
if (!command_line)
panic("%s: Failed to allocate %zu bytes\n", __func__, len);
for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) {
/* Parser modifies command_line, restore it each time */
strcpy(command_line, saved_command_line);
do_initcall_level(level, command_line);
}
kfree(command_line);
}
static void __init do_initcall_level(int level, char *command_line)
{
initcall_entry_t *fn;
parse_args(initcall_level_names[level],
command_line, __start___param,
__stop___param - __start___param,
level, level,
NULL, ignore_unknown_bootoption);
trace_initcall_level(initcall_level_names[level]);
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
do_one_initcall(initcall_from_entry(fn));
}
int __init_or_module do_one_initcall(initcall_t fn)
{
int count = preempt_count();
char msgbuf[64];
int ret;
if (initcall_blacklisted(fn))
return -EPERM;
do_trace_initcall_start(fn);
ret = fn();
do_trace_initcall_finish(fn, ret);
msgbuf[0] = 0;
if (preempt_count() != count) {
sprintf(msgbuf, "preemption imbalance ");
preempt_count_set(count);
}
if (irqs_disabled()) {
strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
local_irq_enable();
}
WARN(msgbuf[0], "initcall %pS returned with %s\n", fn, msgbuf);
add_latent_entropy();
return ret;
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。