movi命令(do_movi函数的源码分析)

以下内容源于网络资源的学习与整理,如有侵权请告知删除。

一、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命令(do_movi函数的源码分析)_第1张图片

删除条件编译语句后,该函数的内容与分析(以“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;
#endif
	cmd = argv[1];// cmd="read"

	switch (cmd[0]) {
	case 'i'://i即init
		raw_area_control.magic_number = 0;
		run_command("mmcinfo", 0);
		return 1;
	case 'r':  //r即read,选择这个
		rw = 0;	/* read case */
		break;
	case 'w'://w即write
		rw = 1; /* write case */
		break;
	default:
		goto usage;
	}

	cmd = argv[2];//cmd="kernel"
	switch (cmd[0]) {
	
	case 'f'://f即fwbl1
		if (argc != 4)
			goto usage;
		attribute = 0x0;
		addr = simple_strtoul(argv[3], NULL, 16);
		break;
	case 'u'://u即u-boot
		if (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=30008000
		break;
	case 'r'://r即rootfs
		if (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。
#endif

	mmc_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");
#else
		if (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);
		}
#endif
		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 bootloader.. %ld, %ld ", rw ? "writing":"reading",
				start_blk, blkcnt);

#if defined(CONFIG_SECURE_BOOT)
#define	BL2_SIZE 8192
		
		sprintf(run_cmd,"mmc %s 0 0x%lx 0x%lx 0x%lx",
				rw ? "write":"read",
				addr + BL2_SIZE, start_blk, blkcnt);
#else
		sprintf(run_cmd,"mmc %s 0 0x%lx 0x%lx 0x%lx",
				rw ? "write":"read",
				addr, start_blk, blkcnt);
#endif
		run_command(run_cmd, 0);
		printf("completed\n");
		return 1;
	}
	
	/* kernel r/w */
	if (attribute == 0x4) {//满足,因为attribute = 0x4
		for (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);
		else
			sprintf(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
	#endif
		run_command(run_cmd, 0);//最终调用run_command函数来运行命令

		printf("completed\n");
		return 1;
	}

	/* root file system r/w */
	if (attribute == 0x8) {//不满足,因为attribute = 0x4
		rfs_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_S3C6410
			if(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;
	#else
		image[1].start_blk = (eFUSE_SIZE/MOVI_BLKSIZE);
	#endif
#else
		image[1].start_blk = capacity - (eFUSE_SIZE/MOVI_BLKSIZE) -
				MOVI_BL1_BLKCNT;
#endif
		image[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;
#else
		image[2].start_blk = image[1].start_blk - MOVI_ENV_BLKCNT;
#endif
		image[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;
#else
		image[3].start_blk = image[2].start_blk - MOVI_BL2_BLKCNT;
#endif
		image[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;
#else
		image[4].start_blk = image[3].start_blk - MOVI_ZIMAGE_BLKCNT;
#endif
		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 */
#if defined(CONFIG_EVT1)
		image[5].start_blk = image[4].start_blk + MOVI_ZIMAGE_BLKCNT;
#else
		image[5].start_blk = image[4].start_blk - MOVI_ROOTFS_BLKCNT;
#endif
		image[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命令的源码分析)。

你可能感兴趣的:(Uboot移植,uboot)