aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2019-10-01 01:01:09 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2019-10-01 01:01:09 +0000
commitd30532f387f68b9004fe170e63dd35d19aba28fc (patch)
tree44d800ea4bf57cbb81ce6c7a4dd42c358afe7184
parentdad46ffc7f0948fd771a87abfc2a7b70d4174d76 (diff)
parent16d4556329fc30de79387e396267c1fde7e47b5a (diff)
downloadgeneric-android10-qpr1-b-s1-release.tar.gz
Change-Id: I991d4c13ed57a89962f165a6a463f31df49c8f9a
-rw-r--r--.checkpatch.conf2
-rw-r--r--Android.bp60
-rw-r--r--citadel/updater/Android.bp38
-rw-r--r--citadel/updater/BUILD12
-rw-r--r--citadel/updater/NOTICE177
-rw-r--r--citadel/updater/WORKSPACE1
-rw-r--r--citadel/updater/updater.cpp1433
-rw-r--r--libnos_datagram/Android.bp10
-rw-r--r--libnos_datagram/citadel.c230
-rw-r--r--nugget/include/citadel_events.h51
10 files changed, 333 insertions, 1681 deletions
diff --git a/.checkpatch.conf b/.checkpatch.conf
index e8e9db6..f0db0f0 100644
--- a/.checkpatch.conf
+++ b/.checkpatch.conf
@@ -5,3 +5,5 @@
--ignore FILE_PATH_CHANGES
--ignore GIT_COMMIT_ID
--ignore SPLIT_STRING
+--ignore CONST_STRUCT
+--ignore LEADING_SPACE
diff --git a/Android.bp b/Android.bp
index 7bf412d..074b9b5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -82,3 +82,63 @@ cc_library_static {
"libbase",
],
}
+
+// A special target to be statically linkeed into recovery which is a system
+// (not vendor) component.
+cc_library_static {
+ name: "libnos_citadel_for_recovery",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ srcs: [
+ ":libnos_client",
+ "libnos_datagram/citadel.c",
+ ],
+ static_libs: [
+ "libnos_for_recovery",
+ ],
+}
+
+// Language and vendor related defaults
+cc_defaults {
+ name: "nos_cc_defaults",
+ clang: true,
+ cflags: [
+ "-pedantic",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wno-zero-length-array",
+ ],
+ conlyflags: [
+ "-std=c11",
+ ],
+ vendor: true,
+ owner: "google",
+}
+
+// Defaults for components under the hw subdirectory
+cc_defaults {
+ name: "nos_cc_hw_defaults",
+ defaults: ["nos_cc_defaults"],
+ relative_install_path: "hw",
+}
+
+// Defaults for components shared between the host and device
+cc_defaults {
+ name: "nos_cc_host_supported_defaults",
+ defaults: ["nos_cc_defaults"],
+ host_supported: true,
+}
+
+cc_library {
+ name: "libnos_client_citadel",
+ srcs: [":libnos_client"],
+ defaults: [
+ "libnos_client_defaults",
+ "nos_cc_defaults",
+ ],
+ shared_libs: ["libnos_datagram_citadel"],
+}
diff --git a/citadel/updater/Android.bp b/citadel/updater/Android.bp
deleted file mode 100644
index 6b1a86b..0000000
--- a/citadel/updater/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// Copyright (C) 2017 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.
-//
-
-cc_binary {
- name: "citadel_updater",
- srcs: [
- "updater.cpp"
- ],
- defaults: ["nos_cc_hw_defaults"],
- cflags: [
- // for openssl/sha.h
- "-Wno-gnu-anonymous-struct",
- "-Wno-nested-anon-types",
- ],
- header_libs: [
- "nos_headers",
- ],
- shared_libs: [
- "libcrypto",
- "libnos",
- "libnos_citadeld_proxy",
- "libnos_client_citadel",
- "libutils",
- ],
-}
diff --git a/citadel/updater/BUILD b/citadel/updater/BUILD
deleted file mode 100644
index 5daeac9..0000000
--- a/citadel/updater/BUILD
+++ /dev/null
@@ -1,12 +0,0 @@
-cc_library(
- name = "libcitadel_updater",
- srcs = [
- "updater.cpp",
- ],
- visibility = ["//visibility:public"],
- deps = [
- "@boringssl//:ssl",
- "@nugget_host_generic//:nos_headers",
- "@nugget_host_generic_libnos//:libnos",
- ],
-)
diff --git a/citadel/updater/NOTICE b/citadel/updater/NOTICE
deleted file mode 100644
index f433b1a..0000000
--- a/citadel/updater/NOTICE
+++ /dev/null
@@ -1,177 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
diff --git a/citadel/updater/WORKSPACE b/citadel/updater/WORKSPACE
deleted file mode 100644
index ea1afae..0000000
--- a/citadel/updater/WORKSPACE
+++ /dev/null
@@ -1 +0,0 @@
-workspace(name = "nugget_host_generic_citadel_updater")
diff --git a/citadel/updater/updater.cpp b/citadel/updater/updater.cpp
deleted file mode 100644
index 93c0383..0000000
--- a/citadel/updater/updater.cpp
+++ /dev/null
@@ -1,1433 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include <memory>
-#include <vector>
-
-#include <getopt.h>
-#include <inttypes.h>
-#include <openssl/sha.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-/* From Nugget OS */
-#include <application.h>
-#include <app_nugget.h>
-#include <citadel_events.h>
-#include <flash_layout.h>
-#include <signed_header.h>
-
-#include <nos/AppClient.h>
-#include <nos/NuggetClient.h>
-#ifdef ANDROID
-#include <nos/CitadeldProxyClient.h>
-#endif
-
-namespace {
-
-using nos::AppClient;
-using nos::NuggetClient;
-using nos::NuggetClientInterface;
-#ifdef ANDROID
-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 statsd;
- int ro;
- int rw;
- int reboot;
- int force_reset;
- int enable_ro;
- int enable_rw;
- int change_pw;
- uint32_t erase_code;
- int ap_uart;
- int selftest;
- 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 {
- OPT_DEVICE = 1000,
- OPT_ID,
- OPT_REPO_SNAPSHOT,
- OPT_STATS,
- OPT_STATSD,
- OPT_RO,
- OPT_RW,
- OPT_REBOOT,
- OPT_FORCE_RESET,
- OPT_ENABLE_RO,
- OPT_ENABLE_RW,
- OPT_CHANGE_PW,
- OPT_ERASE,
- OPT_AP_UART,
- OPT_SELFTEST,
- OPT_SUZYQ,
- OPT_BOARD_ID,
- OPT_EVENT,
-};
-
-const char *short_opts = ":hvlV:fF:c";
-const struct option long_opts[] = {
- /* name hasarg *flag val */
- {"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},
- {"statsd", 0, NULL, OPT_STATSD},
- {"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},
- {"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
- {"help", 0, NULL, 'h'},
- {NULL, 0, NULL, 0},
-};
-
-void usage(const char *progname)
-{
- fprintf(stderr, "\n");
- fprintf(stderr,
- "Usage: %s [actions] [image.bin]\n"
- "\n"
- "Citadel firmware boots in two stages. The first stage\n"
- "bootloader (aka \"RO\") is provided by the SOC hardware team\n"
- "and seldom changes. The application image (\"RW\") is invoked\n"
- "by the RO image. There are two copies (A/B) of each stage,\n"
- "so that the active copy can be protected while the unused\n"
- "copy may be updated. At boot, the newer (valid) copy of each\n"
- "stage is selected.\n"
- "\n"
- "The Citadel image file is the same size of the internal\n"
- "flash, and contains all four firmware components (RO_A,\n"
- "RW_A, RO_B, RW_B) located at the correct offsets. Only the\n"
- "inactive copy (A/B) of each stage (RO/RW) can be modified.\n"
- "The tool will update the correct copies automatically.\n"
- "\n"
- "You must specify the actions to perform. With no actions,\n"
- "this help message is displayed.\n"
- "\n"
- "Actions:\n"
- "\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"
- " --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"
- " --repo_snapshot Show the repo sha1sums for the running image\n"
- "\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 the update password\n"
- "\n"
- " --ap_uart Query the AP UART passthru setting\n"
- " (It can only be set in the BIOS)\n"
- "\n"
- " --erase=CODE Erase all user secrets and reboot.\n"
- " This skips all other actions.\n"
- "\n"
- " --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"
- "\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);
-}
-
-/****************************************************************************/
-/* Handy stuff */
-
-#ifndef MIN
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#endif
-
-int errorcnt;
-void Error(const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- fprintf(stderr, "ERROR: ");
- vfprintf(stderr, format, ap);
- fprintf(stderr, "\n");
- va_end(ap);
-
- errorcnt++;
-}
-
-/* Return true on APP_SUCESS, display error message if it's not */
-int is_app_success(uint32_t retval)
-{
- if (retval == APP_SUCCESS)
- return 1;
-
- errorcnt++;
-
- fprintf(stderr, "Error code 0x%x: ", retval);
- switch (retval) {
- case APP_ERROR_BOGUS_ARGS:
- fprintf(stderr, "bogus args");
- break;
- case APP_ERROR_INTERNAL:
- fprintf(stderr, "app is being stupid");
- break;
- case APP_ERROR_TOO_MUCH:
- fprintf(stderr, "caller sent too much data");
- break;
- case APP_ERROR_IO:
- fprintf(stderr, "problem sending or receiving data");
- break;
- case APP_ERROR_RPC:
- fprintf(stderr, "problem during RPC communication");
- break;
- case APP_ERROR_CHECKSUM:
- fprintf(stderr, "checksum failed");
- break;
- case APP_ERROR_BUSY:
- fprintf(stderr, "the app is already working on a commnad");
- break;
- case APP_ERROR_TIMEOUT:
- fprintf(stderr, "the app took too long to respond");
- break;
- default:
- if (retval >= APP_SPECIFIC_ERROR &&
- retval < APP_LINE_NUMBER_BASE) {
- fprintf(stderr, "app-specific error #%d",
- retval - APP_SPECIFIC_ERROR);
- } else if (retval >= APP_LINE_NUMBER_BASE) {
- fprintf(stderr, "error at line %d",
- retval - APP_LINE_NUMBER_BASE);
- } else {
- fprintf(stderr, "unknown");
- }
- }
- fprintf(stderr, "\n");
-
- return 0;
-}
-
-/****************************************************************************/
-
-std::vector<uint8_t> read_image_from_file(const char *name)
-{
- FILE *fp;
- struct stat st;
-
- fp = fopen(name, "rb");
- if (!fp) {
- perror("fopen");
- Error("Can't open file %s", name);
- return {};
- }
-
- if (fstat(fileno(fp), &st)) {
- perror("fstat");
- Error("Can't fstat file %s", name);
- fclose(fp);
- return {};
- }
-
- if (st.st_size != CHIP_FLASH_SIZE) {
- Error("The firmware image must be exactly %d bytes",
- CHIP_FLASH_SIZE);
- fclose(fp);
- return {};
- }
-
- std::vector<uint8_t> buf(st.st_size);
- if (1 != fread(buf.data(), st.st_size, 1, fp)) {
- perror("fread");
- Error("Can't read %zd bytes", st.st_size);
- fclose(fp);
- return {};
- }
-
- fclose(fp);
- buf.resize(st.st_size);
-
- return buf;
-}
-
-uint32_t compute_digest(void *ptr, size_t len)
-{
- SHA_CTX ctx;
- uint8_t digest[SHA_DIGEST_LENGTH];
- uint32_t retval;
-
- SHA1_Init(&ctx);
- SHA1_Update(&ctx, ptr, len);
- SHA1_Final(digest, &ctx);
-
- memcpy(&retval, digest, sizeof(retval));
- return retval;
-}
-
-uint32_t compute_fb_digest(struct nugget_app_flash_block *blk)
-{
- uint8_t *start_here = ((uint8_t *)blk) +
- offsetof(struct nugget_app_flash_block, offset);
- size_t size_to_hash = sizeof(*blk) -
- offsetof(struct nugget_app_flash_block, offset);
-
- return compute_digest(start_here, size_to_hash);
-}
-
-uint32_t try_update(AppClient &app, const std::vector<uint8_t> &image,
- uint32_t offset, uint32_t imagesize)
-{
- uint32_t stop = offset + imagesize;
- uint32_t rv;
-
- printf("Updating image from 0x%05x to 0x%05x, size 0x%05x\n",
- CHIP_FLASH_BASE + offset, CHIP_FLASH_BASE + stop, imagesize);
-
- for (; offset < stop; offset += CHIP_FLASH_BANK_SIZE) {
- int retries = 3;
- std::vector<uint8_t> data(sizeof(struct nugget_app_flash_block));
- struct nugget_app_flash_block *fb =
- (struct nugget_app_flash_block*)data.data();
-
- fb->offset = offset;
- memcpy(fb->payload, image.data() + offset, CHIP_FLASH_BANK_SIZE);
- fb->block_digest = compute_fb_digest(fb);
-
- printf("writing 0x%05x / 0x%05x",
- CHIP_FLASH_BASE + offset, CHIP_FLASH_BASE + stop);
- do {
- rv = app.Call(NUGGET_PARAM_FLASH_BLOCK, data, nullptr);
- if (rv == NUGGET_ERROR_RETRY)
- printf(" retrying");
- } while (rv == NUGGET_ERROR_RETRY && retries--);
- if (rv) {
- if (rv == NUGGET_ERROR_LOCKED)
- printf(" locked\n");
- else
- printf(" fail %d\n", rv);
- break;
- }
- printf(" ok\n");
- }
-
- return rv;
-}
-
-uint32_t do_update(AppClient &app, const std::vector<uint8_t> &image,
- uint32_t offset_A, uint32_t offset_B)
-{
- struct SignedHeader *hdr;
- uint32_t rv_A, rv_B;
-
- /* Try image A first */
- hdr = (struct SignedHeader *)(image.data() + offset_A);
- rv_A = try_update(app, image, offset_A, hdr->image_size);
-
- /* If that worked, we're done */
- if (rv_A == APP_SUCCESS) {
- return rv_A;
- }
-
- /* Else try image B */
- hdr = (struct SignedHeader *)(image.data() + offset_B);
- rv_B = try_update(app, image, offset_B, hdr->image_size);
-
- return rv_B;
-}
-
-uint32_t do_version(AppClient &app)
-{
- uint32_t retval;
- std::vector<uint8_t> buffer;
- buffer.reserve(512);
-
- retval = app.Call(NUGGET_PARAM_VERSION, buffer, &buffer);
-
- if (is_app_success(retval)) {
- printf("%.*s\n", (int) buffer.size(), buffer.data());
- }
-
- return retval;
-}
-
-uint32_t do_id(AppClient &app)
-{
- uint32_t retval;
- std::vector<uint8_t> buffer;
- buffer.reserve(32);
-
- retval = app.Call(NUGGET_PARAM_DEVICE_ID, buffer, &buffer);
-
- if (is_app_success(retval)) {
- printf("%.*s\n", (int) buffer.size(), buffer.data());
- }
-
- 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 == SIGNED_HEADER_MAGIC_CITADEL ? "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 == 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 == SIGNED_HEADER_MAGIC_CITADEL ? "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(2048);
-
- 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_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;
- 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)) { // old firmware?
- 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);
- }
-
- 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;
- std::vector<uint8_t> ignored = {1}; // older images need this
-
- retval = app.Call(NUGGET_PARAM_REBOOT, ignored, nullptr);
-
- if (is_app_success(retval)) {
- printf("Citadel reboot requested\n");
- }
-
- return retval;
-}
-
-static uint32_t do_change_pw(AppClient &app,
- const char *old_pw, const char *new_pw)
-{
- std::vector<uint8_t> data(sizeof(struct nugget_app_change_update_password));
- struct nugget_app_change_update_password *s =
- (struct nugget_app_change_update_password*)data.data();
-
-
- memset(s, 0xff, sizeof(*s));
- if (old_pw && *old_pw) {
- int len = strlen(old_pw);
- memcpy(&s->old_password.password, old_pw, len);
- s->old_password.digest =
- compute_digest(&s->old_password.password,
- sizeof(s->old_password.password));
- }
-
- if (new_pw && *new_pw) {
- int len = strlen(new_pw);
- memcpy(&s->new_password.password, new_pw, len);
- s->new_password.digest =
- compute_digest(&s->new_password.password,
- sizeof(s->new_password.password));
- }
-
- uint32_t rv = app.Call(NUGGET_PARAM_CHANGE_UPDATE_PASSWORD, data, nullptr);
-
- if (is_app_success(rv))
- printf("Password changed\n");
-
- return rv;
-}
-
-static uint32_t do_enable(AppClient &app, const char *pw)
-{
- std::vector<uint8_t> data(sizeof(struct nugget_app_enable_update));
- struct nugget_app_enable_update *s =
- (struct nugget_app_enable_update*)data.data();
- std::vector<uint8_t> reply;
-
- memset(&s->password, 0xff, sizeof(s->password));
- if (pw && *pw) {
- int len = strlen(pw);
- memcpy(&s->password.password, pw, len);
- s->password.digest =
- compute_digest(&s->password.password,
- sizeof(s->password.password));
- }
- s->which_headers = options.enable_ro ? NUGGET_ENABLE_HEADER_RO : 0;
- s->which_headers |= options.enable_rw ? NUGGET_ENABLE_HEADER_RW : 0;
-
- reply.reserve(1);
- uint32_t rv = app.Call(NUGGET_PARAM_ENABLE_UPDATE, data, &reply);
-
- if (is_app_success(rv))
- /* Reply byte is true only if header was CHANGED to valid */
- printf("Update %s enabled\n", reply[0] ? "changed to" : "is already");
-
- 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_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));
- memcpy(data.data(), &options.erase_code, data.size());
-
- uint32_t rv = app.Call(NUGGET_PARAM_NUKE_FROM_ORBIT, data, nullptr);
-
- if (is_app_success(rv))
- printf("Citadel erase and reboot requested\n");
-
- return rv;
-}
-
-#define MAX_SELFTEST_REPLY_LEN 4096
-static uint32_t do_selftest(AppClient &app, int argc, char *argv[])
-{
- int i, j;
- uint32_t rv;
- std::vector<uint8_t> data;
-
- /* Copy all the args to send, including their terminating '\0' */
- for (i = options.selftest; i < argc; i++) {
- for (j = 0; argv[i][j]; j++) {
- data.push_back(argv[i][j]);
- }
- data.push_back('\0');
- }
-
- /* Send args, get reply */
- data.reserve(MAX_SELFTEST_REPLY_LEN);
- rv = app.Call(NUGGET_PARAM_SELFTEST, data, &data);
- if (is_app_success(rv)) {
- /* Make SURE it's null-terminated */
- size_t len = data.size();
- if (len) {
- data[len - 1] = '\0';
- printf("%s\n", data.data());
- }
- }
- return rv;
-}
-
-// This is currently device-specific, but could be abstracted further
-#ifdef ANDROID
-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,
- int argc, char *argv[])
-{
-#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);
-
- /* 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);
- }
-
- if (options.version &&
- do_version(app) != APP_SUCCESS) {
- 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;
- }
-
- if (options.stats &&
- do_stats(app) != APP_SUCCESS) {
- return 2;
- }
-
- if (options.statsd &&
- do_statsd(client) != APP_SUCCESS) {
- 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) {
- return 3;
- }
-
- if (options.ro &&
- do_update(app, image,
- CHIP_RO_A_MEM_OFF, CHIP_RO_B_MEM_OFF) != APP_SUCCESS) {
- return 4;
- }
-
- if (options.change_pw &&
- do_change_pw(app, old_passwd, passwd) != APP_SUCCESS)
- return 5;
-
- if ((options.enable_ro || options.enable_rw) &&
- do_enable(app, passwd) != APP_SUCCESS)
- return 6;
-
- if (options.reboot &&
- do_reboot(app) != APP_SUCCESS) {
- return 7;
- }
-
- if (options.selftest &&
- do_selftest(app, argc, argv) != APP_SUCCESS) {
- return 1;
- }
-
- if (options.force_reset &&
- do_force_reset(client) != APP_SUCCESS) {
- 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;
-}
-
-} // namespace
-
-int main(int argc, char *argv[])
-{
- int i;
- int idx = 0;
- char *this_prog;
- char *old_passwd = 0;
- char *passwd = 0;
- std::vector<uint8_t> image;
- int got_action = 0;
- char *e = 0;
- int need_file = 0;
- int status = 0;
-
- this_prog= strrchr(argv[0], '/');
- if (this_prog) {
- this_prog++;
- } else {
- this_prog = argv[0];
- }
-
-#ifndef ANDROID
- options.device = secure_getenv("CITADEL_DEVICE");
- if (options.device)
- fprintf(stderr, "-- $CITADEL_DEVICE=%s --\n", options.device);
-#endif
-
- opterr = 0; /* quiet, you */
- while ((i = getopt_long(argc, argv,
- short_opts, long_opts, &idx)) != -1) {
- switch (i) {
- /* program-specific options */
- case 'v':
- 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 'c':
- options.console = optind;
- 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_STATSD:
- options.statsd = 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:
- 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;
- break;
- case OPT_ENABLE_RW:
- options.enable_rw = 1;
- got_action = 1;
- break;
- case OPT_CHANGE_PW:
- options.change_pw = 1;
- got_action = 1;
- break;
- case OPT_ERASE:
- options.erase_code = (uint32_t)strtoul(optarg, &e, 0);
- if (!*optarg || (e && *e)) {
- Error("Invalid argument: \"%s\"\n", optarg);
- }
- got_action = 1;
- break;
- case OPT_AP_UART:
- 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;
- got_action = 1;
- break;
-
- /* generic options below */
- case OPT_DEVICE:
- options.device = optarg;
- break;
- case 'h':
- usage(this_prog);
- return 0;
- case 0:
- break;
- case '?':
- if (optopt)
- Error("Unrecognized options: -%c", optopt);
- else
- Error("Unrecognized options: %s",
- argv[optind - 1]);
- usage(this_prog);
- break;
- case ':':
- Error("Missing argument to %s", argv[optind - 1]);
- break;
- default:
- Error("Internal error at %s:%d", __FILE__, __LINE__);
- exit(1);
- }
- }
-
- if (errorcnt) {
- goto out;
- }
-
- if (!got_action) {
- usage(this_prog);
- goto out;
- }
-
- if (need_file) {
- if (optind < argc) {
- /* Sets errorcnt on failure */
- image = read_image_from_file(argv[optind++]);
- if (errorcnt)
- goto out;
- } else {
- Error("Missing required image file");
- goto out;
- }
- }
-
- if (options.change_pw) {
- /* one arg provided, maybe the old password isn't set */
- if (optind < argc) {
- passwd = argv[optind++];
- } else {
- Error("Need a new password at least. Use '' to clear it.");
- goto out;
- }
- /* two args provided, use both old & new passwords */
- if (optind < argc) {
- old_passwd = passwd;
- passwd = argv[optind++];
- }
- }
-
- if ((options.enable_ro || options.enable_rw) && !passwd) {
- if (optind < argc)
- passwd = argv[optind++];
- else {
- Error("Need a password to enable images. Use '' if none.");
- goto out;
- }
- }
-
- /* Okay, let's do it! */
- status = execute_commands(image, old_passwd, passwd, argc, argv);
- if (status != 0) {
- Error("execute_command failed(%d)!", status);
- }
- /* This is the last action, so fall through either way */
-
-out:
- return !!errorcnt;
-}
diff --git a/libnos_datagram/Android.bp b/libnos_datagram/Android.bp
index 15d49d3..2a2b659 100644
--- a/libnos_datagram/Android.bp
+++ b/libnos_datagram/Android.bp
@@ -19,3 +19,13 @@ cc_library {
defaults: ["nos_cc_host_supported_defaults"],
export_include_dirs: ["include"],
}
+
+cc_library {
+ name: "libnos_datagram_citadel",
+ srcs: ["citadel.c"],
+ defaults: ["nos_cc_defaults"],
+ shared_libs: [
+ "liblog",
+ "libnos_datagram",
+ ],
+}
diff --git a/libnos_datagram/citadel.c b/libnos_datagram/citadel.c
new file mode 100644
index 0000000..026224d
--- /dev/null
+++ b/libnos_datagram/citadel.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "libnos_datagram"
+#include <log/log.h>
+#include <nos/device.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <linux/types.h>
+#include <poll.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+/*****************************************************************************/
+/* Ideally, this should be in <linux/citadel.h> */
+#define CITADEL_IOC_MAGIC 'c'
+struct citadel_ioc_tpm_datagram {
+ __u64 buf;
+ __u32 len;
+ __u32 command;
+};
+#define CITADEL_IOC_TPM_DATAGRAM _IOW(CITADEL_IOC_MAGIC, 1, \
+ struct citadel_ioc_tpm_datagram)
+#define CITADEL_IOC_RESET _IO(CITADEL_IOC_MAGIC, 2)
+/*****************************************************************************/
+
+#define DEV_CITADEL "/dev/citadel0"
+
+static pthread_mutex_t in_buf_mutex = PTHREAD_MUTEX_INITIALIZER;
+static uint8_t in_buf[MAX_DEVICE_TRANSFER];
+static int read_datagram(void *ctx, uint32_t command, uint8_t *buf, uint32_t len) {
+ struct citadel_ioc_tpm_datagram dg = {
+ .buf = (unsigned long)in_buf,
+ .len = len,
+ .command = command,
+ };
+ int ret;
+ int fd;
+
+ if (!ctx) {
+
+ ALOGE("%s: invalid (NULL) device\n", __func__);
+ return -ENODEV;
+ }
+ fd = *(int *)ctx;
+ if (fd < 0) {
+ ALOGE("%s: invalid device\n", __func__);
+ return -ENODEV;
+ }
+
+ if (len > MAX_DEVICE_TRANSFER) {
+ ALOGE("%s: invalid len (%d > %d)\n", __func__,
+ len, MAX_DEVICE_TRANSFER);
+ return -E2BIG;
+ }
+
+ /* Lock the in buffer while it is used for this transaction */
+ if (pthread_mutex_lock(&in_buf_mutex) != 0) {
+ ALOGE("%s: failed to lock in_buf_mutex: %s", __func__, strerror(errno));
+ return -errno;
+ }
+
+ ret = ioctl(fd, CITADEL_IOC_TPM_DATAGRAM, &dg);
+ if (ret < 0) {
+ ALOGE("can't send spi message: %s", strerror(errno));
+ ret = -errno;
+ goto out;
+ }
+
+ memcpy(buf, in_buf, len);
+
+out:
+ if (pthread_mutex_unlock(&in_buf_mutex) != 0) {
+ ALOGE("%s: failed to unlock in_buf_mutex: %s", __func__, strerror(errno));
+ ret = -errno;
+ }
+ return ret;
+}
+
+static pthread_mutex_t out_buf_mutex = PTHREAD_MUTEX_INITIALIZER;
+static uint8_t out_buf[MAX_DEVICE_TRANSFER];
+static int write_datagram(void *ctx, uint32_t command, const uint8_t *buf, uint32_t len) {
+ struct citadel_ioc_tpm_datagram dg = {
+ .buf = (unsigned long)out_buf,
+ .len = len,
+ .command = command,
+ };
+ int ret;
+ int fd;
+
+ if (!ctx) {
+ ALOGE("%s: invalid (NULL) device\n", __func__);
+ return -ENODEV;
+ }
+ fd = *(int *)ctx;
+ if (fd < 0) {
+ ALOGE("%s: invalid device\n", __func__);
+ return -ENODEV;
+ }
+
+ if (len > MAX_DEVICE_TRANSFER) {
+ ALOGE("%s: invalid len (%d > %d)\n", __func__, len,
+ MAX_DEVICE_TRANSFER);
+ return -E2BIG;
+ }
+
+ /* Lock the out buffer while it is used for this transaction */
+ if (pthread_mutex_lock(&out_buf_mutex) != 0) {
+ ALOGE("%s: failed to lock out_buf_mutex: %s", __func__, strerror(errno));
+ return -errno;
+ }
+
+ memcpy(out_buf, buf, len);
+
+ ret = ioctl(fd, CITADEL_IOC_TPM_DATAGRAM, &dg);
+ if (ret < 0) {
+ ALOGE("can't send spi message: %s", strerror(errno));
+ ret = -errno;
+ goto out;
+ }
+
+out:
+ if (pthread_mutex_unlock(&out_buf_mutex) != 0) {
+ ALOGE("%s: failed to unlock out_buf_mutex: %s", __func__, strerror(errno));
+ ret = -errno;
+ }
+ return ret;
+}
+
+static int wait_for_interrupt(void *ctx, int msecs) {
+ int fd = *(int *)ctx;
+ struct pollfd fds = {fd, POLLIN, 0};
+ int rv;
+
+ rv = poll(&fds, 1 /*nfds*/, msecs);
+ if (rv < 0) {
+ ALOGE("poll: %s", strerror(errno));
+ }
+
+ return rv;
+}
+
+static int reset(void *ctx) {
+ int ret;
+ int fd;
+
+ if (!ctx) {
+
+ ALOGE("%s: invalid (NULL) device\n", __func__);
+ return -ENODEV;
+ }
+ fd = *(int *)ctx;
+ if (fd < 0) {
+ ALOGE("%s: invalid device\n", __func__);
+ return -ENODEV;
+ }
+
+ ret = ioctl(fd, CITADEL_IOC_RESET);
+ if (ret < 0) {
+ ALOGE("can't reset Citadel: %s", strerror(errno));
+ return -errno;
+ }
+ return 0;
+}
+
+static void close_device(void *ctx) {
+ int fd;
+
+ if (!ctx) {
+ ALOGE("%s: invalid (NULL) device (ignored)\n", __func__);
+ return;
+ }
+ fd = *(int *)ctx;
+ if (fd < 0) {
+ ALOGE("%s: invalid device (ignored)\n", __func__);
+ return;
+ }
+
+ if (close(fd) < 0)
+ ALOGE("Problem closing device (ignored): %s", strerror(errno));
+ free(ctx);
+}
+
+int nos_device_open(const char *device_name, struct nos_device *dev) {
+ int fd, *new_fd;
+
+ fd = open(device_name ? device_name : DEV_CITADEL, O_RDWR);
+ if (fd < 0) {
+ ALOGE("can't open device: %s", strerror(errno));
+ return -errno;
+ }
+
+ new_fd = (int *)malloc(sizeof(int));
+ if (!new_fd) {
+ ALOGE("can't malloc new fd: %s", strerror(errno));
+ close(fd);
+ return -ENOMEM;
+ }
+ *new_fd = fd;
+
+ dev->ctx = new_fd;
+ dev->ops.read = read_datagram;
+ dev->ops.write = write_datagram;
+ dev->ops.wait_for_interrupt = wait_for_interrupt;
+ dev->ops.reset = reset;
+ dev->ops.close = close_device;
+ return 0;
+}
diff --git a/nugget/include/citadel_events.h b/nugget/include/citadel_events.h
index 336f3c5..154e638 100644
--- a/nugget/include/citadel_events.h
+++ b/nugget/include/citadel_events.h
@@ -44,47 +44,58 @@ extern "C" {
* instead of changing things.
*/
+/*
+ * Event priority. Stored events of lower priority will be evicted to store
+ * higher-priority events if the queue is full.
+ */
+enum event_priority {
+ EVENT_PRIORITY_LOW = 0,
+ EVENT_PRIORITY_MEDIUM = 1,
+ EVENT_PRIORITY_HIGH = 2,
+};
+
+/*
+ * Event ID values live forever.
+ * Add to the list, but NEVER change or delete existing entries.
+ */
+enum event_id {
+ EVENT_NONE = 0, // Unused ID, used as empty marker.
+ EVENT_ALERT = 1, // Globalsec alert fired.
+ EVENT_REBOOTED = 2, // Device rebooted.
+ EVENT_UPGRADED = 3, // Device has upgraded.
+};
+
/* 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;
+ uint32_t priority;
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;
+ uint32_t rstsrc;
+ uint32_t exitpd;
+ uint32_t which0;
+ uint32_t which1;
+ } rebooted;
/* uninterpreted */
union {
- uint32_t w[11];
- uint16_t h[22];
- uint8_t b[44];
+ uint32_t w[10];
+ uint16_t h[20];
+ uint8_t b[40];
} raw;
- } u;
+ } event;
} __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