华南俳烁实业有限公司

考試首頁(yè) | 考試用書 | 培訓(xùn)課程 | 模擬考場(chǎng) | 考試論壇  
  當(dāng)前位置:操作系統(tǒng) > Linux > 文章內(nèi)容
  

Linux基礎(chǔ)教程:Linux設(shè)備樹(Devicetree)

 [ 2016年2月18日 ] 【

根節(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 }

本文糾錯(cuò)】【告訴好友】【打印此文】【返回頂部
將考試網(wǎng)添加到收藏夾 | 每次上網(wǎng)自動(dòng)訪問(wèn)考試網(wǎng) | 復(fù)制本頁(yè)地址,傳給QQ/MSN上的好友 | 申請(qǐng)鏈接 | 意見留言 TOP
關(guān)于本站  網(wǎng)站聲明  廣告服務(wù)  聯(lián)系方式  站內(nèi)導(dǎo)航  考試論壇
Copyright © 2007-2013 中華考試網(wǎng)(Examw.com) All Rights Reserved
商河县| 谷城县| 仙桃市| 永年县| 中超| 元阳县| 望江县| 乌拉特后旗| 枞阳县| 修水县| 哈密市| 普兰店市| 香格里拉县| 广丰县| 普兰县| 太谷县| 龙岩市| 德保县| 夹江县| 德惠市| 醴陵市| 武鸣县| 盐边县| 丽江市| 江华| 日土县| 衡东县| 萍乡市| 和平区| 温宿县| 武威市| 宁强县| 上杭县| 清水河县| 吴旗县| 麻城市| 明水县| 涪陵区| 忻城县| 陆良县| 西乌|