U-boot内核启动分析

(学习笔记,有错见谅,欢迎指出)

正文

  1. 首先已知启动内核在程序中的核心代码为

    s = getenv ("bootcmd");
    ...
    printf("Booting Linux ...\n");            
        	run_command (s, 0);
    

    其中,变量s为:

    nand read.jffs2 0x30007FC0 kernel;bootm 0x30007FC0<INTERRUPT>
    

    1.1 读取操作:表示在nand_flash中从kernel分区读取.jffs2到0x30007FC0。
    1.2 启动操作:在地址0x30007FC0 启动内核。

  2. 分区:

    就是将nand划分为几个区域,一般如下: bootloader-》params-》kernel-》root
    这些分区的划分是在/include/configs/mini2440.h中写死的:

    #define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," \
           "128k(params)," \
           "2m(kernel)," \
           "-(root)"
    

    注:@0表示从0地址开始,256k的bootloader分区可能对某些uboot不够用,这里只是举例而已。
    将上面的信息换算成十六进制:

    #name大小在nand上的起始地址
    0bootloader0x000400000x00000000
    1params0x000200000x00040000
    2kernel0x002000000x00060000
    3root0xfda000000x00260000

    那么上面的nand read.jffs2 0x30007FC0 kernel就等价于: nand read.jffs2 0x30007FC0
    0x00060000 0x00200000
    注:这里的read.jffs2并不是指定要什么特定的格式,而是用read.jffs2不需要块/页对齐,所以这个kernel的分区大小可以随意定。

    [引用来源]

  3. do_nand
       nand read.jffs2功能对应的功能函数为在cmd_nand.c中的int do_nand(),该功能的U_BOOT_CMD宏定义如下:

    "nand read[.jffs2]     - addr off|partition size\n"
    
  4. do_bootm
       bootm对应的功能函数为在cmd_bootm.c下的int do_bootm()。
       首先来看存储在flahs上的系统文件.uimage。由于:
              image=头部+内核
    其中头部定义关键比变量如下:

    typedef struct image_header {
        ...
        uint32_t    ih_load;    /* Data     Load  Address        */
        uint32_t    ih_ep;        /* Entry Point Address        */
    	...
    } image_header_t;
    

       即系统文件的加载地址(运行时先放置的地址)和入口(运行内核是跳转的地址)地址。当运行bootm xxx时候,函数会先读取该头部以获取该uImage的加载和入口地址,当发现该uImage目前所处的内存地址不等于它的加载地址时,该函数会将该uImage移动到它的加载地址上,故将加载地址与存储地址一致以节省启动时间。
    由于视频对应的内核放置在0x3000 8000处(为什么???感觉好像是固定的),故将加载地址减去头部文件的64字节,正好等于0x3000 7FC0 。

  5. do_bootm_linux
       在启动内核前要传递相应参数至cpu(设置启动参数),然后再跳到入口地址启动内核。
    do_bootm_linux函数的主要功能为:
    5.1 设置启动参数
       在0x3000100处以tag格式保存好数据,待U-boot启动内核后,内核读取出数据(大概理解)。

    setup_start_tag (bd);
    ...
    #ifdef CONFIG_SETUP_MEMORY_TAGS
    setup_memory_tags (bd);
    #endif
    #ifdef CONFIG_CMDLINE_TAG
    setup_commandline_tag (bd, commandline);
    #endif
    ...
    setup_end_tag (bd);
    

       每一个启动参数对应一个tag结构体,所谓的设置传递参数其实就是初始化这些tag的值。
    5.1.1 setup_start_tag(bd);

    params = (struct tag *) bd->bi_boot_params;   
    //在board.c中有gd->bd->bi_boot_params = 0x3000 0100
    
    params->hdr.tag = ATAG_CORE;//ATAG_CORE=0x5441 0001
    params->hdr.size = tag_size (tag_core);//tag_size = tag_header(2)+tag_core(3)
    
    params->u.core.flags = 0;
    params->u.core.pagesize = 0;
    params->u.core.rootdev = 0;
    
    params = tag_next (params);//指向下一个tag
    

    5.1.2 setup_memory_tags(bd);
       嵌入式的memory的start与size信息写定即可,无需动态判断。

    params->hdr.tag = ATAG_MEM;//#define ATAG_MEM	0x54410002
    params->hdr.size = tag_size (tag_mem32);
    
    params->u.mem.start = bd->bi_dram[i].start;//0x3000 0000
    params->u.mem.size = bd->bi_dram[i].size;//64M
    
    params = tag_next (params);
    

    5.1.3 setup_commandline_tag (bd, commandline);
       commandline就是U-boot中的bootargs功能。

    char *p;
    if (!commandline)
        return;
    for (p = commandline; *p == ' '; p++);
    if (*p == '\0')
        return;
    params->hdr.tag = ATAG_CMDLINE;//0x544 10009
    params->hdr.size =
        (sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;//头部+命令行字符串长度参数(p)
    strcpy (params->u.cmdline.cmdline, p);
    params = tag_next (params);
    //还会存储字符串的长度和bootargs环境变量
    

    5.1.4 setup_end_tag(bd);
       表示tag结束

    params->hdr.tag = ATAG_NONE;
    params->hdr.size = 0;
    

       Linux内核启动时就会去读取这些tag参数
    5.2 跳到入口地址,启动内核
       再分析功能二,如何跳到入口地址并启动,主要功能由theKernel()函数完成:

    theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);//将入口地址赋给theKernel 
    theKernel (0, bd->bi_arch_number, bd->bi_boot_params);//调用thekernel
    

       thekernel的入口参数有三,后两者的含义是
       bi_arch_number:机器码,uboot机器码需要与内核的机器码相同
       bi_boot_params:uboot需传递给内核的启动参数所位于的地址

    总结

    U-boot目的:启动内核

    • 从flash中读取内核
    • 启动内核
      2.1 设置启动参数
      2.2 跳到入口启动
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值