DO NOT MERGE - Merge Android 10 into master

Bug: 139893257
Change-Id: Iefbd04396ee0ae07fc0f5abea3b34714ad893cee
diff --git a/.checkpatch.conf b/.checkpatch.conf
new file mode 100644
index 0000000..e8e9db6
--- /dev/null
+++ b/.checkpatch.conf
@@ -0,0 +1,7 @@
+# Not Linux, so don't expect a Linux tree.
+--no-tree
+
+# Ignore aspects we don't follow here.
+--ignore FILE_PATH_CHANGES
+--ignore GIT_COMMIT_ID
+--ignore SPLIT_STRING
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..d13eeba
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,2 @@
+BasedOnStyle: Google
+ColumnLimit: 80
diff --git a/BUILD b/BUILD
index 9c8b007..74f705e 100644
--- a/BUILD
+++ b/BUILD
@@ -5,6 +5,7 @@
         "nugget/include/app_transport_test.h",
         "nugget/include/application.h",
         "nugget/include/avb.h",
+        "nugget/include/citadel_events.h",
         "nugget/include/flash_layout.h",
         "nugget/include/keymaster.h",
         "nugget/include/signed_header.h",
diff --git a/citadel/updater/updater.cpp b/citadel/updater/updater.cpp
index 4a8549e..ec8fb3f 100644
--- a/citadel/updater/updater.cpp
+++ b/citadel/updater/updater.cpp
@@ -18,6 +18,7 @@
 #include <vector>
 
 #include <getopt.h>
+#include <inttypes.h>
 #include <openssl/sha.h>
 #include <stdarg.h>
 #include <stddef.h>
@@ -30,6 +31,7 @@
 /* From Nugget OS */
 #include <application.h>
 #include <app_nugget.h>
+#include <citadel_events.h>
 #include <flash_layout.h>
 #include <signed_header.h>
 
@@ -67,6 +69,7 @@
   int id;
   int repo_snapshot;
   int stats;
+  int statsd;
   int ro;
   int rw;
   int reboot;
@@ -80,6 +83,11 @@
   char **selftest_args;
   /* generic connection options */
   const char *device;
+  int suzyq;
+  int board_id;
+  int event;
+  char **board_id_args;
+  int console;
 } options;
 
 enum no_short_opts_for_these {
@@ -87,6 +95,7 @@
   OPT_ID,
   OPT_REPO_SNAPSHOT,
   OPT_STATS,
+  OPT_STATSD,
   OPT_RO,
   OPT_RW,
   OPT_REBOOT,
@@ -97,9 +106,12 @@
   OPT_ERASE,
   OPT_AP_UART,
   OPT_SELFTEST,
+  OPT_SUZYQ,
+  OPT_BOARD_ID,
+  OPT_EVENT,
 };
 
-const char *short_opts = ":hvlV:fF:";
+const char *short_opts = ":hvlV:fF:c";
 const struct option long_opts[] = {
   /* name    hasarg *flag val */
   {"version",       0, NULL, 'v'},
@@ -109,6 +121,7 @@
   {"repo_snapshot", 0, NULL, OPT_REPO_SNAPSHOT},
   {"repo-snapshot", 0, NULL, OPT_REPO_SNAPSHOT},
   {"stats",         0, NULL, OPT_STATS},
+  {"statsd",        0, NULL, OPT_STATSD},
   {"ro",            0, NULL, OPT_RO},
   {"rw",            0, NULL, OPT_RW},
   {"reboot",        0, NULL, OPT_REBOOT},
@@ -124,6 +137,9 @@
   {"ap_uart",       0, NULL, OPT_AP_UART},
   {"ap-uart",       0, NULL, OPT_AP_UART},
   {"selftest",      0, NULL, OPT_SELFTEST},
+  {"suzyq",         0, NULL, OPT_SUZYQ},
+  {"board_id",      0, NULL, OPT_BOARD_ID},
+  {"event",         0, NULL, OPT_EVENT},
 #ifndef ANDROID
   {"device",        1, NULL, OPT_DEVICE},
 #endif
@@ -160,6 +176,8 @@
     "  -l, --long_version   Display the full version info\n"
     "  --id                 Display the Citadel device ID\n"
     "  --stats              Display Low Power stats\n"
+    "  --statsd             Display Low Power stats cached by citadeld\n"
+    "\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"
@@ -183,6 +201,13 @@
     "  --selftest [ARGS]    Run one or more selftests. With no ARGS, it runs\n"
     "                       a default suite. This command will consume all\n"
     "                       following args, so run it alone for best results.\n"
+    "\n"
+    "  --suzyq [0|1]        Set the SuzyQable detection setting\n"
+    "\n"
+    "  --board_id [TYPE FLAG]   Get/Set board ID values\n"
+    "\n"
+    "  --event [NUM]        Get NUM pending event records (default 1)\n"
+    "\n"
 #ifndef ANDROID
     "\n"
     "Options:\n"
@@ -512,7 +537,7 @@
   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" : "--");
+         hdr->magic == SIGNED_HEADER_MAGIC_CITADEL ? "ok" : "--");
 }
 
 static void show_rw_string(const char *name, const uint8_t *ptr)
@@ -522,10 +547,11 @@
 
   if (v->cookie1 == CROS_EC_VERSION_COOKIE1 &&
       v->cookie2 == CROS_EC_VERSION_COOKIE2 &&
-      (v->hdr.magic == MAGIC_DEFAULT || v->hdr.magic == MAGIC_VALID)) {
+      (v->hdr.magic == SIGNED_HEADER_MAGIC_HAVEN ||
+       v->hdr.magic == SIGNED_HEADER_MAGIC_CITADEL)) {
     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" : "--");
+           v->hdr.magic == SIGNED_HEADER_MAGIC_CITADEL ? "ok" : "--");
   } else {
     printf("<invalid>\n");
   }
@@ -600,7 +626,7 @@
 {
   uint32_t retval;
   std::vector<uint8_t> buffer;
-  buffer.reserve(1200);
+  buffer.reserve(2048);
 
   retval = app.Call(NUGGET_PARAM_REPO_SNAPSHOT, buffer, &buffer);
 
@@ -611,6 +637,62 @@
   return retval;
 }
 
+uint32_t do_console(AppClient &app, int argc, char *argv[])
+{
+  std::vector<uint8_t> buffer;
+  uint32_t rv;
+  size_t got;
+
+  if (options.console < argc) {
+    char *s = argv[options.console];
+    char c;
+    do {
+      c = *s++;
+      buffer.push_back(c);
+    } while (c);
+  }
+
+  do {
+    buffer.reserve(4096);
+    rv = app.Call(NUGGET_PARAM_CONSOLE, buffer, &buffer);
+    got = buffer.size();
+
+    if (is_app_success(rv)){
+      buffer.push_back('\0');
+      printf("%s", buffer.data());
+    }
+
+    buffer.resize(0);
+  } while (rv == APP_SUCCESS && got > 0);
+
+  return rv;
+}
+
+static void print_stats(const struct nugget_app_low_power_stats *s)
+{
+  printf("hard_reset_count            %" PRIu64 "\n", s->hard_reset_count);
+  printf("time_since_hard_reset       %" PRIu64 "\n",
+         s->time_since_hard_reset);
+  printf("wake_count                  %" PRIu64 "\n", s->wake_count);
+  printf("time_at_last_wake           %" PRIu64 "\n", s->time_at_last_wake);
+  printf("time_spent_awake            %" PRIu64 "\n", s->time_spent_awake);
+  printf("deep_sleep_count            %" PRIu64 "\n", s->deep_sleep_count);
+  printf("time_at_last_deep_sleep     %" PRIu64 "\n",
+         s->time_at_last_deep_sleep);
+  printf("time_spent_in_deep_sleep    %" PRIu64 "\n",
+         s->time_spent_in_deep_sleep);
+  if (s->time_at_ap_reset == UINT64_MAX)
+    printf("time_at_ap_reset            0x%" PRIx64 "\n", s->time_at_ap_reset);
+  else
+    printf("time_at_ap_reset            %" PRIu64 "\n", s->time_at_ap_reset);
+  if (s->time_at_ap_bootloader_done == UINT64_MAX)
+    printf("time_at_ap_bootloader_done  0x%" PRIx64 "\n",
+           s->time_at_ap_bootloader_done);
+  else
+    printf("time_at_ap_bootloader_done  %" PRIu64 "\n",
+           s->time_at_ap_bootloader_done);
+}
+
 uint32_t do_stats(AppClient &app)
 {
   struct nugget_app_low_power_stats stats;
@@ -618,34 +700,53 @@
   uint32_t retval;
 
   buffer.reserve(sizeof(stats));
-
   retval = app.Call(NUGGET_PARAM_GET_LOW_POWER_STATS, buffer, &buffer);
 
   if (is_app_success(retval)) {
-    if (buffer.size() < sizeof(stats)) {
-      fprintf(stderr, "Only got %zd / %zd bytes back",
+    if (buffer.size() < sizeof(stats)) { // old firmware?
+      fprintf(stderr, "# only got %zd / %zd bytes back\n",
               buffer.size(), sizeof(stats));
-      return -1;
+      memset(&stats, 0, sizeof(stats));
     }
-
-    memcpy(&stats, buffer.data(), sizeof(stats));
-
-    printf("hard_reset_count         %" PRIu64 "\n", stats.hard_reset_count);
-    printf("time_since_hard_reset    %" PRIu64 "\n",
-           stats.time_since_hard_reset);
-    printf("wake_count               %" PRIu64 "\n", stats.wake_count);
-    printf("time_at_last_wake        %" PRIu64 "\n", stats.time_at_last_wake);
-    printf("time_spent_awake         %" PRIu64 "\n", stats.time_spent_awake);
-    printf("deep_sleep_count         %" PRIu64 "\n", stats.deep_sleep_count);
-    printf("time_at_last_deep_sleep  %" PRIu64 "\n",
-           stats.time_at_last_deep_sleep);
-    printf("time_spent_in_deep_sleep %" PRIu64 "\n",
-           stats.time_spent_in_deep_sleep);
+    memcpy(&stats, buffer.data(), std::min(sizeof(stats), buffer.size()));
+    print_stats(&stats);
   }
 
   return retval;
 }
 
+#ifdef ANDROID
+uint32_t do_statsd(CitadeldProxyClient &client)
+{
+  struct nugget_app_low_power_stats stats;
+  std::vector<uint8_t> buffer;
+
+  buffer.reserve(sizeof(stats));
+  ::android::binder::Status s = client.Citadeld().getCachedStats(&buffer);
+
+  if (s.isOk()) {
+    if (buffer.size() < sizeof(stats)) { // old citadeld?
+      fprintf(stderr, "# only got %zd / %zd bytes back\n",
+              buffer.size(), sizeof(stats));
+      memset(&stats, 0, sizeof(stats));
+    }
+    memcpy(&stats, buffer.data(), std::min(sizeof(stats), buffer.size()));
+    print_stats(&stats);
+  } else {
+    printf("ERROR: binder exception %d\n", s.exceptionCode());
+    return APP_ERROR_IO;
+  }
+
+  return 0;
+}
+#else
+uint32_t do_statsd(NuggetClient &client)
+{
+  Error("citadeld isn't attached to this interface");
+  return APP_ERROR_BOGUS_ARGS;
+}
+#endif
+
 uint32_t do_reboot(AppClient &app)
 {
   uint32_t retval;
@@ -740,6 +841,190 @@
   return rv;
 }
 
+static uint32_t do_suzyq(AppClient &app, int argc, char *argv[])
+{
+  int i, j;
+  std::vector<uint8_t> buffer;
+
+  for (i = options.suzyq; i < argc; i++) {
+    for (j = 0; argv[i][j]; j++) {
+      buffer.push_back(strtol(argv[i], NULL, 10));
+    }
+  }
+
+  buffer.reserve(1);
+  uint32_t rv = app.Call(NUGGET_PARAM_RDD_CFG, buffer, &buffer);
+
+  if (is_app_success(rv))
+    printf("Current SuzyQable detection setting is %d\n", buffer[0]);
+
+  return rv;
+}
+
+static void parse_hex_value(uint32_t *val, const char *str)
+{
+  char *e = 0;
+  uint32_t tmp = strtoul(str, &e, 16);
+
+  if (e && *e)
+    Error("Invalid arg: \"%s\"", str);
+  else
+    *val = tmp;
+}
+
+static void show_board_id(const struct nugget_app_board_id *id)
+{
+  printf("0x%08x 0x%08x 0x%08x # ", id->type, id->flag, id->inv);
+
+  if (id->type == 0xffffffff && id->flag == 0xffffffff &&
+      id->inv == 0xffffffff) {
+    printf("unset\n");
+    return;
+  }
+
+  if (id->type ^ ~id->inv) {
+    printf("corrupted\n");
+    return;
+  }
+
+  printf("%s, ", id->flag & 0x80 ? "MP" : "Pre-MP");
+  switch (id->flag & 0x7f) {
+  case 0x7f:
+    printf("DEVBOARD\n");
+    break;
+  case 0x7e:
+    printf("Proto1\n");
+    break;
+  case 0x7c:
+    printf("Proto2+\n");
+    break;
+  case 0x78:
+    printf("EVT1\n");
+    break;
+  case 0x70:
+    printf("EVT2+\n");
+    break;
+  case 0x60:
+    printf("DVT1\n");
+    break;
+  case 0x40:
+    printf("DVT2+\n");
+    break;
+  case 0x00:
+    printf("PVT/MP\n");
+    break;
+  default:
+    printf("(unknown)\n");
+    break;
+  }
+}
+
+static uint32_t do_board_id(AppClient &app, int argc, char *argv[])
+{
+  uint32_t rv;
+  std::vector<uint8_t> request;
+  std::vector<uint8_t> response(sizeof(struct nugget_app_board_id));
+  struct nugget_app_board_id board_id;
+  char answer = 0;
+
+  // User must input both board_type and board_flag to make a set request
+  if (argc - options.board_id >= 2) {
+    uint32_t tmp = 0;
+
+    parse_hex_value(&tmp, argv[options.board_id]);
+    board_id.type = tmp;
+
+    parse_hex_value(&tmp, argv[options.board_id + 1]);
+    board_id.flag = tmp;
+
+    // optional third arg must equal ~type to avoid confirmation
+    if (argc - options.board_id > 2) {
+      parse_hex_value(&tmp, argv[options.board_id + 2]);
+      board_id.inv = tmp;
+    } else {
+      board_id.inv = ~board_id.type;
+    }
+
+    // Any problems parsing args?
+    if (errorcnt)
+      return errorcnt;
+
+    // Confirm unless correct type_inv arg is given
+    if (argc - options.board_id == 2 || board_id.type ^ ~board_id.inv) {
+      printf("\nWriting Board ID:  ");
+      show_board_id(&board_id);
+      printf("\nWARNING: Setting board-id is irreversible!\n");
+      printf("Are you sure? (y/n) ");
+      fflush(stdout);
+      scanf(" %c", &answer);
+      if (answer != 'y'){
+        Error("Operation cancelled");
+        return errorcnt;
+      }
+      board_id.inv = ~board_id.type;
+      printf("\n");
+    }
+
+    request.resize(sizeof(board_id));
+    memcpy(request.data(), &board_id, sizeof(board_id));
+  }
+
+  rv = app.Call(NUGGET_PARAM_BOARD_ID, request, &response);
+
+  if (is_app_success(rv)) {
+    memcpy(&board_id, response.data(), sizeof(board_id));
+    show_board_id(&board_id);
+  }
+
+  return rv;
+}
+
+static uint32_t do_event(AppClient &app, int argc, char *argv[])
+{
+  uint32_t rv;
+  int i, num = 1;
+
+  if (options.event < argc) {
+    num = atoi(argv[options.event]);
+  }
+
+  for (i = 0; i < num; i++) {
+    struct event_record evt;
+    std::vector<uint8_t> buffer;
+    buffer.reserve(sizeof(evt));
+
+    rv = app.Call(NUGGET_PARAM_GET_EVENT_RECORD, buffer, &buffer);
+
+    if (!is_app_success(rv)) {
+      // That check also displays any errors
+      break;
+    }
+
+    if (buffer.size() == 0) {
+      printf("-- no event_records --\n");
+      continue;
+    }
+
+    if (buffer.size() != sizeof(evt)) {
+      fprintf(stderr, "Error: expected %zd bytes, got %zd instead\n",
+             sizeof(evt), buffer.size());
+      rv = 1;
+      break;
+    }
+
+    /* We got an event, let's show it */
+    memcpy(&evt, buffer.data(), sizeof(evt));
+    uint64_t secs = evt.uptime_usecs / 1000000UL;
+    uint64_t usecs = evt.uptime_usecs - (secs * 1000000UL);
+    printf("event record %" PRIu64 "/%" PRIu64 ".%06" PRIu64 ": ",
+           evt.reset_count, secs, usecs);
+    printf("%d  0x%08x 0x%08x 0x%08x\n", evt.id,
+           evt.u.raw.w[0], evt.u.raw.w[1], evt.u.raw.w[2]);
+  }
+
+  return rv;
+}
+
 static uint32_t do_erase(AppClient &app)
 {
   std::vector<uint8_t> data(sizeof(uint32_t));
@@ -863,6 +1148,11 @@
     return 2;
   }
 
+  if (options.statsd &&
+      do_statsd(client) != APP_SUCCESS) {
+    return 2;
+  }
+
   if (options.repo_snapshot &&
       do_repo_snapshot(app) != APP_SUCCESS) {
     return 2;
@@ -902,6 +1192,26 @@
     return 1;
   }
 
+  if (options.suzyq &&
+      do_suzyq(app, argc, argv) != APP_SUCCESS) {
+    return 1;
+  }
+
+  if (options.board_id &&
+      do_board_id(app, argc, argv) != APP_SUCCESS) {
+    return 1;
+  }
+
+  if (options.console &&
+      do_console(app, argc, argv) != APP_SUCCESS) {
+    return 1;
+  }
+
+  if (options.event &&
+      do_event(app, argc, argv) != APP_SUCCESS) {
+    return 1;
+  }
+
   return 0;
 }
 
@@ -949,6 +1259,10 @@
       options.section = parse_section(optarg);
       got_action = 1;
       break;
+    case 'c':
+      options.console = optind;
+      got_action = 1;
+      break;
     case 'f':
       options.file_version = 1;
       need_file = 1;
@@ -971,6 +1285,10 @@
       options.stats = 1;
       got_action = 1;
       break;
+    case OPT_STATSD:
+      options.statsd = 1;
+      got_action = 1;
+      break;
     case OPT_RO:
       options.ro = 1;
       need_file = 1;
@@ -1012,6 +1330,19 @@
       options.ap_uart = 1;
       got_action = 1;
       break;
+    case OPT_SUZYQ:
+      options.suzyq = optind;
+      got_action = 1;
+      break;
+    case OPT_BOARD_ID:
+      options.board_id = optind;
+      options.board_id_args = argv;
+      got_action = 1;
+      break;
+    case OPT_EVENT:
+      options.event = optind;
+      got_action = 1;
+      break;
     case OPT_SELFTEST:
       options.selftest = optind;
       options.selftest_args = argv;
diff --git a/libnos_datagram/include/nos/device.h b/libnos_datagram/include/nos/device.h
index d3d6055..d4c29c3 100644
--- a/libnos_datagram/include/nos/device.h
+++ b/libnos_datagram/include/nos/device.h
@@ -23,7 +23,7 @@
 #endif
 
 /* Max data size for read/write.
- * TODO: Yes, it's a magic number. */
+ * Yes, it's a magic number. See b/37675056#comment8. */
 #define MAX_DEVICE_TRANSFER 2044
 
 struct nos_device_ops {
diff --git a/libnos_transport/WORKSPACE b/libnos_transport/WORKSPACE
index c9384bc..14884e6 100644
--- a/libnos_transport/WORKSPACE
+++ b/libnos_transport/WORKSPACE
@@ -1,11 +1,12 @@
 workspace(name = "nugget_host_generic_libnos_transport")
 
-new_http_archive(
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+http_archive(
     name = "gtest",
-    url = "https://github.com/google/googletest/archive/release-1.8.0.zip",
-    build_file = "../../../core/nugget/BUILD.gtest",
-    sha256 = "f3ed3b58511efd272eb074a3a6d6fb79d7c2e6a0e374323d1e6bcbcc1ef141bf",
-    strip_prefix = "googletest-release-1.8.0",
+    url = "https://github.com/google/googletest/archive/release-1.8.1.zip",
+    sha256 = "927827c183d01734cc5cfef85e0ff3f5a92ffe6188e0d18e909c5efebf28a0c7",
+    strip_prefix = "googletest-release-1.8.1",
 )
 
 local_repository(
diff --git a/libnos_transport/transport.c b/libnos_transport/transport.c
index 7dad955..551c89a 100644
--- a/libnos_transport/transport.c
+++ b/libnos_transport/transport.c
@@ -325,7 +325,7 @@
 
   /* Tell the app to handle the request while also sending the command_info
    * which will be ignored by the v0 protocol. */
-  NLOGD("Write app %d command 0x%08x, crc %04x...", ctx->app_id, command, command_info.crc);
+  NLOGD("Send app %d go command 0x%08x", ctx->app_id, command);
   if (0 != nos_device_write(ctx->dev, command, &command_info, sizeof(command_info))) {
     NLOGE("Failed to send command datagram to app %d", ctx->app_id);
     return APP_ERROR_IO;
diff --git a/nugget/include/app_nugget.h b/nugget/include/app_nugget.h
index 2c3d980..2e96c97 100644
--- a/nugget/include/app_nugget.h
+++ b/nugget/include/app_nugget.h
@@ -262,6 +262,54 @@
  * @errors             APP_ERROR_BOGUS_ARGS
  */
 
+#define NUGGET_PARAM_RDD_CFG 0x000e
+/*
+ * Set / Get Board ID
+ *
+ * This sets or gets the Board ID of the device.
+ *
+ * @param args         <none>  OR   nugget_app_board_id
+ * @param arg_len      0       OR   sizeof nugget_app_board_id
+ * @param reply        struct nugget_app_board_id
+ * @param reply_len    sizeof struct nugget_app_board_id
+ *
+ * @errors             APP_ERROR_BOGUS_ARGS
+ */
+struct nugget_app_board_id {
+  uint32_t type;
+  uint32_t flag;
+  uint32_t inv;                         /* must equal ~type when setting */
+} __packed;
+#define NUGGET_PARAM_BOARD_ID 0x000f
+
+/*
+ * Enable/Disable the RDD SuzyQable Deteaction
+ *
+ * This always returns the current state of the RDD SuezyQable detection
+ * feature.
+ *
+ * The AP can request that the RDD SuezyQable detection to be disabled (0) or
+ * enabled (1).
+ *
+ * @param args         0     OR   1
+ * @param arg_len      0     OR   1 byte
+ * @param reply        0     OR   1 current state
+ * @param reply_len    1 byte
+ *
+ * @errors             APP_ERROR_BOGUS_ARGS
+ */
+
+#define NUGGET_PARAM_GET_EVENT_RECORD 0x0010
+/*
+ * This retrieves one pending event_record (defined in citadel_events.h).
+ * If none are pending, it returns nothing.
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        struct event_record
+ * @param reply_len    sizeof struct event_record  OR  0
+ */
+
 /****************************************************************************/
 /* Test related commands */
 
@@ -309,6 +357,8 @@
   uint64_t deep_sleep_count;
   uint64_t time_at_last_deep_sleep;
   uint64_t time_spent_in_deep_sleep;
+  uint64_t time_at_ap_reset;
+  uint64_t time_at_ap_bootloader_done;
 } __packed;
 
 #define NUGGET_PARAM_GET_LOW_POWER_STATS 0x200
@@ -327,10 +377,7 @@
 /* UNIMPLEMENTED */
 
 /****************************************************************************/
-/* These are bringup / debug functions only.
- *
- * TODO(b/65067435): Remove all of these.
- */
+/* These are bringup / debug functions only. */
 
 #define NUGGET_PARAM_READ32 0xF000
 /*
@@ -363,6 +410,16 @@
  * @param reply_len    0
  */
 
+#define NUGGET_PARAM_CONSOLE 0xF002
+/*
+ * Send optional command, return recent console output
+ *
+ * @param args         command, if any
+ * @param arg_len      sizeof(command)
+ * @param reply        recent console output
+ * @param reply_len    len(recent console output)
+ */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/nugget/include/application.h b/nugget/include/application.h
index 6dd402a..ddc7600 100644
--- a/nugget/include/application.h
+++ b/nugget/include/application.h
@@ -76,6 +76,7 @@
 /* Fake apps used only for testing */
 #define APP_ID_AVB_TEST          0x11
 #define APP_ID_TRANSPORT_TEST    0x12
+#define APP_ID_FACEAUTH_TEST     0x13
 
 /* This app ID should only be used by tests. */
 #define APP_ID_TEST              0xff
@@ -269,11 +270,11 @@
 };
 
 /*
- * TODO(b/66104849): Note that request and response buffers are transferred as
- * byte streams. However, if they will eventually represent structs, the usual
- * ABI alignment requirements will be required. Until we've declared all
- * applications structs in a union, we will need to align the buffers manually.
- * Use this to declare the uint8_t buffers until then:
+ * Note that request and response buffers are transferred as byte streams.
+ * However, if they will eventually represent structs, the usual ABI alignment
+ * requirements will be required. Until we've declared all applications structs
+ * in a union, we will need to align the buffers manually. Use this to declare
+ * the uint8_t buffers until then:
  */
 #define __TRANSPORT_ALIGNED__ __attribute__((aligned(8)))
 
diff --git a/nugget/include/citadel_events.h b/nugget/include/citadel_events.h
new file mode 100644
index 0000000..336f3c5
--- /dev/null
+++ b/nugget/include/citadel_events.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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, software
+ * distributed under the License is 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.
+ */
+#ifndef __CROS_EC_INCLUDE_CITADEL_EVENTS_H
+#define __CROS_EC_INCLUDE_CITADEL_EVENTS_H
+
+#include <assert.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+/*
+ * When Citadel needs to tell the AP something without waiting to be asked, the
+ * process is as follows:
+ *
+ *   1. Citadel adds an event_record to its internal queue, then asserts
+ *      the CTDL_AP_IRQ signal to notify the AP.
+ *
+ *   2. The AP (citadeld) requests pending events from Citadel until they've
+ *      all been retrieved.
+ *
+ *   3. Citadel deasserts CTDL_AP_IRQ.
+ *
+ * Because we may want to compare the history and evolution of events over a
+ * long time and for multiple releases, we should only APPEND to this file
+ * instead of changing things.
+ */
+
+/* Please do not change the size of this struct */
+#define EVENT_RECORD_SIZE 64
+struct event_record {
+  uint64_t reset_count;                 /* zeroed by Citadel power cycle */
+  uint64_t uptime_usecs;                /* since last Citadel reset */
+  uint32_t id;
+  union {
+    /* id-specific information goes here */
+    struct {
+      uint32_t intr_sts[3];
+    } alert;
+    struct {
+      uint32_t bad_thing;
+    } citadel;
+    struct {
+      uint32_t okay_thing;
+    } info;
+
+    /* uninterpreted */
+    union {
+      uint32_t w[11];
+      uint16_t h[22];
+      uint8_t  b[44];
+    } raw;
+  } u;
+} __packed;
+/* Please do not change the size of this struct */
+static_assert(sizeof(struct event_record) == EVENT_RECORD_SIZE,
+              "Muting the Immutable");
+
+/*
+ * Event ID values live forever.
+ * Add to the list, but NEVER change or delete existing entries.
+*/
+enum event_id {
+  EVENT_NONE = 0,                       /* No valid event exists with this ID */
+  EVENT_ALERT = 1,                      /* Security alert reported */
+  EVENT_CITADEL = 2,                    /* Bad: panic, stack overflow, etc. */
+  EVENT_INFO = 3,                       /* FYI: normal reboot, etc. */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __CROS_EC_INCLUDE_CITADEL_EVENTS_H */
diff --git a/nugget/include/flash_layout.h b/nugget/include/flash_layout.h
index 0e82c88..7d65705 100644
--- a/nugget/include/flash_layout.h
+++ b/nugget/include/flash_layout.h
@@ -18,8 +18,13 @@
  */
 
 /* Flash is directly addressable */
+#if defined(CHIP_H1D1)
+#define CHIP_FLASH_BASE              0x80000
+#define CHIP_FLASH_SIZE              (1024 * 1024)
+#else
 #define CHIP_FLASH_BASE              0x40000
 #define CHIP_FLASH_SIZE              (512 * 1024)
+#endif
 #define CHIP_FLASH_HALF              (CHIP_FLASH_SIZE >> 1)
 
 /* Each half has to leave room for the image's signed header */
diff --git a/nugget/include/signed_header.h b/nugget/include/signed_header.h
index 81be877..d98d456 100644
--- a/nugget/include/signed_header.h
+++ b/nugget/include/signed_header.h
@@ -1,15 +1,10 @@
-/* Copyright 2017 The Chromium OS Authors. All rights reserved.
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
 #ifndef __EC_UTIL_SIGNER_COMMON_SIGNED_HEADER_H
 #define __EC_UTIL_SIGNER_COMMON_SIGNED_HEADER_H
 
-/* This is citadel */
-#define CHIP_C
-#define MAGIC_DEFAULT (-1u)
-#define MAGIC_VALID  (-2u)
-
 #ifdef __cplusplus
 #include <endian.h>
 #include <stdio.h>
@@ -18,7 +13,6 @@
 
 #include <assert.h>
 #include <inttypes.h>
-#include <stdint.h>
 #include <string.h>
 
 #define FUSE_MAX 128
@@ -26,14 +20,21 @@
 #define FUSE_PADDING 0x55555555
 
 // B chips
-#define FUSE_IGNORE_B 0xa3badaac   // baked in rom!
+#define FUSE_IGNORE_B 0xa3badaac  // baked in rom!
 #define INFO_IGNORE_B 0xaa3c55c3  // baked in rom!
 
 // Citadel chips
-#define FUSE_IGNORE_C 0x3aabadac   // baked in rom!
+#define FUSE_IGNORE_C 0x3aabadac  // baked in rom!
 #define INFO_IGNORE_C 0xa5c35a3c  // baked in rom!
 
-#if defined(CHIP_C)
+// D2 chips
+#define FUSE_IGNORE_D 0xdaa3baca  // baked in rom!
+#define INFO_IGNORE_D 0x5a3ca5c3  // baked in rom!
+
+#if defined(CHIP_D)
+#define FUSE_IGNORE FUSE_IGNORE_D
+#define INFO_IGNORE INFO_IGNORE_D
+#elif defined(CHIP_C)
 #define FUSE_IGNORE FUSE_IGNORE_C
 #define INFO_IGNORE INFO_IGNORE_C
 #else
@@ -41,10 +42,17 @@
 #define INFO_IGNORE INFO_IGNORE_B
 #endif
 
+#define SIGNED_HEADER_MAGIC_HAVEN (-1u)
+#define SIGNED_HEADER_MAGIC_CITADEL (-2u)
+#define SIGNED_HEADER_MAGIC_D2 (-3u)
+
+/* Default value for _pad[] words */
+#define SIGNED_HEADER_PADDING 0x33333333
+
 typedef struct SignedHeader {
 #ifdef __cplusplus
   SignedHeader()
-      : magic(-1),
+      : magic(SIGNED_HEADER_MAGIC_HAVEN),
         image_size(0),
         epoch_(0x1337),
         major_(0),
@@ -54,13 +62,20 @@
         config1_(0),
         err_response_(0),
         expect_response_(0),
+        swap_mark({0, 0}),
         dev_id0_(0),
         dev_id1_(0) {
     memset(signature, 'S', sizeof(signature));
     memset(tag, 'T', sizeof(tag));
     memset(fusemap, 0, sizeof(fusemap));
     memset(infomap, 0, sizeof(infomap));
-    memset(&_pad, '3', sizeof(_pad));
+    memset(&_pad, SIGNED_HEADER_PADDING, sizeof(_pad));
+    // Below all evolved out of _pad, thus must also be initialized to '3'
+    // for backward compatibility.
+    memset(&rw_product_family_, SIGNED_HEADER_PADDING,
+           sizeof(rw_product_family_));
+    memset(&u, SIGNED_HEADER_PADDING, sizeof(u));
+    memset(&board_id_, SIGNED_HEADER_PADDING, sizeof(board_id_));
   }
 
   void markFuse(uint32_t n) {
@@ -73,16 +88,48 @@
     infomap[n / 32] |= 1 << (n & 31);
   }
 
-  static uint32_t fuseIgnore(bool c) {
-    return c ? FUSE_IGNORE_C : FUSE_IGNORE_B;
+  static uint32_t fuseIgnore(bool c, bool d) {
+    return d ? FUSE_IGNORE_D : c ? FUSE_IGNORE_C : FUSE_IGNORE_B;
   }
 
-  static uint32_t infoIgnore(bool c) {
-    return c ? INFO_IGNORE_C : INFO_IGNORE_B;
+  static uint32_t infoIgnore(bool c, bool d) {
+    return d ? INFO_IGNORE_D : c ? INFO_IGNORE_C : INFO_IGNORE_B;
+  }
+
+  bool plausible() const {
+    switch (magic) {
+      case SIGNED_HEADER_MAGIC_HAVEN:
+      case SIGNED_HEADER_MAGIC_CITADEL:
+      case SIGNED_HEADER_MAGIC_D2:
+        break;
+      default:
+        return false;
+    }
+    if (keyid == -1u) return false;
+    if (ro_base >= ro_max) return false;
+    if (rx_base >= rx_max) return false;
+    if (_pad[0] != SIGNED_HEADER_PADDING) return false;
+    return true;
   }
 
   void print() const {
-    printf("hdr.magic          : %08x\n", magic);
+    printf("hdr.magic          : %08x (", magic);
+    switch (magic) {
+      case SIGNED_HEADER_MAGIC_HAVEN:
+        printf("Haven B");
+        break;
+      case SIGNED_HEADER_MAGIC_CITADEL:
+        printf("Citadel");
+        break;
+      case SIGNED_HEADER_MAGIC_D2:
+        printf("D2");
+        break;
+      default:
+        printf("?");
+        break;
+    }
+    printf(")\n");
+    printf("hdr.ro_base        : %08x\n", ro_base);
     printf("hdr.keyid          : %08x\n", keyid);
     printf("hdr.tag            : ");
     const uint8_t* p = reinterpret_cast<const uint8_t*>(&tag);
@@ -95,11 +142,6 @@
     printf("hdr.minor          : %08x\n", minor_);
     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_));
@@ -108,8 +150,8 @@
     printf("hdr.err_response   : %08x\n", err_response_);
     printf("hdr.expect_response: %08x\n", expect_response_);
 
-    if (dev_id0_) printf("hdr.dev_id0        : %08x\n", dev_id0_);
-    if (dev_id1_) printf("hdr.dev_id1        : %08x\n", dev_id1_);
+    if (dev_id0_) printf("hdr.dev_id0        : %08x (%d)\n", dev_id0_, dev_id0_);
+    if (dev_id1_) printf("hdr.dev_id1        : %08x (%d)\n", dev_id1_, dev_id1_);
 
     printf("hdr.fusemap        : ");
     for (size_t i = 0; i < sizeof(fusemap) / sizeof(fusemap[0]); ++i) {
@@ -147,16 +189,48 @@
   uint32_t config1_;       // bits to mesh with FUSE_FW_DEFINED_BROM_CONFIG1
   uint32_t err_response_;  // bits to or with FUSE_FW_DEFINED_BROM_ERR_RESPONSE
   uint32_t expect_response_;  // action to take when expectation is violated
+
   union {
-    uint32_t
-        _pad[256 - 1 - 96 - 1 - 7 - 1 - 96 - 5 * 1 - 4 - 4 - 9 * 1 - 2 - 1 - 2];
+    // 2nd FIPS signature (gnubby RW)
     struct {
-      // 2nd FIPS signature (gnubby RW)
       uint32_t keyid;
       uint32_t r[8];
       uint32_t s[8];
     } ext_sig;
-  } _pad;
+
+    // FLASH trim override (D2 RO)
+    // iff config1_ & 65536
+    struct {
+      uint32_t FSH_SMW_SETTING_OPTION3;
+      uint32_t FSH_SMW_SETTING_OPTION2;
+      uint32_t FSH_SMW_SETTING_OPTIONA;
+      uint32_t FSH_SMW_SETTING_OPTIONB;
+      uint32_t FSH_SMW_SMP_WHV_OPTION1;
+      uint32_t FSH_SMW_SMP_WHV_OPTION0;
+      uint32_t FSH_SMW_SME_WHV_OPTION1;
+      uint32_t FSH_SMW_SME_WHV_OPTION0;
+    } fsh;
+  } u;
+
+  // Spare space
+  uint32_t _pad[5];
+
+  struct {
+    unsigned size : 12;
+    unsigned offset : 20;
+  } swap_mark;
+  uint32_t rw_product_family_;  // 0 == PRODUCT_FAMILY_ANY
+                                // Stored as (^SIGNED_HEADER_PADDING)
+                                // TODO(ntaha): add reference to product family
+                                // enum when available.
+
+  struct {
+    // CR50 board class locking
+    uint32_t type;       // Board type
+    uint32_t type_mask;  // Mask of board type bits to use.
+    uint32_t flags;      // Flags
+  } board_id_;
+
   uint32_t dev_id0_;  // node id, if locked
   uint32_t dev_id1_;
   uint32_t fuses_chk_;  // top 32 bit of expected fuses hash
diff --git a/nugget/proto/nugget/app/keymaster/keymaster_defs.proto b/nugget/proto/nugget/app/keymaster/keymaster_defs.proto
index 40ec84f..644a9b3 100644
--- a/nugget/proto/nugget/app/keymaster/keymaster_defs.proto
+++ b/nugget/proto/nugget/app/keymaster/keymaster_defs.proto
@@ -257,6 +257,15 @@
   STRONGBOX = 2;
 };
 
+// NOTE: these enum values must be kept in sync with the HAL,
+// as they are used in an HMAC calculation.
+enum HardwareAuthenticatorType {
+  HW_AUTH_NONE = 0;
+  HW_AUTH_PASSWORD = 1;
+  HW_AUTH_FINGERPRINT = 2;
+  // Additional entries must be powers of 2.
+};
+
 enum KeyFormat {
   X509 = 0;   /* for public key export */
   PKCS8 = 1;  /* for asymmetric key pair import */
diff --git a/nugget/proto/nugget/app/protoapi/diagnostics_api.proto b/nugget/proto/nugget/app/protoapi/diagnostics_api.proto
index 0fe5327..f659acc 100644
--- a/nugget/proto/nugget/app/protoapi/diagnostics_api.proto
+++ b/nugget/proto/nugget/app/protoapi/diagnostics_api.proto
@@ -29,7 +29,7 @@
   DiagnosticTest aes_tests = 2;
   DiagnosticTest aes_performance = 3;
   DiagnosticTest ana_batmon = 4;
-  //  TODO (skeys) add remaining applicable tests here
+  // TODO: add remaining applicable tests here
 }
 
 message DiagnosticActions {