[gbl] Integrate GBL bootloader and inject AVB permanent attributes

* Integrate GBL binary into U-Boot rodata section via assembly .incbin.
* Increase bl33 executable limit to 6MB in u-boot.lds.
* Dynamically set gbl_addr and bootgbl environment variables from embedded GBL symbols.
* Inject Fuchsia dev permanent attributes and hash into FDT /gbl node.
* Skip adding raw FDT to ZBI during EFI boot so GBL handles Devicetree handoff.
* Update default boot command to boot GBL (`bootgbl`).
* Fix EFI crashes by adding NULL checks and relocating initialization.
* Update fastboot reboot modes and GPIO upgrade button in U-Boot environment to enter GBL fastboot mode.
* Fix GBL Fastboot Transport protocol return value and error messaging.

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

Change-Id: I55ae5d7a4631384ca281851c165b68401ee424ea
Reviewed-on: https://turquoise-internal-review.googlesource.com/c/third_party/u-boot/+/1370276
Commit-Queue: Sergii Parubochyi <sergiip@google.com>
Reviewed-by: David Pursell <dpursell@google.com>
GitOrigin-RevId: 8d1eb218efd25a64e599334849653288c8cd06c8
diff --git a/arch/arm/cpu/armv8/u-boot.lds b/arch/arm/cpu/armv8/u-boot.lds
index 0aba708..567049e 100644
--- a/arch/arm/cpu/armv8/u-boot.lds
+++ b/arch/arm/cpu/armv8/u-boot.lds
@@ -102,7 +102,7 @@
 		KEEP(*(.__bss_end));
 	}
 
-	ASSERT(_end <= 0x01200000, "bl33 image has exceeded its limit.")
+	ASSERT(_end <= 0x01400000, "bl33 image has exceeded its limit.")
 
 	/DISCARD/ : { *(.dynsym) }
 	/DISCARD/ : { *(.dynstr*) }
diff --git a/board/khadas/configs/kvim3.h b/board/khadas/configs/kvim3.h
index 52bb651..6743209 100644
--- a/board/khadas/configs/kvim3.h
+++ b/board/khadas/configs/kvim3.h
@@ -205,7 +205,7 @@
                 "setenv reboot_mode_android ""normal"";"\
                 "run storeargs;"\
                 "echo reboot_mode is fastboot. Entering fastboot;"\
-                "fastboot;"\
+                "setenv gbl_one_shot_boot_mode bootloader; run bootgbl;"\
             "fi;fi;fi;fi;fi;fi;"\
             "\0" \
         "storeboot="\
@@ -213,7 +213,7 @@
             "run storeargs;"\
             "zbi_boot ${loadaddr} ${loadsize} kernel;"\
             "echo failed to boot kernel. Falling back to fastboot;"\
-            "fastboot;"\
+            "setenv gbl_one_shot_boot_mode bootloader; run bootgbl;"\
             "\0"\
         "factory_reset_poweroff_protect="\
             "echo wipe_data=${wipe_data}; echo wipe_cache=${wipe_cache};"\
@@ -238,7 +238,7 @@
                 "run recovery_from_flash;"\
             "fi; \0" \
          "update="\
-            "fastboot; "\
+            "setenv gbl_one_shot_boot_mode bootloader; run bootgbl; "\
             "\0"\
         "recovery_from_sdcard="\
             "if fatload mmc 0 ${loadaddr} aml_autoscript; then autoscr ${loadaddr}; fi;"\
@@ -259,7 +259,7 @@
         "recovery_from_flash="\
             "zbi_boot ${loadaddr} ${loadsize} recovery;"\
             "echo failed to boot recovery. Falling back to fastboot;"\
-            "run storeargs; fastboot;"\
+            "run storeargs; setenv gbl_one_shot_boot_mode bootloader; run bootgbl;"\
             "\0"\
         "init_display="\
             "get_rebootmode;"\
@@ -365,9 +365,8 @@
             "\0"\
         "upgrade_key="\
             "if gpio input GPIOAO_7; then "\
-                "echo detect upgrade key. Enetering fastboot;"\
-                "run storeargs;"\
-                "run update;"\
+                "echo detect upgrade key. Setting GBL fastboot mode;"\
+                "setenv gbl_one_shot_boot_mode bootloader;"\
             "fi;"\
             "\0"\
         "recovery_key="\
@@ -399,7 +398,7 @@
             "run upgrade_key;"\
             "run switch_bootmode;"
 
-#define CONFIG_BOOTCOMMAND "run storeboot"
+#define CONFIG_BOOTCOMMAND "run bootgbl"
 
 /*
  * logo image path: device/khadas/$(proj_name)/logo_img_files/
diff --git a/board/khadas/kvim3/Makefile b/board/khadas/kvim3/Makefile
index ac966f5..8d8e0c5 100644
--- a/board/khadas/kvim3/Makefile
+++ b/board/khadas/kvim3/Makefile
@@ -1,8 +1,10 @@
 
-obj-y += $(BOARD).o eth_setup.o
+obj-y += $(BOARD).o eth_setup.o gbl_blob.o
 obj-$(CONFIG_ZIRCON_BOOT_IMAGE) += zircon.o zircon_boot.o
 obj-$(CONFIG_AML_LCD) += lcd.o
 
+asflags-y := -Wa,-I$(srctree)/board/khadas/kvim3
+
 fuchsia_sdk=lib/fuchsia/firmware_sdk/pkg
 ccflags-y += \
 	-I$(fuchsia_sdk)/abr/include \
diff --git a/board/khadas/kvim3/atx_permanent_attributes.h b/board/khadas/kvim3/atx_permanent_attributes.h
index 7f45d34..e523f9c 100644
--- a/board/khadas/kvim3/atx_permanent_attributes.h
+++ b/board/khadas/kvim3/atx_permanent_attributes.h
@@ -10,7 +10,7 @@
 #ifndef VIM3_PERMANENT_ATTRIBUTES_H
 #define VIM3_PERMANENT_ATTRIBUTES_H
 
-const unsigned char avb_atx_permanent_attributes[] __attribute__((unused)) = {
+static const unsigned char avb_atx_permanent_attributes[] __attribute__((unused)) = {
 	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xa1, 0x21, 0x50, 0x61,
 	0xd2, 0xa9, 0x3e, 0x6a, 0x6e, 0xa1, 0x4f, 0xaa, 0x43, 0x8b, 0xa1, 0xb9,
 	0x66, 0x14, 0x07, 0x8d, 0x70, 0x0c, 0x90, 0xed, 0x55, 0x2d, 0x26, 0xcf,
@@ -101,4 +101,11 @@
 	0xa4, 0x3d, 0xe4, 0xf3, 0xcc, 0x21, 0x85, 0xce,
 };
 
+static const unsigned char avb_atx_permanent_attributes_hash[32] __attribute__((unused)) = {
+	0x6c, 0x94, 0x37, 0x75, 0xbe, 0x5c, 0x83, 0xe0,
+	0xee, 0x41, 0x8f, 0x5a, 0x84, 0xfb, 0x9e, 0x1e,
+	0x76, 0xf1, 0x68, 0xd9, 0x63, 0xb5, 0x02, 0xab,
+	0x24, 0x6c, 0x1f, 0x5f, 0xbb, 0x01, 0x7b, 0x53
+};
+
 #endif
\ No newline at end of file
diff --git a/board/khadas/kvim3/gbl_blob.S b/board/khadas/kvim3/gbl_blob.S
new file mode 100644
index 0000000..e700070
--- /dev/null
+++ b/board/khadas/kvim3/gbl_blob.S
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+.section .rodata.gbl, "a"
+.align 4
+.global gbl_binary_start
+.global gbl_binary_end
+
+gbl_binary_start:
+.incbin "gbl.efi"
+gbl_binary_end:
diff --git a/board/khadas/kvim3/kvim3.c b/board/khadas/kvim3/kvim3.c
index e3a2231..d2a6865 100644
--- a/board/khadas/kvim3/kvim3.c
+++ b/board/khadas/kvim3/kvim3.c
@@ -71,6 +71,8 @@
 #endif
 #include <asm/arch/timer.h>
 #include <asm/saradc.h>
+#include "atx_permanent_attributes.h"
+
 DECLARE_GLOBAL_DATA_PTR;
 
 //new static eth setup
@@ -754,9 +756,65 @@
 }
 
 #ifdef CONFIG_BOARD_LATE_INIT
+static void inject_gbl_attributes(void *fdt)
+{
+	/*
+	 * Expand FDT to allow adding new nodes/properties.
+	 * We have at least 256KB buffer (since U-Boot reads 0x40000 bytes).
+	 * We can safely expand it by 4KB.
+	 */
+	int new_size = fdt_totalsize(fdt) + 4096;
+	if (new_size > SZ_256K) {
+		printf("U-Boot: Error: expanded DTB size %d exceeds max buffer %d\n",
+		       new_size, SZ_256K);
+		return;
+	}
+	int ret = fdt_open_into(fdt, fdt, new_size);
+	if (ret < 0) {
+		printf("U-Boot: fdt_open_into failed: %d\n", ret);
+		return;
+	}
+
+	int node = fdt_find_or_add_subnode(fdt, 0, "gbl");
+	if (node < 0) {
+		printf("U-Boot: Failed to find/create /gbl node: %d\n", node);
+		return;
+	}
+
+	ret = fdt_setprop(fdt, node, "avb-cert-permanent-attributes",
+			      avb_atx_permanent_attributes, sizeof(avb_atx_permanent_attributes));
+	if (ret) {
+		printf("U-Boot: Failed to set avb-cert-permanent-attributes: %d\n", ret);
+		return;
+	}
+
+	ret = fdt_setprop(fdt, node, "avb-cert-permanent-attributes-hash",
+			      avb_atx_permanent_attributes_hash, sizeof(avb_atx_permanent_attributes_hash));
+	if (ret) {
+		printf("U-Boot: Failed to set avb-cert-permanent-attributes-hash: %d\n", ret);
+	}
+}
+
+extern const uint8_t *gbl_binary_start;
+extern const uint8_t *gbl_binary_end;
+
+static void setup_embedded_gbl_env(void)
+{
+	ulong addr = (ulong)&gbl_binary_start;
+	ulong size = (ulong)&gbl_binary_end - (ulong)&gbl_binary_start;
+	char buf[128];
+
+	sprintf(buf, "0x%lx", addr);
+	setenv("gbl_addr", buf);
+
+	sprintf(buf, "bootefi 0x%lx:0x%lx ${dtb_mem_addr}", addr, size);
+	setenv("bootgbl", buf);
+}
+
 int board_late_init(void)
 {
 		TE(__func__);
+		setup_embedded_gbl_env();
 		//update env before anyone using it
 		run_command("get_rebootmode; echo reboot_mode=${reboot_mode}; "\
 						"if test ${reboot_mode} = factory_reset; then "\
@@ -794,6 +852,20 @@
 				}
 		}
 #endif// #ifndef DTB_BIND_KERNEL
+	{
+		const char *addr_str = getenv("dtb_mem_addr");
+		if (addr_str) {
+			ulong addr = simple_strtoul(addr_str, NULL, 16);
+			void *fdt = (void *)addr;
+			if (fdt_check_header(fdt) == 0) {
+				gd->fdt_blob = fdt;
+				char buf[32];
+				sprintf(buf, "0x%lx", addr);
+				setenv("fdtcontroladdr", buf);
+				inject_gbl_attributes(fdt);
+			}
+		}
+	}
 
 #ifdef CONFIG_POWER_FUSB302
 	fusb302_sink_init();
diff --git a/board/khadas/kvim3/zircon.c b/board/khadas/kvim3/zircon.c
index a144c15..8cd0e5c 100644
--- a/board/khadas/kvim3/zircon.c
+++ b/board/khadas/kvim3/zircon.c
@@ -510,7 +510,7 @@
 	return res;
 }
 
-int zircon_preboot(zbi_header_t *zbi, size_t capacity)
+int zircon_preboot(zbi_header_t *zbi, size_t capacity, bool is_efi_boot)
 {
 #if 0 //Deprecated cpu topology descripiton
 	add_zbi_item_or_log(zbi, capacity, ZBI_TYPE_CPU_CONFIG,  0, &cpu_config,
@@ -603,6 +603,10 @@
 	add_cmdline_entropy(zbi, capacity);
 	add_cpu_topology(zbi, capacity);
 	add_eth_mac_address(zbi, capacity);
-	add_device_tree(zbi, capacity);
+	if (is_efi_boot) {
+		printf("U-Boot: Skipping add_device_tree for EFI boot\n");
+	} else {
+		add_device_tree(zbi, capacity);
+	}
 	return 0;
 }
diff --git a/board/khadas/kvim3/zircon_boot.c b/board/khadas/kvim3/zircon_boot.c
index 579f8d9..7f01c04 100644
--- a/board/khadas/kvim3/zircon_boot.c
+++ b/board/khadas/kvim3/zircon_boot.c
@@ -104,7 +104,7 @@
 		return false;
 	}
 
-	int ret = zircon_preboot(image, capacity);
+	int ret = zircon_preboot(image, capacity, false);
 	if (ret < 0) {
 	    printf("zircon_preboot failed\n");
 	    return false;
@@ -276,7 +276,7 @@
 	if (result != ZBI_RESULT_OK) {
 		return -1;
 	}
-	return add_zbi_items(&zb_ops, buffer, capacity, NULL) ? 0 : -1;
+	return zircon_preboot(buffer, capacity, true) == 0 ? 0 : -1;
 }
 
 int do_zbi_boot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
diff --git a/drivers/mmc/aml_sd_emmc.c b/drivers/mmc/aml_sd_emmc.c
index 27a5dde..f246922 100644
--- a/drivers/mmc/aml_sd_emmc.c
+++ b/drivers/mmc/aml_sd_emmc.c
@@ -1160,6 +1160,7 @@
 }
 
 bool is_aml_sd_mmc(struct mmc *mmc) {
+	if (!mmc) return false;
 	return mmc->cfg->ops == &aml_sd_emmc_ops;
 }
 
diff --git a/fuchsia_build.py b/fuchsia_build.py
index ae9ec3c..b5456ed 100755
--- a/fuchsia_build.py
+++ b/fuchsia_build.py
@@ -23,8 +23,10 @@
 
 _CIPD_DEPS_DIR = _MY_DIR / "cipd_deps"
 
+_GBL_CIPD_VERSION = "latest"
 
-def build():
+
+def build(gbl_path: Optional[Path] = None):
     """Builds the CIPD package."""
 
     # Pass compilers for u-boot host tools build
@@ -41,6 +43,8 @@
         HOSTLD=host_clang / "bin" / "lld",
         CROSS_COMPILE="aarch64-elf-",
     )
+    if gbl_path:
+        build_env["VIM3_GBL_PATH"] = str(gbl_path)
 
     subprocess.run(
         _BUILD_SCRIPT_TARGET,
@@ -62,6 +66,10 @@
         action="store_true",
         help="Clear CIPD dependencies dir before start",
     )
+    parser.add_argument(
+        "--gbl-path",
+        help="Path to local GBL efi binary. If provided, CIPD GBL is not used.",
+    )
 
     return parser.parse_args()
 
@@ -99,7 +107,7 @@
     shutil.rmtree(_CIPD_DEPS_DIR, ignore_errors=True)
 
 
-def fuchsia_build(cipd, clean_cipd):
+def fuchsia_build(cipd, clean_cipd, gbl_path=None):
     if clean_cipd:
         cipd_dep_dir_clean()
 
@@ -143,9 +151,48 @@
             "",
         ),
     ]
+
+    resolved_gbl_path = None
+    if gbl_path:
+        resolved_gbl_path = Path(gbl_path).resolve()
+        if not resolved_gbl_path.exists():
+            sys.exit(f"ERROR: Provided --gbl-path '{gbl_path}' does not exist.")
+
+    if not resolved_gbl_path:
+        list_of_packages.append((
+            "gbl",
+            "fuchsia/third_party/android/gbl/mainline",
+            _GBL_CIPD_VERSION,
+            "",
+        ))
+
     ensure_deps(cipd, list_of_packages)
 
-    build()
+    if not resolved_gbl_path:
+        cipd_gbl_path = _CIPD_DEPS_DIR / "gbl" / "gbl_aarch64_dev.efi"
+        if cipd_gbl_path.exists():
+            resolved_gbl_path = cipd_gbl_path
+            print(f"Using GBL from CIPD: {resolved_gbl_path}")
+        else:
+            sys.exit("ERROR: GBL CIPD package downloaded but gbl_aarch64_dev.efi not found.")
+    else:
+        print(f"Using local GBL: {resolved_gbl_path}")
+
+    target_gbl = _MY_DIR / "board" / "khadas" / "kvim3" / "gbl.efi"
+    if resolved_gbl_path != target_gbl:
+        shutil.copyfile(resolved_gbl_path, target_gbl)
+
+    build(gbl_path=resolved_gbl_path)
+
+    uboot_bin = _MY_DIR / "build" / "u-boot.bin.unsigned"
+    if uboot_bin.exists():
+        size = uboot_bin.stat().st_size
+        max_size = 4 * 1024 * 1024
+        if size > max_size:
+            sys.exit(
+                f"ERROR: Final bootloader image size ({size} bytes / {size / (1024 * 1024):.2f} MiB) "
+                f"exceeds 4 MiB eMMC boot partition limit."
+            )
 
 
 def _main() -> int:
@@ -155,6 +202,7 @@
     fuchsia_build(
         cipd=args.cipd,
         clean_cipd=args.clean_cipd,
+        gbl_path=args.gbl_path,
     )
 
 
diff --git a/include/zircon.h b/include/zircon.h
index fc63a30..966d852 100644
--- a/include/zircon.h
+++ b/include/zircon.h
@@ -13,7 +13,7 @@
 #include <libzbi/zbi.h>
 
 /* called before booting to allow board specific additions to the bootdata */
-int zircon_preboot(zbi_header_t *zbi, size_t capacity);
+int zircon_preboot(zbi_header_t *zbi, size_t capacity, bool is_efi_boot);
 
 AvbIOResult read_rollback_index(AvbOps *ops, size_t rollback_index_location,
 				uint64_t *out_rollback_index);
diff --git a/lib/efi_loader/efi_android_boot.c b/lib/efi_loader/efi_android_boot.c
index 6e994cc..c19d134 100644
--- a/lib/efi_loader/efi_android_boot.c
+++ b/lib/efi_loader/efi_android_boot.c
@@ -65,6 +65,7 @@
 	}
 
 	*max_packet_size = fastboot_func->in_ep->maxpacket;
+	android_boot.max_out_req_length = fastboot_func->out_req->length;
 	return EFI_EXIT(EFI_SUCCESS);
 }
 
@@ -251,6 +252,5 @@
 		return ret;
 	}
 
-	android_boot.max_out_req_length = fastboot_func->out_req->length;
 	return EFI_SUCCESS;
 }
diff --git a/lib/efi_loader/gbl_efi_fastboot_transport.c b/lib/efi_loader/gbl_efi_fastboot_transport.c
index 266bd6c..81016cb 100644
--- a/lib/efi_loader/gbl_efi_fastboot_transport.c
+++ b/lib/efi_loader/gbl_efi_fastboot_transport.c
@@ -235,6 +235,6 @@
 {
 	efi_status_t ret = efi_add_protocol(efi_root, &guid, (void *)&protocol);
 	if (ret != EFI_SUCCESS)
-		printf("Cannot install EFI_ANDROID_BOOT_PROTOCOL\n");
-	return EFI_SUCCESS;
+		printf("Cannot install GBL_EFI_FASTBOOT_TRANSPORT_PROTOCOL\n");
+	return ret;
 }