Merge remote-tracking branch 'goog/upstream-master' into doodle_wip7

* goog/upstream-master:
  libnos_transport: Don't show crc in log messages
  Prepare Nugget OS to report problems to the AP
  Remove meaningless output in citadel_updater
  citadel_updater: Support NUGGET_PARAM_CONSOLE
  keymaster: add defs for HardwareAuthToken
  Track AP reset and HLOS boot times
  signed_header: obfuscate chip name as D2

Bug: 131177129
Bug: 126618512
Bug: 129892600
Bug: 34946126
Test: manual
Change-Id: Iee164d45f9693e9204a05eb24c125d35dcbe61b9
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 8a3b3a4..9fd370c 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>
 
@@ -83,7 +85,9 @@
   const char *device;
   int suzyq;
   int board_id;
+  int event;
   char **board_id_args;
+  int console;
 } options;
 
 enum no_short_opts_for_these {
@@ -104,9 +108,10 @@
   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'},
@@ -134,6 +139,7 @@
   {"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
@@ -200,6 +206,8 @@
     "\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"
@@ -629,19 +637,60 @@
   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);
+  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)
@@ -654,13 +703,12 @@
   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));
+    memcpy(&stats, buffer.data(), std::min(sizeof(stats), buffer.size()));
     print_stats(&stats);
   }
 
@@ -670,27 +718,32 @@
 #ifdef ANDROID
 uint32_t do_statsd(CitadeldProxyClient &client)
 {
-    struct nugget_app_low_power_stats stats;
-    std::vector<uint8_t> buffer;
+  struct nugget_app_low_power_stats stats;
+  std::vector<uint8_t> buffer;
 
-    buffer.reserve(sizeof(stats));
-    ::android::binder::Status s = client.Citadeld().getCachedStats(&buffer);
+  buffer.reserve(sizeof(stats));
+  ::android::binder::Status s = client.Citadeld().getCachedStats(&buffer);
 
-    if (s.isOk()) {
-        memcpy(&stats, buffer.data(), sizeof(stats));
-        print_stats(&stats);
-    } else {
-        printf("ERROR: binder exception %d\n", s.exceptionCode());
-        return APP_ERROR_IO;
+  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;
+  return 0;
 }
 #else
 uint32_t do_statsd(NuggetClient &client)
 {
-    Error("citadeld isn't attached to this interface");
-    return APP_ERROR_BOGUS_ARGS;
+  Error("citadeld isn't attached to this interface");
+  return APP_ERROR_BOGUS_ARGS;
 }
 #endif
 
@@ -821,8 +874,6 @@
 
 static void show_board_id(const struct nugget_app_board_id *id)
 {
-  uint8_t feature;
-
   printf("0x%08x 0x%08x 0x%08x # ", id->type, id->flag, id->inv);
 
   if (id->type == 0xffffffff && id->flag == 0xffffffff &&
@@ -836,18 +887,6 @@
     return;
   }
 
-  feature = (id->type & 0xff000000) >> 24;
-  switch (feature) {
-    case 0x00:
-      printf("Pixel 3, ");
-      break;
-    case 0x01:
-      printf("Pixel 4, ");
-      break;
-    default:
-      printf("feature 0x%2x, ", feature);
-  }
-
   printf("%s, ", id->flag & 0x80 ? "MP" : "Pre-MP");
   switch (id->flag & 0x7f) {
   case 0x7f:
@@ -940,6 +979,52 @@
   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));
@@ -1117,6 +1202,16 @@
     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;
 }
 
@@ -1164,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;
@@ -1240,6 +1339,10 @@
       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_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 2efeb07..2e96c97 100644
--- a/nugget/include/app_nugget.h
+++ b/nugget/include/app_nugget.h
@@ -299,6 +299,17 @@
  * @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 */
 
@@ -346,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
@@ -397,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/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/signed_header.h b/nugget/include/signed_header.h
index 612d22e..d98d456 100644
--- a/nugget/include/signed_header.h
+++ b/nugget/include/signed_header.h
@@ -27,7 +27,7 @@
 #define FUSE_IGNORE_C 0x3aabadac  // baked in rom!
 #define INFO_IGNORE_C 0xa5c35a3c  // baked in rom!
 
-// Dauntless chips
+// D2 chips
 #define FUSE_IGNORE_D 0xdaa3baca  // baked in rom!
 #define INFO_IGNORE_D 0x5a3ca5c3  // baked in rom!
 
@@ -44,7 +44,7 @@
 
 #define SIGNED_HEADER_MAGIC_HAVEN (-1u)
 #define SIGNED_HEADER_MAGIC_CITADEL (-2u)
-#define SIGNED_HEADER_MAGIC_DAUNTLESS (-3u)
+#define SIGNED_HEADER_MAGIC_D2 (-3u)
 
 /* Default value for _pad[] words */
 #define SIGNED_HEADER_PADDING 0x33333333
@@ -100,7 +100,7 @@
     switch (magic) {
       case SIGNED_HEADER_MAGIC_HAVEN:
       case SIGNED_HEADER_MAGIC_CITADEL:
-      case SIGNED_HEADER_MAGIC_DAUNTLESS:
+      case SIGNED_HEADER_MAGIC_D2:
         break;
       default:
         return false;
@@ -121,8 +121,8 @@
       case SIGNED_HEADER_MAGIC_CITADEL:
         printf("Citadel");
         break;
-      case SIGNED_HEADER_MAGIC_DAUNTLESS:
-        printf("Dauntless");
+      case SIGNED_HEADER_MAGIC_D2:
+        printf("D2");
         break;
       default:
         printf("?");
@@ -198,7 +198,7 @@
       uint32_t s[8];
     } ext_sig;
 
-    // FLASH trim override (Dauntless RO)
+    // FLASH trim override (D2 RO)
     // iff config1_ & 65536
     struct {
       uint32_t FSH_SMW_SETTING_OPTION3;
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 */