[gbl] Implement get_var in GBL EFI Fastboot protocol

Delegate fastboot get_var queries from GBL to U-Boot environment variables
via getenv().

TAG=agy
CONV=236c2e4e-69e4-48b6-a8ea-8986bc68bb04

Change-Id: I8e1e68b24ae0479f9bc347e68e02b40077863feb
Reviewed-on: https://turquoise-internal-review.googlesource.com/c/third_party/u-boot/+/1382091
Commit-Queue: Sergii Parubochyi <sergiip@google.com>
Reviewed-by: David Pursell <dpursell@google.com>
GitOrigin-RevId: 323089e5da1412ea9d3b0ab5e34a0d18b06999bc
diff --git a/common/Makefile b/common/Makefile
index e6387b9..578b5ef 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -372,7 +372,10 @@
 
 CFLAGS_env_embedded.o := -Wa,--no-warn -DENV_CRC=$(shell tools/envcrc 2>/dev/null)
 
-fuchsia_include = -I$(fuchsia_sdk)/zbi/include -I$(fuchsia_sdk)/zbi-format/include
+fuchsia_include = -I$(fuchsia_sdk)/zbi/include -I$(fuchsia_sdk)/zbi-format/include -I$(fuchsia_sdk)/abr/include
+CFLAGS_aboot.o += $(fuchsia_include)
+CFLAGS_fb_mmc.o += $(fuchsia_include)
+CFLAGS_fb_nand.o += $(fuchsia_include)
 CFLAGS_cmd_imgread.o += $(fuchsia_include)
 CFLAGS_image.o += $(fuchsia_include)
 CFLAGS_image-zircon.o += $(fuchsia_include)
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index ab3c1db..447e912 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -561,7 +561,7 @@
 //
 // On failure, this updates the fastboot TX buffer with a failure message and
 // returns NULL.
-static const char *parse_fb_cmd_partition(char *cmd)
+const char *parse_fb_cmd_partition(char *cmd)
 {
 	strsep(&cmd, ":");
 	if (cmd == NULL) {
@@ -659,7 +659,7 @@
 	}
 }
 
-static const char* getvar_list[] = {
+const char fastboot_getvar_list[][RESPONSE_LEN] = {
 	"version-baseband", "version-bootloader", "version", "hw-revision", "max-download-size",
 	"serialno", "product", "off-mode-charge", "variant", "battery-soc-ok",
 	"battery-voltage", "partition-type:boot", "partition-size:boot",
@@ -667,8 +667,9 @@
 	"partition-type:odm", "partition-size:odm", "partition-type:data", "partition-size:data",
 	"erase-block-size", "logical-block-size", "secure", "unlocked",
 };
+const size_t fastboot_getvar_list_size = ARRAY_SIZE(fastboot_getvar_list);
 
-static const char* getvar_list_dynamic[] = {
+const char fastboot_getvar_list_dynamic[][RESPONSE_LEN] = {
 	"hw-revision", "battery-voltage", "is-userspace", "is-logical:data",
 	"is-logical:metadata", "is-logical:misc", "is-logical:super", "is-logical:boot",
 	"is-logical:system", "is-logical:vendor", "is-logical:product", "is-logical:odm",
@@ -679,8 +680,9 @@
 	"partition-size:boot", "partition-size:metadata", "partition-size:misc",
 	"partition-size:super", "partition-size:data", "version",
 };
+const size_t fastboot_getvar_list_dynamic_size = ARRAY_SIZE(fastboot_getvar_list_dynamic);
 
-static const char *getvar_list_ab[] = {
+const char fastboot_getvar_list_ab[][RESPONSE_LEN] = {
 	"current-slot",
 	"has-slot:" GPT_DURABLE_BOOT_NAME,
 	"has-slot:" GPT_FVM_NAME,
@@ -716,12 +718,32 @@
 	"vx-locked",
 	"vx-unlockable",
 };
+const size_t fastboot_getvar_list_ab_size = ARRAY_SIZE(fastboot_getvar_list_ab);
+
+
+// Subset of fastboot_getvar_list_ab excluding GBL reserved values
+const char fastboot_getvar_list_ab_gbl_limited[][RESPONSE_LEN] = {
+	"hw-revision",
+	"product",
+	"serialno",
+	"slot-suffixes",
+	"slot-unbootable-reason:a",
+	"slot-unbootable-reason:b",
+	"version",
+	"vx-locked",
+	"vx-unlockable",
+	// GBL would report own version via 'version-bootloader'.
+	// So need extra var to pass u-boot version.
+	"u-boot-version",
+};
+const size_t fastboot_getvar_list_ab_gbl_limited_size =
+	ARRAY_SIZE(fastboot_getvar_list_ab_gbl_limited);
 
 extern ZirconBootOps zb_ops;
 
 // Returns slot info for the given slot string "a" or "b", or NULL on failure.
 // The returned struct is only valid until the next call to this function.
-static AbrSlotInfo* get_slot_info(const char *suffix)
+AbrSlotInfo* fastboot_get_slot_info(const char *suffix)
 {
 	AbrSlotIndex slot_index;
 	if (strcmp(suffix, "a") == 0) {
@@ -746,7 +768,6 @@
 	char *cmd = req->buf;
 	char cmdBuf[RESPONSE_LEN];
 	char* response = response_str;
-	char *s1;
 	size_t chars_left;
 
 	strcpy(response, "OKAY");
@@ -764,15 +785,15 @@
 	if (!strncmp(cmd, "all", 3)) {
 		static int cmdIndex = 0;
 		int getvar_num = 0;
-		if (has_boot_slot == 1 && strlen(getvar_list_ab[cmdIndex]) < 64) {
-			strcpy(cmd, getvar_list_ab[cmdIndex]);
-			getvar_num = (sizeof(getvar_list_ab) / sizeof(getvar_list_ab[0]));
-		} else if (dynamic_partition && strlen(getvar_list_dynamic[cmdIndex]) < 64) {
-			strcpy(cmd, getvar_list_dynamic[cmdIndex]);//only support no-arg cmd
-			getvar_num = (sizeof(getvar_list_dynamic) / sizeof(getvar_list_dynamic[0]));
-		} else if (strlen(getvar_list[cmdIndex]) < 64) {
-			strcpy(cmd, getvar_list[cmdIndex]);//only support no-arg cmd
-			getvar_num = (sizeof(getvar_list) / sizeof(getvar_list[0]));
+		if (has_boot_slot == 1 && cmdIndex < fastboot_getvar_list_ab_size) {
+			strcpy(cmd, fastboot_getvar_list_ab[cmdIndex]);
+			getvar_num = fastboot_getvar_list_ab_size;
+		} else if (dynamic_partition && cmdIndex < fastboot_getvar_list_dynamic_size) {
+			strcpy(cmd, fastboot_getvar_list_dynamic[cmdIndex]);//only support no-arg cmd
+			getvar_num = fastboot_getvar_list_dynamic_size;
+		} else if (cmdIndex < fastboot_getvar_list_size) {
+			strcpy(cmd, fastboot_getvar_list[cmdIndex]);//only support no-arg cmd
+			getvar_num = fastboot_getvar_list_size;
 		}
 		FB_DBG("getvar_num: %d\n", getvar_num);
 		if (++cmdIndex > getvar_num) {
@@ -789,10 +810,19 @@
 		chars_left -= strlen(cmd) + 1;
 	}
 
+	fastboot_get_var(cmd, response, chars_left);
+	fastboot_tx_write_str(response);
+}
+
+int fastboot_get_var(char *cmd, char *response, size_t chars_left)
+{
+	char *s1;
+
 	if (!strcmp_l1("version-baseband", cmd)) {
 		strncat(response, "N/A", chars_left);
 	} else if (!strcmp_l1("version-bootloader", cmd) ||
-		   !strcmp_l1("bootloader-version", cmd)) {
+		   !strcmp_l1("bootloader-version", cmd) ||
+		   !strcmp_l1("u-boot-version", cmd)) {
 		strncat(response, U_BOOT_VERSION, chars_left);
 	} else if (!strcmp_l1("hw-revision", cmd)) {
 		strncat(response, "vim3", chars_left);
@@ -878,6 +908,7 @@
 		if (AbrGetSlotLastMarkedActive(&ops, &slot_index) !=
 		    kAbrResultOk) {
 			fastboot_fail("Failed to fetch last active slot");
+			return -1;
 		} else {
 			const char *slot = AbrGetSlotSuffix(slot_index);
 			strncat(response, slot + 1, chars_left);
@@ -889,7 +920,7 @@
 		strsep(&cmd, ":");
 		if (!cmd) {
 			fastboot_tx_write_str("FAILmissing partition name");
-			return;
+			return -1;
 		}
 
 		char slotted_part[36];
@@ -903,7 +934,7 @@
 		} else {
 			// If neither exists it's an unknown partition.
 			fastboot_tx_write_str("FAILunknown partition");
-			return;
+			return -1;
 		}
 	} else if (!strncmp("partition-size", cmd, strlen("partition-size"))) {
 		char str_num[20];
@@ -912,11 +943,12 @@
 
 		const char *part = parse_fb_cmd_partition(cmd);
 		if (!part) {
-			return;
+			return -1;
 		}
 
 		if (!strncmp("mbr", part, strlen("mbr"))) {
 			strcpy(response, "FAILVariable not implemented");
+			return -1;
 		} else {
 			if (!strcmp("bootloader", part)) {
 				// boot0 and boot1 have the same size.
@@ -939,7 +971,7 @@
 					FB_DBG("find_mmc_partition_by_name fail\n");
 					fastboot_tx_write_str(
 						"FAILpartition does not exist");
-					return;
+					return -1;
 				}
 			}
 			strncat(response, str_num, chars_left);
@@ -952,7 +984,7 @@
 		const char *part = parse_fb_cmd_partition(cmd);
 		if (!part) {
 			fastboot_tx_write_str("FAILpartition does not exist");
-			return;
+			return -1;
 		}
 		// Fastboot doesn't know about any of our image formats so it's
 		// all raw data as far as fastboot is concerned.
@@ -976,9 +1008,10 @@
 		strsep(&cmd, ":");
 		FB_DBG("cmd is %s\n", cmd);
 
-		AbrSlotInfo *slot_info = get_slot_info(cmd);
+		AbrSlotInfo *slot_info = fastboot_get_slot_info(cmd);
 		if (slot_info == NULL) {
 			fastboot_fail("Invalid slot suffix");
+			return -1;
 		} else {
 			strncat(response,
 				slot_info->is_marked_successful ? "yes" : "no",
@@ -991,9 +1024,10 @@
 		strsep(&cmd, ":");
 		FB_DBG("cmd is %s\n", cmd);
 
-		AbrSlotInfo *slot_info = get_slot_info(cmd);
+		AbrSlotInfo *slot_info = fastboot_get_slot_info(cmd);
 		if (slot_info == NULL) {
 			fastboot_fail("Invalid slot suffix");
+			return -1;
 		} else if (slot_info->is_bootable) {
 			strncat(response, "N/A", chars_left);
 		} else {
@@ -1029,9 +1063,10 @@
 		strsep(&cmd, ":");
 		FB_DBG("cmd is %s\n", cmd);
 
-		AbrSlotInfo *slot_info = get_slot_info(cmd);
+		AbrSlotInfo *slot_info = fastboot_get_slot_info(cmd);
 		if (slot_info == NULL) {
 			fastboot_fail("Invalid slot suffix");
+			return -1;
 		} else {
 			strncat(response, slot_info->is_bootable ? "no" : "yes",
 				chars_left);
@@ -1040,9 +1075,10 @@
 		strsep(&cmd, ":");
 		FB_DBG("cmd is %s\n", cmd);
 
-		AbrSlotInfo *slot_info = get_slot_info(cmd);
+		AbrSlotInfo *slot_info = fastboot_get_slot_info(cmd);
 		if (slot_info == NULL) {
 			fastboot_fail("Invalid slot suffix");
+			return -1;
 		} else {
 			char buf[4];
 			sprintf(buf, "%d", slot_info->num_tries_remaining);
@@ -1058,9 +1094,9 @@
 	} else {
 		error("unknown variable: %s\n", cmd);
 		strcpy(response, "FAILVariable not implemented");
+		return -1;
 	}
-
-	fastboot_tx_write_str(response);
+	return 0;
 }
 
 static unsigned int rx_bytes_expected(void)
diff --git a/include/fb_fastboot.h b/include/fb_fastboot.h
index ecced35..2106778 100644
--- a/include/fb_fastboot.h
+++ b/include/fb_fastboot.h
@@ -21,8 +21,23 @@
 #ifndef _FASTBOOT_H_
 #define _FASTBOOT_H_
 
+#include <lib/abr/abr.h>
+
 #define RESPONSE_LEN	(64 + 1)
 void fastboot_fail(const char *s);
 void fastboot_okay(const char *s);
+int fastboot_get_var(char *cmd, char *response, size_t chars_left);
+extern const char fastboot_getvar_list[][RESPONSE_LEN];
+extern const size_t fastboot_getvar_list_size;
+extern const char fastboot_getvar_list_dynamic[][RESPONSE_LEN];
+extern const size_t fastboot_getvar_list_dynamic_size;
+extern const char fastboot_getvar_list_ab[][RESPONSE_LEN];
+extern const size_t fastboot_getvar_list_ab_size;
+extern const char fastboot_getvar_list_ab_gbl_limited[][RESPONSE_LEN];
+extern const size_t fastboot_getvar_list_ab_gbl_limited_size;
+// Returns slot info for the given slot string "a" or "b", or NULL on failure.
+// The returned struct is only valid until the next call to this function.
+AbrSlotInfo *fastboot_get_slot_info(const char *suffix);
+const char *parse_fb_cmd_partition(char *cmd);
 
 #endif/*_FASTBOOT_H_*/
diff --git a/include/gbl_efi_common.h b/include/gbl_efi_common.h
index a4ebbe0..93bc3d2 100644
--- a/include/gbl_efi_common.h
+++ b/include/gbl_efi_common.h
@@ -1,7 +1,26 @@
 /*
- * Copyright (c) 2026 The Fuchsia Authors
+ * Copyright (C) 2024 The Android Open Source Project
  *
- * SPDX-License-Identifier:	BSD-3-Clause
+ * 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_COMMON_H__
diff --git a/include/gbl_efi_fastboot_protocol.h b/include/gbl_efi_fastboot_protocol.h
index be28fb7..3703def 100644
--- a/include/gbl_efi_fastboot_protocol.h
+++ b/include/gbl_efi_fastboot_protocol.h
@@ -1,7 +1,26 @@
 /*
- * Copyright (c) 2026 The Fuchsia Authors
+ * Copyright (C) 2024 The Android Open Source Project
  *
- * SPDX-License-Identifier:	BSD-3-Clause
+ * 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_FASTBOOT_PROTOCOL_H__
diff --git a/include/gbl_efi_fastboot_transport.h b/include/gbl_efi_fastboot_transport.h
index 9fbcbf8..043f0fb 100644
--- a/include/gbl_efi_fastboot_transport.h
+++ b/include/gbl_efi_fastboot_transport.h
@@ -1,7 +1,26 @@
 /*
- * Copyright (c) 2026 The Fuchsia Authors
+ * Copyright (C) 2024 The Android Open Source Project
  *
- * SPDX-License-Identifier:	BSD-3-Clause
+ * 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.
  */
 
 #include <efi_api.h>
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index e1933ee..82c31eb 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -9,6 +9,7 @@
 asflags-y += -DHOST_ARCH="$(HOST_ARCH)" -I.
 ccflags-y += -DHOST_ARCH="$(HOST_ARCH)"
 
+CFLAGS_gbl_efi_fastboot.o += -I$(srctree)/lib/fuchsia/firmware_sdk/pkg/abr/include
 CFLAGS_efi_boottime.o += \
   -DFW_VERSION="0x$(VERSION)" \
   -DFW_PATCHLEVEL="0x$(PATCHLEVEL)"
diff --git a/lib/efi_loader/gbl_efi_fastboot.c b/lib/efi_loader/gbl_efi_fastboot.c
index c32d066..e0d9857 100644
--- a/lib/efi_loader/gbl_efi_fastboot.c
+++ b/lib/efi_loader/gbl_efi_fastboot.c
@@ -9,18 +9,70 @@
 #include <gbl_efi_fastboot_protocol.h>
 #include <mmc.h>
 #include <amlogic/aml_mmc.h>
+#include <version.h>
+#include <g_dnl.h>
+#include <fb_fastboot.h>
+#include <partition_table.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;
+	EFI_ENTRY("%p, %zu, %p, %p, %p", self, num_args, args, buffer_size, buffer);
+	if (num_args == 0 || !args || !buffer_size || (*buffer_size > 0 && !buffer))
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+	char cmd_buf[RESPONSE_LEN];
+	char resp_buf[RESPONSE_LEN] = "";
+	snprintf(cmd_buf, sizeof(cmd_buf), "%s", args[0]);
+
+	if (fastboot_get_var(cmd_buf, resp_buf, sizeof(resp_buf) - 1) != 0)
+		return EFI_EXIT(EFI_NOT_FOUND);
+
+	size_t len = strlen(resp_buf);
+	if (*buffer_size < len + 1) {
+		*buffer_size = len + 1;
+		return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+	}
+
+	strncpy(buffer, resp_buf, *buffer_size);
+	*buffer_size = len;
+	return EFI_EXIT(EFI_SUCCESS);
 }
 
 static efi_status_t EFIAPI get_var_all(struct GblEfiFastbootProtocol *self,
 				       void *context, GetVarAllCallback cb)
 {
-	return EFI_UNSUPPORTED;
+	EFI_ENTRY("%p, %p, %p", self, context, cb);
+	if (!cb)
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+	const char (*var_list)[RESPONSE_LEN];
+	size_t var_list_size;
+
+	if (has_boot_slot == 1) {
+		var_list = fastboot_getvar_list_ab_gbl_limited;
+		var_list_size = fastboot_getvar_list_ab_gbl_limited_size;
+	} else if (dynamic_partition) {
+		var_list = fastboot_getvar_list_dynamic;
+		var_list_size = fastboot_getvar_list_dynamic_size;
+	} else {
+		var_list = fastboot_getvar_list;
+		var_list_size = fastboot_getvar_list_size;
+	}
+
+	for (size_t i = 0; i < var_list_size; i++) {
+		const char *name = var_list[i];
+		char cmd_buf[RESPONSE_LEN];
+		char resp_buf[RESPONSE_LEN] = "";
+		snprintf(cmd_buf, sizeof(cmd_buf), "%s", name);
+		if (fastboot_get_var(cmd_buf, resp_buf, sizeof(resp_buf) - 1) == 0 &&
+		    strncmp(resp_buf, "FAIL", 4) != 0) {
+			const char *const args[] = { name };
+			cb(context, 1, args, resp_buf);
+		}
+	}
+	return EFI_EXIT(EFI_SUCCESS);
 }
 
 static efi_status_t EFIAPI get_staged(struct GblEfiFastbootProtocol *self,
@@ -34,7 +86,26 @@
 					      const char *part_name,
 					      size_t *part_type_len, char *part_type)
 {
-	return EFI_UNSUPPORTED;
+	EFI_ENTRY("%p, %s, %p, %p", self, part_name, part_type_len, part_type);
+	if (!part_name || !part_type_len || (*part_type_len > 0 && !part_type))
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+	char cmd_buf[RESPONSE_LEN];
+	snprintf(cmd_buf, sizeof(cmd_buf), "partition-type:%s", part_name);
+	const char *part = parse_fb_cmd_partition(cmd_buf);
+	if (!part)
+		return EFI_EXIT(EFI_NOT_FOUND);
+
+	const char *type_str = "raw";
+	size_t len = strlen(type_str);
+	if (*part_type_len < len + 1) {
+		*part_type_len = len + 1;
+		return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+	}
+
+	strncpy(part_type, type_str, *part_type_len);
+	*part_type_len = len;
+	return EFI_EXIT(EFI_SUCCESS);
 }
 
 static efi_status_t handle_flash_bootloader(size_t download_buffer_used_size,