一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

arm-linux之uboot向內(nèi)核傳遞參數(shù)(setup_arch分析)

 zzjiwang 2016-06-26

拋開uboot不談,先看看uboot給內(nèi)核傳遞的參數(shù)是什么樣的東西,在arch/arm/kernel/setup.h文件中的struct tag結(jié)構(gòu)體:

struct tag {

       struct tag_header hdr;

       union {

              struct tag_core            core;

              struct tag_mem32       mem;

              struct tag_videotext    videotext;

              struct tag_ramdisk       ramdisk;

              struct tag_initrd    initrd;

              struct tag_serialnr       serialnr;

              struct tag_revision      revision;

              struct tag_videolfb      videolfb;

              struct tag_cmdline       cmdline;

              /*

               * Acorn specific

               */

              struct tag_acorn   acorn;

              /*

               * DC21285 specific

               */

              struct tag_memclk       memclk;

               /*

        * Marvell specific

      */

              struct tag_mv_uboot     mv_uboot;

             // board info

              struct tag_board_info board_info;

              } u;

};

Uboot傳遞給內(nèi)核的參數(shù),都是一些對(duì)一個(gè)個(gè)的設(shè)備參數(shù)的描述,用于對(duì)內(nèi)核進(jìn)行相應(yīng)的初始化,參數(shù)的具體內(nèi)容暫時(shí)無需關(guān)心,有個(gè)大致印象就行,下面一步步看內(nèi)核是怎么接收uboot參數(shù)的,在setup_arch函數(shù)中首先定義struct tag *型指針變量tags

struct tag *tags = (struct tag *)&init_tags;

tags是重點(diǎn),它就是內(nèi)核接收uboot參數(shù)的東西!

init_tags是個(gè)全局靜態(tài)變量,就在本文件(arch/arm/kernel/setup.c)定義如下:

static struct init_tags {

       struct tag_header hdr1;

       struct tag_core   core;

       struct tag_header hdr2;

       struct tag_mem32  mem;

       struct tag_header hdr3;

} init_tags __initdata = {

       { tag_size(tag_core), ATAG_CORE },

       { 1, PAGE_SIZE, 0xff },

       { tag_size(tag_mem32), ATAG_MEM },

       { MEM_SIZE, PHYS_OFFSET },

       { 0, ATAG_NONE }

};

在定義結(jié)構(gòu)體init_tags的同時(shí)聲明了靜態(tài)全局變量init_tags,記住這個(gè)靜態(tài)全局變量不重要,繼續(xù)往下看,還在setup_arch函數(shù)中接下來幾行:

if (__atags_pointer)

       tags = phys_to_virt(__atags_pointer);

else if (mdesc->boot_params)

       tags = phys_to_virt(mdesc->boot_params);

這個(gè)是重點(diǎn),這里根據(jù)情況判斷tags接收uboot參數(shù)的來源,if中說明來源是uboot傳遞,else if說明是由內(nèi)核部分的代碼(即代碼寫死,不是從uboot),這個(gè)是重點(diǎn):

先看看這個(gè)__atags_pointer是什么:

__atags_pointer,定義在匯編文件arch/arm/kernel/head-common.S__switch_data子程序(可參考“ARM架構(gòu)內(nèi)核啟動(dòng)分析-head.S(1.4、stext分析之打開MMU并跳到start kernel”一文)),在內(nèi)核代碼源頭stext運(yùn)行前,由arm寄存器R2保存要傳遞給內(nèi)核的參數(shù)的地址,當(dāng)stext運(yùn)行到子程序__switch_data時(shí),定義變量__atags_pointer保存這個(gè)地址,即__atags_pointer保存了uboot要傳遞給內(nèi)核的參數(shù)的地址,所以這里讓tags獲取__atags_pointer的轉(zhuǎn)換后的虛擬地址,即可訪問。

有的時(shí)候,可能不需要從uboot傳遞參數(shù)到內(nèi)核,也就是說這些參數(shù)寫死在內(nèi)核里而不是在uboot里,那么就可以寫死,寫死是寫死在machine_desc變量的boot_params成員,可以把地址值賦給這個(gè)成員,即可訪問。

一般來說還是從__atags_pointer傳遞,即從uboot傳遞的幾率比較大,我手頭這個(gè)marvell設(shè)備就是如此,畢竟在內(nèi)核代碼的machine_desc變量寫死本質(zhì)還是uboot里存放這些參數(shù)的物理地址,一旦uboot里這些參數(shù)的物理地址變動(dòng),同時(shí)還要改machine_desc變量的這個(gè)值,不如自動(dòng)傳遞方便。

搞明白了參數(shù)的傳遞,下面看內(nèi)核代碼如何使用這些參數(shù),接著setup_arch函數(shù)往下看,如下:

if (tags->hdr.tag != ATAG_CORE)

       convert_to_tag_list(tags);

if (tags->hdr.tag != ATAG_CORE)

       tags = (struct tag *)&init_tags;

結(jié)合本文最前面的struct tags結(jié)構(gòu)體,它的第一個(gè)成員如下:

struct tag_header hdr

記住,struct tag_header的成員tag,如果不等于宏ATAG_CORE的值(arch/arm/kernel/setup.h定義),說明是舊式的參數(shù),需要轉(zhuǎn)換成新格式的參數(shù),所以調(diào)用函數(shù)convert_to_tag_list;如果轉(zhuǎn)換后依然是舊格式的,那么就沒法使用這個(gè)參數(shù)了,改為使用默認(rèn)參數(shù),就是本文開始時(shí)描述的那個(gè)不重要的init_tags靜態(tài)全局變量。

convert_to_tag_list這個(gè)函數(shù)內(nèi)容可以不看,因?yàn)橐粋€(gè)正常的uboot是不會(huì)傳遞舊格式的參數(shù),這里重在理解道理即可。

后面的fixup部分,其實(shí)可以不關(guān)注了,fixup用于內(nèi)核代碼固定的寫死meminfo,而不是由uboot傳遞參數(shù)配置meminfo,應(yīng)該說很少有使用fixup成員寫死meminfo的情況。

言歸正傳,看下面的代碼:

if (tags->hdr.tag == ATAG_CORE) {

       if (meminfo.nr_banks != 0)

              squash_mem_tags(tags);

       save_atags(tags);

    parse_tags(tags);

}

首先全局變量meminfo在這時(shí)候還沒有被初始化,其用于指示物理內(nèi)存bank個(gè)數(shù)的成員nr_banks肯定為0,繼續(xù)往下看,save_atags將把tags里的內(nèi)容拷貝給全局變量atags_copy,重點(diǎn)是下面的parse_tags

觀察parse_tags函數(shù)的實(shí)現(xiàn),這時(shí)必須要搞懂tags指針變量里面的內(nèi)容是什么了,tags指針變量實(shí)際上指向了多個(gè)的struct tags型變量,觀察struct tags結(jié)構(gòu)體即可發(fā)現(xiàn),它是一個(gè)struct tags_header加一個(gè)聯(lián)合的結(jié)構(gòu),這就很明確了,再看parse_tags的實(shí)現(xiàn),它就是對(duì)每一個(gè)它指向的struct tags型變量調(diào)用函數(shù)parse_tag,這個(gè)函數(shù)實(shí)際解析struct tags型變量,終于到重點(diǎn)了,看它的實(shí)現(xiàn):

static int __init parse_tag(const struct tag *tag)

{

       extern struct tagtable __tagtable_begin, __tagtable_end;

       struct tagtable *t;

  

       for (t = &__tagtable_begin; t < &__tagtable_end; t++)

              if (tag->hdr.tag == t->tag) {

                     t->parse(tag);

                     break;

              }

       return t < &__tagtable_end;

}

先看“extern struct tagtable __tagtable_begin, __tagtable_end;”,可參考本人博客前面的描述內(nèi)核匯編啟動(dòng)階段的文章,可以立即感覺到這兩個(gè)東西是在鏈接腳本vmlinux.lds.S中定義的,并且是卡住某一代碼段便于給C函數(shù)調(diào)用;

首先看這兩個(gè)變量在哪里定義,卡住了哪部分內(nèi)容:

__tagtable_begin = .;

       *(.taglist.init)

__tagtable_end = .;

可見是卡住了“.taglist.init”段的全部?jī)?nèi)容,那這個(gè)段里是什么東西呢?在這里,arch/include/asm/setup.h文件中,有這么些內(nèi)容:

#define __tag __used __attribute__((__section__(".taglist.init")))

#define __tagtable(tag, fn) \

static struct tagtable __tagtable_##fn __tag = { tag, fn }

第一行的意思是:宏__tag,定義為__used __attribute__((__section__(".taglist.init")))

第二、三行的意思是:定義宏__tagtable(tag, fn)static struct tagtable __tagtable_##fn __tag = { tag, fn },意思是:在".taglist.init"段中,創(chuàng)建struct tagtable的靜態(tài)變量__tagtable_##fn(fn是什么由參數(shù)指定,后面的__tag起變量描述符的作用,它真正指定了這個(gè)靜態(tài)變量是在".taglist.init"段中鏈接),并賦初值,賦的值就是宏函數(shù)定義時(shí)的參數(shù)tagfn。

說白了就是,以__tagtable(tag, fn)形式定義的宏,實(shí)際是在".taglist.init"段中,創(chuàng)建struct tagtable的靜態(tài)變量,并賦初值給這個(gè)變量,賦的值就是這個(gè)宏的兩個(gè)參數(shù)tagfn。

arch/arm/mach-XXX/core.c、arch/arm/mm/init.carch/arm/kernel/setup.c文件中,定義了很多__tagtable(XXXXXX)這樣的宏,這些宏干什么的?就是解析uboot傳遞給內(nèi)核的參數(shù)用的(當(dāng)然不僅它們解析,后面還有別的代碼解析),現(xiàn)在回到parse_tag函數(shù),應(yīng)該很好理解了,它對(duì)傳遞進(jìn)來的參數(shù),利用__tagtable_begin__tagtable_end,使用所有定義的__tagtable(tag, fn)對(duì)其進(jìn)行遍歷,一旦發(fā)現(xiàn)__tagtable(tag, fn)tag和傳遞進(jìn)來的參數(shù)的參數(shù)頭的tag(struct tags_headertag成員)一樣,就用該__tagtable(tag, fn)fn即解析函數(shù)進(jìn)行解析,這里的marvell設(shè)備的實(shí)現(xiàn)一共定義了11個(gè)這樣的__tagtable(tag, fn),就不一列出了,這里具體描述兩個(gè)比較重要的:

parse_tag_mem32

這個(gè)是初始化meminfo即讓內(nèi)核了解設(shè)備的物理內(nèi)存情況的,它將調(diào)用函數(shù)arm_add_memory,參數(shù)就是uboot傳遞的相應(yīng)參數(shù)的mem結(jié)構(gòu),包括start成員和size成員即物理內(nèi)存起始地址和內(nèi)存大小,arm_add_memory這個(gè)函數(shù)比較簡(jiǎn)單,它把這兩個(gè)參數(shù)寫進(jìn)meminfobank中,并更新benk個(gè)數(shù)值nr_banks。對(duì)于很多小型arm嵌入式應(yīng)用,一般只有一個(gè)物理內(nèi)存,也就只調(diào)用該函數(shù)一次。重中之重的meminfo就是在這里初始化的!

parse_tag_cmdline

它把uboot傳遞的“命令行參數(shù)”賦給靜態(tài)全局變量default_command_line,這個(gè)變量是干什么用的?它很重要,先看看這里的marvell設(shè)備的情況:

ttyS0,115200 ubi.mtd=3 root=ubi0:rootfs rootfstype=ubifs mtdparts=nand_flash:0x200000@0x0(uboot)ro,0x200000@0x200000(env)rw,0x500000@0x400000(kernel0)ro,0x2800000@0x900000(rootfs0)ro,0x500000@0x3100000(kernel1)ro,0x2800000@0x3600000(rootfs1)ro,0x2200000@0x5e00000(config)rw rw)

想必會(huì)明白這個(gè)default_command_line是干什么的了,這里只是拷貝到這個(gè)變量中去,后面還有其他代碼進(jìn)一步解析它。

看完這一部分,接下來是另一部分的解析,接著setup_arch函數(shù)往下看:

parse_cmdline(cmdline_p, from);

form指針變量在setup_arch函數(shù)一開始就指向了default_command_line,到這應(yīng)該能感覺到現(xiàn)在要解析default_command_line了,看parse_cmdline的實(shí)現(xiàn):

無需仔細(xì)看里邊關(guān)于用空格定位每一個(gè)參數(shù)等細(xì)節(jié),重點(diǎn)是看它是由誰來解析的,可以看到兩個(gè)變量__early_begin__early_end,和上面類似,故伎重演,在vmlinux.lds.S中它倆卡住了“.early_param.init”段,這個(gè)段所鏈接的內(nèi)容同樣是在arch/arm/kernel/setup.h中規(guī)定,道理完全一樣具體就不描述了,最終是由__early_param宏解析。具體都在解析些什么內(nèi)容即解析后如何操作,也都是一些和設(shè)備參數(shù)相關(guān)的諸如內(nèi)存、緩存等等的信息,在這里也不詳細(xì)描述了。

總之,對(duì)于uboot向內(nèi)核傳遞參數(shù),需要理解的一個(gè)是內(nèi)核對(duì)uboot所傳參數(shù)的接收、解析的機(jī)制和方法,另外需要了解下所解析和操作的內(nèi)容,尤其對(duì)于一些重要參數(shù)典型如內(nèi)存參數(shù)的解析和操作需要細(xì)致理解。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    丰满人妻一二三区av| 日韩欧美综合中文字幕| 暴力三级a特黄在线观看| av在线免费观看一区二区三区| 国产高清三级视频在线观看| 亚洲一区二区三区四区| 人妻巨大乳一二三区麻豆| 国产一区二区不卡在线播放 | 日韩性生活视频免费在线观看| 国产日韩精品欧美综合区| 亚洲国产精品久久网午夜| 午夜精品在线观看视频午夜| 久久热九九这里只有精品| 热情的邻居在线中文字幕| 日韩高清毛片免费观看| 好吊日在线观看免费视频| 麻豆91成人国产在线观看| 麻豆国产精品一区二区| 99少妇偷拍视频在线| 激情五月天免费在线观看| 亚洲a级一区二区不卡| 在线观看免费无遮挡大尺度视频| 亚洲欧美日韩精品永久| 国产精品十八禁亚洲黄污免费观看| 熟女白浆精品一区二区| 色丁香一区二区黑人巨大| 欧洲一区二区三区蜜桃| 国产中文字幕久久黄色片| 99国产精品国产精品九九| 成人精品视频一区二区在线观看 | 亚洲少妇一区二区三区懂色| 精品国产品国语在线不卡| 丝袜破了有美女肉体免费观看| 国产又粗又长又大高潮视频| 欧美黄色黑人一区二区| 午夜亚洲少妇福利诱惑| 久久国产精品热爱视频| 国产一区二区三区精品免费| 日本久久中文字幕免费| 亚洲a级一区二区不卡| 厕所偷拍一区二区三区视频|