IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    移植u-boot-2010.09到tq2440(四)

    Qiang发表于 2011-02-08 13:03:19
    love 0

    六. 引导zImage
    据我了解,u-boot本身是不支持直接引导zImage的,但是天嵌提供的u-boot就可以直接引导zImage,我就对源码研究了会,结合bootm命令的实现,发现原来引导zImage是如此的简单。
    为了实现直接引导zImage,我添加了一个u-boot的命令boot_zImage,命令添加的方法到处都是,可以到这里看一看:http://qiang.ws/index.php?p=537。我主要说下这个命令的实现原理。
    因为天嵌把nand flash分了三个区,内核映像就烧在第二个分区,第二个分区的起始地址为0x200000,所以从u-boot需要从nand flash的0x200000处读取内核文件,拷贝到SDRAM的0x30008000处,然后在地址gd->bd->bi_boot_params处设置传递给内核的参数,最后跳转到0x30008000执行,下面我贴出代码进行详细的说明:
    /*
    * 使用 tag list方式设置传递给内核的参数
    * pram_base: base address of linux paramter
    */
    static void setup_linux_param(long param_base)
    {
    /* start of tags */
    struct tag *params = (struct tag *)param_base;

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

    /* !!! importart set SDRAM */
    params->hdr.tag = ATAG_MEM;
    params->hdr.size = tag_size (tag_mem32);

    params->u.mem.start = PHYS_SDRAM_1;
    params->u.mem.size = PHYS_SDRAM_1_SIZE;

    params = tag_next (params);

    /* set bootargs */
    char *commandline = getenv (“bootargs”);
    if (!commandline)
    goto end;
    params->hdr.tag = ATAG_CMDLINE;
    params->hdr.size = (sizeof (struct tag_header) + strlen (commandline) + 1 + 4) >> 2;

    strcpy (params->u.cmdline.cmdline, commandline);

    params = tag_next (params);

    end:
    /* end of tags */
    params->hdr.tag = ATAG_NONE;
    params->hdr.size = 0;

    }

    /*
    * 将内核映像从nand flash拷贝到SDRAM中
    * dst: destination address
    * src: source
    * size: size to copy
    * mt: type of storage device
    */
    static inline int copy_kernel_img(ulong dst, const char *src, size_t size)
    {
    int ret = 0;
    if (NF_ReadID() == 0x76) {
    ret = nand_read_ll((unsigned char *)dst,
    (unsigned long)src, (int)size);
    } else {
    ret = nand_read_ll_lp((unsigned char *)dst,
    (unsigned long)src, (int)size);
    }
    return ret;
    }

    int do_boot_zImage (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
    {
    int ret;
    ulong from=0x200000; //这个是内核映像在nand flash中的其实地址
    ulong to=0x30008000; //内核在SDRAM中的起始地址
    size_t size=0x300000; //拷贝内核映像的大小

    /* copy kernel image */
    printf(“Copy linux kernel from 0x%08lx to 0x%08lx, size = 0x%08lx … “,
    from, to, size);
    ret = copy_kernel_img(to, (char *)from, size);
    if (ret) {
    printf(“failed\n”);
    return -1;
    } else {
    printf(“Copy Kernel to SDRAM done,”);
    }

    //这里进行魔数的判断,我觉得做不做无所谓,只是检查一下到底是不是zImage格式的映像而已
    #define LINUX_ZIMAGE_MAGIC 0x016f2818

    if (*(ulong *)(to + 9*4) != LINUX_ZIMAGE_MAGIC) {
    printf(“Warning: this binary is not compressed linux kernel image\n”);
    printf(“zImage magic = 0x%08lx\n”, *(ulong *)(to + 9*4));
    } else {
    printf(“zImage magic = 0x%08lx\n”, *(ulong *)(to + 9*4));
    ;
    }

    printf(“NOW, Booting Linux……\n”);

    /* set atag */
    setup_linux_param(gd->bd->bi_boot_params);

    /* run kernel */
    void(*kernel)(int zero, int arch, uint params);
    kernel = (void(*)(int, int, uint))(to);
    //跳转到0x30008000,这个传递了三个参数,分别是0,机器码和传递给内核的参数的地址,为什么是这三个参数呢?详情自己看内核的源码arch/arm/boot/compressed/head.S
    kernel(0, gd->bd->bi_arch_number,gd->bd->bi_boot_params);

    return 0;
    }

    七. 总结
    没有做移植之前移植认为bootloader很神秘,做完一遍后发现原来bootloader也很简单,并没有之前想象的那么难,希望本文档对你有所帮助,同时也希望大家给我指出不足和错误之处。



沪ICP备19023445号-2号
友情链接