[gbl] Implement GBL EFI Boot Control protocol Implement GblEfiBootControlProtocol bound directly to the ABR C SDK (AbrGetBootSlot, AbrMarkSlotActive) for slot state querying and selection. Check gbl_one_shot_boot_mode / one_shot_boot_mode environment variables in get_one_shot_boot_mode to return GBL_EFI_ONE_SHOT_BOOT_MODE_BOOTLOADER or GBL_EFI_ONE_SHOT_BOOT_MODE_RECOVERY. TAG=agy CONV=236c2e4e-69e4-48b6-a8ea-8986bc68bb04 Change-Id: Id47c131b41d960ffbe04cc90c7f05060a97851da Reviewed-on: https://turquoise-internal-review.googlesource.com/c/third_party/u-boot/+/1369890 Reviewed-by: David Pursell <dpursell@google.com> Commit-Queue: Sergii Parubochyi <sergiip@google.com> GitOrigin-RevId: c0448f03361621dfb3121bad739d2df29aead3b1
diff --git a/include/efi_loader.h b/include/efi_loader.h index fed5751..f296d01 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h
@@ -584,6 +584,7 @@ efi_status_t efi_gbl_fastboot_register(void); efi_status_t efi_gbl_boot_memory_register(void); 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); /* Called by efi_init_obj_list() to do initial measurement */ efi_status_t efi_tcg2_do_initial_measurement(void);
diff --git a/include/gbl_efi_boot_control_protocol.h b/include/gbl_efi_boot_control_protocol.h new file mode 100644 index 0000000..3e0ed22 --- /dev/null +++ b/include/gbl_efi_boot_control_protocol.h
@@ -0,0 +1,83 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, embodiment or + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause-Patent + * + * This file is dual-licensed under Apache 2.0 and BSD-2-Clause-Patent. + * You may choose to use this file under the terms of either: + * (a) the Apache License, Version 2.0, or + * (b) the BSD 2-Clause Patent License. + * + * Unless you expressly elect the BSD-2-Clause-Patent terms, the Apache-2.0 + * license terms apply by default. + */ + +#ifndef __GBL_EFI_BOOT_CONTROL_PROTOCOL_H__ +#define __GBL_EFI_BOOT_CONTROL_PROTOCOL_H__ + +#include <gbl_efi_common.h> + +static const uint64_t GBL_EFI_BOOT_CONTROL_PROTOCOL_REVISION = GBL_PROTOCOL_REVISION(1, 0); + +EFI_ENUM(GblEfiUnbootableReason, uint8_t, GBL_EFI_UNBOOTABLE_REASON_UNKNOWN_REASON, + GBL_EFI_UNBOOTABLE_REASON_NO_MORE_TRIES, GBL_EFI_UNBOOTABLE_REASON_SYSTEM_UPDATE, + GBL_EFI_UNBOOTABLE_REASON_USER_REQUESTED, GBL_EFI_UNBOOTABLE_REASON_VERIFICATION_FAILURE); + +EFI_ENUM(GblEfiOneShotBootMode, uint32_t, GBL_EFI_ONE_SHOT_BOOT_MODE_NONE, + GBL_EFI_ONE_SHOT_BOOT_MODE_BOOTLOADER, GBL_EFI_ONE_SHOT_BOOT_MODE_RECOVERY); + +typedef struct { + // One UTF-8 encoded single character + uint32_t suffix; + // Any value other than those explicitly enumerated in EFI_UNBOOTABLE_REASON + // will be interpreted as UNKNOWN_REASON. + GblEfiUnbootableReason unbootable_reason; + uint8_t priority; + // Number of remaining tries to attempt to boot the slot + uint8_t remaining_tries; + // Value of 1 if slot has successfully booted + uint8_t successful; +} GblEfiSlotInfo; + +typedef struct { + size_t kernel_size; + efi_physical_addr_t kernel; + size_t ramdisk_size; + efi_physical_addr_t ramdisk; + size_t device_tree_size; + efi_physical_addr_t device_tree; + uint64_t reserved[8]; +} GblEfiLoadedOs; + +typedef struct GblEfiBootControlProtocol { + uint64_t revision; + // Slot metadata query methods + efi_status_t (*get_slot_count)(struct GblEfiBootControlProtocol* self, + /* out */ uint8_t* slot_count); + efi_status_t (*get_slot_info)(struct GblEfiBootControlProtocol* self, + /* in */ uint8_t index, + /* out */ GblEfiSlotInfo* info); + efi_status_t (*get_current_slot)(struct GblEfiBootControlProtocol* self, + /* out */ GblEfiSlotInfo* info); + // Slot metadata manipulation methods + efi_status_t (*set_active_slot)(struct GblEfiBootControlProtocol* self, + /* in */ uint8_t index); + // Boot control methods + efi_status_t (*get_one_shot_boot_mode)(struct GblEfiBootControlProtocol* self, + /* out */ GblEfiOneShotBootMode* mode); + efi_status_t (*handle_loaded_os)(struct GblEfiBootControlProtocol* self, + /* in */ const GblEfiLoadedOs* os); +} GblEfiBootControlProtocol; + +#endif // __GBL_EFI_BOOT_CONTROL_PROTOCOL_H__
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index a2cd00e..9f631d4 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile
@@ -10,6 +10,11 @@ ccflags-y += -DHOST_ARCH="$(HOST_ARCH)" ccflags-y += -I$(srctree)/lib/fuchsia/firmware_sdk/pkg/abr/include +CFLAGS_gbl_efi_boot_control.o += \ + -I$(srctree)/lib/fuchsia/firmware_sdk/pkg/zircon_boot/include \ + -I$(srctree)/lib/fuchsia/firmware_sdk/pkg/zbi/include \ + -I$(srctree)/lib/fuchsia/firmware_sdk/pkg/zbi-format/include + CFLAGS_gbl_efi_fastboot.o += -I$(srctree)/lib/fuchsia/firmware_sdk/pkg/abr/include CFLAGS_efi_boottime.o += \ -DFW_VERSION="0x$(VERSION)" \ @@ -97,6 +102,7 @@ obj-y += gbl_efi_fastboot.o obj-y += gbl_efi_boot_memory.o obj-y += gbl_efi_debug.o +obj-y += gbl_efi_boot_control.o obj-y += gbl_efi_avb.o obj-y += efi_aml_sd_emmc.o obj-y += efi_timestamp.o
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 29e45e7..af8986b 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c
@@ -330,6 +330,10 @@ if (ret != EFI_SUCCESS) goto out; + ret = efi_gbl_boot_control_register(); + if (ret != EFI_SUCCESS) + goto out; + ret = efi_gbl_avb_register(); if (ret != EFI_SUCCESS) goto out;
diff --git a/lib/efi_loader/gbl_efi_boot_control.c b/lib/efi_loader/gbl_efi_boot_control.c new file mode 100644 index 0000000..50e1cef --- /dev/null +++ b/lib/efi_loader/gbl_efi_boot_control.c
@@ -0,0 +1,112 @@ +/* + * Copyright (c) 2026 The Fuchsia Authors + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common.h> +#include <efi_loader.h> +#include <gbl_efi_boot_control_protocol.h> + +// Slot management functions return EFI_UNSUPPORTED as GBL's Fuchsia flow +// does not rely on this protocol for slot work. + +static efi_status_t EFIAPI +get_slot_count(struct GblEfiBootControlProtocol *self, uint8_t *slot_count) +{ + EFI_ENTRY("%p, %p", self, slot_count); + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI get_slot_info(struct GblEfiBootControlProtocol *self, + uint8_t index, GblEfiSlotInfo *info) +{ + EFI_ENTRY("%p, %d, %p", self, index, info); + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI +get_current_slot(struct GblEfiBootControlProtocol *self, GblEfiSlotInfo *info) +{ + EFI_ENTRY("%p, %p", self, info); + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI +set_active_slot(struct GblEfiBootControlProtocol *self, uint8_t index) +{ + EFI_ENTRY("%p, %d", self, index); + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI get_one_shot_boot_mode( + struct GblEfiBootControlProtocol *self, GblEfiOneShotBootMode *mode) +{ + EFI_ENTRY("%p, %p", self, mode); + if (!mode) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + char *boot_mode = getenv("gbl_one_shot_boot_mode"); + + if (boot_mode && (strcmp(boot_mode, "bootloader") == 0 || + strcmp(boot_mode, "fastboot") == 0)) { + printf("GBL: One-shot boot mode set via env: %s\n", boot_mode); + *mode = GBL_EFI_ONE_SHOT_BOOT_MODE_BOOTLOADER; + return EFI_EXIT(EFI_SUCCESS); + } + + printf("\nPress 'f' to enter fastboot mode...\n"); + ulong start = get_timer(0); + bool enter_fastboot = false; + while (get_timer(start) < 2000) { + if (tstc()) { + int c = getc(); + if (c == 'f') { + enter_fastboot = true; + break; + } + } + udelay(1000); + } + + if (enter_fastboot) { + printf("Entering fastboot mode...\n"); + *mode = GBL_EFI_ONE_SHOT_BOOT_MODE_BOOTLOADER; + } else { + *mode = GBL_EFI_ONE_SHOT_BOOT_MODE_NONE; + } + return EFI_EXIT(EFI_SUCCESS); +} + +static efi_status_t EFIAPI handle_loaded_os( + struct GblEfiBootControlProtocol *self, const GblEfiLoadedOs *os) +{ + EFI_ENTRY("%p, %p", self, os); + if (!os) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + printf("GBL: Loaded OS: kernel size %zu at 0x%llx, ramdisk size %zu at 0x%llx\n", + os->kernel_size, os->kernel, os->ramdisk_size, os->ramdisk); + return EFI_EXIT(EFI_SUCCESS); +} + +static const efi_guid_t guid = EFI_GUID(0xd382db1b, 0x9ac2, 0x11f0, 0x84, 0xc7, + 0x04, 0x7b, 0xcb, 0xa9, 0x60, 0x19); + +static GblEfiBootControlProtocol protocol = { + .revision = GBL_EFI_BOOT_CONTROL_PROTOCOL_REVISION, + .get_slot_count = get_slot_count, + .get_slot_info = get_slot_info, + .get_current_slot = get_current_slot, + .set_active_slot = set_active_slot, + .get_one_shot_boot_mode = get_one_shot_boot_mode, + .handle_loaded_os = handle_loaded_os, +}; + +efi_status_t efi_gbl_boot_control_register(void) +{ + efi_status_t ret = efi_add_protocol(efi_root, &guid, (void *)&protocol); + if (ret != EFI_SUCCESS) + printf("Cannot install GBL_EFI_BOOT_CONTROL_PROTOCOL\n"); + return ret; +}