Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1638504
  • 博文数量: 197
  • 博客积分: 10046
  • 博客等级: 上将
  • 技术积分: 1983
  • 用 户 组: 普通用户
  • 注册时间: 2006-08-07 12:36
个人简介

在外企做服务器开发, 目前是项目经理, 管理两个server开发的项目。不做嵌入式好久了。

文章分类
文章存档

2011年(2)

2010年(6)

2009年(18)

2008年(30)

2007年(100)

2006年(41)

分类: LINUX

2008-01-21 15:35:04

还可以参考  我的这篇文章: smdk2410开发板SDRAM上地址空间分布,以及u-boot 如何搬运kernel

http://blog.chinaunix.net/u/22617/showart.php?id=322222

 

 


#ifndef CFG_BOOTM_LEN
#define CFG_BOOTM_LEN    0x800000    /* use 8MByte as default max gunzip size */
#endif

image_header_t header; //这是很重要的全局变量, 会被armlinux.c 里面的do_bootm_linux()使用


ulong load_addr = CFG_LOAD_ADDR;        /* Default Load Address */
//定义在include/configs/*.h 中 ,比如ep7312.h 是这样定义的:

//#define    CFG_LOAD_ADDR        0xc0500000    /* default load address    */


int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
    ulong    iflag;
    ulong    addr;
    ulong    data, len, checksum;
    ulong *len_ptr;
    uint    unc_len = CFG_BOOTM_LEN;
    int    i, verify;
    char    *name, *s;
    int    (*appl)(int, char *[]);
    image_header_t *hdr = &header;//之前定义的全局变量


    s = getenv ("verify");
    verify = (s && (*s == 'n')) ? 0 : 1;

//addr 就是kernel的临时下载的地址

    if (argc < 2) {
        addr = load_addr;//我们的环境: load_addr = 0x33000000

    } else {
        addr = simple_strtoul(argv[1], NULL, 16);
    }

    SHOW_BOOT_PROGRESS (1);
    printf ("## Booting image at %08lx ...\n", addr);

//读取kernel image的header

    /* 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
    memmove (&header, (char *)addr, sizeof(image_header_t));

//判断魔数,一般不会出错

    if (ntohl(hdr->ih_magic) != IH_MAGIC) {
#ifdef __I386__    /* correct image format not implemented yet - fake it */
        if (fake_header(hdr, (void*)addr, -1) != NULL) {
            /* to compensate for the addition below */
            addr -= sizeof(image_header_t);
            /* turnof verify,
             * fake_header() does not fake the data crc
             */

            verify = 0;
        } else
#endif    /* __I386__ */
     {
        puts ("Bad Magic Number\n");
        SHOW_BOOT_PROGRESS (-1);
        return 1;
     }
    }
    SHOW_BOOT_PROGRESS (2);



    data = (ulong)&header;
    len = sizeof(image_header_t); //header的长度0x40 (64个byte)


    checksum = ntohl(hdr->ih_hcrc);
    hdr->ih_hcrc = 0;

//crc校验

    if (crc32 (0, (uchar *)data, len) != checksum) {
        puts ("Bad Header Checksum\n");
        SHOW_BOOT_PROGRESS (-2);
        return 1;
    }
    SHOW_BOOT_PROGRESS (3);

#ifdef CONFIG_HAS_DATAFLASH
    if (addr_dataflash(addr)){
        len = ntohl(hdr->ih_size) + sizeof(image_header_t);
        read_dataflash(addr, len, (char *)CFG_LOAD_ADDR);
        addr = CFG_LOAD_ADDR;
    }
#endif


    /* for multi-file images we need the data part, too */
    print_image_hdr ((image_header_t *)addr);


//////////////////////////////////////////////////////////////////////////////////


    //这里很关键的, 指向了后面的kernel的部分

    data = addr + sizeof(image_header_t);//指向后面的kernel部分

    len = ntohl(hdr->ih_size); //kernel的实际大小,就是编译后的大小


    if (verify) {
        puts (" Verifying Checksum ... ");
        if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) {
            printf ("Bad Data CRC\n");
            SHOW_BOOT_PROGRESS (-3);
            return 1;
        }
        puts ("OK\n");
    }
    SHOW_BOOT_PROGRESS (4);

    len_ptr = (ulong *)data;

#if defined(__PPC__)
    if (hdr->ih_arch != IH_CPU_PPC)
#elif defined(__ARM__)
    if (hdr->ih_arch != IH_CPU_ARM)
#elif defined(__I386__)
    if (hdr->ih_arch != IH_CPU_I386)
#elif defined(__mips__)
    if (hdr->ih_arch != IH_CPU_MIPS)
#elif defined(__nios__)
    if (hdr->ih_arch != IH_CPU_NIOS)
#elif defined(__M68K__)
    if (hdr->ih_arch != IH_CPU_M68K)
#elif defined(__microblaze__)
    if (hdr->ih_arch != IH_CPU_MICROBLAZE)
#elif defined(__nios2__)
    if (hdr->ih_arch != IH_CPU_NIOS2)
#elif defined(__blackfin__)
    if (hdr->ih_arch != IH_CPU_BLACKFIN)
#elif defined(__avr32__)
    if (hdr->ih_arch != IH_CPU_AVR32)
#else
# error Unknown CPU type
#endif
    {
        printf ("Unsupported Architecture 0x%x\n", hdr->ih_arch);
        SHOW_BOOT_PROGRESS (-4);
        return 1;
    }
    SHOW_BOOT_PROGRESS (5);

    switch (hdr->ih_type) {
    case IH_TYPE_STANDALONE:
        name = "Standalone Application";
        /* A second argument overwrites the load address */
        if (argc > 2) {
            hdr->ih_load = htonl(simple_strtoul(argv[2], NULL, 16));
        }
        break;
    case IH_TYPE_KERNEL:
        name = "Kernel Image";
        break;
    case IH_TYPE_MULTI:
        name = "Multi-File Image";
        len = ntohl(len_ptr[0]);
        /* OS kernel is always the first image */
        data += 8; /* kernel_len + terminator */
        for (i=1; len_ptr[i]; ++i)
            data += 4;
        break;
    default: printf ("Wrong Image Type for %s command\n", cmdtp->name);
        SHOW_BOOT_PROGRESS (-5);
        return 1;
    }
    SHOW_BOOT_PROGRESS (6);

//执行kernel的准备工作


//--------进入最后的阶段

    /*
     * We have reached the point of no return: we are going to
     * overwrite all exception vector code, so we cannot easily
     * recover from any failures any more...
     */


    iflag = disable_interrupts();

#ifdef CONFIG_AMIGAONEG3SE
    /*
     * We've possible left the caches enabled during
     * bios emulation, so turn them off again
     */

    icache_disable();
    invalidate_l1_instruction_cache();
    flush_data_cache();
    dcache_disable();
#endif



    /* 最关键的地方: 搬运kernel到ih_load指定的地址上去*/


    switch (hdr->ih_comp) {
    case IH_COMP_NONE: // -C none

        if(ntohl(hdr->ih_load) == addr) { //判断download的地址是否和kernel规定的地址相同

            printf (" XIP %s ... ", name); //XIP: 原地执行

        } else {
#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
            size_t l = len;
            void *to = (void *)ntohl(hdr->ih_load);
            void *from = (void *)data;

            printf (" Loading %s ... ", name);

            while (l > 0) {
                size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l;
                WATCHDOG_RESET();
                memmove (to, from, tail);
                to += tail;
                from += tail;
                l -= tail;
            }
#else    /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
        //这里就是搬运的代码

        memmove(void * dest, const void * src, size_t count) ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
#endif    /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
        }
        break;
    case IH_COMP_GZIP:
        printf (" Uncompressing %s ... ", name);
        if (gunzip ((void *)ntohl(hdr->ih_load), unc_len, // 把它解压到 ih_load的位置上去

             (uchar *)data, &len) != 0) {
            puts ("GUNZIP ERROR - must RESET board to recover\n");
            SHOW_BOOT_PROGRESS (-6);
            do_reset (cmdtp, flag, argc, argv);
        }
        break;
#ifdef CONFIG_BZIP2
    case IH_COMP_BZIP2:
        printf (" Uncompressing %s ... ", name);
        /*
         * If we've got less than 4 MB of malloc() space,
         * use slower decompression algorithm which requires
         * at most 2300 KB of memory.
         */

        i = BZ2_bzBuffToBuffDecompress ((char*)ntohl(hdr->ih_load),
                        &unc_len, (char *)data, len,
                        CFG_MALLOC_LEN < (4096 * 1024), 0);
        if (i != BZ_OK) {
            printf ("BUNZIP2 ERROR %d - must RESET board to recover\n", i);
            SHOW_BOOT_PROGRESS (-6);
            udelay(100000);
            do_reset (cmdtp, flag, argc, argv);
        }
        break;
#endif /* CONFIG_BZIP2 */
    default:
        if (iflag)
            enable_interrupts();
        printf ("Unimplemented compression type %d\n", hdr->ih_comp);
        SHOW_BOOT_PROGRESS (-7);
        return 1;
    }

    //搬运完毕

    puts ("OK\n");
    SHOW_BOOT_PROGRESS (7);



    switch (hdr->ih_type) {
    case IH_TYPE_STANDALONE:
        if (iflag)
            enable_interrupts();

        /* load (and uncompress), but don't start if "autostart"
         * is set to "no"
         */

        if (((s = getenv("autostart")) != NULL) && (strcmp(s,"no") == 0)) {
            char buf[32];
            sprintf(buf, "%lX", len);
            setenv("filesize", buf);
            return 0;
        }
        appl = (int (*)(int, char *[]))ntohl(hdr->ih_ep);
        (*appl)(argc-1, &argv[1]);
        return 0;
    case IH_TYPE_KERNEL:
    case IH_TYPE_MULTI:
        /* handled below */
        break;
    default:
        if (iflag)
            enable_interrupts();
        printf ("Can't boot image type %d\n", hdr->ih_type);
        SHOW_BOOT_PROGRESS (-8);
        return 1;
    }
    SHOW_BOOT_PROGRESS (8);



    
//判断何种操作系统

    switch (hdr->ih_os) {
    default:            /* handled by (original) Linux case */
    case IH_OS_LINUX:
#ifdef CONFIG_SILENT_CONSOLE
     fixup_silent_linux();
#endif

//接下来就要调用do_bootm_linux() 函数了,这里要启动kernel

     do_bootm_linux (cmdtp, flag, argc, argv,
             addr, len_ptr, verify);
     break;
    case IH_OS_NETBSD:
     do_bootm_netbsd (cmdtp, flag, argc, argv,
             addr, len_ptr, verify);
     break;

#ifdef CONFIG_LYNXKDI
    case IH_OS_LYNXOS:
     do_bootm_lynxkdi (cmdtp, flag, argc, argv,
             addr, len_ptr, verify);
     break;
#endif

    case IH_OS_RTEMS:
     do_bootm_rtems (cmdtp, flag, argc, argv,
             addr, len_ptr, verify);
     break;

#if (CONFIG_COMMANDS & CFG_CMD_ELF)
    case IH_OS_VXWORKS:
     do_bootm_vxworks (cmdtp, flag, argc, argv,
             addr, len_ptr, verify);
     break;
    case IH_OS_QNX:
     do_bootm_qnxelf (cmdtp, flag, argc, argv,
             addr, len_ptr, verify);
     break;
#endif /* CFG_CMD_ELF */
#ifdef CONFIG_ARTOS
    case IH_OS_ARTOS:
     do_bootm_artos (cmdtp, flag, argc, argv,
             addr, len_ptr, verify);
     break;
#endif
    }

    SHOW_BOOT_PROGRESS (-9);
#ifdef DEBUG
    puts ("\n## Control returned to monitor - resetting...\n");
    do_reset (cmdtp, flag, argc, argv);
#endif
    return 1;
}

U_BOOT_CMD(
     bootm,    CFG_MAXARGS,    1,    do_bootm,
     "bootm - boot application image from memory\n",
     "[addr [arg ...]]\n - boot application image stored in memory\n"
     "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
     "\t'arg' can be the address of an initrd image\n"
#ifdef CONFIG_OF_FLAT_TREE
    "\tWhen booting a Linux kernel which requires a flat device-tree\n"
    "\ta third argument is required which is the address of the of the\n"
    "\tdevice-tree blob. To boot that kernel without an initrd image,\n"
    "\tuse a '-' for the second argument. If you do not pass a third\n"
    "\ta bd_info struct will be passed instead\n"
#endif
);

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