根节点
一个最简单的设备树必须包含根节点,cpus节点,memory节点。根节点的名字及全路径都是“/”,至少需要包含model和 compatible两个属性。model属性我们在属性那节已经说过是用来描述产品型号的,类型为字符串,推荐的格式为 “manufacturer,model-number”(非强制的)。根节点的model属性描述的是板子的型号或者芯片平台的型号,如:
model = "Atmel AT91SAM9G20 family SoC"
model = "Samsung SMDK5420 board based on EXYNOS5420"
从软件的层面讲model属性仅仅表示一个名字而已,没有更多的作用。compatible属性则不同,该属性决定软件如何匹配硬件对硬件进行初始化。属性那一节我们说过compatible属性的类型是字符串数组,按照范围从小到大的顺序排列,每个字符串表示一种匹配类型。根节点的 compatible属性表示平台如何匹配,比如‘compatible = "samsung,smdk5420", "samsung,exynos5420", "samsung,exynos5"’,表示软件应该首先匹配'samsung,smdk5420',这个是一款开发板。如果无法匹配,再试着匹配"samsung,exynos5420",这个是一款芯片平台。如果还是无法匹配,还可以试着匹配 "samsung,exynos5",这是一个系列的芯片平台。这里说的匹配是指软件根据该信息找到对应的代码,如对应的初始化函数。
根节点表示的是整个板子或者芯片平台,所以在系统初始化比较早的时候就需要确认是什么平台,怎样初始化。对于Linux,是通过在 start_kernel函数调用setup_arch函数实现的。不同的架构,setup_arch函数的实现不同,对于arm架构,setup_arch函数源代码位于arch/arm/kernel/setup.c中。以下是该函数的部分源代码(代码来自内核版本4.4-rc7 的官方版本,本节后边所有代码都来自该版本)。
935 void __init setup_arch(char **cmdline_p)
936 {
937 const struct machine_desc *mdesc;
938
939 setup_processor();
940 mdesc = setup_machine_fdt(__atags_pointer);
941 if (!mdesc)
942 mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
943 machine_desc = mdesc;
944 machine_name = mdesc->name;
第940行setup_machine_fdt函数的输入是设备树(DTB)首地址,返回的mdesc是描述平台信息的结构体。还记得我们在概述那节说过启动程序如uboot把设备树读到内存中,然后在启动内核的同时将设备树首地址传给内核,此处__atags_pointer就是启动程序传给内核的设备树地址(此时内存中的设备树已经是DTB形式)。setup_machine_fdt中的fdt是flat device tree的缩写,fdt的意思是说设备树在内存中是在一块连续地址存储的,fdt和dtb说的都是同一个东西。setup_machine_tags是在设备树初始化失败的时候才调用的,所以不用管他。machine_desc和machine_name都是静态全局变量,用来保存指针方便后边引用的。为了更好的理解setup_machine_fdt具体实现了什么功能,我们首先看下machine_desc结构体。不同的架构,该结构体定义差别很大,arm架构源代码位于arch/arm/include/asm/mach/arch.h,复制如下:
27 struct machine_desc {
28 unsigned int nr; /* architecture number */
29 const char *name; /* architecture name */
30 unsigned long atag_offset; /* tagged list (relative) */
31 const char *const *dt_compat; /* array of device tree
32 * 'compatible' strings */
33
34 unsigned int nr_irqs; /* number of IRQs */
35
36 #ifdef CONFIG_ZONE_DMA
37 phys_addr_t dma_zone_size; /* size of DMA-able area */
38 #endif
39
40 unsigned int video_start; /* start of video RAM */
41 unsigned int video_end; /* end of video RAM */
42
43 unsigned char reserve_lp0 :1; /* never has lp0 */
44 unsigned char reserve_lp1 :1; /* never has lp1 */
45 unsigned char reserve_lp2 :1; /* never has lp2 */
46 enum reboot_mode reboot_mode; /* default restart mode */
47 unsigned l2c_aux_val; /* L2 cache aux value */
48 unsigned l2c_aux_mask; /* L2 cache aux mask */
49 void (*l2c_write_sec)(unsigned long, unsigned);
50 const struct smp_operations *smp; /* SMP operations */
51 bool (*smp_init)(void);
52 void (*fixup)(struct tag *, char **);
53 void (*dt_fixup)(void);
54 long long (*pv_fixup)(void);
55 void (*reserve)(void);/* reserve mem blocks */
56 void (*map_io)(void);/* IO mapping function */
57 void (*init_early)(void);
58 void (*init_irq)(void);
59 void (*init_time)(void);
60 void (*init_machine)(void);
61 void (*init_late)(void);
62 #ifdef CONFIG_MULTI_IRQ_HANDLER
63 void (*handle_irq)(struct pt_regs *);
64 #endif
65 void (*restart)(enum reboot_mode, const char *);
66 };
67
从以上结构体的注释可以看出,该结构体包含了非常多的信息。注意第31行的dt_compat变量,该变量就是用来匹配设备树的compatible属性的。
setup_machine_fdt函数的实现也是架构相关的,arm架构源代码位于arch/arm/kernel/devtree.c,复制代码如下:
203 /**
204 * setup_machine_fdt - Machine setup when an dtb was passed to the kernel
205 * @dt_phys: physical address of dt blob
206 *
207 * If a dtb was passed to the kernel in r2, then use it to choose the
208 * correct machine_desc and to setup the system.
209 */
210 const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
211 {
212 const struct machine_desc *mdesc, *mdesc_best = NULL;
213
214 #ifdef CONFIG_ARCH_MULTIPLATFORM
215 DT_MACHINE_START(GENERIC_DT, "Generic DT based system")
216 MACHINE_END
217
218 mdesc_best = &__mach_desc_GENERIC_DT;
219 #endif
220
221 if (!dt_phys || !early_init_dt_verify(phys_to_virt(dt_phys)))
222 return NULL;
223
224 mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach);
225
226 if (!mdesc) {
227 const char *prop;
228 int size;
229 unsigned long dt_root;
230
231 early_print("\nError: unrecognized/unsupported "
232 "device tree compatible list:\n[ ");
233
234 dt_root = of_get_flat_dt_root();
235 prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
236 while (size > 0) {
237 early_print("'%s' ", prop);
238 size -= strlen(prop) + 1;
239 prop += strlen(prop) + 1;
240 }
241 early_print("]\n\n");
242
243 dump_machine_table(); /* does not return */
244 }
245
246 /* We really don't want to do this, but sometimes firmware provides buggy data */
247 if (mdesc->dt_fixup)
248 mdesc->dt_fixup();
249
250 early_init_dt_scan_nodes();
251
252 /* Change machine number to match the mdesc we're using */
253 __machine_arch_type = mdesc->nr;
254
255 return mdesc;
256 }
2015职称计算机考试书PowerPoint2007中 .. 定价:¥45 优惠价:¥42 更多书籍 | |
2015年全国职称计算机考试教材(2007模 .. 定价:¥225 优惠价:¥213 更多书籍 |