您的位置:首页 > 其它

uboot分析之bootm_start

2014-02-21 12:08 423 查看
bootm命令执行过程中调用了bootm_start函数,这个函数比较重要,所以先分析它。

1.common/cmd_bootm.c

 
static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  
{  
    void        *os_hdr;  
    int     ret;  
    memset ((void *)&images, 0, sizeof (images));//images是一个bootm_headers_t类型的全局变量。见下面的分析。   
    images.verify = getenv_yesno ("verify");//从环境变量中检查是否要对镜像的数据(不是镜像头)进行校验。   
    bootm_start_lmb();//不做任何有意义的工作,除了定义# define lmb_reserve(lmb, base, size)   
    /* get kernel image header, start address and length */寻找可用的内核镜像,见下面的分析。主要根据传入的参数检查镜像的合法性并获取信息。  
    os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,  
            &images, &images.os.image_start, &images.os.image_len);//返回指向内存中镜像头的指针   
    if (images.os.image_len == 0) {  
        puts ("ERROR: can't get kernel image!/n");  
        return 1;  
    }  
    /* get image parameters */  
    switch (genimg_get_format (os_hdr)) {//根据镜像魔数获取镜像类型   
    case IMAGE_FORMAT_LEGACY:  
        images.os.type = image_get_type (os_hdr);//镜像类型   
        images.os.comp = image_get_comp (os_hdr);//压缩类型   
        images.os.os = image_get_os (os_hdr);//操作系统类型   
        images.os.end = image_get_image_end (os_hdr);//当前镜像的尾地址   
        images.os.load = image_get_load (os_hdr);//镜像数据的载入地址   
        break;  
    default:  
        puts ("ERROR: unknown image format type!/n");  
        return 1;  
    }  
    /* find kernel entry point */  
    if (images.legacy_hdr_valid) {//如果镜像已经通过验证   
        images.ep = image_get_ep (&images.legacy_hdr_os_copy);//获取入口地址,填充images.ep 。   
    } else {  
        puts ("Could not find kernel entry point!/n");  
        return 1;  
    }  
    if (((images.os.type == IH_TYPE_KERNEL) ||  
         (images.os.type == IH_TYPE_MULTI)) &&  
        (images.os.os == IH_OS_LINUX)) {  
        /* find ramdisk */3250的配置中这个函数不做任何工作  
        ret = boot_get_ramdisk (argc, argv, &images, IH_INITRD_ARCH,  
                &images.rd_start, &images.rd_end);  
        if (ret) {  
            puts ("Ramdisk image is corrupt or invalid/n");  
            return 1;  
        }  
    }  
    images.os.start = (ulong)os_hdr;//指向内存中镜像的头地址   
    images.state = BOOTM_STATE_START;//标记引导状态   
    return 0;  
}  
 

总结一下这个函数的主要工作:第一步校验镜像的正确性,获取镜像的信息(根据镜像头),第二部将第一步获取的信息存入images(主要是填充image_info_t类型的os成员)

2. bootm_headers_t

 
typedef struct bootm_headers {  
    /* 
     * Legacy os image header, if it is a multi component image 
     * then boot_get_ramdisk() and get_fdt() will attempt to get 
     * data from second and third component accordingly. 
     */  
    image_header_t    *legacy_hdr_os;        /* image header pointer */  
    image_header_t    legacy_hdr_os_copy;    /* header copy */  
    ulong        legacy_hdr_valid;  
#ifndef USE_HOSTCC   
    image_info_t    os;        /* os image info */  
    ulong        ep;        /* entry point of OS */  
    ulong        rd_start, rd_end;/* ramdisk start/end */  
    ulong        ft_len;        /* length of flat device tree */  
    ulong        initrd_start;  
    ulong        initrd_end;  
    ulong        cmdline_start;  
    ulong        cmdline_end;  
    bd_t        *kbd;  
#endif   
    int        verify;        /* getenv("verify")[0] != 'n' */  
#define    BOOTM_STATE_START        (0x00000001)   
#define    BOOTM_STATE_LOADOS        (0x00000002)   
#define    BOOTM_STATE_RAMDISK    (0x00000004)   
#define    BOOTM_STATE_FDT        (0x00000008)   
#define    BOOTM_STATE_OS_CMDLINE    (0x00000010)   
#define    BOOTM_STATE_OS_BD_T    (0x00000020)   
#define    BOOTM_STATE_OS_PREP    (0x00000040)   
#define    BOOTM_STATE_OS_GO        (0x00000080)   
    int        state;  
} bootm_headers_t;  
/* 
 * Legacy format image header, 
 * all data in network byte order (aka natural aka bigendian). 
 */内核镜像头  include/image.h  
typedef struct image_header {  
    uint32_t    ih_magic;        /* Image Header Magic Number    */镜像头部幻数,为#define IH_MAGIC    0x27051956  
    uint32_t    ih_hcrc;            /* Image Header CRC Checksum    */镜像头部crc校验码  
    uint32_t    ih_time;            /* Image Creation Timestamp    */镜像创建时间戳  
    uint32_t    ih_size;            /* Image Data Size        */镜像数据大小(不算头部)1828536  
    uint32_t    ih_load;            /* Data     Load  Address        */数据将要载入的内存地址   80008000  
    uint32_t    ih_ep;            /* Entry Point Address        */镜像入口地址        80008000             
    uint32_t    ih_dcrc;            /* Image Data CRC Checksum    */镜像数据校验码  
    uint8_t        ih_os;        /* Operating System        */操作系统类型    #define IH_OS_LINUX        5  
    uint8_t        ih_arch;        /* CPU architecture        */CPU架构类型    #define IH_ARCH_ARM        2  
    uint8_t        ih_type;        /* Image Type            */镜像类型        IH_TYPE_KERNEL  
    uint8_t        ih_comp;    /* Compression Type        */压缩类型        IH_COMP_NONE  
    uint8_t        ih_name[IH_NMLEN];    /* Image Name        */镜像名字Linux-2.6.27.8,#define IH_NMLEN        32  
} image_header_t;  
镜像信息      include/image.h  
typedef struct image_info {  
    ulong        start, end;            /* start/end of blob */镜像的起始地址和尾地址  
    ulong        image_start, image_len;         /* start of image within blob, len of image */镜像数据的开始地址和长度  
    ulong        load;                /* load addr for the image */镜像数据的装载地址  
    uint8_t        comp, type, os;            /* compression, type of image, os type */压缩类型,镜像类型和操作系统类型  
} image_info_t;  
 

3。boot_get_kernel

 
/** 
 * boot_get_kernel - find kernel image 
 * @os_data: pointer to a ulong variable, will hold os data start address 
 * @os_len: pointer to a ulong variable, will hold os data length 
 * 
 * boot_get_kernel() tries to find a kernel image, verifies its integrity 
 * and locates kernel data. 
 * 
 * returns: 
 *     pointer to image header if valid image was found, plus kernel start 
 *     address and length, otherwise NULL 
 */  
寻找可用的内核镜像  
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)  
{  
    image_header_t    *hdr;  
    ulong        img_addr;  
    /* find out kernel image address */  
    if (argc < 2) {//如果参数太少   
        img_addr = load_addr;    //使用默认的镜像载入地址,这个地址是在配置头文件中定义的 ulong load_addr = CONFIG_SYS_LOAD_ADDR;   
        debug ("*  kernel: default image load address = 0x%08lx/n",  
                load_addr);  
    } else {  
        img_addr = simple_strtoul(argv[1], NULL, 16);//参数足够的话,把第二个参数转化为16进制作为地址   
        debug ("*  kernel: cmdline image address = 0x%08lx/n", img_addr);  
    }  
    show_boot_progress (1);  
    /* copy from dataflash if needed */  
    img_addr = genimg_get_image (img_addr);//对于3250,这个函数什么都没做。因为没有dataflash.   
    /* check image type, for FIT images get FIT kernel node */  
    *os_data = *os_len = 0;  
    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);//检验镜像的合法性(校验码、魔数、架构类型等),并打印信息。见下面的分析。   
        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;  
        case IH_TYPE_MULTI:  
            image_multi_getimg (hdr, 0, os_data, os_len);  
            break;  
        case IH_TYPE_STANDALONE:  
            *os_data = image_get_data (hdr);  
            *os_len = image_get_data_size (hdr);  
            break;  
        default:  
            printf ("Wrong Image Type for %s command/n", cmdtp->name);  
            show_boot_progress (-5);  
            return NULL;  
        }  
        /* 
         * copy image header to allow for image overwrites during kernel 
         * decompression. 
         */拷贝一份镜像的头部到images中。  
        memmove (&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t));  
        /* save pointer to image header */  
        images->legacy_hdr_os = hdr;//images中指针指向镜像的头部   
        images->legacy_hdr_valid = 1;//镜像已经检验合格,置标志量   
        show_boot_progress (6);  
        break;  
    default:  
        printf ("Wrong Image Format for %s command/n", cmdtp->name);  
        show_boot_progress (-108);  
        return NULL;  
    }  
    debug ("   kernel data at 0x%08lx, len = 0x%08lx (%ld)/n",  
            *os_data, *os_len, *os_len);  
    return (void *)img_addr;  
}  
 

4。image_get_kernel

 
common/cmd_bootm.c  
static image_header_t *image_get_kernel (ulong img_addr, int verify)  
{  
    image_header_t *hdr = (image_header_t *)img_addr;  
    if (!image_check_magic(hdr)) {    //检查镜像头部的魔数是否等于 IH_MAGIC   
        puts ("Bad Magic Number/n");  
        show_boot_progress (-1);  
        return NULL;  
    }  
    show_boot_progress (2);  
    if (!image_check_hcrc (hdr)) {//检查镜像头部的校验码(hcrc为0时镜像头的校验码)   
        puts ("Bad Header Checksum/n");  
        show_boot_progress (-2);  
        return NULL;  
    }  
    show_boot_progress (3);  
    image_print_contents (hdr);//根据传入的镜像头地址,打印镜像的信息,见下面的分析。   
/* 
   Image Name:   Linux-2.6.27.8 
   Image Type:   ARM Linux Kernel Image (uncompressed) 
   Data Size:    1828536 Bytes = 1.7 MiB 
   Load Address: 80008000 
   Entry Point:  80008000 
*/  
    if (verify) {//是否要对镜像的数据部分进行校验   
        puts ("   Verifying Checksum ... ");  
        if (!image_check_dcrc (hdr)) {  
            printf ("Bad Data CRC/n");  
            show_boot_progress (-3);  
            return NULL;  
        }  
        puts ("OK/n");  
    }  
    show_boot_progress (4);  
    if (!image_check_target_arch (hdr)) {//检查是否是IH_ARCH_ARM架构   
        printf ("Unsupported Architecture 0x%x/n", image_get_arch (hdr));  
        show_boot_progress (-4);  
        return NULL;  
    }  
    return hdr;  
}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  command u-boot 移植