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" \
""