uboot代码2:stage2代码,启动内核

 

一、uboot最终目的:

1.读出内核 do_nand read kernel
{
  flash上存的内核:uImage = 头部 + 真正的内核;
}
2.启动内核。 do_bootm_linux
{
  (1)设置启动参数; uboot到kernel的启动参数的传递, 靠的就是告诉kernel参数存放的绝对地址,并按照约定好的格式存放。具体的格式约定比较复杂,见uboot
  (2)跳到入口地址.
}


二、在uboot里,打印一下环境变量,下面两句是启动kernel的关键字:

bootcmd=nand read 0x30000000 0x60000 0x200000;bootm 0x30000000
bootargs=noinitrd root=/dev/nfs nfsroot=192.168.2.109:/home/fs/work/nfs_root/fs_mini_mdev ip=192.168.2.111:192.168.2.109:192.168.2.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0

 

三、分析uboot代码,看它是如何实现上述功能的:

  写的比较抽象,仅供个人理解。

//uImage头部
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 加载地址, 要运行内核时, 先把内核放在哪里*/
    uint32_t    ih_ep;        /* Entry Point Address 要运行内核时,直接跳到这个地址就可以了*/
    uint32_t    ih_dcrc;    /* Image Data CRC Checksum    */
    uint8_t        ih_os;        /* Operating System        */
    uint8_t        ih_arch;    /* CPU architecture        */
    uint8_t        ih_type;    /* Image Type            */
    uint8_t        ih_comp;    /* Compression Type        */
    uint8_t        ih_name[IH_NMLEN];    /* Image Name        */
} image_header_t;

//uboot和kernel传递参数所依赖的结构体,详细内容见 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;
};
//cmd_nand.c
//bootcmd-- nand read 0x30000000 0x60000 0x200000
int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
    nand_read_opts(nand, &opts); // nand_read_opts : drivers/nand/nand_util.c
}

//cmd_bootm.c
//bootcmd-- bootm 0x30000000
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
    addr = simple_strtoul(argv[1], NULL, 16);
    //printf ("## Booting image at %08lx ...\n", addr); 
    memmove (&header, (char *)addr, sizeof(image_header_t));
    //puts ("   Verifying Checksum ... ");
    
    //unsigned long int data = start addr of kernel int the sdram after the cmd of nand read;
    if(ntohl(hdr->ih_load) == data) //如果期望的kernel运行地址 = 实际从nand 读入内存的kernel起始地址。(都不含头)
    {// 不需要移动
        printf ("   XIP %s ... ", name);
    } 
    else 
    {// 需要移动
        //printf ("   Loading %s ... ", name);
        len  = ntohl(hdr->ih_size);
        memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
    }
    
    do_bootm_linux (cmdtp, flag, argc, argv,
             addr, len_ptr, verify)
    {
        void (*theKernel)(int zero, int arch, uint params);
        theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);
        
        setup_start_tag (bd)/设置内核启动参数的其实存放地址bi_boot_params
        {
            bd_t *bd = gd->bd; //gd->bd->bi_boot_params = 0x30000100;
        }
        //这之后从bi_boot_params开始,依次存入各启动参数
        setup_memory_tags (bd); 
        setup_commandline_tag (bd, commandline);//  char *commandline = getenv ("bootargs");
        setup_end_tag (bd);//表示完成启动参数的传递。
        
        theKernel (0, bd->bi_arch_number, bd->bi_boot_params);//跳到入口地址
    }
}


//uboot的核心:通过run_command实现各种功能
void main_loop (void)
{
    getenv ("bootdelay");
    
    //uboot如何启动内核:
    s = getenv ("bootcmd");
    printf("Booting Linux ...\n");            
    run_command (s, 0)
    {
        (cmdtp->cmd) (cmdtp, flag, argc, argv);
    }
    
    //uboot如何接受用户命令:
    for (;;) 
    {
        readline (CFG_PROMPT); //read input into console_buffer
        strcpy (lastcommand, console_buffer);
        run_command (lastcommand, flag);
    }

}

 

posted @ 2015-12-13 23:42  oucaijun  阅读(488)  评论(0编辑  收藏  举报
下载TeamViewer完整版 下载TeamViewer