Saturday, May 26, 2012

Bootloader與Kernel間參數傳遞機制




Tag list 被用來在 bootloader  linux kernel 之間傳遞參數,這裡分析一下相關的數據結構,主要包括兩個部分: Tag list  Tag parser list 
先來看 Tag list 
這個 list 是在 bootloader 中填充的,其數據結構定義在 bootloader  linux kernel 中均有定義,是一致的。我們來看 linux kernel 中的定義:

top/arch/arm/include/asm/setup.h
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;
    } u;
} ;
struct tag_header {
    __u32 size;
    __u32 tag;
} ;

其中 tag 的取值如下,暫且稱之為 tag type :

# define ATAG_CORE            0x54410001
# define ATAG_MEM            0x54410002
# define ATAG_VIDEOTEXT        0x54410003
# define ATAG_RAMDISK        0x54410004
# define ATAG_INITRD            0x54410005
# define ATAG_INITRD2        0x54420005
# define ATAG_SERIAL            0x54410006
# define ATAG_REVISION        0x54410007
# define ATAG_VIDEOLFB        0x54410008
# define ATAG_CMDLINE        0x54410009
# define ATAG_ACORN            0x41000101
# define ATAG_MEMCLK        0x41000402

其數據結構用圖形表示就是:
 
其實就是一個鏈表,通過 Tag size 以及當前 tag 的位置來定位下一個 tag 的位置。而且第一個 tag 的類型必然是 ATAG_CORE 

參數就是按照這個結構進行傳遞的,那麼 kernel 是如何進行解析的呢?
我們來看 tag parser list:
同樣是在 top/arch/arm/include/asm/setup.h ,有如下定義:

top/arch/arm/include/asm/setup.h
struct tagtable {
    __u32 tag;
    int ( * parse) ( const struct tag * ) ;
} ;
# define __tag __used __attribute__( ( __section__( ".taglist.init" ) ) )
# define __tagtable( tag, fn) /
static struct tagtable __tagtable_# # fn __tag = { tag, fn }

從上面知道, tag parser list 存在於 .taglist.init 段,他們的定義將通過宏 __tagtable(tag, fn) 的形式給出,比如在 top/arch/arm/kernel/setup.c 中:

top/arch/arm/kernel/setup.c
__tagtable( ATAG_CORE, parse_tag_core) ;
__tagtable( ATAG_MEM, parse_tag_mem32) ;
__tagtable( ATAG_VIDEOTEXT, parse_tag_videotext) ;
__tagtable( ATAG_RAMDISK, parse_tag_ramdisk) ;
__tagtable( ATAG_SERIAL, parse_tag_serialnr) ;
__tagtable( ATAG_REVISION, parse_tag_revision) ;
__tagtable( ATAG_CMDLINE, parse_tag_cmdline) ;

通過這樣的定義,每個 tag table 的表項就自 動連接在了一起,而且存在於同一個段中。如圖所示:
可以看到,所有支持的 tag parser 都列在這 裡了。
 kernel 中,將針對 tag list 中的每一項在這個 tag parser list 中進行查找,如果有 對應的處理項,則調用解析函數,於是就完成了參數的傳遞以及解析!

注意:
 top/arch/arm/kernel/head-common.s 中會對從 bootloader 傳遞過來的 tag list 進行合法性判斷:
以標號 __vet_atags 開始的一段處理就要是 判斷 tag list 的第一項是否是 ATAG_CORE ,同時判斷長度是否越界!

No comments: