解剖嵌入式设备开发时以SD卡启动时SD卡的存储结构(以三星exynos4412为例)

时间:2021-03-28 17:54:26

   目前面对高性能产品的嵌入式开发中,用SD卡来代替以往的JLINK显得备受大家喜欢,而且MCU厂家也对以SD卡启动的支持度越来越大,反而对JLINK不在那么重视(不过依旧保留着)。一些以开发开发板的公司在提供他们自身的bootloader(只是其中一部分是他们自身的代码而已,下面我会讲到这一点)时其原码并不对外公开,不过大家喜欢的u-boot的原码是开源的,可是像友善之臂他们的那样,还得通过他们的superboot来把u-boot二进制代码载入到LAND FLASH,EMMC等这类外部rom设备中,这也意味着我们还得借助superboot来完成我们u-boot的烧写,虽然这样做不是不行,他们不开源源码但是有二进制可执行文件给咱们用,可对于习惯于开源的人来说,无疑总感觉不爽,因此下面就来介绍如何脱离superboot来完成我们的开发。

  跟踪三星厂商提供的他们修改过的uboot代码,在主目录中我们可以看到一个名叫sd—fuse的子目录,这个子目录下有一个makefile,查看makefile我们可以知道它的作用是为了编译产生一个工具mkbl2,这是这个makefile的一部分内容(通过这可以知道是为了生成工具mkbl2):

 25 SOURCES = $(OBJECTS:.o=.c)
 26
 27 all:
 28     $(CC) $(CFLAGS) mkbl2 V310-EVT1-mkbl2.c
 29     $(CC) $(CFLAGS) sd_fdisk sd_fdisk.c
那么这个mkbl2工具是起什么作用的呢,或者说它能干嘛,通过上面可看到它的信赖源文件V310—EVT1-mkbl2.c,那下面我们当然是来看这个源码文件喽:

 66     for(i = 0;i < (14 * 1024) - 4;i++)
 67     {
 68         checksum += (unsigned char)(Buf[i]);
 69     }
 70     *(unsigned int*)(Buf+i) = checksum;
 71
 72     fp = fopen(argv[2], "wb");
 73     if (fp == NULL)
 74     {
 75         printf("destination file open error\n");
 76         free(Buf);
 77         return -1;
 78     }
 79
 80     a   = Buf;
 81     nbytes  = fwrite( a, 1, BufLen, fp);
 82
 83     if ( nbytes != BufLen )
 84     {
 85         printf("destination file write error\n");
 86         free(Buf);
 87         fclose(fp);
 88         return -1;
 89     }
 90
 91     free(Buf);
 92     fclose(fp);
 93
 94     return 0;
 95 }
上面是其中的部分代码,可以看到它是从一个指定文件(这个指定文件下面会说到,其实就是个二进制文件)中复制出前14K内容,把前(14*1024-4)=14332字节做个和校验(checksum)得到一个4字节的校验码,再把它放到14332字节之后,输出一个新的14K的二进制文件。知道了它的作用之后我们继续跟踪下去,在sd-fuse目录下有一个tiny4412的二级子目录,下面可以看到这些文件:E4412_N.bl1.bin  E4412_tzsw.bin  fast_fuse.sh  sd_fusing.sh,这里有两个脚本文件:fast_fuse.sh  sd_fusing.sh,还两个由三星提供的二进制文件:E4412_N.bl1.bin  E4412_tzsw.bin,sd—fusing.sh是对SD卡的,那下面来看看这个脚本是用来干嘛的:

 44 E4412_UBOOT=../../u-boot.bin
 45 MKBL2=../mkbl2
 46
 47 if [ ! -f ${E4412_UBOOT} ]; then
 48     echo "Error: u-boot.bin NOT found, please build it & try again."
 49     exit -1
 50 fi
 51
 52 if [ ! -f ${MKBL2} ]; then
 53     echo "Error: can not find host tool - mkbl2, stop."
 54     exit -1
 55 fi
 56
 57 #<make bl2>
 58 ${MKBL2} ${E4412_UBOOT} bl2.bin 14336
 59
 60 ####################################
 61 # fusing images
 62
 63 signed_bl1_position=1
 64 bl2_position=17
 65 uboot_position=49
 66 tzsw_position=705
 67
 68 #<BL1 fusing>
 69 echo "---------------------------------------"
 70 echo "BL1 fusing"
 71 dd iflag=dsync oflag=dsync if=./E4412_N.bl1.bin of=$1 seek=$signed_bl1_position
 72
 73 #<BL2 fusing>
 74 echo "---------------------------------------"
 75 echo "BL2 fusing"
 76 dd iflag=dsync oflag=dsync if=./bl2.bin of=$1 seek=$bl2_position
 77
 78 #<u-boot fusing>
 79 echo "---------------------------------------"
 80 echo "u-boot fusing"
 81 dd iflag=dsync oflag=dsync if=${E4412_UBOOT} of=$1 seek=$uboot_position
 82
 83 #<TrustZone S/W fusing>
 84 echo "---------------------------------------"
 85 echo "TrustZone S/W fusing"
 86 dd iflag=dsync oflag=dsync if=./E4412_tzsw.bin of=$1 seek=$tzsw_position
 87
 88 #<flush to disk>
 89 sync
 90
 91 ####################################
 92 #<Message Display>
 93 echo "---------------------------------------"
 94 echo "U-boot image is fused successfully."
 95 echo "Eject SD card and insert it again."
分析: 44 E4412_UBOOT=../../u-boot.bin
 45 MKBL2=../mkbl2
 58 ${MKBL2} ${E4412_UBOOT} bl2.bin 14336
原来之前说到的mkbl2作用是把u-boot.bin来产生一个和校验,生成文件bl2.bin,下面接着看:
 63 signed_bl1_position=1
 64 bl2_position=17
 65 uboot_position=49
 66 tzsw_position=705
 71 dd iflag=dsync oflag=dsync if=./E4412_N.bl1.bin of=$1 seek=$signed_bl1_position
 76 dd iflag=dsync oflag=dsync if=./bl2.bin of=$1 seek=$bl2_position
 81 dd iflag=dsync oflag=dsync if=${E4412_UBOOT} of=$1 seek=$uboot_position
 86 dd iflag=dsync oflag=dsync if=./E4412_tzsw.bin of=$1 seek=$tzsw_position
 89 sync
可以看到我们通过dd命令(其用法大家可以man一下)把E4412_N.bl1.bin放在SD卡的第1block开始到第17block总共16个block,共8K,(-rw-r--r-- 1 chenpan chenpan  8192 Mar 22  2013 E4412_N.bl1.bin
-rw-r--r-- 1 chenpan chenpan 94208 Mar 22  2013 E4412_tzsw.bin从这也看到了E4412—N.bl1.bin文件大小为8192字节,正好8K),这里会有人问为何不从SD卡的第0block开始,SD卡的前512字节被填充为0,网上说这里原本用来放一些分区信息的。另外的.bin文件也类似的写进SD卡的指定块(17-49,49-705,705-),sync是自动填充NUL(0)。
所以我们的SD卡存储结构就在上面了。大家也可以动手画出来加深映像。

下面该看看superboot.bin了,我们把它的前560字节打出来:

$hexdump -n 560 Superboot4412.bin
0000000 7bb1 0ac1 3351 33ec 3e84 3b80 2c81 2cf3
0000010 0007 ea00 fffe eaff fffe eaff fffe eaff
0000020 fffe eaff fffe eaff fffe eaff fffe eaff
0000030 fffe eaff 00e8 e59f 0000 e590 1102 e3a0
0000040 0001 e110 0024 0a00 00d8 e59f 0000 e590
0000050 0001 e310 0020 0a00 00cc e59f 0000 e590
0000060 0003 e200 0003 e330 0004 0a00 00bc e59f
0000070 0000 e590 0001 e310 0000 0a00 0016 ea00
0000080 00ac e59f 0000 e590 0003 e200 0003 e330
0000090 0004 0a00 009c e59f 0000 e590 0001 e310
00000a0 0000 0a00 000c ea00 208c e59f 4000 e592
00000b0 2088 e59f 5000 e592 6084 e59f 0006 e154
00000c0 f005 01a0 007c e59f 0000 e590 0007 e200
00000d0 0007 e330 0000 1a00 0010 ea00 0068 e59f
00000e0 1068 e59f 3068 e59f 0001 e150 0003 0a00
00000f0 0003 e151 2004 3490 2004 3481 fffb 3aff
0000100 1050 e59f 2000 e3a0 0001 e153 2004 3483
0000110 fffc 3aff 0010 ea00 fffe eaff 0eb7 ea00
0000120 07b6 ea00 0600 1002 12c0 1002 1188 1002
0000130 1184 1002 1198 1002 1194 1002 0020 0202
0000140 0024 0202 0d10 fcba 1398 1002 2a44 0202
0000150 2a44 0202 2a44 0202 2a44 0202 4070 e92d
0000160 0031 eb00 4070 e6ff 0034 eb00 50ff e200
0000170 01a2 eb00 6000 e1a0 0004 e1a0 00df eb00
0000180 0000 e355 000c 1a00 0036 eb00 0000 e350
0000190 0004 1a00 0078 e59f 1078 e59f 0980 e581
00001a0 f000 e320 fffe eaff 006c e59f 1064 e59f
00001b0 0984 e581 ffd9 ebff 0013 ea00 0000 e356
00001c0 0004 0a00 0054 e59f 1048 e59f 0984 e581
00001d0 ffd2 ebff 000c ea00 015f eb00 0001 e350
00001e0 0004 1a00 0038 e59f 1028 e59f 0984 e581
00001f0 ffca ebff 0004 ea00 0028 e59f 1014 e59f
0000200 0980 e581 f000 e320 fffe eaff 0000 e3a0
0000210 8070 e8bd 0060 dead 0000 1002 50b1 50b1
0000220 50b2 50b1 50b3 50b1 0061 dead 00a8 e59f
0000230
再把E4412_N.bl1.bin的前560字节给打出来:

$hexdump -n 560 E4412_N.bl1.bin
0000000 69a3 18d3 7de9 66b9 6bd1 6ed5 79d4 79a6
0000010 0007 ea00 fffe eaff fffe eaff fffe eaff
0000020 fffe eaff fffe eaff fffe eaff fffe eaff
0000030 fffe eaff 00dc e59f 0000 e590 1102 e3a0
0000040 0001 e110 0024 0a00 00cc e59f 0000 e590
0000050 0001 e310 0020 0a00 00c0 e59f 0000 e590
0000060 0003 e200 0003 e330 0004 0a00 00b0 e59f
0000070 0000 e590 0001 e310 0000 0a00 0016 ea00
0000080 00a0 e59f 0000 e590 0003 e200 0003 e330
0000090 0004 0a00 0090 e59f 0000 e590 0001 e310
00000a0 0000 0a00 000c ea00 2080 e59f 4000 e592
00000b0 207c e59f 5000 e592 6078 e59f 0006 e154
00000c0 f005 01a0 0070 e59f 0000 e590 0007 e200
00000d0 0007 e330 0000 1a00 07c8 ea00 005c e59f
00000e0 105c e59f 305c e59f 0001 e150 0003 0a00
00000f0 0003 e151 2004 3490 2004 3481 fffb 3aff
0000100 1044 e59f 2000 e3a0 0001 e153 2004 3483
0000110 fffc 3aff 002b ea00 0600 1002 12c0 1002
0000120 1188 1002 1184 1002 1198 1002 1194 1002
0000130 0020 0202 0024 0202 0d10 fcba 1398 1002
0000140 2aa4 0202 2aa4 0202 2aa4 0202 2aa4 0202
0000150 1201 e3a0 000c e591 0000 e350 0002 1a00
0000160 1000 e3a0 2104 e59f 1008 e582 ff1e e12f
0000170 00fc e59f 0700 e590 0702 e380 0b02 e380
0000180 10ec e59f 0700 e581 0001 e1a0 0704 e590
0000190 0402 e380 0040 e380 0704 e581 0001 e1a0
00001a0 0900 e590 0402 e380 0080 e380 0900 e581
00001b0 0907 e301 1719 e281 0008 e581 1842 e281
00001c0 0008 e581 ff1e e12f 4070 e92d ffdf ebff
00001d0 ffe6 ebff 002b eb00 4070 e6ff 002e eb00
00001e0 50ff e200 019d eb00 6000 e1a0 0004 e1a0
00001f0 00da eb00 0000 e355 000a 1a00 0030 eb00
0000200 0000 e350 0004 1a00 0068 e59f 1068 e59f
0000210 0980 e581 f000 e320 fffe eaff 005c e59f
0000220 ff30 e12f 000f ea00 0000 e356 0002 0a00
0000230
大家是不是发现了什么了?对,从第16字节开始一直到512字节这些指令操作码是一样的,也就是说superboot的起始位置也是用了三星给的启动代码,superboot是把BL1及superboot结合在一起了,如果有哪位arm-gnu汇编大神非常想知道superboot的具体工作,可以去反汇编(arm-linux-objdump -D -b binary -m arm Superboot4412.bin > superboot.asm &&vim superboot.asm ),或者通过网络入侵友善之臂的网站去找(纯属开个玩笑而已,这可是犯法的事咱不干)。

好了,今天是1/10这到这里吧!欢迎各路大神来指点错误,谢谢大家!