前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux 设备树展开 unflatten_device_tree 和 设备创建

Linux 设备树展开 unflatten_device_tree 和 设备创建

原创
作者头像
bingwang
发布2024-03-15 16:42:06
3970
发布2024-03-15 16:42:06
举报
文章被收录于专栏:Linux kernelLinux kernel

1 uboot将Linux DTB二进制文件传递给Linux kernel, Linux kernel在启动过程中,会将DTB二进制文件加载进内存,并将device tree展开,通过深度遍历整棵树,填充每个节点和属性, 调用过程start_kernel() -> setup_arch() -> unflatten_device_tree()

代码语言:C
复制
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,

代码语言:bash
复制
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

代码语言:bash
复制
dtc -I fs -O dts /sys/firmware/devicetree/base/  -o linux_board.dts

调用过程如下:

代码语言:C
复制
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。

代码语言:C
复制
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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档