[efi] Honor ABR one-shot bootloader flag on EFI reset

When GBL handles 'fastboot reboot-bootloader', it sets the ABR one-shot
bootloader flag in durable_boot and calls UEFI ResetSystem(), which
invokes efi_reset_system_boottime(). Unconditionally running 'reboot'
sets the Amlogic reboot mode register (AO_SEC_SD_CFG15) to normal boot,
causing legacy U-Boot to boot Zircon instead of entering fastboot after
a bootloader rollback.

Add GetAndClearOneShotBootloaderFlag() in zircon_boot.c (preserving
one-shot recovery if set) and call it in efi_reset_system_boottime() to
run 'reboot fastboot' when requested, logging a warning if the reboot
command returns before falling back to do_reset().

TAG=agy
CONV=d6901459-7b8c-4e0a-8447-092869375046
Bug: 571205565
Test: Built VIM3 U-Boot with ./fuchsia_build.py

Change-Id: I020bcd960f94135f3266512cb170c9204eec2107
Reviewed-on: https://turquoise-internal-review.googlesource.com/c/third_party/u-boot/+/1683274
Reviewed-by: David Pursell <dpursell@google.com>
Commit-Queue: Sergii Parubochyi <sergiip@google.com>
GitOrigin-RevId: 8e7ac1835c7d1d9a54fca2fa5b4a3a139b887fd6
diff --git a/board/khadas/kvim3/zircon_boot.c b/board/khadas/kvim3/zircon_boot.c
index 7f01c04..fcd9020 100644
--- a/board/khadas/kvim3/zircon_boot.c
+++ b/board/khadas/kvim3/zircon_boot.c
@@ -279,6 +279,18 @@
 	return zircon_preboot(buffer, capacity, true) == 0 ? 0 : -1;
 }
 
+bool GetAndClearOneShotBootloaderFlag(void)
+{
+	AbrOps abr_ops = GetAbrOpsFromZirconBootOps(&zb_ops);
+	AbrDataOneShotFlags one_shot_flags = kAbrDataOneShotFlagNone;
+	if (AbrGetAndClearOneShotFlags(&abr_ops, &one_shot_flags) ==
+	    kAbrResultOk &&
+	    AbrIsOneShotRecoveryBootSet(one_shot_flags)) {
+		AbrSetOneShotRecovery(&abr_ops, true);
+	}
+	return AbrIsOneShotBootloaderBootSet(one_shot_flags);
+}
+
 int do_zbi_boot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
 	long unsigned int loadaddr;
diff --git a/include/efi_loader.h b/include/efi_loader.h
index f296d01..6b86e8e 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -586,6 +586,7 @@
 efi_status_t efi_gbl_debug_register(void);
 efi_status_t efi_gbl_boot_control_register(void);
 efi_status_t efi_gbl_avb_register(void);
+bool GetAndClearOneShotBootloaderFlag(void);
 /* Called by efi_init_obj_list() to do initial measurement */
 efi_status_t efi_tcg2_do_initial_measurement(void);
 /* measure the pe-coff image, extend PCR and add Event Log */
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 7fa507a..0a9305e 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -210,8 +210,17 @@
 	case EFI_RESET_COLD:
 	case EFI_RESET_WARM:
 	case EFI_RESET_PLATFORM_SPECIFIC:
-		run_command("reboot", 0);
+		// TODO(https://fxbug.dev/573411501): Remove once GBL U-Boot rollout is
+		// complete. GBL already checks the ABR one-shot flag on boot, so this
+		// is only needed when flashing back to legacy U-Boot, which only checks
+		// the hardware reboot register (set by "reboot fastboot").
+		if (GetAndClearOneShotBootloaderFlag()) {
+			run_command("reboot fastboot", 0);
+		} else {
+			run_command("reboot", 0);
+		}
 		// Fallback if 'reboot' is unavailable or returns
+		printf("Warning: 'reboot' command failed, falling back to do_reset()\n");
 		do_reset(NULL, 0, 0, NULL);
 		break;
 	case EFI_RESET_SHUTDOWN: