[efi] Expose eMMC boot partitions to GBL Register the "bootloader" raw partition on eMMC hardware partition 1 (boot0) using GBL_VENDOR_MEDIA_DEVICE_PATH_GUID, and mirror block writes to hardware partition 2 (boot1) starting at block offset 1. This allows GBL fastboot to query `partition-size:bootloader` and flash or stream-flash `bootloader` directly via `EFI_BLOCK_IO_PROTOCOL` when running `fx flash` or `ffx target flash` on VIM3. TAG=agy CONV=d6901459-7b8c-4e0a-8447-092869375046 Bug: 496295142 Bug: 565499464 Test: Verified fx flash and ffx target flash on VIM3 Change-Id: I34f454143a467bbd83911effbd53a508522c1ff1 Reviewed-on: https://turquoise-internal-review.googlesource.com/c/third_party/u-boot/+/1678534 Reviewed-by: David Pursell <dpursell@google.com> Commit-Queue: Sergii Parubochyi <sergiip@google.com> GitOrigin-RevId: 615c25aa87d6ef89ecf5a60b1af5436d70778bfb
diff --git a/lib/efi_loader/efi_aml_sd_emmc.c b/lib/efi_loader/efi_aml_sd_emmc.c index 413416f..a1c9147 100644 --- a/lib/efi_loader/efi_aml_sd_emmc.c +++ b/lib/efi_loader/efi_aml_sd_emmc.c
@@ -11,6 +11,26 @@ #define VENDOR_PATH_DATA_LEN 16 +// GBL vendor-defined media device path GUID used to expose an EFI block device +// as a raw partition to GBL instead of a GPT disk. +// See: +// https://android.googlesource.com/platform/bootable/libbootloader/+/refs/heads/main/gbl/docs/partitions.md +#define GBL_VENDOR_MEDIA_DEVICE_PATH_GUID \ + EFI_GUID(0xa09773e3, 0xf027, 0x4f33, 0xad, 0xb3, 0xbd, 0x8d, 0xcf, \ + 0x4b, 0x38, 0x54) + +// eMMC hardware partition indices used by `mmc_select_hwpart()`. +// See `amlmmc_write_bootloader()` in `common/cmd_aml_mmc.c`. +#define MMC_HWPART_USER 0 +#define MMC_HWPART_BOOT0 1 +#define MMC_HWPART_BOOT1 2 + +// On Amlogic GXL and newer SoCs (including G12B / VIM3), block 0 of the eMMC +// boot partitions (`boot0` and `boot1`) is reserved for `storage_emmc_boot_info` +// metadata, and the bootloader image starts at block 1 (`GXL_START_BLK`). +// See `amlmmc_write_bootloader()` in `common/cmd_aml_mmc.c`. +#define GXL_START_BLK 1 + // Represents the EFI device path for a hardware partition on a Amlogic SD // eMMC. struct efi_aml_sd_disk_hwpart_device_path { @@ -27,6 +47,10 @@ bool is_write; efi_block_io2_token_t *token; bool io_started; + // For writes to the virtual "bootloader" device, tracks whether the + // first write pass to `boot0` (MMC_HWPART_BOOT0) has finished and we + // are now mirroring the write to `boot1` (MMC_HWPART_BOOT1). + bool write_boot1; }; // Represents a hardware partition on an Amlogic SD eMMC device. @@ -42,12 +66,19 @@ }; // Represents an Amlogic SD eMMC device. +// +// Exposes 2 EFI block devices to GBL: +// - `hwparts[0]` ("hwpart-0"): eMMC `user` hardware partition (GPT disk). +// - `hwparts[1]` ("bootloader"): virtual GBL raw partition that reads from +// `boot0` (MMC_HWPART_BOOT0) and mirrors writes to both `boot0` +// (MMC_HWPART_BOOT0) and `boot1` (MMC_HWPART_BOOT1) starting at +// `GXL_START_BLK`. struct efi_aml_sd_disk { struct mmc *mmc; int dev; efi_block_io2_token_t *io2_token; struct efi_event *timer_event; - struct efi_aml_sd_disk_hwpart hwparts[3]; + struct efi_aml_sd_disk_hwpart hwparts[2]; int curr_hwpart; // current hardware partition to process. efi_status_t status; }; @@ -109,12 +140,23 @@ return; } // Initiates the read/write if it has not started. - mmc_select_hwpart(disk->dev, disk->curr_hwpart); + // + // `curr_hwpart == 0` accesses the `user` partition (hwpart 0). + // `curr_hwpart == 1` is the virtual "bootloader" partition: + // reads and the first write pass target `boot0` (hwpart 1), and + // the second write pass (`write_boot1`) mirrors to `boot1` + // (hwpart 2). Both boot partitions skip block 0 (`GXL_START_BLK`). + int hwpart = (disk->curr_hwpart == 0) ? MMC_HWPART_USER : + (request->write_boot1 ? MMC_HWPART_BOOT1 : + MMC_HWPART_BOOT0); + uint64_t blk_off = request->blk_off + + (disk->curr_hwpart == 0 ? 0 : GXL_START_BLK); + mmc_select_hwpart(disk->dev, hwpart); if (request->is_write ? - aml_sd_write_async(disk->mmc, request->blk_off, + aml_sd_write_async(disk->mmc, blk_off, request->blk_cnt, request->buffer) : - aml_sd_read_async(disk->mmc, request->blk_off, + aml_sd_read_async(disk->mmc, blk_off, request->blk_cnt, request->buffer)) { handle_driver_error(disk, EFI_DEVICE_ERROR); @@ -126,6 +168,19 @@ if (aml_sd_poll_io(disk->mmc)) { handle_driver_error(disk, EFI_DEVICE_ERROR); } else if (!aml_sd_is_busy(disk->mmc)) { + // When writing to the virtual "bootloader" device + // (`curr_hwpart == 1`), after the write to `boot0` + // finishes, repeat the write to `boot1` so both eMMC + // boot partitions stay in sync (matching + // `amlmmc_write_bootloader` in `common/cmd_aml_mmc.c`). + if (disk->curr_hwpart == 1 && request->is_write && + !request->write_boot1) { + request->write_boot1 = true; + request->io_started = false; + return; + } + if (disk->curr_hwpart != MMC_HWPART_USER) + mmc_select_hwpart(disk->dev, MMC_HWPART_USER); efi_io2_finish(request, EFI_SUCCESS); // Sets to the next hardware partition to poll. // This ensures fairness and prevents one busy block device from @@ -335,7 +390,16 @@ disk->mmc = mmc; disk->dev = CONFIG_FASTBOOT_FLASH_MMC_DEV; - // Creates a block device for boot0/boot1/user hardware partitions. + // Creates two EFI block devices: + // - hwpart 0 ("hwpart-0"): the eMMC `user` hardware partition, which + // contains the GPT. Left without `GBL_VENDOR_MEDIA_DEVICE_PATH_GUID` + // so GBL treats it as a GPT disk. + // - hwpart 1 ("bootloader"): a virtual raw partition tagged with + // `GBL_VENDOR_MEDIA_DEVICE_PATH_GUID` so GBL exposes the entire + // device as the "bootloader" fastboot partition. Reads access + // `boot0` (MMC_HWPART_BOOT0) and writes mirror to both `boot0` + // (MMC_HWPART_BOOT0) and `boot1` (MMC_HWPART_BOOT1) in + // `efi_disk_poll()`. for (size_t hwpart = 0; hwpart < ARRAY_SIZE(disk->hwparts); hwpart++) { struct efi_aml_sd_disk_hwpart *disk_hwpart = &disk->hwparts[hwpart]; @@ -349,8 +413,15 @@ DEVICE_PATH_SUB_TYPE_VENDOR_PATH; disk_hwpart->dp.path.dp.length = sizeof(disk_hwpart->dp.path) + VENDOR_PATH_DATA_LEN; - snprintf(disk_hwpart->dp.vendor_defined_data, - VENDOR_PATH_DATA_LEN, "hwpart-%ld", hwpart); + if (hwpart == 0) { + snprintf(disk_hwpart->dp.vendor_defined_data, + VENDOR_PATH_DATA_LEN, "hwpart-%ld", hwpart); + } else { + disk_hwpart->dp.path.guid = + (efi_guid_t)GBL_VENDOR_MEDIA_DEVICE_PATH_GUID; + snprintf(disk_hwpart->dp.vendor_defined_data, + VENDOR_PATH_DATA_LEN, "bootloader"); + } disk_hwpart->dp.end.type = DEVICE_PATH_TYPE_END; disk_hwpart->dp.end.sub_type = DEVICE_PATH_SUB_TYPE_END; // Populates `EFI_BLOCK_IO_MEDIA` @@ -364,7 +435,9 @@ disk_hwpart->media.io_align = mmc->write_bl_len; uint64_t total_blocks = (hwpart == 0 ? mmc->capacity_user : mmc->capacity_boot); - total_blocks /= mmc->write_bl_len; + // Reserve block 0 (`GXL_START_BLK`) on the boot partitions. + total_blocks = total_blocks / mmc->write_bl_len - + (hwpart == 0 ? 0 : GXL_START_BLK); disk_hwpart->media.last_block = max(1ULL, total_blocks) - 1; // Populates `EFI_BLOCK_IO2_PROTOCOL`. disk_hwpart->ops_io2.media = &disk_hwpart->media;