[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;
+}