Merge remote-tracking branch 'goog/upstream-master' into nos-merge-upstream

* goog/upstream-master:
  avb.proto: add resetchallenge and getproduction
  flash: update of cert & provisioning data offsets
  Suppress clang 7.0 warnings.
  Add retry logic to get_status() function
  Define static lib for 'recovery' system module
  flash_layout: Add manufacturing related config
  updater: Add option to wiggle Citadel's reset line
  updater: Add command to read Low Power Stats
  Reserve a fake AVB_TEST app ID just for testing
  keymaster: add factory-setup methods

Bug: 74946926
Change-Id: Ic4bf32b5994a0f159ce4d0efaab6e1427ae1142e
diff --git a/Android.bp b/Android.bp
index 6350262..a07fdbb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,7 +23,6 @@
 cc_defaults {
     name: "nos_proto_defaults",
     cflags: [
-        "-Wno-extended-offsetof",
         "-Wno-unused-parameter",
     ],
 }
diff --git a/citadel/updater/Android.bp b/citadel/updater/Android.bp
index 8ea42a4..6b1a86b 100644
--- a/citadel/updater/Android.bp
+++ b/citadel/updater/Android.bp
@@ -33,5 +33,6 @@
         "libnos",
         "libnos_citadeld_proxy",
         "libnos_client_citadel",
+        "libutils",
     ],
 }
diff --git a/citadel/updater/updater.cpp b/citadel/updater/updater.cpp
index 1cff116..4f70ae2 100644
--- a/citadel/updater/updater.cpp
+++ b/citadel/updater/updater.cpp
@@ -52,9 +52,11 @@
 struct options_s {
   /* actions to take */
   int version;
+  int stats;
   int ro;
   int rw;
   int reboot;
+  int force_reset;
   int enable_ro;
   int enable_rw;
   int change_pw;
@@ -65,9 +67,11 @@
 
 enum no_short_opts_for_these {
   OPT_DEVICE = 1000,
+  OPT_STATS,
   OPT_RO,
   OPT_RW,
   OPT_REBOOT,
+  OPT_FORCE_RESET,
   OPT_ENABLE_RO,
   OPT_ENABLE_RW,
   OPT_CHANGE_PW,
@@ -78,9 +82,11 @@
 const struct option long_opts[] = {
   /* name    hasarg *flag val */
   {"version",     0, NULL, 'v'},
+  {"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},
@@ -117,26 +123,28 @@
     "\n"
     "Actions:\n"
     "\n"
-    "  -v, --version     Display the Citadel version info\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"
+    "  -v, --version       Display the Citadel version info\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"
     "\n"
-    "      --enable_ro   Mark new RO image as good\n"
-    "      --enable_rw   Mark new RW image as good\n"
+    "      --enable_ro     Mark new RO image as good\n"
+    "      --enable_rw     Mark new RW image as good\n"
     "\n"
-    "      --change_pw   Change update password\n"
+    "      --change_pw     Change update password\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);
@@ -341,6 +349,38 @@
   return retval;
 }
 
+uint32_t do_stats(AppClient &app)
+{
+  struct nugget_app_low_power_stats stats;
+  std::vector<uint8_t> buffer;
+  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 %lud / %lud bytes back",
+              buffer.size(), sizeof(stats));
+      return -1;
+    }
+
+    memcpy(&stats, buffer.data(), sizeof(stats));
+
+    printf("hard_reset_count         %lu\n", stats.hard_reset_count);
+    printf("time_since_hard_reset    %lu\n", stats.time_since_hard_reset);
+    printf("wake_count               %lu\n", stats.wake_count);
+    printf("time_at_last_wake        %lu\n", stats.time_at_last_wake);
+    printf("time_spent_awake         %lu\n", stats.time_spent_awake);
+    printf("deep_sleep_count         %lu\n", stats.deep_sleep_count);
+    printf("time_at_last_deep_sleep  %lu\n", stats.time_at_last_deep_sleep);
+    printf("time_spent_in_deep_sleep %lu\n", stats.time_spent_in_deep_sleep);
+  }
+
+  return retval;
+}
+
 uint32_t do_reboot(AppClient &app)
 {
   uint32_t retval;
@@ -426,26 +466,38 @@
   return rv;
 }
 
-std::unique_ptr<NuggetClientInterface> select_client()
-{
+// This is currently device-specific, but could be abstracted further
 #ifdef ANDROID
-  return std::unique_ptr<NuggetClientInterface>(new CitadeldProxyClient());
-#else
-  return std::unique_ptr<NuggetClientInterface>(
-      new NuggetClient(options.device ? options.device : ""));
-#endif
+static uint32_t do_force_reset(CitadeldProxyClient &client)
+{
+    bool b = false;
+
+    return !client.Citadeld().reset(&b).isOk();
 }
+#else
+static uint32_t do_force_reset(NuggetClient &client)
+{
+  struct nos_device *d = client.Device();
+
+  return d->ops.reset(d->ctx);
+}
+#endif
 
 int execute_commands(const std::vector<uint8_t> &image,
                      const char *old_passwd, const char *passwd)
 {
-  auto client = select_client();
-  client->Open();
-  if (!client->IsOpen()) {
+#ifdef ANDROID
+  CitadeldProxyClient client;
+#else
+  NuggetClient client(options.device ? options.device : "");
+#endif
+
+  client.Open();
+  if (!client.IsOpen()) {
     Error("Unable to connect");
     return 1;
   }
-  AppClient app(*client, APP_ID_NUGGET);
+  AppClient app(client, APP_ID_NUGGET);
 
   /* Try all requested actions in reasonable order, bail out on error */
 
@@ -459,6 +511,11 @@
     return 2;
   }
 
+  if (options.stats &&
+      do_stats(app) != APP_SUCCESS) {
+    return 2;
+  }
+
   if (options.rw &&
       do_update(app, image,
           CHIP_RW_A_MEM_OFF, CHIP_RW_B_MEM_OFF) != APP_SUCCESS) {
@@ -484,6 +541,11 @@
     return 7;
   }
 
+  if (options.force_reset &&
+      do_force_reset(client) != APP_SUCCESS) {
+    return 1;
+  }
+
   return 0;
 }
 
@@ -522,6 +584,10 @@
       options.version = 1;
       got_action = 1;
       break;
+    case OPT_STATS:
+      options.stats = 1;
+      got_action = 1;
+      break;
     case OPT_RO:
       options.ro = 1;
       got_action = 1;
@@ -534,6 +600,10 @@
       options.reboot = 1;
       got_action = 1;
       break;
+    case OPT_FORCE_RESET:
+      options.force_reset = 1;
+      got_action = 1;
+      break;
     case OPT_ENABLE_RO:
       options.enable_ro = 1;
       got_action = 1;
diff --git a/libnos_transport/transport.c b/libnos_transport/transport.c
index c328c18..140d257 100644
--- a/libnos_transport/transport.c
+++ b/libnos_transport/transport.c
@@ -16,6 +16,7 @@
 
 #include <nos/transport.h>
 
+#include <errno.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -62,14 +63,33 @@
   uint8_t buf[6];
   uint32_t command = CMD_ID(app_id) | CMD_IS_READ | CMD_TRANSPORT;
 
-  if (0 != dev->ops.read(dev->ctx, command, buf, sizeof(buf))) {
-    NLOGV("Failed to read device status");
+  uint16_t retries = 10;
+  while (retries--) {
+    int err = dev->ops.read(dev->ctx, command, buf, sizeof(buf));
+
+    if (err == 0) {
+      /* The read operation is successful */
+      *status = *(uint32_t *)buf;
+      *ulen = *(uint16_t *)(buf + 4);
+
+      return 0;
+    }
+
+    if (err == -EAGAIN) {
+      /* Linux driver returns EAGAIN error if Citadel chip is asleep.
+       * Give to the chip a little bit of time to awake and retry reading
+       * status again. */
+      usleep(5000);
+      continue;
+    }
+
+    /* Citadel driver returned an error */
+    NLOGE("Failed to read device status: %d", err);
     return -1;
   }
 
-  *status = *(uint32_t *)buf;
-  *ulen = *(uint16_t *)(buf + 4);
-  return 0;
+  NLOGE("Failed to read device status");
+  return -1;
 }
 
 static int clear_status(const struct nos_device *dev, uint8_t app_id)
@@ -94,18 +114,8 @@
   uint32_t status;
   uint16_t ulen;
   uint32_t poll_count = 0;
-  uint16_t retries = 10;
 
-  /* Make sure it's idle */
-  while (retries) {
-    if (get_status(dev, app_id, &status, &ulen) == 0) {
-      break;
-    }
-    --retries;
-    usleep(5000);
-  }
-  if (!retries) {
-    NLOGE("Failed to read device status");
+  if (get_status(dev, app_id, &status, &ulen) != 0) {
     return APP_ERROR_IO;
   }
   NLOGV("%d: query status 0x%08x  ulen 0x%04x", __LINE__, status, ulen);
diff --git a/nugget/include/application.h b/nugget/include/application.h
index f7e2142..45824b3 100644
--- a/nugget/include/application.h
+++ b/nugget/include/application.h
@@ -73,6 +73,9 @@
 #define APP_ID_WEAVER            0x03
 #define APP_ID_PROTOBUF          0x04
 
+/* Fake apps used only for testing */
+#define APP_ID_AVB_TEST          0x11
+
 /* This app ID should only be used by tests. */
 #define APP_ID_TEST              0xff
 
diff --git a/nugget/include/flash_layout.h b/nugget/include/flash_layout.h
index 5049a85..580970d 100644
--- a/nugget/include/flash_layout.h
+++ b/nugget/include/flash_layout.h
@@ -69,4 +69,18 @@
 /* The flash controller prevents bulk writes that cross row boundaries */
 #define CHIP_FLASH_ROW_SIZE          256	/* row size */
 
+/* Manufacturing related data. */
+/* Certs in the RO region are written as 4-kB + 3-kB blocks to the A &
+ * B banks respectively.
+ */
+#define RO_CERTS_A_OFF                     (CHIP_RO_A_MEM_OFF + 0x2800)
+#define RO_CERTS_B_OFF                     (CHIP_RO_B_MEM_OFF + 0x2800)
+#define RO_CERTS_A_SIZE                     0x01000
+#define RO_CERTS_B_SIZE                     0x00c00
+/* We have an unused 3-kB region in the B bank, for future proofing. */
+#define RO_CERTS_PAD_B_SIZE                 0x00c00
+/* Factory provision data is written as a 2-kB block to the A bank. */
+#define RO_PROVISION_DATA_A_OFF             0x3800
+#define RO_PROVISION_DATA_A_SIZE            0x0800
+
 #endif	/* __CROS_EC_FLASH_LAYOUT_H */
diff --git a/nugget/proto/nugget/app/avb/avb.proto b/nugget/proto/nugget/app/avb/avb.proto
index b9422a2..bc0c700 100644
--- a/nugget/proto/nugget/app/avb/avb.proto
+++ b/nugget/proto/nugget/app/avb/avb.proto
@@ -41,6 +41,8 @@
   rpc Reset (ResetRequest) returns (ResetResponse);
   rpc BootloaderDone (BootloaderDoneRequest) returns (BootloaderDoneResponse);
   rpc GetOwnerKey (GetOwnerKeyRequest) returns (GetOwnerKeyResponse);
+  rpc GetResetChallenge (GetResetChallengeRequest) returns (GetResetChallengeResponse);
+  rpc ProductionResetTest (ProductionResetTestRequest) returns (ProductionResetTestResponse);
 }
 
 enum LockIndex {
@@ -131,6 +133,7 @@
 // SetProduction
 message SetProductionRequest {
   bool production = 1;
+  bytes device_data = 2;
 }
 message SetProductionResponse {}
 
@@ -145,16 +148,43 @@
 message CarrierLockTestResponse {}
 
 // Reset
+message ResetToken {
+  enum Selectors {
+    INVALID = 0;
+    CURRENT = 1;
+  };
+  uint32 selector = 1;
+  bytes signature = 2;
+}
+
 message ResetRequest {
   enum ResetKind {
-    FACTORY = 0;
+    PRODUCTION = 0;
     LOCKS = 1;
-  }
+  };
 
   ResetKind kind = 1;
+  ResetToken token = 2; // optional
 }
 message ResetResponse {}
 
+// GetResetChallenge
+message GetResetChallengeRequest {}
+message GetResetChallengeResponse {
+  uint32 selector = 1;
+  uint64 nonce = 2;
+  bytes device_data = 3;
+}
+
+// ProductionResetTest
+message ProductionResetTestRequest {
+  uint32 selector = 1;
+  uint64 nonce = 2;
+  bytes device_data = 3;
+  bytes signature = 4;
+}
+message ProductionResetTestResponse {}
+
 // BootloaderDone
 message BootloaderDoneRequest {}
 
diff --git a/nugget/proto/nugget/app/keymaster/keymaster.proto b/nugget/proto/nugget/app/keymaster/keymaster.proto
index d20d4c5..603e041 100644
--- a/nugget/proto/nugget/app/keymaster/keymaster.proto
+++ b/nugget/proto/nugget/app/keymaster/keymaster.proto
@@ -75,6 +75,10 @@
   rpc SetRootOfTrust (SetRootOfTrustRequest) returns (SetRootOfTrustResponse);
   // Only callable by the Bootloader.
   rpc SetBootState (SetBootStateRequest) returns (SetBootStateResponse);
+  // Only callable at the Device Factory.
+  rpc ProvisionDeviceIds (ProvisionDeviceIdsRequest) returns (ProvisionDeviceIdsResponse);
+  // Only callable at the Device Factory.
+  rpc ReadTeeBatchCertificate (ReadTeeBatchCertificateRequest) returns (ReadTeeBatchCertificateResponse);
 }
 
 /*
@@ -267,4 +271,33 @@
 message SetBootStateResponse {
   // Specified in keymaster_defs.proto:ErrorCode
   ErrorCode error_code = 1;
-}
\ No newline at end of file
+}
+
+// ProvisionDeviceIds
+// Only callable at the Device Factory
+message ProvisionDeviceIdsRequest {
+  bytes product_brand = 1;
+  bytes product_device = 2;
+  bytes product_name = 3;
+  bytes serialno = 4;
+  bytes product_manufacturer = 5;
+  bytes product_model = 6;
+  bytes imei = 7;
+  bytes meid = 8;
+}
+message ProvisionDeviceIdsResponse {
+  // Specified in keymaster_defs.proto:ErrorCode
+  ErrorCode error_code = 1;
+}
+
+// ReadTeeBatchCertificate
+// Only callable at the Device Factory
+message ReadTeeBatchCertificateRequest {
+  Algorithm algorithm = 1;
+}
+message ReadTeeBatchCertificateResponse {
+  ErrorCode error_code = 1;
+  RSAKey rsa = 2;   // rsa or ec set based on request algorithm selector.
+  ECKey ec = 3;
+  bytes batch_cert = 4;
+}