根節(jié)點(diǎn)
一個(gè)最簡(jiǎn)單的設(shè)備樹必須包含根節(jié)點(diǎn),cpus節(jié)點(diǎn),memory節(jié)點(diǎn)。根節(jié)點(diǎn)的名字及全路徑都是“/”,至少需要包含model和 compatible兩個(gè)屬性。model屬性我們?cè)趯傩阅枪?jié)已經(jīng)說(shuō)過(guò)是用來(lái)描述產(chǎn)品型號(hào)的,類型為字符串,推薦的格式為 “manufacturer,model-number”(非強(qiáng)制的)。根節(jié)點(diǎn)的model屬性描述的是板子的型號(hào)或者芯片平臺(tái)的型號(hào),如:
model = "Atmel AT91SAM9G20 family SoC"
model = "Samsung SMDK5420 board based on EXYNOS5420"
從軟件的層面講model屬性僅僅表示一個(gè)名字而已,沒(méi)有更多的作用。compatible屬性則不同,該屬性決定軟件如何匹配硬件對(duì)硬件進(jìn)行初始化。屬性那一節(jié)我們說(shuō)過(guò)compatible屬性的類型是字符串?dāng)?shù)組,按照范圍從小到大的順序排列,每個(gè)字符串表示一種匹配類型。根節(jié)點(diǎn)的 compatible屬性表示平臺(tái)如何匹配,比如‘compatible = "samsung,smdk5420", "samsung,exynos5420", "samsung,exynos5"’,表示軟件應(yīng)該首先匹配'samsung,smdk5420',這個(gè)是一款開發(fā)板。如果無(wú)法匹配,再試著匹配"samsung,exynos5420",這個(gè)是一款芯片平臺(tái)。如果還是無(wú)法匹配,還可以試著匹配 "samsung,exynos5",這是一個(gè)系列的芯片平臺(tái)。這里說(shuō)的匹配是指軟件根據(jù)該信息找到對(duì)應(yīng)的代碼,如對(duì)應(yīng)的初始化函數(shù)。
根節(jié)點(diǎn)表示的是整個(gè)板子或者芯片平臺(tái),所以在系統(tǒng)初始化比較早的時(shí)候就需要確認(rèn)是什么平臺(tái),怎樣初始化。對(duì)于Linux,是通過(guò)在 start_kernel函數(shù)調(diào)用setup_arch函數(shù)實(shí)現(xiàn)的。不同的架構(gòu),setup_arch函數(shù)的實(shí)現(xiàn)不同,對(duì)于arm架構(gòu),setup_arch函數(shù)源代碼位于arch/arm/kernel/setup.c中。以下是該函數(shù)的部分源代碼(代碼來(lái)自內(nèi)核版本4.4-rc7 的官方版本,本節(jié)后邊所有代碼都來(lái)自該版本)。
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函數(shù)的輸入是設(shè)備樹(DTB)首地址,返回的mdesc是描述平臺(tái)信息的結(jié)構(gòu)體。還記得我們?cè)诟攀瞿枪?jié)說(shuō)過(guò)啟動(dòng)程序如uboot把設(shè)備樹讀到內(nèi)存中,然后在啟動(dòng)內(nèi)核的同時(shí)將設(shè)備樹首地址傳給內(nèi)核,此處__atags_pointer就是啟動(dòng)程序傳給內(nèi)核的設(shè)備樹地址(此時(shí)內(nèi)存中的設(shè)備樹已經(jīng)是DTB形式)。setup_machine_fdt中的fdt是flat device tree的縮寫,fdt的意思是說(shuō)設(shè)備樹在內(nèi)存中是在一塊連續(xù)地址存儲(chǔ)的,fdt和dtb說(shuō)的都是同一個(gè)東西。setup_machine_tags是在設(shè)備樹初始化失敗的時(shí)候才調(diào)用的,所以不用管他。machine_desc和machine_name都是靜態(tài)全局變量,用來(lái)保存指針?lè)奖愫筮呉玫摹榱烁玫睦斫鈙etup_machine_fdt具體實(shí)現(xiàn)了什么功能,我們首先看下machine_desc結(jié)構(gòu)體。不同的架構(gòu),該結(jié)構(gòu)體定義差別很大,arm架構(gòu)源代碼位于arch/arm/include/asm/mach/arch.h,復(fù)制如下:
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
從以上結(jié)構(gòu)體的注釋可以看出,該結(jié)構(gòu)體包含了非常多的信息。注意第31行的dt_compat變量,該變量就是用來(lái)匹配設(shè)備樹的compatible屬性的。
setup_machine_fdt函數(shù)的實(shí)現(xiàn)也是架構(gòu)相關(guān)的,arm架構(gòu)源代碼位于arch/arm/kernel/devtree.c,復(fù)制代碼如下:
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職稱計(jì)算機(jī)考試書PowerPoint2007中 .. 定價(jià):¥45 優(yōu)惠價(jià):¥42 更多書籍 | |
2015年全國(guó)職稱計(jì)算機(jī)考試教材(2007模 .. 定價(jià):¥225 優(yōu)惠價(jià):¥213 更多書籍 |