设备树仅仅起到信息传递的作用,对配置信息的处理相对来说比较简单,即从设备树中将信息提取出来,然后赋给内核中的某一变量。
函数调用过程:
start_kernel // init/main.c
setup_arch(&command_line); // arch/arm/kernel/setup.c
mdesc = setup_machine_fdt(__atags_pointer); // arch/arm/kernel/devtree.c
early_init_dt_scan_nodes(); // drivers/of/ftd.c
/* 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);
设备树中运行时的配置信息有哪些?
在根节点中它有一个字节点chosen,在其里面有个bootargs。这个就是内核启动时的命令行参数。在里面可以指定根文件系统在哪里,第一个运行的应用程序是哪一个,内核中的打印信息从什么设备中打印出来。
memory,不同的板子起始地址和大小是不一样的,需要在设备树里面把这些地址和大小告诉内核。地址和大小放在memory节点的reg属性中。地址使用多少个32位的数据来表示,大小是用多少个32位的数据来表示,需要在根节点的address-cells和size-cells中指定。
/ {
#address-cells = <1>;
#size-cells = <1>;
memory {
device_type = "memory";
reg = <0x30000000 0x4000000 0 4096>;
};
}
比如说对于2440,它是32位的cpu,它的address用一个32位的数据来表示,它的size用1个32位的数据来表示。
a. /chosen节点中bootargs属性的值, 存入全局变量: boot_command_line
b. 确定根节点的这2个属性的值: #address-cells, #size-cells
存入全局变量: dt_root_addr_cells, dt_root_size_cells
c. 解析/memory中的reg属性, 提取出"base, size", 最终调用memblock_add(base, size);