Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1658707
  • 博文数量: 174
  • 博客积分: 5493
  • 博客等级: 上校
  • 技术积分: 5802
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-05 15:13
个人简介

炼狱,是为追逐光芒

文章分类

全部博文(174)

文章存档

2017年(1)

2016年(3)

2015年(9)

2014年(5)

2013年(23)

2012年(56)

2011年(45)

2010年(32)

分类: LINUX

2012-04-23 14:54:22

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

首先看两个重要的数据结构:
第一个是global_data,定义在include/asm-arm/global_data.h文件中:

点击(此处)折叠或打开

  1. typedef struct global_data {
  2.     bd_t *bd;
  3.     unsigned long flags;
  4.     unsigned long baudrate;
  5.     unsigned long have_console; /* serial_init() was called */
  6.     unsigned long reloc_off; /* Relocation Offset */
  7.     unsigned long env_addr; /* Address of Environment struct */
  8.     unsigned long env_valid; /* Checksum of Environment valid? */
  9.     unsigned long fb_base; /* base address of frame buffer */
  10. #ifdef CONFIG_VFD
  11.     unsigned char vfd_type; /* display type */
  12. #endif
  13. #if 0
  14.     unsigned long cpu_clk; /* CPU clock in */
  15.     unsigned long bus_clk;
  16.     unsigned long ram_size; /* RAM size */
  17.     unsigned long reset_status; /* reset status register at boot */
  18. #endif
  19.     void **jt; /* jump table */
  20. } 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中:

点击(此处)折叠或打开

  1. typedef struct bd_info {
  2.     int bi_baudrate; /* serial console baudrate */
  3.     unsigned long bi_ip_addr; /* IP Address */
  4.     unsigned char bi_enetaddr[6]; /* Ethernet adress */
  5.     struct environment_s *bi_env;
  6.     ulong bi_arch_number; /* unique id for this board */
  7.     ulong bi_boot_params; /* where this board expects params */
  8.     struct /* RAM configuration */
  9.     {
  10.     ulong start;
  11.     ulong size;
  12.     } bi_dram[CONFIG_NR_DRAM_BANKS];
  13. #ifdef CONFIG_HAS_ETH1
  14.     /* second onboard ethernet port */
  15.     unsigned char bi_enet1addr[6];
  16. #endif
  17. } 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函数定义于同一个文件中:

点击(此处)折叠或打开

  1. static void setup_start_tag (bd_t *bd)
  2. {
  3.     params = (struct tag *) bd->bi_boot_params;
  4.     params->hdr.tag = ATAG_CORE;
  5.     params->hdr.size = tag_size (tag_core);
  6.     params->u.core.flags = 0;
  7.     params->u.core.pagesize = 0;
  8.     params->u.core.rootdev = 0;
  9.     params = tag_next (params);
  10. }
其中用到了一个重要的指针:params,这是一个指向struct tag的指针,在文件的开始处声明,可以被这个文件中的所有函数访问:
static struct tag *params;
struct tag的定义位于include/asm-arm/setup.h中:

点击(此处)折叠或打开

  1. struct tag {
  2.     struct tag_header hdr;
  3.     union {
  4.         struct tag_core core;
  5.         struct tag_mem32 mem;
  6.         struct tag_videotext videotext;
  7.         struct tag_ramdisk ramdisk;
  8.         struct tag_initrd initrd;
  9.         struct tag_serialnr serialnr;
  10.         struct tag_revision revision;
  11.         struct tag_videolfb videolfb;
  12.         struct tag_cmdline cmdline;
  13.         /*
  14.          * Acorn specific
  15.          */
  16.         struct tag_acorn acorn;
  17.         /*
  18.          * DC21285 specific
  19.          */
  20.         struct tag_memclk memclk;
  21.     } u;
  22. };
包括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字段来识别到底是什么参数,然后再解析出来使用。

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