[從0到1搭嵌入式工程]編譯打包和升級的實現
我們以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卡升級,是在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卡升要複雜好多。