[gbl] Implement GBL EFI Boot Memory protocol
Implement GblEfiBootMemoryProtocol to provide kernel and FDT boot
buffers to GBL based on U-Boot environment variables ('loadaddr',
'loadsize', 'fdtaddr').
To ensure safety against dynamic memory allocations in GBL, reserve
the kernel and FDT memory ranges in the EFI memory map (as
EFI_BOOT_SERVICES_DATA) immediately upon protocol registration,
preventing UEFI page allocation overlap. Also validate that environment
variables have not changed when GBL queries get_boot_buffer.
TAG=agy
CONV=236c2e4e-69e4-48b6-a8ea-8986bc68bb04
Change-Id: Icb61b5618c0697a7fde25e44212cca4451f87c04
Reviewed-on: https://turquoise-internal-review.googlesource.com/c/third_party/u-boot/+/1370272
Commit-Queue: Sergii Parubochyi <sergiip@google.com>
Reviewed-by: David Pursell <dpursell@google.com>
GitOrigin-RevId: 51dd525ff405e606538780047562b3bf488ea55e
diff --git a/include/efi_loader.h b/include/efi_loader.h
index c77e996..e2894c9 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -582,6 +582,7 @@
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);
+efi_status_t efi_gbl_boot_memory_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_boot_memory_protocol.h b/include/gbl_efi_boot_memory_protocol.h
new file mode 100644
index 0000000..2141303
--- /dev/null
+++ b/include/gbl_efi_boot_memory_protocol.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2025 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_MEMORY_PROTOCOL_H__
+#define __GBL_EFI_BOOT_MEMORY_PROTOCOL_H__
+
+#include <gbl_efi_common.h>
+
+static const uint64_t GBL_EFI_BOOT_MEMORY_PROTOCOL_REVISION = GBL_PROTOCOL_REVISION(1, 0);
+
+EFI_ENUM(GblEfiBootBufferType, uint32_t, GBL_EFI_BOOT_BUFFER_TYPE_GENERAL_LOAD,
+ GBL_EFI_BOOT_BUFFER_TYPE_KERNEL, GBL_EFI_BOOT_BUFFER_TYPE_RAMDISK,
+ GBL_EFI_BOOT_BUFFER_TYPE_FDT, GBL_EFI_BOOT_BUFFER_TYPE_PVMFW_DATA,
+ GBL_EFI_BOOT_BUFFER_TYPE_FASTBOOT_DOWNLOAD);
+
+EFI_ENUM(GblEfiPartitionBufferFlag, uint32_t, GBL_EFI_PARTITION_BUFFER_FLAG_PRELOADED = 1 << 0);
+
+typedef struct GblEfiBootMemoryProtocol {
+ uint64_t revision;
+ efi_status_t (*get_partition_buffer)(struct GblEfiBootMemoryProtocol* self,
+ /* in */ const char* base_name,
+ /* out */ size_t* size,
+ /* out */ void** addr,
+ /* out */ GblEfiPartitionBufferFlag* flag);
+ efi_status_t (*sync_partition_buffer)(struct GblEfiBootMemoryProtocol* self,
+ /* in */ bool sync_preloaded);
+ efi_status_t (*get_boot_buffer)(struct GblEfiBootMemoryProtocol* self,
+ /* in */ GblEfiBootBufferType buf_type,
+ /* out */ size_t* size,
+ /* out */ void** addr);
+} GblEfiBootMemoryProtocol;
+
+#endif //__GBL_EFI_BOOT_MEMORY_PROTOCOL_H__
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 82c31eb..e860185 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -94,6 +94,7 @@
obj-y += efi_android_boot.o
obj-y += gbl_efi_fastboot_transport.o
obj-y += gbl_efi_fastboot.o
+obj-y += gbl_efi_boot_memory.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 c5696af..779d8e6 100644
--- a/lib/efi_loader/efi_setup.c
+++ b/lib/efi_loader/efi_setup.c
@@ -322,6 +322,10 @@
if (ret != EFI_SUCCESS)
goto out;
+ ret = efi_gbl_boot_memory_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_boot_memory.c b/lib/efi_loader/gbl_efi_boot_memory.c
new file mode 100644
index 0000000..adc88ca
--- /dev/null
+++ b/lib/efi_loader/gbl_efi_boot_memory.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2026 The Fuchsia Authors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <gbl_efi_boot_memory_protocol.h>
+
+static ulong reserved_kaddr;
+static ulong reserved_ksize;
+static ulong reserved_fdt_addr;
+static ulong reserved_fdt_size;
+
+static efi_status_t EFIAPI get_partition_buffer(
+ struct GblEfiBootMemoryProtocol *self, const char *base_name,
+ size_t *size, void **addr, GblEfiPartitionBufferFlag *flag)
+{
+ EFI_ENTRY("%p, %s, %p, %p, %p", self, base_name, size, addr, flag);
+ // We don't have any preloaded partitions in memory.
+ return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI sync_partition_buffer(
+ struct GblEfiBootMemoryProtocol *self, bool sync_preloaded)
+{
+ EFI_ENTRY("%p, %d", self, sync_preloaded);
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI get_boot_buffer(struct GblEfiBootMemoryProtocol *self,
+ GblEfiBootBufferType buf_type,
+ size_t *size, void **addr)
+{
+ EFI_ENTRY("%p, %d, %p, %p", self, buf_type, size, addr);
+ if (!size || !addr) {
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+ }
+
+ *addr = NULL;
+
+ switch (buf_type) {
+ case GBL_EFI_BOOT_BUFFER_TYPE_KERNEL: {
+ ulong kaddr = getenv_hex("loadaddr", 0x0);
+ ulong ksize = getenv_hex("loadsize", 0x4000000);
+ if (kaddr != reserved_kaddr || ksize != reserved_ksize) {
+ printf("GBL Boot Memory WARNING: 'loadaddr' or 'loadsize' changed after registration! (Registered: 0x%lx/0x%lx, Current: 0x%lx/0x%lx)\n",
+ reserved_kaddr, reserved_ksize, kaddr, ksize);
+ }
+ if (reserved_kaddr != 0) {
+ *addr = (void *)(uintptr_t)reserved_kaddr;
+ *size = (size_t)reserved_ksize;
+ }
+ break;
+ }
+ case GBL_EFI_BOOT_BUFFER_TYPE_FDT: {
+ ulong fdt_addr = getenv_hex("fdtaddr", 0x0);
+ if (fdt_addr != reserved_fdt_addr) {
+ printf("GBL Boot Memory WARNING: 'fdtaddr' changed after registration! (Registered: 0x%lx, Current: 0x%lx)\n",
+ reserved_fdt_addr, fdt_addr);
+ }
+ if (reserved_fdt_addr != 0) {
+ *addr = (void *)(uintptr_t)reserved_fdt_addr;
+ *size = (size_t)reserved_fdt_size;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (*addr) {
+ return EFI_EXIT(EFI_SUCCESS);
+ }
+
+ // Fallback to let GBL allocate its own buffer for the rest buffer types.
+ return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static const efi_guid_t guid = EFI_GUID(0x309f2874, 0xad59, 0x4fd2, 0xaf, 0x5e,
+ 0xce, 0x0f, 0x4a, 0xb4, 0x01, 0xa6);
+
+static GblEfiBootMemoryProtocol protocol = {
+ .revision = GBL_EFI_BOOT_MEMORY_PROTOCOL_REVISION,
+ .get_partition_buffer = get_partition_buffer,
+ .sync_partition_buffer = sync_partition_buffer,
+ .get_boot_buffer = get_boot_buffer,
+};
+
+efi_status_t efi_gbl_boot_memory_register(void)
+{
+ efi_status_t ret = efi_add_protocol(efi_root, &guid, (void *)&protocol);
+ if (ret != EFI_SUCCESS) {
+ printf("Cannot install GBL_EFI_BOOT_MEMORY_PROTOCOL\n");
+ return ret;
+ }
+
+ reserved_kaddr = getenv_hex("loadaddr", 0x0);
+ reserved_ksize = getenv_hex("loadsize", 0x4000000);
+ if (reserved_kaddr != 0) {
+ efi_add_memory_map(reserved_kaddr, reserved_ksize,
+ EFI_BOOT_SERVICES_DATA);
+ }
+
+ reserved_fdt_addr = getenv_hex("fdtaddr", 0x0);
+ reserved_fdt_size = 0x200000;
+ if (reserved_fdt_addr != 0) {
+ efi_add_memory_map(reserved_fdt_addr, reserved_fdt_size,
+ EFI_BOOT_SERVICES_DATA);
+ }
+
+ return EFI_SUCCESS;
+}