工程编译:
我们以nand分区,分为bootloader、kernel、rootfs、homefs为例。
rootfs是linux系统必须的文件目录系统和工具的集合,挂载在跟目录/下,homefs可以认为是我们自己的应用程序、自己的依赖库,放在homefs中,放在/home目录中。
那么编译打包的过程,就是把固件运行所需的全部文件,打成一个包, 在升级时,由升级程序把这个包拆开,把相应的文件保存在对应的分区上。
要完成整个包的编译,要先编出bootloader、kernel和rootfs的整个目录。
生成之后,放在out目录中,开始编我们自己的应用程序。
1:先编译我们自己代码的公共库, 生成.a,放在对应的目录;
2:编译各个模块的应用程序, 并把生成的可执行文件,cp到out/home/app 下供后面打包用;
3:依赖的.a库,已经在编译时编进可执行文件了,依赖的.so库,还需要cp到out/home/lib中;
4:固件需要的工具和文件,比如sd格式化工具, 升级工具,加密工具,提示音文件等等 cp到相应的目录下。
等所有运行需要的文件都放到out目录以后,此时,bootloader和kernel是可执行文件,rootfs和homefs还只是目录和文件,需要我们制作成文件系统。
这里采用jffs2文件系统, 使用mkfs.jffs2工具,把rootfs和home目录下的所有文件,分别制作成 rootfs.jffs2和home.jffs2。
然后把四个独立的文件,使用dd工具再次打包,dd if=boot.bin of=bootimg bs=xx count=xx , dd kernel.img -> sysimg, dd rootfs.jffs2 -> sysimg seek=xxx, 指定offset,把kernel和rootfs打包到一起成sysimg。 同样,把home.jffs2 打包成homeimg。这是打了三个不同部分的img包。
再把boot.bin kernel.img rootfs.jffs2 home.jffs2 使用dd和偏移量, 打包到allimg中。这个包是完整包。
这样就有了四个img, 根据需要升级的部分,决定使用哪个img进行升级。
在home目录下,使用7za工具,对home目录进行 加密 压缩, 压缩成homeimg_m.7z
密码从哪里来?
从0--z中随机生成32位长度的密码。
对homeimg_m.7z 执行md5sum,
把这几个文件cat到一个文件中
cat md5 password ver homeimg_m.7z > home1
dd if home1 of keyrsa bs=980 count=1 把home1文件的前面777字节放在keyrsa中,当做加密的key。
dd if home1 of home2 bs=980 skip=1 把home1中剩下的放在home2
使用keyrsa 生成公钥, enc_keyrsa,
cat ver enc_keyrsa home2 > home_m
至此,固件打包完成,主要固件有bootimg/sysimg/home_m/allimg。
升级:从SD卡升级allimg,
从SD卡升级,是在boot阶段进行的, uboot在监测到SD卡之后, 读取文件名,将文件读取到ram中, 计算文件的crc校验,和从设备flash上读取的对应的crc进行比对, 如果是一致的,就不进行升级。
如果不一致,说明需要升级,这个时候,根据包的类型,是allimg的话,擦除allimg整个区域,如果是bootimg,擦除boot区域,其他一样, 然后把文件整块的数据,写入对应的flash区域,然后把新的crc作为新的环境变量,写入特定的flash区域。重启设备,就是在新的固件下运行了。
网络升级:网络升级的固件一般是经过加密压缩的home_m。
trigger固件进行升级, 固件从服务器端,获取最新的固件的下载url,和固件本身的md5用于校验下载完整性,发送请求,把home_m下载到内存中/tmp/downloadloadimg/home_m, 下载的过程,可以根据ls -l出来的文件大小,与总文件大小的比值,确定下载的百分比。下载成功以后,执行md5sum,和服务器发下来的md5比较,一致为ok。这时,把/tmp/downloadloadimg/home_m mv 到/home/home_m, access 到这个文件,说明下载成功100%。 reboo重启设备。
这个时候,在线升级已经完成了一半。
在kernel启动之后,运行的init.sh脚本中,我们判断/home/home_m , 就开始去进行解压升级。
dd if /home/home_m of /tmp/newver bs=22 count=1, 也就是把固件的前22位取出来,根据打包的顺序, 前面是固件版本号, 和当前的版本号比较,不同就升级。
用工具对home_m 进行解包。
创建 /tmp/update 目录,把home_m放到内存中去,把rsa解码工具 和 7ZA工具也cp过来,开始解。
dd if home_m of ver bs=22 count=1 版本号
dd if home_m of home1 bs=22 skip=1 count=9999999 除了版本号之外的部分
删掉home_m 因为内存可能不够了
dd if home1 of enc_key bs=1024 count=1 取出加密部分
dd if home1 of home2 bs=1024 skip=1 count=9999999 剩余部分
rm home1
使用rsa_pub_dec enc_key dec_enc_key 解密出来,如果dec_enc_key 文件的大小是128, 正确继续,否则退出。
cat dec_enc_key home2 > home3
rm home2
dd if home3 of home4 bs=66 skip=1 count=9999999 前66位
dd if home3 of md5 bs=33 count=1 取 md5
dd if home3 of pwd bs=33 skip=1 count=1 取 密码
dd if home4 of verin bs=22 count=1 取版本
dd if home4 of home_m.7z bs=22 skip=1 count=999999999
判断刚才得到的几个版本号是否有问题
用得到的解压密码,用7za工具解压home_m.7z,
在/home/目录下,分目录对比version,如果version不一致, 就把/home/xxx目录下的文件都删掉,然后把/tmp/update/home/目录下对应的目录copy过去。
用md5 对比/tmp目录和/home目录中的md5, 全部都对上 OK。
把版本文件cp过去, over, 最终升级成功。要比SD卡升要复杂好多。