Snap for 4818534 from 8879f6cf88cb454c665edb4593bc20e08f182525 to pi-release

Change-Id: If1ae5ebef12de7f2d1db571e1609782573ec0f99
diff --git a/citadel/updater/updater.cpp b/citadel/updater/updater.cpp
index 776401e..ecc8c35 100644
--- a/citadel/updater/updater.cpp
+++ b/citadel/updater/updater.cpp
@@ -48,11 +48,24 @@
 using nos::CitadeldProxyClient;
 #endif
 
+enum hdr_section {
+  SEC_BOGUS = 0,
+  SEC_RO_A,
+  SEC_RO_B,
+  SEC_RW_A,
+  SEC_RW_B,
+};
+
 /* Global options */
 struct options_s {
   /* actions to take */
   int version;
+  int long_version;
+  enum hdr_section section;
+  int file_version;
+  enum hdr_section file_section;
   int id;
+  int repo_snapshot;
   int stats;
   int ro;
   int rw;
@@ -62,6 +75,7 @@
   int enable_rw;
   int change_pw;
   uint32_t erase_code;
+  int ap_uart;
   /* generic connection options */
   const char *device;
 } options;
@@ -69,6 +83,7 @@
 enum no_short_opts_for_these {
   OPT_DEVICE = 1000,
   OPT_ID,
+  OPT_REPO_SNAPSHOT,
   OPT_STATS,
   OPT_RO,
   OPT_RW,
@@ -78,26 +93,37 @@
   OPT_ENABLE_RW,
   OPT_CHANGE_PW,
   OPT_ERASE,
+  OPT_AP_UART,
 };
 
-const char *short_opts = ":hv";
+const char *short_opts = ":hvlV:fF:";
 const struct option long_opts[] = {
   /* name    hasarg *flag val */
-  {"version",     0, NULL, 'v'},
-  {"id",          0, NULL, OPT_ID},
-  {"stats",       0, NULL, OPT_STATS},
-  {"ro",          0, NULL, OPT_RO},
-  {"rw",          0, NULL, OPT_RW},
-  {"reboot",      0, NULL, OPT_REBOOT},
-  {"force_reset", 0, NULL, OPT_FORCE_RESET},
-  {"enable_ro",   0, NULL, OPT_ENABLE_RO},
-  {"enable_rw",   0, NULL, OPT_ENABLE_RW},
-  {"change_pw",   0, NULL, OPT_CHANGE_PW},
-  {"erase",       1, NULL, OPT_ERASE},
+  {"version",       0, NULL, 'v'},
+  {"long_version",  0, NULL, 'l'},
+  {"long-version",  0, NULL, 'l'},
+  {"id",            0, NULL, OPT_ID},
+  {"repo_snapshot", 0, NULL, OPT_REPO_SNAPSHOT},
+  {"repo-snapshot", 0, NULL, OPT_REPO_SNAPSHOT},
+  {"stats",         0, NULL, OPT_STATS},
+  {"ro",            0, NULL, OPT_RO},
+  {"rw",            0, NULL, OPT_RW},
+  {"reboot",        0, NULL, OPT_REBOOT},
+  {"force_reset",   0, NULL, OPT_FORCE_RESET},
+  {"force-reset",   0, NULL, OPT_FORCE_RESET},
+  {"enable_ro",     0, NULL, OPT_ENABLE_RO},
+  {"enable-ro",     0, NULL, OPT_ENABLE_RO},
+  {"enable_rw",     0, NULL, OPT_ENABLE_RW},
+  {"enable-rw",     0, NULL, OPT_ENABLE_RW},
+  {"change_pw",     0, NULL, OPT_CHANGE_PW},
+  {"change-pw",     0, NULL, OPT_CHANGE_PW},
+  {"erase",         1, NULL, OPT_ERASE},
+  {"ap_uart",       0, NULL, OPT_AP_UART},
+  {"ap-uart",       0, NULL, OPT_AP_UART},
 #ifndef ANDROID
-  {"device",      1, NULL, OPT_DEVICE},
+  {"device",        1, NULL, OPT_DEVICE},
 #endif
-  {"help",        0, NULL, 'h'},
+  {"help",          0, NULL, 'h'},
   {NULL, 0, NULL, 0},
 };
 
@@ -126,29 +152,37 @@
     "\n"
     "Actions:\n"
     "\n"
-    "  -v, --version       Display the Citadel version info\n"
-    "      --id            Display the Citadel device ID\n"
-    "      --stats         Display Low Power stats\n"
-    "      --rw            Update RW firmware from the image file\n"
-    "      --ro            Update RO firmware from the image file\n"
-    "      --reboot        Tell Citadel to reboot\n"
-    "      --force_reset   Pulse Citadel's reset line\n"
+    "  -v, --version        Display the running version\n"
+    "  -l, --long_version   Display the full version info\n"
+    "  --id                 Display the Citadel device ID\n"
+    "  --stats              Display Low Power stats\n"
+    "  -V SECTION           Show Citadel headers for RO_A | RO_B | RW_A | RW_B\n"
+    "  -f                   Show image file version info\n"
+    "  -F SECTION           Show file headers for RO_A | RO_B | RW_A | RW_B\n"
+    "  --repo_snapshot      Show the repo sha1sums for the running image\n"
     "\n"
-    "      --enable_ro     Mark new RO image as good\n"
-    "      --enable_rw     Mark new RW image as good\n"
+    "  --rw                 Update RW firmware from the image file\n"
+    "  --ro                 Update RO firmware from the image file\n"
+    "  --enable_ro          Mark new RO image as good (requires password)\n"
+    "  --enable_rw          Mark new RW image as good (requires password)\n"
+    "  --reboot             Tell Citadel to reboot\n"
+    "  --force_reset        Pulse Citadel's reset line\n"
     "\n"
-    "      --change_pw     Change update password\n"
+    "  --change_pw          Change the update password\n"
+    "\n"
+    "  --ap_uart            Query the AP UART passthru setting\n"
+    "                       (It can only be set in the BIOS)\n"
     "\n\n"
-    "      --erase=CODE    Erase all user secrets and reboot.\n"
-    "                      This skips all other actions.\n"
+    "  --erase=CODE         Erase all user secrets and reboot.\n"
+    "                       This skips all other actions.\n"
 #ifndef ANDROID
     "\n"
     "Options:\n"
     "\n"
-    "      --device=SN     Connect to the FDTI device with the given\n"
-    "                      serial number (try \"lsusb -v\"). A default\n"
-    "                      can be specified with the CITADEL_DEVICE\n"
-    "                      environment variable.\n"
+    "  --device=SN          Connect to the FDTI device with the given\n"
+    "                       serial number (try \"lsusb -v\"). A default\n"
+    "                       can be specified with the CITADEL_DEVICE\n"
+    "                       environment variable.\n"
 #endif
     "\n",
     progname);
@@ -368,6 +402,192 @@
   return retval;
 }
 
+uint32_t do_long_version(AppClient &app)
+{
+  uint32_t retval;
+  std::vector<uint8_t> buffer;
+  buffer.reserve(1024);
+
+  retval = app.Call(NUGGET_PARAM_LONG_VERSION, buffer, &buffer);
+
+  if (is_app_success(retval)) {
+    printf("%.*s\n", (int)buffer.size(), buffer.data());
+  }
+
+  return retval;
+}
+
+static enum hdr_section parse_section(const char *str)
+{
+  bool is_ro, is_a;
+
+  // matching this:  /r?[ow]_?[ab]/i
+
+  if (tolower(*str) == 'r') {
+    str++;
+  }
+
+  if (tolower(*str) == 'o') {
+    is_ro = true;
+  } else if (tolower(*str) == 'w') {
+    is_ro = false;
+  } else {
+    Error("Invalid section \"%s\"", str);
+    return SEC_BOGUS;
+  }
+  str++;
+
+  if (*str == '_') {
+    str++;
+  }
+
+  if (tolower(*str) == 'a') {
+    is_a = true;
+  } else if (tolower(*str) == 'b') {
+    is_a = false;
+  } else {
+    Error("Invalid section \"%s\"", str);
+    return SEC_BOGUS;
+  }
+
+  if (is_ro) {
+    return is_a ? SEC_RO_A : SEC_RO_B;
+  }
+
+  return is_a ? SEC_RW_A : SEC_RW_B;
+}
+
+static void show_header(const uint8_t *ptr)
+{
+  const struct SignedHeader *hdr;
+
+  hdr = reinterpret_cast<const struct SignedHeader*>(ptr);
+  hdr->print();
+}
+
+#define CROS_EC_VERSION_COOKIE1 0xce112233
+#define CROS_EC_VERSION_COOKIE2 0xce445566
+
+// The start of the RW sections looks like this
+struct compiled_version_struct {
+  // The header comes first
+  const struct SignedHeader hdr;
+  // The the vector table. Citadel has 239 entries
+  uint32_t vectors[239];
+  // A magic number to be sure we're looking at the right thing
+  uint32_t cookie1;
+  // Then the short version string
+  char version[32];
+  // And another magic number
+  uint32_t cookie2;
+};
+
+static void show_ro_string(const char *name, const uint8_t *ptr)
+{
+  const struct SignedHeader *hdr;
+
+  hdr = reinterpret_cast<const struct SignedHeader*>(ptr);
+  printf("%s:    %d.%d.%d/%08x %s\n", name,
+         hdr->epoch_, hdr->major_, hdr->minor_, be32toh(hdr->img_chk_),
+         hdr->magic == MAGIC_VALID ? "ok" : "--");
+}
+
+static void show_rw_string(const char *name, const uint8_t *ptr)
+{
+  const struct compiled_version_struct *v;
+  v = reinterpret_cast<const struct compiled_version_struct*>(ptr);
+
+  if (v->cookie1 == CROS_EC_VERSION_COOKIE1 &&
+      v->cookie2 == CROS_EC_VERSION_COOKIE2 &&
+      (v->hdr.magic == MAGIC_DEFAULT || v->hdr.magic == MAGIC_VALID)) {
+    printf("%s:    %d.%d.%d/%s %s\n", name,
+           v->hdr.epoch_, v->hdr.major_, v->hdr.minor_, v->version,
+           v->hdr.magic == MAGIC_VALID ? "ok" : "--");
+  } else {
+    printf("<invalid>\n");
+  }
+}
+
+uint32_t do_section(AppClient &app __attribute__((unused)))
+{
+  uint16_t param;
+
+  switch (options.section) {
+  case SEC_RO_A:
+    param = NUGGET_PARAM_HEADER_RO_A;
+    break;
+  case SEC_RO_B:
+    param = NUGGET_PARAM_HEADER_RO_B;
+    break;
+  case SEC_RW_A:
+    param = NUGGET_PARAM_HEADER_RW_A;
+    break;
+  case SEC_RW_B:
+    param = NUGGET_PARAM_HEADER_RW_B;
+    break;
+  default:
+    return 1;
+  }
+
+  uint32_t retval;
+  std::vector<uint8_t> buffer;
+  buffer.reserve(sizeof(SignedHeader));
+
+  retval = app.Call(param, buffer, &buffer);
+
+  if (is_app_success(retval)) {
+    show_header(buffer.data());
+  }
+
+  return retval;
+}
+
+uint32_t do_file_version(const std::vector<uint8_t> &image)
+{
+  show_ro_string("RO_A", image.data() + CHIP_RO_A_MEM_OFF);
+  show_ro_string("RO_B", image.data() + CHIP_RO_B_MEM_OFF);
+  show_rw_string("RW_A", image.data() + CHIP_RW_A_MEM_OFF);
+  show_rw_string("RW_B", image.data() + CHIP_RW_B_MEM_OFF);
+  return 0;
+}
+
+uint32_t do_file_section(const std::vector<uint8_t> &image)
+{
+  switch (options.file_section) {
+  case SEC_RO_A:
+    show_header(image.data() + CHIP_RO_A_MEM_OFF);
+    break;
+  case SEC_RO_B:
+    show_header(image.data() + CHIP_RO_B_MEM_OFF);
+    break;
+  case SEC_RW_A:
+    show_header(image.data() + CHIP_RW_A_MEM_OFF);
+    break;
+  case SEC_RW_B:
+    show_header(image.data() + CHIP_RW_B_MEM_OFF);
+    break;
+  default:
+    return 1;
+  }
+
+  return 0;
+}
+
+uint32_t do_repo_snapshot(AppClient &app)
+{
+  uint32_t retval;
+  std::vector<uint8_t> buffer;
+  buffer.reserve(1200);
+
+  retval = app.Call(NUGGET_PARAM_REPO_SNAPSHOT, buffer, &buffer);
+
+  if (is_app_success(retval)) {
+    printf("%.*s\n", (int)buffer.size(), buffer.data());
+  }
+
+  return retval;
+}
+
 uint32_t do_stats(AppClient &app)
 {
   struct nugget_app_low_power_stats stats;
@@ -406,9 +626,9 @@
 uint32_t do_reboot(AppClient &app)
 {
   uint32_t retval;
-  std::vector<uint8_t> data = {NUGGET_REBOOT_HARD};
+  std::vector<uint8_t> ignored = {1};           // older images need this
 
-  retval = app.Call(NUGGET_PARAM_REBOOT, data, nullptr);
+  retval = app.Call(NUGGET_PARAM_REBOOT, ignored, nullptr);
 
   if (is_app_success(retval)) {
     printf("Citadel reboot requested\n");
@@ -475,6 +695,26 @@
   return rv;
 }
 
+static uint32_t do_ap_uart(AppClient &app)
+{
+  std::vector<uint8_t> buffer;
+  buffer.reserve(1);
+
+  static const char * const cfgstr[] = {
+    "disabled", "USB", "enabled", "SSC", "Citadel",
+  };
+  static_assert(sizeof(cfgstr)/sizeof(cfgstr[0]) == NUGGET_AP_UART_NUM_CFGS,
+                "Bad size of constant array");
+
+  uint32_t rv = app.Call(NUGGET_PARAM_AP_UART_PASSTHRU, buffer, &buffer);
+
+  if (is_app_success(rv))
+    printf("Current AP UART setting is %s\n", cfgstr[buffer[0]]);
+
+  return rv;
+}
+
+
 static uint32_t do_erase(AppClient &app)
 {
   std::vector<uint8_t> data(sizeof(uint32_t));
@@ -523,6 +763,11 @@
 
   /* Try all requested actions in reasonable order, bail out on error */
 
+  if (options.ap_uart &&
+      do_ap_uart(app) != APP_SUCCESS) {
+    return 1;
+  }
+
   if (options.erase_code) {                     /* zero doesn't count */
     /* whether we succeed or not, only do this */
     return do_erase(app);
@@ -533,6 +778,26 @@
     return 2;
   }
 
+  if (options.long_version &&
+      do_long_version(app) != APP_SUCCESS) {
+    return 2;
+  }
+
+  if (options.section &&
+      do_section(app) != APP_SUCCESS) {
+    return 2;
+  }
+
+  if (options.file_version &&
+      do_file_version(image) != APP_SUCCESS) {
+    return 2;
+  }
+
+  if (options.file_section &&
+      do_file_section(image) != APP_SUCCESS) {
+    return 2;
+  }
+
   if (options.id &&
       do_id(app) != APP_SUCCESS) {
     return 2;
@@ -543,6 +808,10 @@
     return 2;
   }
 
+  if (options.repo_snapshot &&
+      do_repo_snapshot(app) != APP_SUCCESS) {
+    return 2;
+  }
   if (options.rw &&
       do_update(app, image,
           CHIP_RW_A_MEM_OFF, CHIP_RW_B_MEM_OFF) != APP_SUCCESS) {
@@ -588,6 +857,7 @@
   std::vector<uint8_t> image;
   int got_action = 0;
   char *e = 0;
+  int need_file = 0;
 
   this_prog= strrchr(argv[0], '/');
   if (this_prog) {
@@ -611,20 +881,44 @@
       options.version = 1;
       got_action = 1;
       break;
+    case 'l':
+      options.long_version = 1;
+      got_action = 1;
+      break;
+    case 'V':
+      options.section = parse_section(optarg);
+      got_action = 1;
+      break;
+    case 'f':
+      options.file_version = 1;
+      need_file = 1;
+      got_action = 1;
+      break;
+    case 'F':
+      options.file_section = parse_section(optarg);
+      need_file = 1;
+      got_action = 1;
+      break;
     case OPT_ID:
       options.id = 1;
       got_action = 1;
       break;
+    case OPT_REPO_SNAPSHOT:
+      options.repo_snapshot = 1;
+      got_action = 1;
+      break;
     case OPT_STATS:
       options.stats = 1;
       got_action = 1;
       break;
     case OPT_RO:
       options.ro = 1;
+      need_file = 1;
       got_action = 1;
       break;
     case OPT_RW:
       options.rw = 1;
+      need_file = 1;
       got_action = 1;
       break;
     case OPT_REBOOT:
@@ -655,6 +949,10 @@
       }
       got_action = 1;
       break;
+    case OPT_AP_UART:
+      options.ap_uart = 1;
+      got_action = 1;
+      break;
 
       /* generic options below */
     case OPT_DEVICE:
@@ -691,14 +989,14 @@
     goto out;
   }
 
-  if (options.ro || options.rw) {
+  if (need_file) {
     if (optind < argc) {
       /* Sets errorcnt on failure */
       image = read_image_from_file(argv[optind++]);
       if (errorcnt)
         goto out;
     } else {
-      Error("An image file is required with --ro and --rw");
+      Error("Missing required image file");
       goto out;
     }
   }
@@ -708,8 +1006,7 @@
     if (optind < argc) {
       passwd = argv[optind++];
     } else {
-      Error("Need a new password at least."
-            " Use '' to clear it.");
+      Error("Need a new password at least. Use '' to clear it.");
       goto out;
     }
     /* two args provided, use both old & new passwords */
diff --git a/libnos_transport/transport.c b/libnos_transport/transport.c
index 6f09be0..b2a703c 100644
--- a/libnos_transport/transport.c
+++ b/libnos_transport/transport.c
@@ -56,8 +56,12 @@
 
 #endif
 
-/* Citadel might take up to 100ms to wake up */
-#define RETRY_COUNT 25
+/*
+ * If Citadel is rebooting it will take a while to become responsive again. We
+ * expect a reboot to take around 100ms but we'll keep trying for 300ms to leave
+ * plenty of margin.
+ */
+#define RETRY_COUNT 60
 #define RETRY_WAIT_TIME_US 5000
 
 static int nos_device_read(const struct nos_device *dev, uint32_t command,
diff --git a/nugget/include/app_nugget.h b/nugget/include/app_nugget.h
index aa8a798..f8e8fda 100644
--- a/nugget/include/app_nugget.h
+++ b/nugget/include/app_nugget.h
@@ -39,7 +39,7 @@
 
 #define NUGGET_PARAM_VERSION 0x0000
 /*
- * Return the current build string
+ * Return the one-line version string of the running image
  *
  * @param args         <none>
  * @param arg_len      0
@@ -74,18 +74,12 @@
 /*
  * Reboot Citadel
  *
- * @param args         uint8_t hard        0 = soft reboot, 1 = hard reboot
- * @param arg_len      sizeof(uint8_t)
+ * @param args         <none>
+ * @param arg_len      0
  * @param reply        <none>
  * @param reply_len    0
  */
 
-enum NUGGET_REBOOT_ARG_TYPE {
-  NUGGET_REBOOT_SOFT = 0,
-  NUGGET_REBOOT_HARD = 1,
-};
-
-
 /*********
  * Firmware updates are written to flash with invalid headers. If an update
  * password exists, headers can only be marked valid by providing that
@@ -167,6 +161,106 @@
  */
 
 
+#define NUGGET_PARAM_LONG_VERSION 0x0007
+/*
+ * Return the multi-line description of all images
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        Null-terminated ASCII string
+ * @param reply_len    Max length to return
+ *
+ * @errors             APP_ERROR_TOO_MUCH
+ */
+
+#define NUGGET_PARAM_HEADER_RO_A 0x0008
+/*
+ * Return the signature header for RO_A
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        struct SignedHeader
+ * @param reply_len    Max length to return
+ *
+ * @errors             APP_ERROR_TOO_MUCH
+ */
+
+#define NUGGET_PARAM_HEADER_RO_B 0x0009
+/*
+ * Return the signature header for RO_B
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        struct SignedHeader
+ * @param reply_len    Max length to return
+ *
+ * @errors             APP_ERROR_TOO_MUCH
+ */
+
+#define NUGGET_PARAM_HEADER_RW_A 0x000a
+/*
+ * Return the signature header for RW_A
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        struct SignedHeader
+ * @param reply_len    Max length to return
+ *
+ * @errors             APP_ERROR_TOO_MUCH
+ */
+
+#define NUGGET_PARAM_HEADER_RW_B 0x000b
+/*
+ * Return the signature header for RW_B
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        struct SignedHeader
+ * @param reply_len    Max length to return
+ *
+ * @errors             APP_ERROR_TOO_MUCH
+ */
+
+#define NUGGET_PARAM_REPO_SNAPSHOT 0x000c
+/*
+ * Return the multi-line repo snapshot info for the current image
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        Null-terminated ASCII string
+ * @param reply_len    Max length to return
+ *
+ * @errors             APP_ERROR_TOO_MUCH
+ */
+
+enum nugget_ap_uart_passthru_cfg {
+  NUGGET_AP_UART_OFF,                   /* off */
+  NUGGET_AP_UART_IS_USB,                /* USB CCD is in use over SBU */
+  NUGGET_AP_UART_ENABLED,               /* AP UART is on SBU lines */
+  NUGGET_AP_UART_SSC_UART,              /* This doesn't actually exist */
+  NUGGET_AP_UART_CITADEL_UART,          /* Citadel UART on SBU lines (ew) */
+
+  NUGGET_AP_UART_NUM_CFGS,
+};
+#define NUGGET_PARAM_AP_UART_PASSTHRU 0x000d
+/*
+ * Enable/Disable the AP UART PASSTHRU function
+ *
+ * This always returns the current state of the AP UART passthru feature. Even
+ * if the AP UART is disabled, a SuzyQable may connected to use the SBU lines.
+ *
+ * The AP can only request that the AP UART passthru feature be enabled
+ * (NUGGET_AP_UART_ENABLED), or disabled (NUGGET_AP_UART_OFF). The other enums
+ * are for internal testing.
+ *
+ * @param args         <none>  OR  enum nugget_ap_uart_passthru_cfg
+ * @param arg_len        0     OR   1 byte
+ * @param reply        enum nugget_param_ap_uart_passthru
+ * @param reply_len    1 byte
+ *
+ * @errors             APP_ERROR_BOGUS_ARGS
+ */
+
 /****************************************************************************/
 /* Test related commands */
 
diff --git a/nugget/include/signed_header.h b/nugget/include/signed_header.h
index 9ce33e6..81be877 100644
--- a/nugget/include/signed_header.h
+++ b/nugget/include/signed_header.h
@@ -82,6 +82,7 @@
   }
 
   void print() const {
+    printf("hdr.magic          : %08x\n", magic);
     printf("hdr.keyid          : %08x\n", keyid);
     printf("hdr.tag            : ");
     const uint8_t* p = reinterpret_cast<const uint8_t*>(&tag);
@@ -92,8 +93,13 @@
     printf("hdr.epoch          : %08x\n", epoch_);
     printf("hdr.major          : %08x\n", major_);
     printf("hdr.minor          : %08x\n", minor_);
-    printf("hdr.timestamp      : %016" PRIu64 "x, %s", timestamp_,
+    printf("hdr.timestamp      : %016" PRIx64 ", %s", timestamp_,
            asctime(localtime(reinterpret_cast<const time_t*>(&timestamp_))));
+    printf("hdr.image_size     : %08x\n", image_size);
+    printf("hdr.ro_base        : %08x\n", ro_base);
+    printf("hdr.ro_max         : %08x\n", ro_max);
+    printf("hdr.rx_base        : %08x\n", rx_base);
+    printf("hdr.rx_max         : %08x\n", rx_max);
     printf("hdr.img_chk        : %08x\n", be32toh(img_chk_));
     printf("hdr.fuses_chk      : %08x\n", be32toh(fuses_chk_));
     printf("hdr.info_chk       : %08x\n", be32toh(info_chk_));
diff --git a/nugget/proto/nugget/app/keymaster/keymaster.options b/nugget/proto/nugget/app/keymaster/keymaster.options
index 99730ae..f765aaf 100644
--- a/nugget/proto/nugget/app/keymaster/keymaster.options
+++ b/nugget/proto/nugget/app/keymaster/keymaster.options
@@ -2,4 +2,14 @@
 nugget.app.keymaster.ImportWrappedKeyRequest.gcm_tag max_size:16
 nugget.app.keymaster.ImportWrappedKeyRequest.masking_key max_size:32
 nugget.app.keymaster.SetRootOfTrustRequest.digest max_size:32
-nugget.app.keymaster.SetBootStateRequest.public_key max_size:32
\ No newline at end of file
+nugget.app.keymaster.SetBootStateRequest.public_key max_size:32
+nugget.app.keymaster.SetBootStateRequest.boot_hash max_size:32
+nugget.app.keymaster.ComputeSharedHmacRequest.hmac_sharing_params max_count:3
+nugget.app.keymaster.ComputeSharedHmacResponse.sharing_check max_size:32
+nugget.app.keymaster.DTupHandshakeRequest.nonce_client max_size:32
+nugget.app.keymaster.DTupHandshakeResponse.nonce_citadel max_size:32
+nugget.app.keymaster.DTupHandshakeResponse.signature max_size:32
+nugget.app.keymaster.DTupFetchInputEventResponse.signature max_size:32
+nugget.app.keymaster.GetBootInfoResponse.boot_key max_size:32
+nugget.app.keymaster.GetBootInfoResponse.boot_hash max_size:32
+nugget.app.keymaster.ProvisionPresharedSecretRequest.preshared_secret max_size:32
diff --git a/nugget/proto/nugget/app/keymaster/keymaster.proto b/nugget/proto/nugget/app/keymaster/keymaster.proto
index 603e041..47a7d60 100644
--- a/nugget/proto/nugget/app/keymaster/keymaster.proto
+++ b/nugget/proto/nugget/app/keymaster/keymaster.proto
@@ -79,6 +79,32 @@
   rpc ProvisionDeviceIds (ProvisionDeviceIdsRequest) returns (ProvisionDeviceIdsResponse);
   // Only callable at the Device Factory.
   rpc ReadTeeBatchCertificate (ReadTeeBatchCertificateRequest) returns (ReadTeeBatchCertificateResponse);
+
+  /*
+   * More KM4 methods.
+   */
+  rpc GetHmacSharingParameters (GetHmacSharingParametersRequest) returns (GetHmacSharingParametersResponse);
+  rpc ComputeSharedHmac (ComputeSharedHmacRequest) returns (ComputeSharedHmacResponse);
+
+  /*
+   * DTup input session methods.
+   */
+  rpc HandshakeDTup (DTupHandshakeRequest) returns (DTupHandshakeResponse);
+  rpc FetchDTupInputEvent (DTupFetchInputEventRequest) returns (DTupFetchInputEventResponse);
+
+  /*
+   * More vendor specific methods.
+   */
+  // Only callable once per boot.
+  rpc SetSystemVersionInfo (SetSystemVersionInfoRequest) returns (SetSystemVersionInfoResponse);
+  rpc GetBootInfo (GetBootInfoRequest) returns (GetBootInfoResponse);
+
+  /*
+   * Called during provisioning by the CitadelProvision tool.
+   */
+  rpc ProvisionPresharedSecret (ProvisionPresharedSecretRequest) returns (ProvisionPresharedSecretResponse);
+  // These are implemented with a enum, so new RPCs must be appended, and
+  // deprecated RPCs need placeholders.
 }
 
 /*
@@ -186,6 +212,7 @@
   KeyPurpose purpose = 1;
   KeyBlob blob = 2;
   KeyParameters params = 3;
+  HardwareAuthToken auth_token = 4;
 }
 message BeginOperationResponse {
   ErrorCode error_code = 1;
@@ -198,6 +225,8 @@
   OperationHandle handle = 1;
   KeyParameters params = 2;
   bytes input = 3;
+  HardwareAuthToken auth_token = 4;
+  VerificationToken verification_token = 5;
 }
 message UpdateOperationResponse {
   ErrorCode error_code = 1;
@@ -212,6 +241,8 @@
   KeyParameters params = 2;
   bytes input = 3;
   bytes signature = 4;
+  HardwareAuthToken auth_token = 5;
+  VerificationToken verification_token = 6;
 };
 message FinishOperationResponse {
   ErrorCode error_code = 1;
@@ -245,6 +276,23 @@
 }
 // ImportWrappedKey returns a ImportKeyResponse.
 
+// GetHmacSharingParametersRequest
+message GetHmacSharingParametersRequest {
+}
+message GetHmacSharingParametersResponse {
+  ErrorCode error_code = 1;
+  HmacSharingParameters hmac_sharing_params = 2;
+}
+
+// ComputeSharedHmacRequest
+message ComputeSharedHmacRequest {
+  repeated HmacSharingParameters hmac_sharing_params = 1;
+}
+message ComputeSharedHmacResponse {
+  ErrorCode error_code = 1;
+  bytes sharing_check = 2;
+}
+
 /*
  * Vendor HAL.
  */
@@ -252,7 +300,7 @@
 // SetRootOfTrustRequest
 // Only callable by the Bootloader.
 message SetRootOfTrustRequest {
-  bytes digest = 1;
+  bytes digest = 1;                  // This is a SHA256 digest.
 }
 message SetRootOfTrustResponse {
   // Specified in keymaster_defs.proto:ErrorCode
@@ -263,10 +311,11 @@
 // Only callable by the Bootloader.
 message SetBootStateRequest {
   bool is_unlocked = 1;
-  bytes public_key = 2;
-  uint32 color = 3;
+  bytes public_key = 2;              // This is a SHA256 digest.
+  BootColor color = 3;
   uint32 system_version = 4;
   uint32 system_security_level = 5;
+  bytes boot_hash = 6;               // This is a SHA256 digest.
 }
 message SetBootStateResponse {
   // Specified in keymaster_defs.proto:ErrorCode
@@ -301,3 +350,51 @@
   ECKey ec = 3;
   bytes batch_cert = 4;
 }
+
+message DTupHandshakeRequest {
+  bytes nonce_client = 1;
+}
+
+message DTupHandshakeResponse {
+  DTupError error_code = 1;
+  bytes nonce_citadel = 2;
+  bytes signature = 3;
+}
+
+message DTupFetchInputEventRequest {}
+
+message DTupFetchInputEventResponse {
+  DTupError error_code = 1;
+  DTupKeyEvent event = 2;
+  bytes signature = 3;
+}
+
+message SetSystemVersionInfoRequest {
+  uint32 system_version = 1;  // getprop "ro.build.version.release"
+  uint32 system_security_level = 2; // getprop "ro.build.version.security_patch"
+  uint32 vendor_security_level = 3; // getprop "ro.vendor.build.security_patch"
+}
+
+message SetSystemVersionInfoResponse {
+  // Specified in keymaster_defs.proto:ErrorCode
+  ErrorCode error_code = 1;
+}
+
+message GetBootInfoRequest {}
+
+message GetBootInfoResponse {
+  ErrorCode error_code = 1;
+  bool is_unlocked = 2;
+  BootColor boot_color = 3;
+  bytes boot_key = 4;               // This is a SHA256 digest.
+  bytes boot_hash = 5;              // This is a SHA256 digest.
+}
+
+message ProvisionPresharedSecretRequest {
+  bytes preshared_secret = 1;
+  bool get_status = 2;
+}
+message ProvisionPresharedSecretResponse {
+  ErrorCode error_code = 1;
+  PresharedSecretStatus status = 2;
+}
diff --git a/nugget/proto/nugget/app/keymaster/keymaster_defs.proto b/nugget/proto/nugget/app/keymaster/keymaster_defs.proto
index c3fbbc8..1dcb5b6 100644
--- a/nugget/proto/nugget/app/keymaster/keymaster_defs.proto
+++ b/nugget/proto/nugget/app/keymaster/keymaster_defs.proto
@@ -89,6 +89,8 @@
   ATTESTATION_ID_MEID = 0x902cb; // (TagType:BYTES | 715)
   ATTESTATION_ID_MANUFACTURER = 0x902cc; // (TagType:BYTES | 716)
   ATTESTATION_ID_MODEL = 0x902cd; // (TagType:BYTES | 717)
+  VENDOR_PATCHLEVEL = 0x302ce; // (TagType:UINT | 718)
+  BOOT_PATCHLEVEL = 0x302cf; // (TagType:UINT | 719)
   ASSOCIATED_DATA = 0x903e8; // (TagType:BYTES | 1000)
   NONCE = 0x903e9; // (TagType:BYTES | 1001)
   /* RESERVED: AUTH_TOKEN = 0x903ea; // (TagType:BYTES | 1002) */
@@ -263,3 +265,23 @@
   PKCS8 = 1;  /* for asymmetric key pair import */
   RAW = 3;    /* for symmetric key import and export*/
 }
+
+enum DTupError {
+  DTUP_OK = 0;
+  DTUP_NO_EVENT = 1;
+}
+
+/* matches Linux event device codes */
+enum DTupKeyEvent {
+    DTUP_RESERVED = 0;
+    DTUP_VOL_DOWN = 114;
+    DTUP_VOL_UP = 115;
+    DTUP_PWR = 116;
+}
+
+enum BootColor {
+    BOOT_VERIFIED_GREEN = 0;
+    BOOT_SELFSIGNED_YELLOW = 1;
+    BOOT_UNVERIFIED_ORANGE = 2;
+    BOOT_VERIFY_FAILED_RED = 3;
+}
\ No newline at end of file
diff --git a/nugget/proto/nugget/app/keymaster/keymaster_types.options b/nugget/proto/nugget/app/keymaster/keymaster_types.options
index 18678aa..ab60bbf 100644
--- a/nugget/proto/nugget/app/keymaster/keymaster_types.options
+++ b/nugget/proto/nugget/app/keymaster/keymaster_types.options
@@ -1 +1,3 @@
-nugget.app.keymaster.KeyParameters.params max_count:20
\ No newline at end of file
+nugget.app.keymaster.KeyParameters.params max_count:20
+nugget.app.keymaster.HmacSharingParameters.seed max_size:32
+nugget.app.keymaster.HmacSharingParameters.nonce max_size:32
diff --git a/nugget/proto/nugget/app/keymaster/keymaster_types.proto b/nugget/proto/nugget/app/keymaster/keymaster_types.proto
index f5399ee..977595c 100644
--- a/nugget/proto/nugget/app/keymaster/keymaster_types.proto
+++ b/nugget/proto/nugget/app/keymaster/keymaster_types.proto
@@ -59,6 +59,15 @@
   bytes nonce = 2;
 }
 
+message HardwareAuthToken {
+  uint64 challenge = 1;
+  uint64 user_id = 2;
+  uint64 authenticator_id = 3;
+  HardwareAuthenticatorType authenticator_type = 4;
+  uint64 timestamp = 5;
+  bytes mac = 6;
+}
+
 message VerificationToken {
   uint64 challenge = 1;
   uint64 timestamp = 2;
@@ -87,3 +96,8 @@
 message SymmetricKey {
   bytes material = 1;
 }
+
+enum PresharedSecretStatus {
+  NOT_SET = 0;
+  ALREADY_SET = 1;
+}