使用u-boot引导linux的启动过程

使用u-boot引导linux的启动过程

在使用u-boot引导linux的过程中,需要进行一系列的步骤,以下从内核映像的制作开始概述linux的整个启动过程。

一.内核映像的制作

u-boot编译过程中有生成工具mkimage,该工具用来生成u-bootbootm命令引导的内核映像,命令如下:

#mkimage –n “linux-2.6.26.5” –A arm –O linux –T kernel –C none –a 0x30008000 –e 0x30008040 –d zImage zImage.img

执行该命令后,原来的内核文件在开头被加上了64字节的头信息,该信息的数据结构如下:

typedef struct image_header {

       uint32_t   ih_magic;       /* Image Header Magic Number    */

       uint32_t   ih_hcrc;  /* Image Header CRC Checksum  */

       uint32_t   ih_time;   /* Image Creation Timestamp       */

       uint32_t   ih_size;    /* Image Data Size        */

       uint32_t   ih_load;   /* Data    Load  Address   ,该部分即0x30008000,即系统的加载的地址      */

       uint32_t   ih_ep;      /* Entry Point Address  ,该部分即头后的地址0x30008040,即系统的入口地址      */

 

       uint32_t   ih_dcrc;  /* Image Data CRC Checksum     */

       uint8_t           ih_os;             /* Operating System      linux       */

       uint8_t           ih_arch;   /* CPU architecture       arm       */

       uint8_t           ih_type;   /* Image Type        kernel      */

       uint8_t           ih_comp; /* Compression Type     none       */

       uint8_t           ih_name[IH_NMLEN];   /* Image Name*/  IH_NMLEN=32字节

} image_header_t;

 

二.通过bootm引导linux内核启动

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])

{

      os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,

                     &images, &os_data, &os_len);//取得内核信息,包括所在的地址

 

 

switch (genimg_get_format (os_hdr)) {

       case IMAGE_FORMAT_LEGACY:

              type = image_get_type (os_hdr);

              comp = image_get_comp (os_hdr);

              os = image_get_os (os_hdr);

 

              image_end = image_get_image_end (os_hdr);

              load_start = image_get_load (os_hdr);

              break;

//以上是从mkimage生成的64字节中取信息

……

switch (os) {

       default:                  /* handled by (original) Linux case */

       case IH_OS_LINUX:

#ifdef CONFIG_SILENT_CONSOLE

           fixup_silent_linux();

#endif

           do_bootm_linux (cmdtp, flag, argc, argv, &images);//启动Linux内核

           break;    //images在函数boot_get_kernel()中配置

}

//

static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],

              bootm_headers_t *images, ulong *os_data, ulong *os_len)

{

     if (argc < 2) {//没有参数的情况,直接bootm

              img_addr = load_addr; //ulong load_addr = CFG_LOAD_ADDR;

                           //fs2410即为 0x30008000

              debug ("*  kernel: default image load address = 0x%08lx\n",

                            load_addr);

              }

    

    switch (genimg_get_format ((void *)img_addr)) {

       case IMAGE_FORMAT_LEGACY:

              printf ("## Booting kernel from Legacy Image at %08lx ...\n",

                            img_addr);

              hdr = image_get_kernel (img_addr, images->verify);

//以上函数即为image_header_t *hdr = (image_header_t *)img_addr;

              if (!hdr)

                     return NULL;

              show_boot_progress (5);

 

              /* get os_data and os_len */

              switch (image_get_type (hdr)) {

              case IH_TYPE_KERNEL:

                    *os_data = image_get_data (hdr); 

                    *os_len = image_get_data_size (hdr);

                     break;

 

        memmove (&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t));

//hdr的内容复制到images中去

 

              /* save pointer to image header */

              images->legacy_hdr_os = hdr;

 

    return (void *)img_addr;

}

//

void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],

                   bootm_headers_t *images)

{

int   machid = bd->bi_arch_number; //machine id, linux内核中会验证

char *commandline = getenv ("bootargs");//传递的参数

if (images->legacy_hdr_valid) {

              ep = image_get_ep (&images->legacy_hdr_os_copy);

}

theKernel = (void (*)(int, int, uint))ep; //即为0x30008040的地址

setup_start_tag (bd);

setup_commandline_tag (bd, commandline);//定义传递到内核中的参数

       theKernel (0, machid, bd->bi_boot_params);//启动内核

}

/

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

}

 

int board_init (void)

{

     /* arch number of SMDK2410-Board */

      gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;   //193

 

       /* adress of boot parameters */

      gd->bd->bi_boot_params = 0x30000100;                //参数的地址

}

本段部分参考百度文库《bootm命令浅析》

三 linux内核部分的启动过程

              b     1f

              .word      0x016f2818           @ Magic numbers to help the loader

              .word      start               @ absolute load/run zImage address

              .word      _edata                   @ zImage end address

1:            mov r7, r1                    @ save architecture ID  MACH_TYPE_SMDK2410 

              mov r8, r2                    @ save atags pointer  0x30000100;

 

 

 

 

__lookup_machine_type:

       adr   r3, 3b

       ldmia       r3, {r4, r5, r6}

       sub  r3, r3, r4               @ get offset between virt&phys

       add  r5, r5, r3               @ convert virt addresses to

       add  r6, r6, r3               @ physical address space

1:     ldr   r3, [r5, #MACHINFO_TYPE]       @ get machine type

       teq   r3, r1                           @ matches loader number?

       beq  2f                         @ found

       add  r5, r5, #SIZEOF_MACHINE_DESC     @ next machine_desc

       cmp r5, r6

       blo   1b

       mov r5, #0                           @ unknown machine

2:     mov pc, lr

//

  DEFINE(MACHINFO_TYPE,          offsetof(struct machine_desc, nr));

 

struct machine_desc {

       unsigned int           nr;          /* architecture number   */

    ……

}

 

 

 

MACHINE_START(SMDK2410, "SMDK2410")                      

       .phys_io  = S3C2410_PA_UART,

       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,

       .boot_params  = S3C2410_SDRAM_PA + 0x100,// 传递的参数的保存地址,即为0x30000100

       .map_io          = smdk2410_map_io,

       .init_irq   = s3c24xx_init_irq,     

       .init_machine  = smdk2410_init, 

       .timer             = &s3c24xx_timer,

MACHINE_END

//

#define MACHINE_START(_type,_name)                  \//mach-smdk2410.c

static const struct machine_desc __mach_desc_##_type    \

 __used                                            \

 __attribute__((__section__(".arch.info.init"))) = {     \

      .nr          = MACH_TYPE_##_type,            \   // MACH_TYPE_ SMDK2410

       .name             = _name,

 

#define MACHINE_END                            \

};

/

smdk2410             ARCH_SMDK2410        SMDK2410           193 //定义于mach-types,u-boot中的数值对应

/

Setup_arch()

{

char *from = default_command_line;

    ……

tags = phys_to_virt(mdesc->boot_params);//0x300000100取参数

……

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

              if (meminfo.nr_banks != 0)

                     squash_mem_tags(tags);

              save_atags(tags);

              parse_tags(tags);//此处解析,循环中会执行到 strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE),即为

//static int __init parse_tag_cmdline(const struct tag *tag)

//{

//strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);

//return 0;

//}

  

       }

……

       memcpy(boot_command_line, from, COMMAND_LINE_SIZE);

       boot_command_line[COMMAND_LINE_SIZE-1] = '\0';

       parse_cmdline(cmdline_p, from);

……

}

//

Start_kernel()

{//启动中与参数相关的函数

……

setup_arch(&command_line);

……

setup_command_line(command_line);

……

parse_early_param();

……

parse_args

}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值