[gbl] Implement GBL EFI Fastboot protocol for bootloader flashing and EFI execution Implement the GblEfiFastbootProtocol in U-Boot to allow GBL to delegate certain fastboot commands to the firmware. Specifically, implement the command_exec method to handle: - 'fastboot flash bootloader': Delegates to amlmmc_write_bootloader to flash both eMMC boot partitions (boot0/boot1). - 'fastboot oem run-staged-efi': Executes the staged EFI image from GBL's download buffer using U-Boot's bootefi command. This enables GBL to support bootloader updates and recovery EFI execution over fastboot. Bug: 496295142 TAG=agy CONV=236c2e4e-69e4-48b6-a8ea-8986bc68bb04 Change-Id: I42dc35148d5d52c9860a7f6bd5a44124f3b4eec1 Reviewed-on: https://turquoise-internal-review.googlesource.com/c/third_party/u-boot/+/1351452 Reviewed-by: Dov Shlachter <dovs@google.com> Commit-Queue: Sergii Parubochyi <sergiip@google.com> GitOrigin-RevId: 9c97c64467406120f97c29cc138527d9572145f5
diff --git a/include/efi_loader.h b/include/efi_loader.h index 17f2175..c77e996 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h
@@ -581,6 +581,7 @@ efi_status_t efi_android_boot_register(void); efi_status_t efi_gbl_fastboot_transport_register(void); efi_status_t efi_rng_sw_register(void); +efi_status_t efi_gbl_fastboot_register(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/include/gbl_efi_common.h b/include/gbl_efi_common.h new file mode 100644 index 0000000..a4ebbe0 --- /dev/null +++ b/include/gbl_efi_common.h
@@ -0,0 +1,16 @@ +/* + * Copyright (c) 2026 The Fuchsia Authors + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __GBL_EFI_COMMON_H__ +#define __GBL_EFI_COMMON_H__ + +#define GBL_PROTOCOL_REVISION(major, minor) ((((major) & 0xFFFF) << 16) | ((minor) & 0xFFFF)) + +#define EFI_ENUM(camelname, width, ...) \ + enum { __VA_ARGS__ }; \ + typedef width camelname + +#endif /* __GBL_EFI_COMMON_H__ */
diff --git a/include/gbl_efi_fastboot_protocol.h b/include/gbl_efi_fastboot_protocol.h new file mode 100644 index 0000000..be28fb7 --- /dev/null +++ b/include/gbl_efi_fastboot_protocol.h
@@ -0,0 +1,65 @@ +/* + * Copyright (c) 2026 The Fuchsia Authors + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __GBL_EFI_FASTBOOT_PROTOCOL_H__ +#define __GBL_EFI_FASTBOOT_PROTOCOL_H__ + +#include <efi_api.h> +#include <gbl_efi_common.h> + +#define GBL_EFI_FASTBOOT_PROTOCOL_GUID \ + EFI_GUID(0xc67e48a0, 0x5eb8, 0x4127, 0xbe, 0x89, 0xdf, 0x2e, 0xd9, \ + 0x3d, 0x8a, 0x9a) + +#define GBL_EFI_FASTBOOT_PROTOCOL_REVISION GBL_PROTOCOL_REVISION(1, 0) + +#define GBL_EFI_FASTBOOT_SERIAL_NUMBER_MAX_LEN_UTF8 32 + +typedef void (*GetVarAllCallback)(void* context, size_t num_args, + const char *const *args, + const char *val); + +EFI_ENUM(GblEfiFastbootMessageType, uint32_t, + GBL_EFI_FASTBOOT_MESSAGE_TYPE_OKAY, + GBL_EFI_FASTBOOT_MESSAGE_TYPE_FAIL, + GBL_EFI_FASTBOOT_MESSAGE_TYPE_INFO); + +typedef efi_status_t (*FastbootMessageSender)(void* context, + GblEfiFastbootMessageType msg_type, + size_t msg_len, const char *msg); + +EFI_ENUM(GblEfiFastbootCommandExecResult, uint32_t, + GBL_EFI_FASTBOOT_COMMAND_EXEC_RESULT_PROHIBITED, + GBL_EFI_FASTBOOT_COMMAND_EXEC_RESULT_DEFAULT_IMPL, + GBL_EFI_FASTBOOT_COMMAND_EXEC_RESULT_CUSTOM_IMPL); + +typedef struct GblEfiFastbootProtocol { + uint64_t revision; + char serial_number[GBL_EFI_FASTBOOT_SERIAL_NUMBER_MAX_LEN_UTF8]; + + efi_status_t (*get_var)(struct GblEfiFastbootProtocol *self, + size_t num_args, const char *const *args, + size_t *buffer_size, char *buffer); + efi_status_t (*get_var_all)(struct GblEfiFastbootProtocol *self, + void *context, GetVarAllCallback cb); + + efi_status_t (*get_staged)(struct GblEfiFastbootProtocol *self, + size_t *buffer_size, size_t *buffer_remains, + uint8_t *buffer); + + efi_status_t (*command_exec)(struct GblEfiFastbootProtocol *self, + size_t num_args, const char *const *args, + size_t download_buffer_size, + size_t download_buffer_used_size, + uint8_t *download_buffer, + GblEfiFastbootCommandExecResult *implementation, + FastbootMessageSender sender, void *context); + efi_status_t (*get_partition_type)(struct GblEfiFastbootProtocol *self, + const char *part_name, + size_t *part_type_len, char *part_type); +} GblEfiFastbootProtocol; + +#endif /* __GBL_EFI_FASTBOOT_PROTOCOL_H__ */
diff --git a/include/gbl_efi_fastboot_transport.h b/include/gbl_efi_fastboot_transport.h index 1f7807c..30dd62c 100644 --- a/include/gbl_efi_fastboot_transport.h +++ b/include/gbl_efi_fastboot_transport.h
@@ -1,12 +1,13 @@ /* - * Copyright (c) 2025 The Fuchsia Authors + * Copyright (c) 2026 The Fuchsia Authors * * SPDX-License-Identifier: BSD-3-Clause */ #include <efi_api.h> +#include <gbl_efi_common.h> -#define GBL_EFI_FASTBOOT_TRANSPORT_PROTOCOL_REVISION 0x00000000 +#define GBL_EFI_FASTBOOT_TRANSPORT_PROTOCOL_REVISION GBL_PROTOCOL_REVISION(1, 0) #define GBL_EFI_FASTBOOT_TRANSPORT_PROTOCOL_GUID \ EFI_GUID(0xedade92c, 0x5c48, 0x440d, 0x84, 0x9c, 0xe2, 0xa0, 0xc7, \ @@ -20,12 +21,12 @@ typedef struct GblEfiFastbootTransportProtocol { uint64_t revision; const char *description; - EfiStatus (*start)(struct GblEfiFastbootTransportProtocol *self); - EfiStatus (*stop)(struct GblEfiFastbootTransportProtocol *self); - EfiStatus (*receive)(struct GblEfiFastbootTransportProtocol *self, + efi_status_t (*start)(struct GblEfiFastbootTransportProtocol *self); + efi_status_t (*stop)(struct GblEfiFastbootTransportProtocol *self); + efi_status_t (*receive)(struct GblEfiFastbootTransportProtocol *self, size_t *buffer_size, void *buffer, GblEfiFastbootRxMode mode); - EfiStatus (*send)(struct GblEfiFastbootTransportProtocol *self, + efi_status_t (*send)(struct GblEfiFastbootTransportProtocol *self, size_t *buffer_size, const void *buffer); - EfiStatus (*flush)(struct GblEfiFastbootTransportProtocol *self); + efi_status_t (*flush)(struct GblEfiFastbootTransportProtocol *self); } GblEfiFastbootTransportProtocol;
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 4d6d1ca..e1933ee 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile
@@ -92,6 +92,7 @@ obj-y += efi_android_boot.o obj-y += gbl_efi_fastboot_transport.o +obj-y += gbl_efi_fastboot.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 1bdb868..c5696af 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c
@@ -318,6 +318,10 @@ if (ret != EFI_SUCCESS) goto out; + ret = efi_gbl_fastboot_register(); + if (ret != EFI_SUCCESS) + goto out; + /* Secure boot */ ret = efi_init_secure_boot(); if (ret != EFI_SUCCESS)
diff --git a/lib/efi_loader/gbl_efi_fastboot.c b/lib/efi_loader/gbl_efi_fastboot.c new file mode 100644 index 0000000..c32d066 --- /dev/null +++ b/lib/efi_loader/gbl_efi_fastboot.c
@@ -0,0 +1,199 @@ +/* + * Copyright (c) 2026 The Fuchsia Authors + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common.h> +#include <efi_loader.h> +#include <gbl_efi_fastboot_protocol.h> +#include <mmc.h> +#include <amlogic/aml_mmc.h> + +static efi_status_t EFIAPI get_var(struct GblEfiFastbootProtocol *self, + size_t num_args, const char *const *args, + size_t *buffer_size, char *buffer) +{ + return EFI_UNSUPPORTED; +} + +static efi_status_t EFIAPI get_var_all(struct GblEfiFastbootProtocol *self, + void *context, GetVarAllCallback cb) +{ + return EFI_UNSUPPORTED; +} + +static efi_status_t EFIAPI get_staged(struct GblEfiFastbootProtocol *self, + size_t *buffer_size, size_t *buffer_remains, + uint8_t *buffer) +{ + return EFI_UNSUPPORTED; +} + +static efi_status_t EFIAPI get_partition_type(struct GblEfiFastbootProtocol *self, + const char *part_name, + size_t *part_type_len, char *part_type) +{ + return EFI_UNSUPPORTED; +} + +static efi_status_t handle_flash_bootloader(size_t download_buffer_used_size, + uint8_t *download_buffer, + FastbootMessageSender sender, void *context) +{ + if (sender) { + const char *msg = "Flashing bootloader via amlmmc...\n"; + sender(context, GBL_EFI_FASTBOOT_MESSAGE_TYPE_INFO, strlen(msg), msg); + } + + // Call amlmmc_write_bootloader + // We use AML_BL_BOOT to write to both boot0 and boot1 + int ret = amlmmc_write_bootloader(CONFIG_FASTBOOT_FLASH_MMC_DEV, + AML_BL_BOOT, + download_buffer_used_size, + download_buffer); + if (ret) { + if (sender) { + const char *msg = "Flash bootloader failed\n"; + sender(context, GBL_EFI_FASTBOOT_MESSAGE_TYPE_FAIL, strlen(msg), msg); + } + return EFI_DEVICE_ERROR; + } + + if (sender) { + const char *msg = "Flash bootloader success\n"; + sender(context, GBL_EFI_FASTBOOT_MESSAGE_TYPE_OKAY, strlen(msg), msg); + } + return EFI_SUCCESS; +} + +static efi_status_t handle_run_staged_efi(size_t download_buffer_used_size, + uint8_t *download_buffer, + FastbootMessageSender sender, void *context) +{ + if (download_buffer_used_size == 0 || !download_buffer) { + if (sender) { + const char *msg = "No EFI image staged\n"; + sender(context, GBL_EFI_FASTBOOT_MESSAGE_TYPE_FAIL, strlen(msg), msg); + } + return EFI_NOT_FOUND; + } + + if (sender) { + const char *msg = "Running staged EFI image...\n"; + sender(context, GBL_EFI_FASTBOOT_MESSAGE_TYPE_INFO, strlen(msg), msg); + } + + // We need to run the image. + // Similar to cb_run_staged_efi, we can use bootefi command. + char cmd[128]; + snprintf(cmd, sizeof(cmd), "bootefi 0x%lx:0x%lx ${dtb_mem_addr}", + (unsigned long)download_buffer, + (unsigned long)download_buffer_used_size); + + printf("Executing: %s\n", cmd); + + // This might not return if successful + run_command(cmd, 0); + + // If it returns, it failed or exited + if (sender) { + const char *msg = "EFI image returned\n"; + sender(context, GBL_EFI_FASTBOOT_MESSAGE_TYPE_FAIL, strlen(msg), msg); + } + return EFI_DEVICE_ERROR; +} + +typedef efi_status_t (*fastboot_cmd_handler_t)(size_t download_buffer_used_size, + uint8_t *download_buffer, + FastbootMessageSender sender, void *context); + +struct fastboot_cmd_match { + const char *const *args; + size_t num_args; + fastboot_cmd_handler_t handler; +}; + +#define CMD_ENTRIES_2(cb, w1, w2) \ + { \ + .args = (const char*const[]){w1, w2}, \ + .num_args = 2, \ + .handler = cb, \ + }, \ + { \ + .args = (const char*const[]){w1 " " w2}, \ + .num_args = 1, \ + .handler = cb, \ + } + +static const struct fastboot_cmd_match cmd_matches[] = { + CMD_ENTRIES_2(handle_flash_bootloader, "flash", "bootloader"), + CMD_ENTRIES_2(handle_run_staged_efi, "oem", "run-staged-efi"), +}; + +static efi_status_t EFIAPI command_exec(struct GblEfiFastbootProtocol *self, + size_t num_args, const char *const *args, + size_t download_buffer_size, + size_t download_buffer_used_size, + uint8_t *download_buffer, + GblEfiFastbootCommandExecResult *implementation, + FastbootMessageSender sender, void *context) +{ + EFI_ENTRY("%p, %zu, %p, %zu, %zu, %p", self, num_args, args, + download_buffer_size, download_buffer_used_size, download_buffer); + + if (num_args == 0 || !args || !implementation) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + // Default to not implemented by us + *implementation = GBL_EFI_FASTBOOT_COMMAND_EXEC_RESULT_DEFAULT_IMPL; + + for (size_t i = 0; i < ARRAY_SIZE(cmd_matches); i++) { + const struct fastboot_cmd_match *match = &cmd_matches[i]; + if (num_args < match->num_args) + continue; + + bool found = true; + for (size_t j = 0; j < match->num_args; j++) { + if (strcmp(args[j], match->args[j]) != 0) { + found = false; + break; + } + } + + if (found) { + *implementation = GBL_EFI_FASTBOOT_COMMAND_EXEC_RESULT_CUSTOM_IMPL; + return EFI_EXIT(match->handler(download_buffer_used_size, + download_buffer, + sender, context)); + } + } + + return EFI_EXIT(EFI_SUCCESS); +} + +static const efi_guid_t guid = GBL_EFI_FASTBOOT_PROTOCOL_GUID; + +static GblEfiFastbootProtocol protocol = { + .revision = GBL_EFI_FASTBOOT_PROTOCOL_REVISION, + .serial_number = "VIM3-GBL-FASTBOOT", + .get_var = get_var, + .get_var_all = get_var_all, + .get_staged = get_staged, + .command_exec = command_exec, + .get_partition_type = get_partition_type, +}; + +efi_status_t efi_gbl_fastboot_register(void) +{ + char *serial = getenv("serial#"); + if (serial) { + strncpy(protocol.serial_number, serial, sizeof(protocol.serial_number) - 1); + protocol.serial_number[sizeof(protocol.serial_number) - 1] = '\0'; + } + + efi_status_t ret = efi_add_protocol(efi_root, &guid, (void *)&protocol); + if (ret != EFI_SUCCESS) + printf("Cannot install GBL_EFI_FASTBOOT_PROTOCOL\n"); + return ret; +}
diff --git a/lib/efi_loader/gbl_efi_fastboot_transport.c b/lib/efi_loader/gbl_efi_fastboot_transport.c index cba4dd5..266bd6c 100644 --- a/lib/efi_loader/gbl_efi_fastboot_transport.c +++ b/lib/efi_loader/gbl_efi_fastboot_transport.c
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 The Fuchsia Authors + * Copyright (c) 2026 The Fuchsia Authors * * SPDX-License-Identifier: BSD-3-Clause */