以下内容源于网络资源的学习与整理,如有侵权请告知删除。
一、do_movi函数分析
当执行movi相关命令时,实际执行的是do_movi函数。
x210 # help movi
movi init - Initialize moviNAND and show card info
movi read {u-boot | kernel} {addr} - Read data from sd/mmc
movi write {fwbl1 | u-boot | kernel} {addr} - Write data to sd/mmc
movi read rootfs {addr} [bytes(hex)] - Read rootfs data from sd/mmc by size
movi write rootfs {addr} [bytes(hex)] - Write rootfs data to sd/mmc by size
movi read {sector#} {bytes(hex)} {addr} - instead of this, you can use "mmc read"
movi write {sector#} {bytes(hex)} {addr} - instead of this, you can use "mmc write"x210 # movi read kernel 30008000
reading kernel.. 1073, 8192
MMC read: dev # 0, block # 1073, count 8192 ...8192 blocks read: OK
completed
x210 #
该函数位于/common/cmd_movi.c文件中,根据是否定义了CONFIG_GENERIC_MMC这个宏来选择不同的内容。因为在/include/configs/X210_sd.h文件定义了这个宏,所以这里的do_movi函数是底下的那个。
删除条件编译语句后,该函数的内容与分析(以“movi read kernel 30008000”为例进)如下:
/*
执行命令“ movi read kernel 30008000 ”时,
argc=4,argv[0]="movi",argv[1]="read",argv[2]="kenel",argv[3]="30008000"
*/int do_movi(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{char *cmd;ulong addr, start_blk, blkcnt;uint rfs_size;char run_cmd[100];uint rw = 0, attribute = 0;int i;member_t *image;struct mmc *mmc;int dev_num = 0;#if defined(CONFIG_VOGUES)//不满足int boot_dev;
#endifcmd = argv[1];// cmd="read"switch (cmd[0]) {case 'i'://i即initraw_area_control.magic_number = 0;run_command("mmcinfo", 0);return 1;case 'r': //r即read,选择这个rw = 0; /* read case */break;case 'w'://w即writerw = 1; /* write case */break;default:goto usage;}cmd = argv[2];//cmd="kernel"switch (cmd[0]) {case 'f'://f即fwbl1if (argc != 4)goto usage;attribute = 0x0;addr = simple_strtoul(argv[3], NULL, 16);break;case 'u'://u即u-bootif (argc != 4)goto usage;attribute = 0x2;addr = simple_strtoul(argv[3], NULL, 16);break;case 'k'://k即kernel,选择这个if (argc != 4)goto usage;attribute = 0x4;addr = simple_strtoul(argv[3], NULL, 16);//把字符串形式的数字转为数字,此时addr=30008000break;case 'r'://r即rootfsif (argc != 5)goto usage;attribute = 0x8;addr = simple_strtoul(argv[3], NULL, 16);break;default:goto usage;}#if defined(CONFIG_VOGUES)//不满足boot_dev = movi_boot_src();if (boot_dev) {/* boot device is NOR *//* read kernel from eMMC */mmc = find_mmc_device(0);printf("MMC #0 is boot device\r\n");} else {/* boot device is SD card *//* read kernel from SD card */mmc = find_mmc_device(1);printf("MMC #1 is boot device\r\n");}
#else//执行这个mmc = find_mmc_device(dev_num);//这里的dev_num在开头就赋值为0,表示inand。
#endifmmc_init(mmc);//初始化/* firmware BL1 r/w */if (attribute == 0x0) {//不满足,因为attribute = 0x4/* on write case we should write BL1 1st. */for (i=0, image = raw_area_control.image; i<15; i++) {if (image[i].attribute == attribute)break;}start_blk = image[i].start_blk;blkcnt = image[i].used_blk;printf("%s FWBL1 .. %ld, %ld ", rw ? "writing":"reading",start_blk, blkcnt);sprintf(run_cmd,"mmc %s 0 0x%lx 0x%lx 0x%lx",rw ? "write":"read",addr, start_blk, blkcnt);run_command(run_cmd, 0);printf("completed\n");return 1;}/* u-boot r/w */if (attribute == 0x2) {//不满足,因为attribute = 0x4/* on write case we should write BL2 1st. */
#if defined(CONFIG_FUSED) for (i=0, image = raw_area_control.image; i<15; i++) {if (image[i].attribute == 0x1)break;}start_blk = image[i].start_blk;blkcnt = image[i].used_blk;printf("%s BL1.. %ld, %ld ", rw ? "writing":"reading",start_blk, blkcnt);sprintf(run_cmd,"mmc %s 0 0x%lx 0x%lx 0x%lx",rw ? "write":"read",addr, start_blk, blkcnt);run_command(run_cmd, 0);printf("completed\n");
#elseif (rw) {start_blk = raw_area_control.image[1].start_blk;blkcnt = raw_area_control.image[1].used_blk;printf("Writing BL1 to sector %ld (%ld sectors).. ",start_blk, blkcnt);movi_write_bl1(addr);}
#endiffor (i=0, image = raw_area_control.image; i<15; i++) {if (image[i].attribute == attribute)break;}start_blk = image[i].start_blk;blkcnt = image[i].used_blk;printf("%s bootloader.. %ld, %ld ", rw ? "writing":"reading",start_blk, blkcnt);#if defined(CONFIG_SECURE_BOOT)
#define BL2_SIZE 8192sprintf(run_cmd,"mmc %s 0 0x%lx 0x%lx 0x%lx",rw ? "write":"read",addr + BL2_SIZE, start_blk, blkcnt);
#elsesprintf(run_cmd,"mmc %s 0 0x%lx 0x%lx 0x%lx",rw ? "write":"read",addr, start_blk, blkcnt);
#endifrun_command(run_cmd, 0);printf("completed\n");return 1;}/* kernel r/w */if (attribute == 0x4) {//满足,因为attribute = 0x4for (i=0, image = raw_area_control.image; i<15; i++) {if (image[i].attribute == attribute)//根据attribute来匹配到底是哪个image[](即raw分区表中的哪个分区)break;}start_blk = image[i].start_blk;//计算这个分区的信息(起始扇区号、)blkcnt = image[i].used_blk;printf("%s kernel.. %ld, %ld ", rw ? "writing" : "reading",start_blk, blkcnt);#if defined(CONFIG_VOGUES)//不满足if (boot_dev)sprintf(run_cmd, "mmc %s 0 0x%lx 0x%lx 0x%lx",rw ? "write" : "read", addr, start_blk, blkcnt);elsesprintf(run_cmd, "mmc %s 1 0x%lx 0x%lx 0x%lx",rw ? "write" : "read", addr, start_blk, blkcnt);#else//执行这个sprintf(run_cmd, "mmc %s 0 0x%lx 0x%lx 0x%lx",rw ? "write" : "read", addr, start_blk, blkcnt);//rw=0,所以是read#endifrun_command(run_cmd, 0);//最终调用run_command函数来运行命令printf("completed\n");return 1;}/* root file system r/w */if (attribute == 0x8) {//不满足,因为attribute = 0x4rfs_size = simple_strtoul(argv[4], NULL, 16);for (i=0, image = raw_area_control.image; i<15; i++) {if (image[i].attribute == attribute)break;}start_blk = image[i].start_blk;blkcnt = rfs_size/MOVI_BLKSIZE +((rfs_size&(MOVI_BLKSIZE-1)) ? 1 : 0);image[i].used_blk = blkcnt;printf("%s RFS.. %ld, %ld ", rw ? "writing":"reading",start_blk, blkcnt);sprintf(run_cmd,"mmc %s 0 0x%lx 0x%lx 0x%lx",rw ? "write":"read",addr, start_blk, blkcnt);run_command(run_cmd, 0);printf("completed\n");return 1;}return 1;usage:printf("Usage:\n%s\n", cmdtp->usage);return -1;
}
二、init_raw_area_table函数分析
注意到上面的do_movi函数中频繁用到member_t *image这个变量。
其中member_t是struct member结构体的别名,这个结构体的一个实例就表示一个分区的信息。
/** start_blk: start block number for image* used_blk: blocks occupied by image* size: image size in bytes* attribute: attributes of image* 0x1: u-boot parted (BL1)* 0x2: u-boot (BL2)* 0x4: kernel* 0x8: root file system* 0x10: environment area* 0x20: reserved* description: description for image* by scsuh*/
typedef struct member {uint start_blk;uint used_blk;uint size;uint attribute; /* attribute of image */char description[16];
} member_t; /* 32 bytes */
在/common/cmd_movi.c文件中,init_raw_area_table函数构建了一个raw分区表。
raw分区表的数据类型如下(这个数据类型的一个实例就是一个raw分区表):
/** magic_number: 0x24564236* start_blk: start block number for raw area* total_blk: total block number of card* next_raw_area: add next raw_area structure* description: description for raw_area* image: several image that is controlled by raw_area structure* by scsuh*/
typedef struct raw_area {uint magic_number; /* to identify itself */uint start_blk; /* compare with PT on coherency test */uint total_blk;uint next_raw_area; /* should be sector number */char description[16];member_t image[15];
} raw_area_t; /* 512 bytes */
//定义raw_area_t数据类型的一个变量raw_area_control,即定义一个分区表
//后面将填充这个变量的image[]成员(image[]成员表示具体分区的信息)
raw_area_t raw_area_control;
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;if (host->high_capacity) {capacity = host->capacity;#ifdef CONFIG_S3C6410if(IS_SD(host))capacity -= 1024;#endif} else {capacity = host->capacity;}dev_desc->block_read(dev_desc->dev,capacity - (eFUSE_SIZE/MOVI_BLKSIZE) - 1,1, &raw_area_control);if (raw_area_control.magic_number == MAGIC_NUMBER_MOVI) {return 0;}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;//指向分区表的开头位置#if defined(CONFIG_EVT1)#if defined(CONFIG_FUSED)/* image 0 should be fwbl1 */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);#endif
#endif/* image 1 should be bl2 */
#if defined(CONFIG_EVT1)#if defined(CONFIG_FUSED)image[1].start_blk = image[0].start_blk + MOVI_FWBL1_BLKCNT;#elseimage[1].start_blk = (eFUSE_SIZE/MOVI_BLKSIZE);#endif
#elseimage[1].start_blk = capacity - (eFUSE_SIZE/MOVI_BLKSIZE) -MOVI_BL1_BLKCNT;
#endifimage[1].used_blk = MOVI_BL1_BLKCNT;image[1].size = SS_SIZE;image[1].attribute = 0x1;strcpy(image[1].description, "u-boot parted");dbg("bl1: %d\n", image[1].start_blk);/* image 2 should be environment */
#if defined(CONFIG_EVT1)image[2].start_blk = image[1].start_blk + MOVI_BL1_BLKCNT;
#elseimage[2].start_blk = image[1].start_blk - MOVI_ENV_BLKCNT;
#endifimage[2].used_blk = MOVI_ENV_BLKCNT;image[2].size = CFG_ENV_SIZE;image[2].attribute = 0x10;strcpy(image[2].description, "environment");dbg("env: %d\n", image[2].start_blk);/* image 3 should be bl2 */
#if defined(CONFIG_EVT1)image[3].start_blk = image[2].start_blk + MOVI_ENV_BLKCNT;
#elseimage[3].start_blk = image[2].start_blk - MOVI_BL2_BLKCNT;
#endifimage[3].used_blk = MOVI_BL2_BLKCNT;image[3].size = PART_SIZE_BL;image[3].attribute = 0x2;strcpy(image[3].description, "u-boot");dbg("bl2: %d\n", image[3].start_blk);/* image 4 should be kernel */
#if defined(CONFIG_EVT1)image[4].start_blk = image[3].start_blk + MOVI_BL2_BLKCNT;
#elseimage[4].start_blk = image[3].start_blk - MOVI_ZIMAGE_BLKCNT;
#endifimage[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 */
#if defined(CONFIG_EVT1)image[5].start_blk = image[4].start_blk + MOVI_ZIMAGE_BLKCNT;
#elseimage[5].start_blk = image[4].start_blk - MOVI_ROOTFS_BLKCNT;
#endifimage[5].used_blk = MOVI_ROOTFS_BLKCNT;image[5].size = PART_SIZE_ROOTFS;image[5].attribute = 0x8;strcpy(image[5].description, "rfs");dbg("rfs: %d\n", image[5].start_blk);for (i=6; i<15; i++) {raw_area_control.image[i].start_blk = 0;raw_area_control.image[i].used_blk = 0;}}
}
由于CONFIG_FUSED 宏没有定义,故总共5个分区:
image数组 | 扇区号 | 分区名 | 大小 |
---|---|---|---|
image[1] | 1-16 | u-boot parted,即BL1 | 8KB |
image[2] | 17-48 | environment | 16KB |
image[3] | 49-1072 | u-boot,即BL2 | 512KB |
image[4] | 1073-9264 | kernel | 4MB |
image[5] | 9265-62512 | rfs,即rootfs | 26MB |
注意,这里定义的image[5]的扇区号与大小,好像不是很适合实际情况?
movi命令下的分区表、fastboot命令下的分区表,两者相辅相成,利用movi或者fastboot flash命令时,参数中的bootLoader、kernel、system等标签都可以从这两张表中找到对应的地址。
关于fastboot命令下的分区表,见博客如何将镜像烧写至iNand(fastboot命令的源码分析)。