U-Boot如何为内核设置启动参数

 

大家都知道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 Hz!        */
  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 ;

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

  1. #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中:

  1. gd = ( gd_t * )( _armboot_start - CFG_MALLOC_LEN - sizeof ( gd_t )) ;
  2. memset   (( void * ) gd , 0 , sizeof ( gd_t )) ;
  3. gd -> bd = ( bd_t * )(( char * ) gd - sizeof ( bd_t )) ;
  4. memset   ( gd -> bd , 0 , sizeof ( bd_t )) ;

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

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

  1. gd -> bd -> bi_boot_params = 0 xa0000100 ;

说明参数位置在0xa0000100。

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

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

  1. bd_t * bd = gd -> bd ;
  2. 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.  
  5.     params -> hdr . tag = ATAG_CORE ;
  6.     params -> hdr . size = tag_size   ( tag_core ) ;
  7.  
  8.     params -> u . core . flags = 0 ;
  9.     params -> u . core . pagesize = 0 ;
  10.     params -> u . core . rootdev = 0 ;
  11.  
  12.     params = tag_next   ( params ) ;
  13. }

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

  1. 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.         /*
  15.          * Acorn specific
  16.          */
  17.         struct   tag_acorn     acorn ;
  18.  
  19.         /*
  20.          * DC21285 specific
  21.          */
  22.         struct   tag_memclk     memclk ;
  23.     }   u ;
  24. } ;

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

  1. struct tag_header {
  2.     u32   size ;
  3.     u32   tag ;
  4. } ;

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

  1. #define ATAG_CORE 0x54410001
  2. #define ATAG_NONE 0x00000000
  3. #define ATAG_CORE 0x54410001
  4. #define ATAG_MEM 0x54410002
  5. #define ATAG_VIDEOTEXT 0x54410003
  6. #define ATAG_RAMDISK 0x54410004
  7. #define ATAG_INITRD 0x54410005
  8. #define ATAG_INITRD2 0x54420005
  9. #define ATAG_SERIAL 0x54410006
  10. #define ATAG_REVISION 0x54410007
  11. #define ATAG_VIDEOLFB 0x54410008
  12. #define ATAG_CMDLINE 0x54410009
  13. #define ATAG_ACORN 0x41000101
  14. #define ATAG_MEMCLK 0x41000402

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

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

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

具体每个tag的定义可以查看相关文件。
这样,就把每个tag放到了从内存0xa0000100开始的地址,然后由内核根据tag_header的tag字段来识别到底是什么参数,然后再解析出来使用。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值