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命令實現的分區信息。