以下内容源于网络资源的学习与整理,如有侵权请告知删除。
在文章如何将镜像烧写至iNand(fastboot命令的源码分析)中写到,system、kernel、bootloader的烧写都是write_to_ptn函数直接或间接调用do_mmcops函数来完成的。这里简单分析该函数。
一、mmc命令基本用法
x210 # help mmc
mmc read <device num> addr blk# cnt
mmc write <device num> addr blk# cnt
mmc rescan <device num>
mmc list - list available devicesx210 # mmc list
S3C_HSMMC0_dev0
S3C_HSMMC2_dev1x210 # mmc read 0 3A000000 17 32
MMC read: dev # 0, block # 17, count 32 ...32 blocks read: OKx210 #
(1)列出mmc设备:mmc list
列出系统中的mmc设备。
(2)读/写mmc设备:mmc read/write <device num> addr blk# cnt
device num:表示mmc设备的编号。开发板上可能有多个mmc设备,比如X210开发板的inand编号为0,外接的SD卡编号是1。
addr:表示将mmc设备上的数据读取到哪个内存地址(将哪个内存地址的内容写入mmc设备)。
blk:表示从mmc设备的哪个扇区开始读取(写入)。
cnt:表示读取(写入)多少个扇区的数据。
比如“mmc read 0 3A000000 17 32”,表示从mmc设备0上,以第17扇区为开始,读取32个扇区的数据,存储到以内存地址3A000000为开始的内存空间中。
因为环境变量就存储在inand的第17扇区开始的32个扇区内,因此这条命令其实就是把环境变量读取到内存3A000000开始的内存空间中,后续我们可以用md命令来验证一下。
一开始我以为这条命令中的17、32是16进制的,因为uboot默认采用16进制,但其实是十进制的,这取决于mmc这个命令对应的源码中如何对参数进行解析的。
注意读取到某个地址为开始的内存空间,这段内存空间不能与uboot在内存中的空间有重叠,否则uboot会被覆盖。因为uboot的链接地址对应的物理地址是33E00000,而内存空间的物理地址范围是0x30000000~0x4FFFFFFF(见博客uboot中的虚拟地址映射),所以这里选取一个比较安全的地址3A000000作为测试。
拓展:可以用md命令打印查看某段内存中的值。
经过测试证明,第二个参数是十六进制的数字,而且以字节为单位的。
x210 # mmc read 0 3A000000 17 32
MMC read: dev # 0, block # 17, count 32 ...32 blocks read: OKx210 # help md
md [.b, .w, .l] address [# of objects]- memory displayx210 # md.b 3A000000 9
3a000000: ca 25 4f 80 6d 74 64 70 61 .%O.mtdpax210 # md.b 3A000000 22
3a000000: ca 25 4f 80 6d 74 64 70 61 72 74 3d 38 30 30 30 .%O.mtdpart=8000
3a000010: 30 20 34 30 30 30 30 30 20 33 30 30 30 30 30 30 0 400000 3000000
3a000020: 00 62 .b
x210 #x210 # md.b 3A000000 200
3a000000: ca 25 4f 80 6d 74 64 70 61 72 74 3d 38 30 30 30 .%O.mtdpart=8000
3a000010: 30 20 34 30 30 30 30 30 20 33 30 30 30 30 30 30 0 400000 3000000
3a000020: 00 62 6f 6f 74 64 65 6c 61 79 3d 33 00 62 61 75 .bootdelay=3.bau
3a000030: 64 72 61 74 65 3d 31 31 35 32 30 30 00 65 74 68 drate=115200.eth
3a000040: 61 64 64 72 3d 30 30 3a 34 30 3a 35 63 3a 32 36 addr=00:40:5c:26
3a000050: 3a 30 61 3a 35 62 00 73 65 72 76 65 72 69 70 3d :0a:5b.serverip=
3a000060: 31 39 32 2e 31 36 38 2e 31 2e 31 34 31 00 67 61 192.168.1.141.ga
3a000070: 74 65 77 61 79 69 70 3d 31 39 32 2e 31 36 38 2e tewayip=192.168.
3a000080: 31 2e 31 00 69 70 61 64 64 72 3d 31 39 32 2e 31 1.1.ipaddr=192.1
3a000090: 36 38 2e 31 2e 38 38 00 6e 65 74 6d 61 73 6b 3d 68.1.88.netmask=
3a0000a0: 32 35 35 2e 32 35 35 2e 32 35 35 2e 30 00 62 6f 255.255.255.0.bo
3a0000b0: 6f 74 61 72 67 73 3d 63 6f 6e 73 6f 6c 65 3d 74 otargs=console=t
3a0000c0: 74 79 53 41 43 32 2c 31 31 35 32 30 30 20 72 6f tySAC2,115200 ro
3a0000d0: 6f 74 3d 2f 64 65 76 2f 6d 6d 63 62 6c 6b 30 70 ot=/dev/mmcblk0p
3a0000e0: 32 20 72 77 20 69 6e 69 74 3d 2f 6c 69 6e 75 78 2 rw init=/linux
3a0000f0: 72 63 20 72 6f 6f 74 66 73 74 79 70 65 3d 65 78 rc rootfstype=ex
3a000100: 74 33 00 62 6f 6f 74 63 6d 64 3d 6d 6f 76 69 20 t3.bootcmd=movi
3a000110: 72 65 61 64 20 6b 65 72 6e 65 6c 20 33 30 30 30 read kernel 3000
3a000120: 38 30 30 30 3b 20 62 6f 6f 74 6d 20 33 30 30 30 8000; bootm 3000
3a000130: 38 30 30 30 00 00 73 6f 6c 65 3d 74 74 79 53 41 8000..sole=ttySA
3a000140: 43 32 2c 31 31 35 32 30 30 00 69 70 61 64 64 72 C2,115200.ipaddr
3a000150: 3d 31 39 32 2e 31 36 38 2e 31 2e 38 38 00 62 6f =192.168.1.88.bo
3a000160: 6f 74 63 6d 64 3d 6d 6f 76 69 20 72 65 61 64 20 otcmd=movi read
3a000170: 6b 65 72 6e 65 6c 20 33 30 30 30 38 30 30 30 3b kernel 30008000;
3a000180: 20 62 6f 6f 74 6d 20 33 30 30 30 38 30 30 30 00 bootm 30008000.
3a000190: 00 6e 6f 6e 65 00 00 38 2e 31 2e 32 30 00 00 30 .none..8.1.20..0
3a0001a0: 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0...............
3a0001b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3a0001c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3a0001d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3a0001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3a0001f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
x210 #
二、do_mmcops函数的源码分析
当执行mmc相关命令时,实际执行的是do_mmcops函数。
该函数位于/common/cmd_mmc.c文件中,内容与分析如下:
/*以“mmc read 0 3A000000 17 32”为例进行说明
argc=6
argv[0]="mmc"
argv[1]="read"
argv[2]="0" 选取哪个mmc设备
argv[3]="3A000000" 读取到哪个内容地址
argv[4]="17" 从哪个扇区开始读写
argv[5]="32" 读取多少个扇区
*/int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{int rc = 0;switch (argc) {default: /* at least 5 args */if (strcmp(argv[1], "read") == 0){int dev = simple_strtoul(argv[2], NULL, 10);//dev=0void *addr = (void *)simple_strtoul(argv[3], NULL, 16);//读取数据到哪个内存地址u32 cnt = simple_strtoul(argv[5], NULL, 10);//读取多少个扇区u32 blk = simple_strtoul(argv[4], NULL, 10);//从哪个扇区开始读写u32 n;u32 read_cnt;u32 cnt_to_read;void *addr_to_read;struct mmc *mmc = find_mmc_device(dev);//寻找dev=0的这个设备if (!mmc)return 1;printf("\nMMC read: dev # %d, block # %d, count %d ...",dev, blk, cnt);rc = mmc_init(mmc);if(rc)return rc;n = 0;addr_to_read = addr;do {if (cnt - n > MAXIMUM_BLOCK_COUNT)cnt_to_read = MAXIMUM_BLOCK_COUNT;elsecnt_to_read = cnt - n; //设备0read_cnt = mmc->block_dev.block_read(dev, blk, cnt_to_read, addr_to_read);n += read_cnt;blk += read_cnt;addr_to_read += read_cnt * 512;if(cnt_to_read != read_cnt) {printf("%d blocks read: %s\n",n, "ERROR");return -1;}} while(cnt > n);/* flush cache after read */flush_cache((ulong)addr, cnt * 512); /* FIXME */printf("%d blocks read: %s\n",n, "OK");return 0;} else if (strcmp(argv[1], "write") == 0){int dev = simple_strtoul(argv[2], NULL, 10);void *addr = (void *)simple_strtoul(argv[3], NULL, 16);u32 cnt = simple_strtoul(argv[5], NULL, 10);int blk = simple_strtoul(argv[4], NULL, 10);u32 n;u32 written_cnt;u32 cnt_to_write;void *addr_to_write = addr;struct mmc *mmc = find_mmc_device(dev);if (!mmc)return 1;printf("\nMMC write: dev # %d, block # %d, count %d ... ",dev, blk, cnt);rc = mmc_init(mmc);if(rc)return rc;n = 0;addr_to_write = addr;do {if (cnt - n > MAXIMUM_BLOCK_COUNT)cnt_to_write = MAXIMUM_BLOCK_COUNT;elsecnt_to_write = cnt - n;written_cnt = mmc->block_dev.block_write(dev, blk, cnt_to_write, addr_to_write);n += written_cnt;blk += written_cnt;addr_to_write += written_cnt * 512;if(cnt_to_write != written_cnt) {printf("%d blocks written: %s\n",n, "ERROR");return -1;}} while(cnt > n);printf("%d blocks written: %s\n",n, "OK");return 0;} else {printf("Usage:\n%s\n", cmdtp->usage);rc = 1;}return rc;}
}