Hi,欢迎来到中国嵌入式培训高端品牌 - 华清远见嵌入式学院<北京总部官网>,专注嵌入式工程师培养15年!
当前位置: > 嵌入式学院 > 嵌入式学习 > 讲师博文 > FS4412中uboot对emmc的分区解析
FS4412中uboot对emmc的分区解析
时间:2017-11-27作者:华清远见

Author:runner 2017.10.15

声明

平台: fs4412 (Samsung exynos4412)

u-boot版本: u-boot-2010.03-FS4412

简述

在FS4412的开发中,uboot通过movi、fdisk、fastboot等命令对emmc做了相应的分区操作,这里主要分析,这些命令是如何对emmc进行分区的,每条命令使用的分区之间有什么联系和区别。

 

uboot对emmc分区分析

整个u-boot源码的入口是在u-boot-2010.03-FS4412/cpu/arm_cortexa9/start.S,对于该文件中所做的具体工作,我们这里进行分析,主要看该文件中调用emmc初始化的位置:

图中提示的start_armboot函数的实现是在u-boot-2010.03-FS4412/lib_arm/board.c中;当然我们的目的肯定不是只简单的找到这个函数就够了,我们需要了解这个函数中还调用了一个关键的函数接口去初始化emmc,如下:

这里的mmc_initialize函数的具体实现是在u-boot-2010.03-FS4412/drivers/mmc/mmc.c中;那么该函数的主要目的实际上是调用mmc_init,mmc_init又是如何实现的?我们接着往下追,mmc_init函数的实现还是在这个文件中。我们的目的是找到mmc被分区的部分为大家解读,所以对于这个函数其它部分就不做赘述,这里只看该函数最后调用的mmc_startup,如下:

mmc_startup函数的实现也是在上述文件中,该函数调用init_raw_area_table接口实现对emmc的分区操作:

init_raw_area_table函数的实现是在u-boot-2010.03-FS4412/common/cmd_movi.c中。具体实现如下:

 C++ Code 

int init_raw_area_table (block_dev_desc_t *dev_desc)

{

    struct mmc *host = find_mmc_device(dev_desc->dev);

 

    /* when last block does not have raw_area definition. */

    if (raw_area_control.magic_number != MAGIC_NUMBER_MOVI)

    {

        int  i = 0;

        member_t *image;

        u32 capacity;

 

        dbg("The host name is %s\n", host->name);

 

        if(host->high_capacity)

        {

            capacity = host->capacity;

        }

        else

        {

            capacity = host->capacity * (host->read_bl_len / MOVI_BLKSIZE);

        }

 

        dbg("Warning: cannot find the raw area table(%p) %08x\n",

            &raw_area_control, raw_area_control.magic_number);

 

        /* add magic number */

        raw_area_control.magic_number = MAGIC_NUMBER_MOVI;

 

        /* init raw_area will be 16MB */

        raw_area_control.start_blk = 16 * 1024 * 1024 / MOVI_BLKSIZE;

        raw_area_control.total_blk = capacity;

        raw_area_control.next_raw_area = 0;

        strcpy(raw_area_control.description, "initial raw table");

 

        image = raw_area_control.image;

 

        /* image 0 should be fwbl1 */

        if(strcmp(host->name, "S5P_MSHC4") == 0)

            image[0].start_blk = 0;

        else

            image[0].start_blk = (eFUSE_SIZE / MOVI_BLKSIZE);

 

        image[0].used_blk = MOVI_FWBL1_BLKCNT;

        image[0].size = FWBL1_SIZE;

        image[0].attribute = 0x0;

        strcpy(image[0].description, "fwbl1");

        dbg("fwbl1: %d\n", image[0].start_blk);

 

        /* image 1 should be bl2 */

        image[1].start_blk = image[0].start_blk + image[0].used_blk;

        image[1].used_blk = MOVI_BL2_BLKCNT;

        image[1].size = BL2_SIZE;

        image[1].attribute = 0x3;

        strcpy(image[1].description, "bl2");

        dbg("bl2: %d\n", image[1].start_blk);

 

#if 0

        /* image 2 should be uboot */

        image[2].start_blk = image[1].start_blk + image[1].used_blk;

        image[2].used_blk = MOVI_UBOOT_BLKCNT;

        image[2].size = PART_SIZE_UBOOT;

        image[2].attribute = 0x2;

        strcpy(image[2].description, "bootloader");

        dbg("u-boot: %d\n", image[2].start_blk);

#else

        /*BL1,BL2,u-boot have been combined together when compiling for EMMC*/

        if(strcmp(host->name, "S5P_MSHC4") == 0)

            image[2].start_blk = 0;

        else

            image[2].start_blk = (eFUSE_SIZE / MOVI_BLKSIZE);

 

        image[2].used_blk = MOVI_FWBL1_BLKCNT + MOVI_UBOOT_BLKCNT + MOVI_BL2_BLKCNT;

        image[2].size = PART_SIZE_UBOOT + FWBL1_SIZE + BL2_SIZE;

        image[2].attribute = 0x2;

        strcpy(image[2].description, "bootloader");

        dbg("u-boot: %d\n", image[2].start_blk);

#endif

        /* image 3 should be environment */

        image[3].start_blk = (544 * 1024) / MOVI_BLKSIZE;

        image[3].used_blk = MOVI_ENV_BLKCNT;

        image[3].size = CONFIG_ENV_SIZE;

        image[3].attribute = 0x10;

        strcpy(image[3].description, "environment");

        dbg("env: %d\n", image[3].start_blk);

 

        /* image 4 should be kernel */

        image[4].start_blk = image[3].start_blk + image[3].used_blk;

        image[4].used_blk = MOVI_ZIMAGE_BLKCNT;

        image[4].size = PART_SIZE_KERNEL;

        image[4].attribute = 0x4;

        strcpy(image[4].description, "kernel");

        dbg("knl: %d\n", image[4].start_blk);

 

        /* image 5 should be RFS */

        image[5].start_blk = image[4].start_blk + image[4].used_blk;

        image[5].used_blk = MOVI_ROOTFS_BLKCNT;

        image[5].size = PART_SIZE_ROOTFS;

        image[5].attribute = 0x8;

        strcpy(image[5].description, "ramdisk");

        dbg("rfs: %d\n", image[5].start_blk);

 

#ifdef CONFIG_RECOVERY

        /* image 6 should be Recovery */

        image[6].start_blk = image[5].start_blk + image[5].used_blk;

        image[6].used_blk = RAW_AREA_SIZE / MOVI_BLKSIZE - image[5].start_blk;

        image[6].size = image[6].used_blk * MOVI_BLKSIZE;

        image[6].attribute = 0x6;

        strcpy(image[6].description, "Recovery");

        dbg("recovery: %d\n", image[6].start_blk);

#endif

 

 

        /* image 7 should be disk */

        image[7].start_blk = RAW_AREA_SIZE / MOVI_BLKSIZE;

        image[7].size = capacity - RAW_AREA_SIZE;

        image[7].used_blk = image[7].size / MOVI_BLKSIZE;

        image[7].attribute = 0xff;

        strcpy(image[7].description, "disk");

        dbg("disk: %d\n", image[7].start_blk);

        for (i = 8; i < 15; i++)

        {

            raw_area_control.image[i].start_blk = 0;

            raw_area_control.image[i].used_blk = 0;

        }

 

 

    }

 

    return 0;

}

 

 

可以看到:

image[0] 存放的是BL1,start_blk = 0 / 1,used_blk = (8*1024)/512

image[1] 存放的是BL2,start_blk = image[0].start_blk + image[0].used_blk; used_blk = (16*1024)/512

image[2] 存放的是Bootloader,

image[3] 存放的是environment(环境变量)

image[4] 存放的是kernel

image[5] 存放的是ramdisk

image[6] 存放的是Recovery

image[7] 存放的是disk(即文件系统)

 

后面的几个分区的起始地址和使用地址,都是通过上面一一偏移得到的,有兴趣的同学可以自己查阅源码进行计算。这样的话,我们就知道了平时烧写的kernel镜像或者ramdisk镜像在emmc中存放的地址空间了。

 

fdisk命令分区分析

我们知道使用fdisk命令对emmc 分区时,命令格式如下:

fdisk -c 0 300 1024 300

或者使用fdisk命令查询分区大小:

fdisk -p 0

那么这四个分区分别代表什么意思呢?要搞清楚这个问题,我们就要去看fdisk命令的实现过程了,fdisk命令在uboot源码中实现的位置是在common/cmd_mmc_fdisk.c中。在该文件中对于这个命令其它实现的部分我不做赘述,直接看具体分区的操作,函数名称为:make_mmc_partition , 实现如下:

 C++ Code 

 

int make_mmc_partition(int total_block_count, unsigned char *mbr, int flag, char *argv[])

{

    unsigned int        block_start = 0, block_offset;

 

    SDInfo      sdInfo;

    PartitionInfo   partInfo[4];

 

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

    memset((unsigned char *)&sdInfo, 0x00, sizeof(SDInfo));

 

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

    get_SDInfo(total_block_count, &sdInfo);

 

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

    // ??? Unit??§?????????

    block_start = calc_unit(DISK_START, sdInfo);

    block_offset    = calc_unit(SYSTEM_PART_SIZE, sdInfo);

    /* modify by cym 20131206 */

#if 0

    block_offset    = calc_unit(SYSTEM_PART_SIZE, sdInfo);

 

    printf("block_start = %d, block_offset = %d\n", block_start, block_offset);

#else

    if (flag)

        block_offset = calc_unit((unsigned long long)

                                 simple_strtoul(argv[3], NULL, 0) * 1024 * 1024, sdInfo);

    else

        block_offset = calc_unit(SYSTEM_PART_SIZE, sdInfo);

#endif

    /* end modify */

 

 

    partInfo[0].bootable    = 0x00;

    partInfo[0].partitionId = 0x83;

 

    make_partitionInfo(block_start, block_offset, sdInfo, &partInfo[0]);

 

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

    block_start += block_offset;

    /* modify by cym 20131206 */

#if 0

    if (strcmp(argv[2], "1") == 0)// TF card

        block_offset = calc_unit(_300MB, sdInfo);

    else

        block_offset = calc_unit(USER_DATA_PART_SIZE, sdInfo);

#else

    if (flag)

        block_offset = calc_unit((unsigned long long)

                                 simple_strtoul(argv[4], NULL, 0) * 1024 * 1024, sdInfo);

    else

    {

        if (strcmp(argv[2], "1") == 0)// TF card

            block_offset = calc_unit(_300MB, sdInfo);

        else

            block_offset = calc_unit(USER_DATA_PART_SIZE, sdInfo);

    }

#endif

    /* end modify */

 

 

    partInfo[1].bootable    = 0x00;

    partInfo[1].partitionId = 0x83;

 

    make_partitionInfo(block_start, block_offset, sdInfo, &partInfo[1]);

 

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

    block_start += block_offset;

    /* modify by cym 20131206 */

#if 0

    block_offset = calc_unit(CACHE_PART_SIZE, sdInfo);

#else

    if(flag)

        block_offset =

            calc_unit((unsigned long long)

                      simple_strtoul(argv[5], NULL, 0) * 1024 * 1024, sdInfo);

    else

        block_offset = calc_unit(CACHE_PART_SIZE, sdInfo);

#endif

    /* end modify */

 

 

    partInfo[2].bootable    = 0x00;

    partInfo[2].partitionId = 0x83;

 

    make_partitionInfo(block_start, block_offset, sdInfo, &partInfo[2]);

 

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

    block_start += block_offset;

    block_offset = BLOCK_END;

 

    partInfo[3].bootable    = 0x00;

    partInfo[3].partitionId = 0x0C;

 

    make_partitionInfo(block_start, block_offset, sdInfo, &partInfo[3]);

 

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

    memset(mbr, 0x00, sizeof(*mbr) * 512); // liang, clean the mem again

    mbr[510] = 0x55;

    mbr[511] = 0xAA;

 

    encode_partitionInfo(partInfo[0], &mbr[0x1CE]);

    encode_partitionInfo(partInfo[1], &mbr[0x1DE]);

    encode_partitionInfo(partInfo[2], &mbr[0x1EE]);

    encode_partitionInfo(partInfo[3], &mbr[0x1BE]);

 

    return 0;

}

 

从上述代码中我们可以看到,在执行fdisk命令时打印的四个分区实际上就是partInfo的四个元素,partInfo[0]代表的是system分区,partInfo[1]代表的是userdata分区, partInfo[2]代表的是cache分区,剩下的partInfo[3]是fat分区。所以在fdisk命令执行完成后,出现的四个分区1、2、3、4依次为fat、system、userdata、cache。

 

fastboot命令分析

我们在uboot状态下执行fastboot命令的时候显示的8个分区信息,跟前面咱们看到几个分区又是什么样的关系呢?实际上这里的bootloader、kernel、ramdisk、Recovery就是最前面提到的那几个分区,由uboot在启动时调用mmc_init实现的。而后面的system、userdata、cache、fat四个分区统称为disk分区,同样也是fdisk命令实现的分区信息。


发表评论

全国咨询电话:400-611-6270,双休日及节假日请致电值班手机:15010390966

在线咨询: 曹老师QQ(3337544669), 徐老师QQ(1462495461), 刘老师 QQ(3108687497)

企业培训洽谈专线:010-82600901,院校合作洽谈专线:010-82600350,在线咨询:QQ(248856300)

Copyright 2004-2018 华清远见教育集团 版权所有 ,京ICP备16055225号,京公海网安备11010802025203号