| /* |
| * 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; |
| } |