1. 程式人生 > >uboot給linux傳遞引數流程

uboot給linux傳遞引數流程

是用mindmanager轉的,格式有點不太好。

1 ATAG

1.1 為什麼用ATAG

         ubootatagkernel傳遞資訊

         atag的定義可以在ubootinclude/asm/setup.h 中找到對應linux中的定義位於arch/arm/include/asm/setup.h中。兩者的定義要相同。

         引數連結串列必須以ATAG_CORE 開始,以ATAG_NONE 結束。這裡的ATAG_CORE,ATAG_NONE 是各個引數的標記,本身是一個32 位值,例如在setup.h中的定義:

         /* The list must start with an ATAG_CORE node */

          #define ATAG_CORE0x54410001

         其它的引數標記還包括: ATAG_MEM32 , ATAG_INITRD , ATAG_RAMDISK ,ATAG_COMDLINE 等。每個引數標記就代表一個引數結構體由各個引數結構體構成了引數連結串列。引數連結串列的結構體為:

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_initrdinitrd;

     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_memclkmemclk;

} u;

};

引數結構體包括兩個部分,一個是 tag_header 結構體,一個是u 聯合體。

tag_header 結構體的定義如下

struct tag_header 

{

u32 size;

u32 tag;

};

                其中 size表示整個tag 結構體的大小(用字的個數來表示而不是位元組的個數)等於tag_header 的大小加上u 聯合體的大小例如引數結構體ATAG_CORE size= (sizeof(tag->tag_header)+sizeof(tag->u.core))>>2一般通過函式 tag_size(struct * tag_xxx)來獲得每個引數結構體的size。其中tag:表示整個tag 結構體的標記,如:ATAG_CORE等。

1.2 uboot傳遞ATAG

        在uboot下的do_bootm_linux函式中,呼叫:

        theKernel (0, machid, bd->bi_boot_params);

        來啟動核心。

        將bi_boot_paramsATAG作為引數傳遞給linux核心。

       呼叫的時候,R00R1machidR2ATAG的地址。

       同時在該函式中,會看到一堆的setup_xxx_tag的函式。cmdline就是這樣傳的。

1.3 linux接收ATAG

       在arch/arm/kernel/head.S中的stext中有這麼一句:

  /*

   * r1 = machine no, r2 = atags or dtb,

   * r8 = phys_offset, r9 = cpuid, r10 = procinfo

   */

  bl __vet_atags

       與uboottheKernel 的引數是對應的。

       __vet_atags是讀r2地址上的sizetag看是否是正確的ATAG_CORE

2 linux接收ATAG流程

2.1 stext (arch/arm/kernel/head.S)

2.2 __mmap_switched (arch/arm/kernel/head-common.S)

str  r2, [r6]

.long  __atags_pointer       @ r6

ATAG指標存到__atags_pointer變數中。

2.3 start_kernel init/mai.c

2.3.1 setup_arch(&command_line); 在這裡面將command_line指向static char __initdata cmd_line[COMMAND_LINE_SIZE];

setup_machine_tags

__atags_pointer得到tags

  if (__atags_pointer)

     tags = phys_to_virt(__atags_pointer);

  else if (mdesc->atag_offset)

     tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);

。。。。

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

     if (meminfo.nr_banks != 0)

       squash_mem_tags(tags);

     save_atags(tags);

     parse_tags(tags);解析tags

  }

parse_tags 解析tags

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;

}

/arch/arm/kernel/vmlinux.lds中有__tagtable_begin

 .init.tagtable : { 

  __tagtable_begin = .;

  *(.taglist.init)

  __tagtable_end = .;

 }

所有的解析函式用__tagtable宣告:

__tagtable(ATAG_CORE, parse_tag_core);

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

#define __tagtable(tag, fn) \

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

所以所有的解析函式都是放在了taglist.init區域。

parse_tag_cmdline函式中,將cmdline複製到default_command_line變數中。

strlcat(default_command_line, tag->u.cmdline.cmdline,

儲存到boot_command_line

setup_machine_tags中:

strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);

儲存到command_line

setup_arch中,將引數command_line指向cmd_line

  /* populate cmd_line too for later use, preserving boot_command_line */

  strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);

  *cmdline_p = cmd_line;