summaryrefslogtreecommitdiff
path: root/common/vboot/vboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/vboot/vboot.c')
-rw-r--r--common/vboot/vboot.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/common/vboot/vboot.c b/common/vboot/vboot.c
new file mode 100644
index 0000000000..27c57b27c2
--- /dev/null
+++ b/common/vboot/vboot.c
@@ -0,0 +1,199 @@
+/* Copyright 2017 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.
+ */
+
+/*
+ * Verify and jump to a RW image if power supply is not sufficient.
+ */
+
+#include "battery.h"
+#include "charge_manager.h"
+#include "chipset.h"
+#include "console.h"
+#include "host_command.h"
+#include "rsa.h"
+#include "rwsig.h"
+#include "sha256.h"
+#include "shared_mem.h"
+#include "system.h"
+#include "usb_pd.h"
+#include "vboot.h"
+#include "vb21_struct.h"
+
+#define CPRINTS(format, args...) cprints(CC_VBOOT, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_VBOOT, format, ## args)
+
+enum vboot_ec_slot {
+ VBOOT_EC_SLOT_A,
+ VBOOT_EC_SLOT_B,
+};
+
+static int has_matrix_keyboard(void)
+{
+ return 0;
+}
+
+static int is_vboot_ec_supported(void)
+{
+#ifdef CONFIG_VBOOT_EC
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+static int is_low_power_ap_boot_supported(void)
+{
+ return 0;
+}
+
+static int verify_slot(int slot)
+{
+ const struct vb21_packed_key *vb21_key;
+ const struct vb21_signature *vb21_sig;
+ const struct rsa_public_key *key;
+ const uint8_t *sig;
+ const uint8_t *data;
+ int len;
+
+ CPRINTS("Verifying RW_%c", slot == VBOOT_EC_SLOT_A ? 'A' : 'B');
+
+ vb21_key = (const struct vb21_packed_key *)(
+ CONFIG_MAPPED_STORAGE_BASE +
+ CONFIG_EC_PROTECTED_STORAGE_OFF +
+ CONFIG_RO_PUBKEY_STORAGE_OFF);
+ if (vb21_is_packed_key_valid(vb21_key)) {
+ CPRINTS("Invalid key");
+ return EC_ERROR_INVAL;
+ }
+ key = (const struct rsa_public_key *)
+ ((const uint8_t *)vb21_key + vb21_key->key_offset);
+
+ if (slot == VBOOT_EC_SLOT_A) {
+ data = (const uint8_t *)(CONFIG_MAPPED_STORAGE_BASE +
+ CONFIG_EC_WRITABLE_STORAGE_OFF +
+ CONFIG_RW_A_STORAGE_OFF);
+ vb21_sig = (const struct vb21_signature *)(
+ CONFIG_MAPPED_STORAGE_BASE +
+ CONFIG_EC_WRITABLE_STORAGE_OFF +
+ CONFIG_RW_A_SIGN_STORAGE_OFF);
+ } else {
+ data = (const uint8_t *)(CONFIG_MAPPED_STORAGE_BASE +
+ CONFIG_EC_WRITABLE_STORAGE_OFF +
+ CONFIG_RW_B_STORAGE_OFF);
+ vb21_sig = (const struct vb21_signature *)(
+ CONFIG_MAPPED_STORAGE_BASE +
+ CONFIG_EC_WRITABLE_STORAGE_OFF +
+ CONFIG_RW_B_SIGN_STORAGE_OFF);
+ }
+
+ if (vb21_is_signature_valid(vb21_sig, vb21_key)) {
+ CPRINTS("Invalid signature");
+ return EC_ERROR_INVAL;
+ }
+ sig = (const uint8_t *)vb21_sig + vb21_sig->sig_offset;
+ len = vb21_sig->data_size;
+
+ if (vboot_is_padding_valid(data, len,
+ CONFIG_RW_SIZE - CONFIG_RW_SIG_SIZE)) {
+ CPRINTS("Invalid padding");
+ return EC_ERROR_INVAL;
+ }
+
+ if (vboot_verify(data, len, key, sig)) {
+ CPRINTS("Invalid data");
+ return EC_ERROR_INVAL;
+ }
+
+ return EC_SUCCESS;
+}
+
+static int verify_and_jump(void)
+{
+ uint8_t slot;
+ int rv;
+
+ /* 1. Decide which slot to try */
+ if (system_get_bbram(SYSTEM_BBRAM_IDX_TRY_SLOT, &slot)) {
+ CPRINTS("Failed to read try slot");
+ slot = VBOOT_EC_SLOT_A;
+ }
+
+ /* 2. Verify the slot */
+ rv = verify_slot(slot);
+ if (rv) {
+ if (rv != EC_ERROR_INVAL)
+ /* Unknown error. The other slot isn't worth trying. */
+ return rv;
+ /* Verification error. The other slot is worth trying. */
+ slot = 1 - slot;
+ if (verify_slot(slot))
+ /* Both slots failed */
+ return rv;
+ /* Proceed with the other slot. AP will help us fix it. */
+ }
+
+ /* 3. Jump (and reboot) */
+ system_run_image_copy(slot == VBOOT_EC_SLOT_A ?
+ SYSTEM_IMAGE_RW : SYSTEM_IMAGE_RW_B);
+
+ return EC_ERROR_UNKNOWN;
+}
+
+/* Request more power: charging battery or more powerful AC adapter */
+static void request_power(void)
+{
+ /* TODO: Blink LED */
+}
+
+static void request_recovery(void)
+{
+ /* TODO: Blink LED */
+}
+
+static int is_manual_recovery(void)
+{
+ return host_get_events() & EC_HOST_EVENT_KEYBOARD_RECOVERY;
+}
+
+void vboot_main(void)
+{
+ int port = charge_manager_get_active_charge_port();
+
+ if (port >= CONFIG_USB_PD_PORT_COUNT) {
+ /* AC is not type-c. No chance to boot. */
+ request_power();
+ return;
+ }
+
+ if (pd_comm_is_enabled(port))
+ /* Normal RW boot or unlocked RO boot.
+ * Hoping enough power will be supplied after PD negotiation. */
+ return;
+
+ /* PD communication is disabled. Probably this is RO image */
+ CPRINTS("PD comm disabled");
+
+ if (is_manual_recovery()) {
+ if (battery_is_present() || has_matrix_keyboard()) {
+ request_power();
+ return;
+ }
+ CPRINTS("Enable C%d PD communication", port);
+ pd_comm_enable(port, 1);
+ /* TODO: Inform PD task and make it negotiate */
+ return;
+ }
+
+ if (!is_vboot_ec_supported() && !is_low_power_ap_boot_supported()) {
+ request_power();
+ return;
+ }
+
+ /* If successful, this won't return. */
+ verify_and_jump();
+
+ /* Failed to jump. Need recovery. */
+ request_recovery();
+}