Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1157879
  • 博文数量: 241
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2279
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(241)

文章存档

2023年(8)

2022年(2)

2021年(3)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友
最近访客

分类: LINUX

2016-09-11 15:55:43

当配置了CONFIG_PPC时将调用common/cmd_bootm.c中的do_bootm_linux。本处是调用libarm/armlinux.c中的。
u-boot.h中
static struct tag *params;
typedef struct bd_info {
    int   bi_baudrate; /* serial console baudrate */波特率
    unsigned long bi_ip_addr; /* IP Address */即服务器IP地址
    unsigned char bi_enetaddr[6]; /* Ethernet adress */
    struct environment_s        *bi_env;
//开发板机器ID,即1008(MACH_TYPE_SMDK2440),gd->bd->bi_arch_number = MACH_TYPE_SMDK2440; (smdk2440.c)
    ulong         bi_arch_number; /* unique id for this board */
//准确地说,这是启动参数的地址,gd->bd->bi_boot_params =0x30000100;(smdk2440.c),与内核中需要一致。
    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;
在u-boot下输入bd就可以查看开发板的一些信息
uplooking # bd
arch_number = 0x0000065A
env_t       = 0x00000000
boot_params = 0x50000100
DRAM bank   = 0x00000000
-> start    = 0x50000000
-> size     = 0x08000000
ethaddr     = 00:40:5C:26:0A:5B
ip_addr     = 192.168.1.20
baudrate    = 115200 bps



///////////////////////////////////////////////////////////////////////////////////////
command.h
/*
 * Monitor Command Table
 */

struct cmd_tbl_s {
    char        *name;        /* Command Name            *//*命令名*/
    int        maxargs;    /* maximum number of arguments    *//*命令的最大参数个数*/
    int        repeatable;    /* autorepeat allowed?        *//*是否自动重复*/
                    /* Implementation function    */
    int        (*cmd)(struct cmd_tbl_s *, int, int, char *[]);/*命令执行函数*/
    char        *usage;        /* Usage message    (short)    */ /*简单的使用说明*/
#ifdef    CFG_LONGHELP
    char        *help;        /* Help  message    (long)    */ /*详细使用说明*/
#endif
#ifdef CONFIG_AUTO_COMPLETE /*自动补全参数*/
    /* do auto completion on the arguments */
    int        (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
在文件include/command.h中定义了结构体cmd_tbl_s,各成员含义如上面注释。U-boot的每一条命令都将封装成结构体 cmd_tbl_s存到链接文件中指定的.u_boot_cmd区。当向u-boot中添加命令时都将调用宏 U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)来初始化一个cmd_tbl_s 结构体。
typedef struct cmd_tbl_s cmd_tbl_t;
//////////////////////////////////////////////////////////////////////////// 
当定义了CONFIG_PPC时将使用common/cmd_bootm.c文件中的do_bootm_linux函数;当系统中没有定义该宏时,系统将使用lib_arm/armlinux.c文件中定义的do_bootm_linux函数。注意:这两个函数有很大的区别

void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
       ulong addr, ulong *len_ptr, int verify)
{
       ulong len = 0, checksum;
       ulong initrd_start, initrd_end;
       ulong data;
      void (*theKernel)(int zero, int arch, uint params);
       image_header_t *hdr = &header;
      bd_t *bd = gd->bd;
#ifdef CONFIG_CMDLINE_TAG
      char *commandline = getenv ("bootargs");//调用了getenv将bootargs环境变量保存在commandline
#endif
    //uboot set参数命令行bootm 50008000;
    //打印出来发现 hdr->ih_ep = 0x800050  也就是必须ntohl之后才是50008000
     theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);  
    //打印出来发现theKernel == 0x50008000
    //设置内核入口地址(不是加载地址,加载是程序存储地址),入口地址是PC指针,倒是后程序跳到这个地址运行
//mkimage.c   
//#define     ntohl(a) SWAP_LONG(a)
//#define     htonl(a) SWAP_LONG(a) 
/***
#define SWAP_LONG(x) \
 ((__u32)( \
  (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
  (((__u32)(x) & (__u32)0x0000ff00UL) <<  8) | \
  (((__u32)(x) & (__u32)0x00ff0000UL) >>  8) | \
  (((__u32)(x) & (__u32)0xff000000UL) >> 24) )) 
****/ 
 /*
  * Check if there is an initrd image //跳过 不是initrd镜像
  */
      if (argc >= 3) {
                  addr = simple_strtoul (argv[2], NULL, 16);
                  printf ("## Loading Ramdisk Image at %08lx ...\n", addr);
  /* Copy header so we can blank CRC field for re-calculation */
#ifdef CONFIG_HAS_DATAFLASH
                 if (addr_dataflash (addr)) {
                          read_dataflash (addr, sizeof (image_header_t),     (char *) &header);
                 }
                 else
#endif
                  memcpy (&header, (char *) addr,    sizeof (image_header_t));
                  if (ntohl (hdr->ih_magic) != IH_MAGIC) {
                          printf ("Bad Magic Number\n");
                          do_reset (cmdtp, flag, argc, argv);
                  }
                 data = (ulong) & header;
                  len = sizeof (image_header_t);
                 checksum = ntohl (hdr->ih_hcrc);
                  hdr->ih_hcrc = 0;
                   if (crc32 (0, (unsigned char *) data, len) != checksum) {
                        printf ("Bad Header Checksum\n");
                        do_reset (cmdtp, flag, argc, argv);
                  }
                  print_image_hdr (hdr);
                  data = addr + sizeof (image_header_t);
                   len = ntohl (hdr->ih_size);
#ifdef CONFIG_HAS_DATAFLASH
                 if (addr_dataflash (addr)) {
                         read_dataflash (data, len, (char *) CFG_LOAD_ADDR);
                         data = CFG_LOAD_ADDR;
                }
#endif
/**
**do_bootm函数中
**    s = getenv ("verify");
    verify = (s && (*s == 'n')) ? 0 : 1;
//为是否对镜像头做校验做准备,读取uboot的环境变量verify,
如果环境变量verify等于’n’,则局部变量verify赋值成为0;如果环境变量verify为空(即没有
定义环境变量verify)或者环境变量verify不等于’n’,则局部变量verify赋值成为1。
**
**/
                    if (verify) {
                                 ulong csum = 0;
                                 printf ("   Verifying Checksum ... ");
                                 csum = crc32 (0, (unsigned char *) data, len);
                                 if (csum != ntohl (hdr->ih_dcrc)) {
                                            printf ("Bad Data CRC\n");
                                            do_reset (cmdtp, flag, argc, argv);
                                 }
                                printf ("OK\n");
                 }
                  if ((hdr->ih_os != IH_OS_LINUX) || (hdr->ih_arch != IH_CPU_ARM) || (hdr->ih_type != IH_TYPE_RAMDISK)) {
                              printf ("No Linux ARM Ramdisk Image\n");
                              do_reset (cmdtp, flag, argc, argv);
                 }
#if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO)
  /*
   *we need to copy the ramdisk to SRAM to let Linux boot
   */
                 memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);//与上文的memcpy (&header, (char *) addr,    sizeof (image_header_t));区别??
                 data = ntohl(hdr->ih_load);
#endif /* CONFIG_B2 || CONFIG_EVB4510 */
  /*
   * Now check if we have a multifile image
   */
       }      //end of " if (argc >= 3) {"
      else if ((hdr->ih_type == IH_TYPE_MULTI) && (len_ptr[1])) {
               ulong tail = ntohl (len_ptr[0]) % 4;
               int i;
    /* skip kernel length and terminator */
               data = (ulong) (&len_ptr[2]);
  /* skip any additional image length fields */
               for (i = 1; len_ptr[i]; ++i)
                           data += 4;
  /* add kernel length, and align */
              data += ntohl (len_ptr[0]);
               if (tail) {
                   data += 4 - tail;
              }
              len = ntohl (len_ptr[1]);
       }
       else {
  /*
   * no initrd image
   */
                len = data = 0;
        }
#ifdef DEBUG
 if (!data) {
  printf ("No initrd\n");
 }
#endif
 if (data) {
  initrd_start = data;
  initrd_end = initrd_start + len;
 } else {
  initrd_start = 0;
  initrd_end = 0;
 }
 debug ("## Transferring control to Linux (at address %08lx) ...\n",
        (ulong) theKernel);
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
    defined (CONFIG_CMDLINE_TAG) || \
    defined (CONFIG_INITRD_TAG) || \
    defined (CONFIG_SERIAL_TAG) || \
    defined (CONFIG_REVISION_TAG) || \
    defined (CONFIG_LCD) || \
    defined (CONFIG_VFD)
 setup_start_tag (bd);
#ifdef CONFIG_SERIAL_TAG
 setup_serial_tag (?ms);
#endif
#ifdef CONFIG_REVISION_TAG
 setup_revision_tag (?ms);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
 setup_memory_tags (bd);
#endif
#ifdef CONFIG_CMDLINE_TAG
 setup_commandline_tag (bd, commandline); //设置启动命令行tags
#endif
#ifdef CONFIG_INITRD_TAG
 if (initrd_start && initrd_end)
  setup_initrd_tag (bd, initrd_start, initrd_end);
#endif
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
 setup_videolfb_tag ((gd_t *) gd);
#endif
 setup_end_tag (bd);
#endif
 /* we assume that the kernel is in place */
 printf ("\nStarting kernel ...\n\n");
#ifdef CONFIG_USB_DEVICE
 {
  extern void udc_disconnect (void);
  udc_disconnect ();
 }
#endif
 cleanup_before_linux ();
//传递的参数
//R0必须为0 ????
//R1:机器类型ID ,本机为ARM(bd-> bi_arch_number)
//R2:启动参数列表在内存中的位置(bd-> bi_boot_params)
         theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
//<嵌入式linux应用开发>P264 bd->bi_boot_params就是标记列表的开始地址。
}



///image.h
/*
 * all data in network byte order (aka natural aka bigendian)
 */
typedef struct image_header {
 uint32_t ih_magic; /* Image Header Magic Number */ /*镜像幻数*/
 uint32_t ih_hcrc; /* Image Header CRC Checksum */ /* 镜像头CRC校验值*/
 uint32_t ih_time; /* Image Creation Timestamp */ /* 镜像创建时间*/
 uint32_t ih_size; /* Image Data Size  *//* 镜像大小*/
 uint32_t ih_load; /* Data  Load  Address  *//* 数据加载地址*/
 uint32_t ih_ep;  /* Entry Point Address  */  //theKernel函数指针指向这个地址,也就是从uboot跳到内核的地址,* 镜像入口*/
 uint32_t ih_dcrc; /* Image Data CRC Checksum */ /* 镜像数据区的CRC校验值*/
 uint8_t  ih_os;  /* Operating System  *//* 操作系统类型*/
 uint8_t  ih_arch; /* CPU architecture  *//* CPU架构*/
 uint8_t  ih_type; /* Image Type   */ /* 镜像类型*/
 uint8_t  ih_comp; /* Compression Type  */ /* 压缩类型*/
 uint8_t  ih_name[IH_NMLEN]; /* Image Name  *//* 镜像名*/
} image_header_t;

Linux编译出的二进制文件是zImage,uboot中提供mkimage工具可将zImage制作成uImage,实际上就是在zImage前加一个image_header头。制作uImage的命令如下。

./mkimage  -n 'linux-2.6.36' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000 -d zImage  uImage.bin

Mkimage工具参数的含义如下:

-A ==> 设置体系架构类型

-O ==> 设置操作系统类型

-T ==> 设置镜像类型

-C ==> 设置压缩类型

-a ==> 设置加载地址

-e ==> 设置镜像入口位置

-n ==> 设置镜像名

-d ==> 设置生成最终镜像所需的文件

-x ==> 设置片上执行


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