Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1432408
  • 博文数量: 1334
  • 博客积分: 645
  • 博客等级: 上士
  • 技术积分: 5762
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-25 16:56
文章分类

全部博文(1334)

文章存档

2014年(108)

2013年(1059)

2012年(169)

分类: LINUX

2012-12-26 15:16:48

大家都知道U-Boot启动的时候会将启动参数的地址放入R2中,然后再启动内核。我们看看这些参数是如何设置的。

    

    首先看两个重要的数据结构:

    第一个是global_data,定义在include/asm-arm/global_data.h文件中:

    

    typedef struct global_data {

     bd_t *bd;

     unsigned long flags;

     unsigned long baudrate;

     unsigned long have_console; /* serial_init() was called */

     unsigned long reloc_off; /* Relocation Offset */

     unsigned long env_addr; /* Address of Environment struct */

     unsigned long env_valid; /* Checksum of Environment valid? */

     unsigned long fb_base; /* base address of frame buffer */

    #ifdef CONFIG_VFD

     unsigned char vfd_type; /* display type */

    #endif

    #if 0

     unsigned long cpu_clk; /* CPU clock in Hz! */

     unsigned long bus_clk;

     unsigned long ram_size; /* RAM size */

     unsigned long reset_status; /* reset status register at boot */

    #endif

     void **jt; /* jump table */

    } gd_t;

    在同一个文件中有如下定义:

    #define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")

    在需要使用gd指针的时候,只需要加入DECLARE_GLOBAL_DATA_PTR这句话就可以了。可以知道,gd指针始终是放在r8中的。

    其中的第一个变量,bd_t结构体,定义于include/asm-arm/u-boot.h中:

    

    typedef struct bd_info {

     int bi_baudrate; /* serial console baudrate */

     unsigned long bi_ip_addr; /* IP Address */

     unsigned char bi_enetaddr[6]; /* Ethernet adress */

     struct environment_s *bi_env;

     ulong bi_arch_number; /* unique id for this board */

     ulong bi_boot_params; /* where this board expects params */

     struct /* RAM configuration */

     {

     ulong start;

     ulong size;

     } bi_dram[CONFIG_NR_DRAM_BANKS];

    #ifdef CONFIG_HAS_ETH1

     /* second onboard ethernet port */

     unsigned char bi_enet1addr[6];

    #endif

    } bd_t;

    bd_t中的变量bi_boot_params,表示传递给内核的参数的位置。

    然后看看gd和bd的初始化,在lib_arm/board.c中:

    gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

    memset ((void*)gd, 0, sizeof (gd_t));

    gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));

    memset (gd->bd, 0, sizeof (bd_t));

    说明这两个结构体在内存中的位置是在uboot的代码在往下的地址处,所以进行操作的时候不要覆盖了这个位置!

    在board/up270/up270.c中,有如下初始化:

    gd->bd->bi_boot_params = 0xa0000100;

    说明参数位置在0xa0000100。

    现在,具体看看uboot是如何(按什么格式)把参数放入内存中。

    在lib_arm/armlinux.c的do_bootm_linux函数中:

    bd_t *bd = gd->bd;

    setup_start_tag (bd);

    setup_start_tag函数定义于同一个文件中:

    static void setup_start_tag (bd_t *bd)

    {

     params = (struct tag *) bd->bi_boot_params;

     params->hdr.tag = ATAG_CORE;

     params->hdr.size = tag_size (tag_core);

     params->u.core.flags = 0;

     params->u.core.pagesize = 0;

     params->u.core.rootdev = 0;

     params = tag_next (params);

    }

    其中用到了一个重要的指针:params,这是一个指向struct tag的指针,在文件的开始处声明,可以被这个文件中的所有函数访问:

    static struct tag *params;

    struct tag的定义位于include/asm-arm/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;

    };

    包括teg_header和tag的内容。tag_header定义在同一个文件中,如下:

    struct tag_header {

     u32 size;

     u32 tag;

    };

    tag和tag_header和内核中的结构一模一样。tag_header中的tag字段表示的是这个tag的类型,在内核和Bootloader中通过一些固定的整形常量来表示:

    #define ATAG_CORE 0x54410001

    #define ATAG_NONE 0x00000000

    #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

    set_xxx_tags函数给不同的参数赋值,和set_start_tag类似,就不多说了。需要注意的一个是tag_next。这是一个宏:

    #define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))

    作用就是让param跳过刚刚设置好的tag,指向下一个tag开始的地方。所以在每个set_xxx_tag函数的最好都调用这个宏。

    具体每个tag的定义可以查看相关文件。

    这样,就把每个tag放到了从内存0xa0000100开始的地址,然后由内核根据tag_header的tag字段来识别到底是什么参数,然后再解析出来使用。

阅读(385) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~