UBoot 2021
setenv("bootargs", "$");
if ( boot_fw_num )
{
setenv("flag_boot_rootfs", "1");
sprintf(boot_cmd, "%s", "run boot_fw1");
}
else
{
setenv("flag_boot_rootfs", "0");
sprintf(boot_cmd, "%s", "run boot_fw0");
}
save_env();
printf("Booting System %d\n", boot_fw_num);
sub_41E03BAC((int)boot_cmd);
UBoot 2022
set_nvram_param("bootargs", cmdline);
if ( boot_part_num )
{
set_nvram_param("flag_boot_rootfs", "1");
sprintf((int)bootm_cmd, "%s", "run boot_fw1");
sprintf((int)try_value, "%d", __try_sys2 + 1);
try_name = "flag_try_sys2_failed";
}
else
{
set_nvram_param("flag_boot_rootfs", "0");
sprintf((int)bootm_cmd, "%s", "run boot_fw0");
sprintf((int)try_value, "%d", _try_sys1 + 1);
try_name = "flag_try_sys1_failed";
}
set_nvram_param(try_name, try_value);
saveenv();
log("Booting System %d\n", boot_part_num);
bootm(bootm_cmd, 0);
On new Xiaomi bootloaders, the flag_try_sysX_failed
counter increases with each reboot. The stock firmware resets the flag_try_sysX_failed
counter to 0 after a successful boot.
It probably makes sense to do the same in OpenWRT firmware.
Example of a similar task: https://github.com/openwrt/openwrt/blob/ced3fbcda18e200315cb077f7e2b362ae52ee065/target/linux/ramips/mt76x8/base-files/etc/init.d/bootcount#L11-L14
Official installation manual: https://openwrt.org/toh/xiaomi/ax3200
For the 2022 bootloader, this option is incorrect!
For a new bootloader you should do this:
nvram set boot_fw1="run boot_rd_img;bootm"
nvram set flag_try_sys1_failed=8
nvram set flag_try_sys2_failed=8
nvram set flag_boot_rootfs=0
nvram set flag_boot_success=1
nvram set flag_last_success=1
nvram commit
Uboot 2021
_try_sys = flag_try_sys2_failed > 1;
if ( flag_try_sys2_failed <= 1 )
_try_sys = flag_try_sys1_failed > 1;
if ( _try_sys )
boot_fw_num = 1;
else
boot_fw_num = 0;
if ( _try_sys )
{
boot_fw_num = 0;
}
Uboot 2022
flag_ota_reboot_is_2 = flag_ota_reboot > 1;
if ( flag_ota_reboot <= 1 )
flag_ota_reboot_is_2 = flag_last_success > 1;
if ( flag_ota_reboot_is_2 )
{
boot_part_num = 0;
}
else
{
try_sys_is_OK = try_sys2 == 0;
if ( try_sys2 )
try_sys_is_OK = try_sys1 == 0;
if ( !try_sys_is_OK )
log("Boot failure detected on both systems\n");
if ( flag_ota_reboot )
{
...
}
else
{
if ( flag_last_success )
_try_sys = try_sys2 > 5;
else
_try_sys = try_sys1 > 5;
if ( _try_sys )
boot_part_num = 1 - flag_last_success;
else
boot_part_num = flag_last_success;
}
}
Stock firmware after boot: /etc/init.d/boot_check
START=99
RCSTATFILE='/tmp/rc.timing'
BOOTCHECKCODEFILE='/tmp/rc.done'
set_setup_flag(){
local flg=0
local flag_boot_rootfs=$(nvram get flag_boot_rootfs)
local flag_ota_root=$(nvram get flag_ota_reboot)
local flag_boot_success=$(nvram get flag_boot_success)
local flag_try_sys1_failed=$(nvram get flag_try_sys1_failed)
local flag_try_sys2_failed=$(nvram get flag_try_sys2_failed)
local flag_last_success=$(nvram get flag_last_success)
[ "$flag_ota_root" != "0" ] && {
flg=1
nvram set flag_ota_reboot=0
}
[ "$flag_boot_success" != "1" ] && {
flg=1
nvram set flag_boot_success=1
}
[ "$flag_try_sys1_failed" != "0" ] && {
flg=1
nvram set flag_try_sys1_failed=0
}
[ "$flag_try_sys2_failed" != "0" ] && {
flg=1
nvram set flag_try_sys2_failed=0
}
[ "$flag_boot_rootfs" = "0" -o "$flag_boot_rootfs" = "1" ] && [ "$flag_boot_rootfs" != "$flag_last_success" ] && {
flg=1
nvram set flag_last_success=$flag_boot_rootfs
}
[ "$flg" = "1" ] && nvram commit
}
start() {
...
# set bootup flag
set_setup_flag
...
# boot finished
xqled sys_ok
echo "BOOTCHECKCODE=0;" > $BOOTCHECKCODEFILE
echo "boot_done" > /tmp/boot_check_done
elog "Booting up finished."
}