项目2:实现双系统启动 - 通过U-Boot选择加载Linux或RTOS
本项目将指导您如何配置U-Boot,使其能够在启动时提供选择菜单,让用户决定加载Linux操作系统或实时操作系统(RTOS)。这种双系统启动配置在嵌入式开发中非常有用,特别是当您需要在同一硬件平台上测试不同操作系统时。
在开始本项目前,您需要了解以下内容:
确保您已经准备好以下文件:
我们需要设置不同的环境变量来加载不同的系统:
# Linux启动命令
setenv bootcmd_linux 'fatload mmc 0:1 ${loadaddr} zImage; fatload mmc 0:1 ${fdt_addr} board.dtb; bootz ${loadaddr} - ${fdt_addr}'
# RTOS启动命令 (以FreeRTOS为例)
setenv bootcmd_rtos 'fatload mmc 0:1 ${loadaddr} rtos.bin; go ${loadaddr}'
# 默认启动Linux
setenv bootcmd 'run bootcmd_linux'
在U-Boot中添加一个交互式菜单,让用户可以选择启动的系统:
# 菜单定义
setenv menu_title 'Select Operating System'
setenv menu_1 'Boot Linux'
setenv menu_2 'Boot RTOS'
setenv menu_timeout '5'
# 菜单命令
setenv menu_cmd_1 'run bootcmd_linux'
setenv menu_cmd_2 'run bootcmd_rtos'
# 菜单脚本
setenv bootmenu "
setenv bootdelay 3
setenv menu_timeout ${menu_timeout}
while true; do
echo
echo '==========================================='
echo ' ${menu_title}'
echo '==========================================='
echo '1: ${menu_1}'
echo '2: ${menu_2}'
echo
echo 'Press 1 or 2 to select, or wait ${menu_timeout}s for default'
echo '==========================================='
setenv bootchoice
for i in 0 1 2 3 4 5 6 7 8 9; do
if test -n \"${bootchoice}\"; then
break
fi
if test ${i} -lt ${menu_timeout}; then
setenv oldtime ${time}
setenv time
if test \"${oldtime}\" != \"${time}\"; then
setenv time ${oldtime}
setexpr i ${i} + 1
fi
fi
if test ${i} -eq ${menu_timeout}; then
setenv bootchoice 1
break
fi
if test -n \"${getc}\"; then
setenv c ${getc}
else
if mmc dev 0; then
mw.b 0x80000000 0x1 1
mmc read 0x80000000 0x0 0x1
setenv c *0x80000000
fi
fi
if test \"${c}\" = \"1\"; then
setenv bootchoice 1
elif test \"${c}\" = \"2\"; then
setenv bootchoice 2
fi
done
if test \"${bootchoice}\" = \"1\"; then
echo 'Selected: ${menu_1}'
run menu_cmd_1
elif test \"${bootchoice}\" = \"2\"; then
echo 'Selected: ${menu_2}'
run menu_cmd_2
else
echo 'Timeout, booting default (${menu_1})'
run menu_cmd_1
fi
done
"
# 设置默认启动命令为菜单
setenv bootcmd 'run bootmenu'
saveenv
保存环境变量并重启开发板进行测试:
# 保存环境变量
saveenv
# 重启开发板
reset
您应该看到类似以下的启动菜单:
===========================================
Select Operating System
===========================================
1: Boot Linux
2: Boot RTOS
Press 1 or 2 to select, or wait 5s for default
===========================================
如果您使用的是较新版本的U-Boot,可以利用内置的菜单系统:
# 创建menu.cfg文件
menu title Select Operating System
menu timeout 20
menu margin 1
menu label Boot Linux
linux /boot/zImage
fdt /boot/board.dtb
append console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait
menu label Boot RTOS
kernel /boot/rtos.bin
bootm
然后将此文件编译为U-Boot可识别的格式:
mkimage -T script -C none -n 'Boot Menu' -d menu.cfg boot.scr
最后在U-Boot中加载这个菜单:
setenv bootcmd 'fatload mmc 0:1 ${loadaddr} boot.scr; source ${loadaddr}'
saveenv
您可以通过读取GPIO状态来自动选择启动的系统:
# 检查GPIO状态
gpio input 23
if test ${?} -eq 0; then
echo "Booting Linux (GPIO23 LOW)"
run bootcmd_linux
else
echo "Booting RTOS (GPIO23 HIGH)"
run bootcmd_rtos
fi
将启动选择存储在非易失性存储器中:
# 读取EEPROM中的启动选择
i2c dev 0
i2c read 0x50 0x00 0x1 0x80000000
setenv boot_choice *0x80000000
if test "${boot_choice}" = "1"; then
run bootcmd_linux
elif test "${boot_choice}" = "2"; then
run bootcmd_rtos
else
# 默认启动
run bootcmd_linux
fi
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 菜单不显示 | U-Boot版本不支持getc命令 | 使用更简单的菜单实现或升级U-Boot |
| RTOS无法启动 | 镜像加载地址不正确 | 检查RTOS的入口地址和加载地址是否匹配 |
| Linux启动失败 | 设备树或内核参数错误 | 验证设备树兼容性和内核命令行参数 |
| 环境变量不保存 | 存储设备写保护或损坏 | 检查环境存储区域并尝试重新保存 |
您可以扩展此项目以支持更多系统选项,如:
添加通过网络(TFTP)加载系统的选项:
setenv bootcmd_net 'tftp ${loadaddr} zImage; tftp ${fdt_addr} board.dtb; bootz ${loadaddr} - ${fdt_addr}'
在加载镜像前验证其完整性和真实性:
setenv bootcmd_linux '
fatload mmc 0:1 ${loadaddr} zImage;
fatload mmc 0:1 ${fdt_addr} board.dtb;
fatload mmc 0:1 ${sig_addr} zImage.sig;
if check_sig ${loadaddr} ${filesize} ${sig_addr}; then
bootz ${loadaddr} - ${fdt_addr};
else
echo "Invalid signature!";
fi
'