zynqMP支持multiboot功能,根據選擇的啓動模式爲QSPI32,可知系統會從FLASH的0地址開始查詢可用的鏡像,如果在0地址處未找到可用的系統鏡像,則會偏移32K的地方繼續尋找可用的鏡像文件。
目前FLASH上的分區如下:
分區名稱 |
包含文件 |
起始地址 |
終止地址 |
分區長度 |
flash0 |
zynq.bin |
0x00000000 |
0x20000000 |
32MB |
flash1 |
zynq_bk.bin |
0x20000000 |
0x40000000 |
32MB |
flash2 |
log |
0x40000000 |
0x80000000 |
64MB |
上電後,zynqMP首先會從FLASH的0地址處開始校驗鏡像的頭部信息,如果可用,就直接將這塊分區的鏡像搬移到內存中去運行;如果flash0分區中的鏡像文件被破壞,那麼zynqMP就會自動往後偏移32K的地址去查找可用的鏡像,也就是從0x8000的地址繼續查找,如果不可用,繼續偏移32K,一直到遍歷FLASH的所有空間。
在項目中,一個完整的zynqMP.bin文件約爲32M,所以直接在偏移0地址32M的地方存放備份鏡像文件。(注意32M是32K的整數倍,因爲偏移是按32K爲單位進行的)。
zynqMP.bin中包含有fsbl、PMW、ATF、uboot、dtb、Image、rootfs等內容。dtb、Image、rootfs共同組成image.ub文件。
要想實現備份鏡像能正常啓動內核,就需要將內核存放的地址告訴uboot,也就是設置uboot的 CONFIG_EXTRA_ENV_SETTINGS。由於zynqMP.bin是從32M的地址開始存放,image.ub的存放地址是相當於32M(0x2000000)偏移940000,內核存放的地址就是0x2940000
思考:爲何需要將內核地址告訴u-boot就行,那zynqMP又是如何知道u-boot的地址呢?
答案:zynqMP以32K爲偏移單位來自動搜尋可用的鏡像,那如何來判斷可用還是不可用呢?其實是通過FSBL文件的前部分字節來判斷的,也就是說找到FSBL後,就認爲鏡像可用,ATF、PMW以及U-BOOT都是緊挨着存放的,也就是說FSBL正常執行了,U-BOOT就正常執行了,但內核與U-boot不是放在一起的,所以內核的地址要告訴u-boot纔行。
具體設置如下:
#define CONFIG_EXTRA_ENV_SETTINGS \
SERIAL_MULTI \
CONSOLE_ARG \
PSSERIAL0 \
"nc=setenv stdout nc;setenv stdin nc;\0" \
"ethaddr=00:0a:35:00:22:01\0" \
"autoload=no\0" \
"clobstart=0x10000000\0" \
"netstart=0x10000000\0" \
"dtbnetstart=0x11800000\0" \
"loadaddr=0x10000000\0" \
"bootsize=0x900000\0" \
"bootstart=0x0\0" \
"boot_img=BOOT.BIN\0" \
"load_boot=tftpboot ${clobstart} ${boot_img}\0" \
"update_boot=setenv img boot; setenv psize ${bootsize}; setenv installcmd \"install_boot\"; run load_boot test_img; setenv img; setenv psize; setenv installcmd\0" \
"install_boot=sf probe 0 && sf erase ${bootstart} ${bootsize} && " \
"sf write ${clobstart} ${bootstart} ${filesize}\0" \
"bootenvsize=0x40000\0" \
"bootenvstart=0x900000\0" \
"eraseenv=sf probe 0 && sf erase ${bootenvstart} ${bootenvsize}\0" \
"kernelsize=0x1600000\0" \
"kernelstart=0x2940000\0" \
"kernel_img=image.ub\0" \
"load_kernel=tftpboot ${clobstart} ${kernel_img}\0" \
"update_kernel=setenv img kernel; setenv psize ${kernelsize}; setenv installcmd \"install_kernel\"; run load_kernel test_crc; setenv img; setenv psize; setenv installcmd\0" \
"install_kernel=sf probe 0 && sf erase ${kernelstart} ${kernelsize} && " \
"sf write ${clobstart} ${kernelstart} ${filesize}\0" \
"cp_kernel2ram=sf probe 0 && sf read ${netstart} ${kernelstart} ${kernelsize}\0" \
"dtb_img=system.dtb\0" \
"load_dtb=tftpboot ${clobstart} ${dtb_img}\0" \
"update_dtb=setenv img dtb; setenv psize ${dtbsize}; setenv installcmd \"install_dtb\"; run load_dtb test_img; setenv img; setenv psize; setenv installcmd\0" \
"fault=echo ${img} image size is greater than allocated place - partition ${img} is NOT UPDATED\0" \
"test_crc=if imi ${clobstart}; then run test_img; else echo ${img} Bad CRC - ${img} is NOT UPDATED; fi\0" \
"test_img=setenv var \"if test ${filesize} -gt ${psize}\\; then run fault\\; else run ${installcmd}\\; fi\"; run var; setenv var\0" \
"netboot=tftpboot ${netstart} ${kernel_img} && bootm\0" \
"default_bootcmd=run cp_kernel2ram && bootm ${netstart}\0" \
""