[gigaboot] add support for new partition names

Adds support for `fastboot flash` to specify either new or old partition
names. Getting this in early allows it to soak for a bit so that devs
will flash it to their devices, at which point we could start
transitioning to the new patition scheme if we want.

Bug: 68692
Test: unittests, `fx flash-remote`, `fastboot flash ziron_a <img>`
Change-Id: I928d814c5043493949d98862fe5542f2d9eec728
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/490004
Reviewed-by: Yecheng Zhao <zyecheng@google.com>
Commit-Queue: David Pursell <dpursell@google.com>
diff --git a/src/firmware/gigaboot/src/diskio.c b/src/firmware/gigaboot/src/diskio.c
index 27526a9..7fb9ced 100644
--- a/src/firmware/gigaboot/src/diskio.c
+++ b/src/firmware/gigaboot/src/diskio.c
@@ -6,6 +6,7 @@
 #include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
+#include <zircon/compiler.h>
 #include <zircon/errors.h>
 #include <zircon/hw/gpt.h>
 #include <zircon/types.h>
@@ -460,30 +461,60 @@
   return status;
 }
 
-int guid_value_from_name(const char* guid_name, uint8_t* value) {
-  if (!strncmp(guid_name, GUID_ZIRCON_A_NAME, GPT_NAME_LEN)) {
-    uint8_t guid_value[GPT_GUID_LEN] = GUID_ZIRCON_A_VALUE;
-    memcpy(value, guid_value, GPT_GUID_LEN);
-  } else if (!strncmp(guid_name, GUID_ZIRCON_B_NAME, GPT_NAME_LEN)) {
-    uint8_t guid_value[GPT_GUID_LEN] = GUID_ZIRCON_B_VALUE;
-    memcpy(value, guid_value, GPT_GUID_LEN);
-  } else if (!strncmp(guid_name, GUID_ZIRCON_R_NAME, GPT_NAME_LEN)) {
-    uint8_t guid_value[GPT_GUID_LEN] = GUID_ZIRCON_R_VALUE;
-    memcpy(value, guid_value, GPT_GUID_LEN);
-  } else if (!strncmp(guid_name, GUID_VBMETA_A_NAME, GPT_NAME_LEN)) {
-    uint8_t guid_value[GPT_GUID_LEN] = GUID_VBMETA_A_VALUE;
-    memcpy(value, guid_value, GPT_GUID_LEN);
-  } else if (!strncmp(guid_name, GUID_VBMETA_B_NAME, GPT_NAME_LEN)) {
-    uint8_t guid_value[GPT_GUID_LEN] = GUID_VBMETA_B_VALUE;
-    memcpy(value, guid_value, GPT_GUID_LEN);
-  } else if (!strncmp(guid_name, GUID_VBMETA_R_NAME, GPT_NAME_LEN)) {
-    uint8_t guid_value[GPT_GUID_LEN] = GUID_VBMETA_R_VALUE;
-    memcpy(value, guid_value, GPT_GUID_LEN);
-  } else if (!strncmp(guid_name, GUID_EFI_NAME, GPT_NAME_LEN)) {
-    uint8_t guid_value[GPT_GUID_LEN] = GUID_EFI_VALUE;
-    memcpy(value, guid_value, GPT_GUID_LEN);
-  } else {
-    return -1;
+// Mapping from either legacy or new partition naming scheme to the expected
+// on-disk type GUID.
+static const struct {
+  const char* legacy_name;
+  const char* name;
+  const uint8_t type_guid[GPT_GUID_LEN];
+} partition_map[] = {
+    {
+        .legacy_name = GUID_ZIRCON_A_NAME,
+        .name = GPT_ZIRCON_A_NAME,
+        .type_guid = GUID_ZIRCON_A_VALUE,
+    },
+    {
+        .legacy_name = GUID_ZIRCON_B_NAME,
+        .name = GPT_ZIRCON_B_NAME,
+        .type_guid = GUID_ZIRCON_B_VALUE,
+    },
+    {
+        .legacy_name = GUID_ZIRCON_R_NAME,
+        .name = GPT_ZIRCON_R_NAME,
+        .type_guid = GUID_ZIRCON_R_VALUE,
+    },
+    // Note: even though both vbmeta names are actually the same, still check
+    // both constants here to avoid depending on this always being true.
+    {
+        .legacy_name = GUID_VBMETA_A_NAME,
+        .name = GPT_VBMETA_A_NAME,
+        .type_guid = GUID_VBMETA_A_VALUE,
+    },
+    {
+        .legacy_name = GUID_VBMETA_B_NAME,
+        .name = GPT_VBMETA_B_NAME,
+        .type_guid = GUID_VBMETA_B_VALUE,
+    },
+    {
+        .legacy_name = GUID_VBMETA_R_NAME,
+        .name = GPT_VBMETA_R_NAME,
+        .type_guid = GUID_VBMETA_R_VALUE,
+    },
+    {
+        .legacy_name = GUID_EFI_NAME,
+        // No bootloader_{a,b,r} support, just use standard "bootloader".
+        .name = "bootloader",
+        .type_guid = GUID_EFI_VALUE,
+    },
+};
+
+const uint8_t* partition_type_guid(const char* name) {
+  for (size_t i = 0; i < countof(partition_map); ++i) {
+    if (strcmp(partition_map[i].legacy_name, name) == 0 ||
+        strcmp(partition_map[i].name, name) == 0) {
+      return partition_map[i].type_guid;
+    }
   }
-  return 0;
+
+  return NULL;
 }
diff --git a/src/firmware/gigaboot/src/diskio.h b/src/firmware/gigaboot/src/diskio.h
index 2665c0c..996de96 100644
--- a/src/firmware/gigaboot/src/diskio.h
+++ b/src/firmware/gigaboot/src/diskio.h
@@ -61,10 +61,17 @@
 
 efi_status disk_write(disk_t* disk, size_t offset, void* data, size_t length);
 
-// guid_value_from_name takes in a GUID name and puts the associated GUID value
-// into value.
-// Returns 0 on success, -1 if the guid_name was not found.
-int guid_value_from_name(const char* guid_name, uint8_t* value);
+// Converts a user-facing partition name into a type GUID.
+//
+// Accepts both legacy and new partition names, but always returns the legacy
+// type GUID since that's what all Gigaboot devices use at the moment. Accepting
+// both names will allow us to start moving over to the new partition scheme in
+// the future if we want.
+//
+// name: partition name.
+//
+// Returns the matching partition type GUID, or NULL if no match was found.
+const uint8_t* partition_type_guid(const char* name);
 
 __END_CDECLS
 
diff --git a/src/firmware/gigaboot/src/diskio_test.cc b/src/firmware/gigaboot/src/diskio_test.cc
index 33574b4..be0701b 100644
--- a/src/firmware/gigaboot/src/diskio_test.cc
+++ b/src/firmware/gigaboot/src/diskio_test.cc
@@ -30,6 +30,7 @@
 
 using testing::_;
 using testing::DoAll;
+using testing::ElementsAreArray;
 using testing::Return;
 using testing::SetArgPointee;
 
@@ -394,24 +395,26 @@
   EXPECT_EQ(partitions[3], partition);
 }
 
-TEST(GuidValueFromName, KnownPartitionNames) {
+TEST(PartitionTypeGuid, KnownPartitionNames) {
   const std::pair<const char*, const std::vector<uint8_t>> known_partitions[] = {
-      {"zircon-a", GUID_ZIRCON_A_VALUE}, {"zircon-b", GUID_ZIRCON_B_VALUE},
-      {"zircon-r", GUID_ZIRCON_R_VALUE}, {"vbmeta_a", GUID_VBMETA_A_VALUE},
-      {"vbmeta_b", GUID_VBMETA_B_VALUE}, {"vbmeta_r", GUID_VBMETA_R_VALUE},
+      {"zircon_a", GUID_ZIRCON_A_VALUE}, {"zircon-a", GUID_ZIRCON_A_VALUE},
+      {"zircon_b", GUID_ZIRCON_B_VALUE}, {"zircon-b", GUID_ZIRCON_B_VALUE},
+      {"zircon_r", GUID_ZIRCON_R_VALUE}, {"zircon-r", GUID_ZIRCON_R_VALUE},
+      {"vbmeta_a", GUID_VBMETA_A_VALUE}, {"vbmeta_b", GUID_VBMETA_B_VALUE},
+      {"vbmeta_r", GUID_VBMETA_R_VALUE}, {"bootloader", GUID_EFI_VALUE},
       {"fuchsia-esp", GUID_EFI_VALUE},
   };
 
   for (const auto& [name, expected_guid] : known_partitions) {
-    std::vector<uint8_t> guid(GPT_GUID_LEN);
-    EXPECT_EQ(0, guid_value_from_name(name, guid.data()));
-    EXPECT_EQ(expected_guid, guid);
+    const uint8_t* type_guid = partition_type_guid(name);
+    EXPECT_THAT(expected_guid, ElementsAreArray(type_guid, GPT_GUID_LEN));
   }
 }
 
-TEST(GuidValueFromName, UnknownPartitionName) {
-  std::vector<uint8_t> guid(GPT_GUID_LEN);
-  EXPECT_NE(0, guid_value_from_name("unknown_partition", guid.data()));
+TEST(PartitionTypeGuid, UnknownPartitionName) {
+  EXPECT_EQ(nullptr, partition_type_guid(""));
+  EXPECT_EQ(nullptr, partition_type_guid("unknown_partition"));
+  EXPECT_EQ(nullptr, partition_type_guid("zircon_a_with_suffix"));
 }
 
 struct IsUsbBootState {
diff --git a/src/firmware/gigaboot/src/fastboot.c b/src/firmware/gigaboot/src/fastboot.c
index 56d3079..d6622a3 100644
--- a/src/firmware/gigaboot/src/fastboot.c
+++ b/src/firmware/gigaboot/src/fastboot.c
@@ -437,13 +437,13 @@
     return;
   }
 
-  uint8_t guid_value[GPT_GUID_LEN];
-  if (guid_value_from_name(partition, guid_value)) {
-    fb_send_fail("could not find guid value of partition");
+  const uint8_t *type_guid = partition_type_guid(partition);
+  if (!type_guid) {
+    fb_send_fail("could not find partition type GUID");
     return;
   }
 
-  efi_status status = write_partition(gImg, gSys, guid_value, partition, PARTITION_OFFSET,
+  efi_status status = write_partition(gImg, gSys, type_guid, partition, PARTITION_OFFSET,
                                       (unsigned char *)curr_img.data, curr_img.size);
   if (status != EFI_SUCCESS) {
     char err_msg[FB_CMD_MAX_LEN];
@@ -466,9 +466,9 @@
     return;
   }
 
-  uint8_t guid_value[GPT_GUID_LEN];
-  if (guid_value_from_name(partition, guid_value)) {
-    fb_send_fail("could not find guid value of partition");
+  const uint8_t *type_guid = partition_type_guid(partition);
+  if (!type_guid) {
+    fb_send_fail("could not find partition type GUID");
     return;
   }
 
@@ -479,7 +479,7 @@
   }
 
   gpt_entry_t entry;
-  if (disk_find_partition(&disk, DEBUG, guid_value, NULL, NULL, &entry)) {
+  if (disk_find_partition(&disk, DEBUG, type_guid, NULL, NULL, &entry)) {
     fb_send_fail("could not find partition");
     return;
   }