summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorMatt Delco <delco@google.com>2019-02-13 12:58:58 -0800
committerchrome-bot <chrome-bot@chromium.org>2019-03-21 03:31:38 -0700
commitb6f4defb81d24b696c111abae97648fe303f8322 (patch)
tree51961529a51f99c3d9fa845b2d64f0a5555b2b8f /firmware
parent90a95ea62ade991769540f4a0c0e6465f3b3926c (diff)
downloadvboot-b6f4defb81d24b696c111abae97648fe303f8322.tar.gz
vboot: add diagnostic mode
This change adds diagnostic mode. When enabled for a board (based on defconfig in depthcharge) the user can press Ctrl-C or F12 at a recovery mode screen, at which point an nv bit is set and the system reboots. Upon reboot, if the nv bit is set then the user is prompted to confirm launch of the diagnostic rom via the power button. If user confirms then the diagnostic payload is verified and run (if verify fails or payload doesn't run then a recovery reason is recorded and system reboots to recovery mode). If the user does not confirm then the system reboots. BUG=b:124358784 BRANCH=None TEST=Locally built and flashed using change that enabled feature for atlas and set to use payload 2 (tianocore) rather than 5 (diagnostic). Confirmed that Ctrl-C is functional or not based on defconfig and that Ctrl-C sets NV bit and reboots. Confirmed that NV bit can be set and queried via crossystem. Confirmed that during boot confirmation screen appears or not based on NV bit. Confirmed that pressing power button caused payload to be verified and run. Confirmed that non-matching hash (build configured to use sha1 rather than sha256) caused payload to not be run and system reboot to recovery. Confirmed that Esc or timeout caused system to reboot. CQ-DEPEND=CL:1471056 Change-Id: I8979d4eeb443bf64b727ee86a814c46d1d27ff37 Signed-off-by: Matt Delco <delco@google.com> Reviewed-on: https://chromium-review.googlesource.com/1470723 Reviewed-by: Julius Werner <jwerner@chromium.org>
Diffstat (limited to 'firmware')
-rw-r--r--firmware/2lib/include/2recovery_reasons.h6
-rw-r--r--firmware/include/vboot_api.h6
-rw-r--r--firmware/lib/include/vboot_kernel.h5
-rw-r--r--firmware/lib/vboot_api_kernel.c21
-rw-r--r--firmware/lib/vboot_ui.c142
5 files changed, 177 insertions, 3 deletions
diff --git a/firmware/2lib/include/2recovery_reasons.h b/firmware/2lib/include/2recovery_reasons.h
index a35892c2..f8e6dbe9 100644
--- a/firmware/2lib/include/2recovery_reasons.h
+++ b/firmware/2lib/include/2recovery_reasons.h
@@ -219,6 +219,12 @@ enum vb2_nv_recovery {
/* Recovery hash space lock error in RO firmware */
VB2_RECOVERY_RO_TPM_REC_HASH_L_ERROR = 0x5f,
+ /* Failed to disable the TPM [prior to running untrusted code] */
+ VB2_RECOVERY_TPM_DISABLE_FAILED = 0x60,
+
+ /* Alt FW Failed hash verification */
+ VB2_RECOVERY_ALTFW_HASH_FAILED = 0x61,
+
/* Unspecified/unknown error in rewritable firmware */
VB2_RECOVERY_RW_UNSPECIFIED = 0x7f,
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index 9d8c8a0d..6202fe91 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -687,6 +687,8 @@ enum VbScreenType_t {
VB_SCREEN_SET_VENDOR_DATA = 0x214,
/* Confirm vendor data menu screen */
VB_SCREEN_CONFIRM_VENDOR_DATA = 0x215,
+ /* Confirm reboot for running diagnostics rom */
+ VB_SCREEN_CONFIRM_DIAG = 0x216,
};
/**
@@ -1017,6 +1019,7 @@ enum {
};
enum VbAltFwIndex_t {
+ VB_ALTFW_DIAGNOSTIC = -1,
VB_ALTFW_DEFAULT = 0,
VB_ALTFW_FIRST = 1,
VB_ALTFW_SECOND,
@@ -1037,7 +1040,8 @@ enum VbAltFwIndex_t {
* >0 (i.e., positive #) run a payload by # based in altfw/list file
* <0 (i.e., negative #) run a specific payload by name without using
* the altfw/list file. Typically payloads in this category will be
- * verified before they are run. Currently no #s are defined.
+ * verified before they are run. Currently these #s are defined:
+ * -1 diagnostic payload
*/
int VbExLegacy(enum VbAltFwIndex_t altfw_num);
diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h
index c3c4585b..7a8087e4 100644
--- a/firmware/lib/include/vboot_kernel.h
+++ b/firmware/lib/include/vboot_kernel.h
@@ -60,6 +60,11 @@ VbError_t VbBootNormal(struct vb2_context *ctx);
VbError_t VbBootDeveloper(struct vb2_context *ctx);
/**
+ * Handle a diagnostic-mode boot.
+ */
+VbError_t VbBootDiagnostic(struct vb2_context *ctx);
+
+/**
* Handle a recovery-mode boot.
*/
VbError_t VbBootRecovery(struct vb2_context *ctx);
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index 17b3b7b2..78f35744 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -431,6 +431,27 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
else
retval = VbBootRecovery(&ctx);
VbExEcEnteringMode(0, VB_EC_RECOVERY);
+ } else if (DIAGNOSTIC_UI && vb2_nv_get(&ctx, VB2_NV_DIAG_REQUEST)) {
+ struct vb2_shared_data *sd = vb2_get_sd(&ctx);
+ if (sd->vbsd->flags & VBSD_OPROM_MATTERS)
+ vb2_nv_set(&ctx, VB2_NV_OPROM_NEEDED, 0);
+ vb2_nv_set(&ctx, VB2_NV_DIAG_REQUEST, 0);
+
+ /*
+ * Diagnostic boot. This has a UI but only power button
+ * is used for input so no detachable-specific UI is needed.
+ * This mode is also 1-shot so it's placed before developer
+ * mode.
+ */
+ retval = VbBootDiagnostic(&ctx);
+ /*
+ * The diagnostic menu should either boot a rom, or
+ * return either of reboot or shutdown. The following
+ * check is a safety precaution.
+ */
+ if (!retval) {
+ retval = VBERROR_REBOOT_REQUIRED;
+ }
} else if (ctx.flags & VB2_CONTEXT_DEVELOPER_MODE) {
if (kparams->inflags & VB_SALK_INFLAGS_VENDOR_DATA_SETTABLE)
ctx.flags |= VB2_CONTEXT_VENDOR_DATA_SETTABLE;
diff --git a/firmware/lib/vboot_ui.c b/firmware/lib/vboot_ui.c
index 6d19a164..2e3bb270 100644
--- a/firmware/lib/vboot_ui.c
+++ b/firmware/lib/vboot_ui.c
@@ -17,6 +17,7 @@
#include "gbb_header.h"
#include "load_kernel_fw.h"
#include "rollback_index.h"
+#include "tlcl.h"
#include "utility.h"
#include "vb2_common.h"
#include "vboot_api.h"
@@ -44,7 +45,10 @@ static void VbAllowUsbBoot(struct vb2_context *ctx)
* Checks GBB flags against VbExIsShutdownRequested() shutdown request to
* determine if a shutdown is required.
*
- * Returns true if a shutdown is required and false if no shutdown is required.
+ * Returns zero or more of the following flags (if any are set then typically
+ * shutdown is required):
+ * VB_SHUTDOWN_REQUEST_LID_CLOSED
+ * VB_SHUTDOWN_REQUEST_POWER_BUTTON
*/
static int VbWantShutdown(struct vb2_context *ctx, uint32_t key)
{
@@ -70,7 +74,7 @@ static int VbWantShutdown(struct vb2_context *ctx, uint32_t key)
if (sd->gbb_flags & GBB_FLAG_DISABLE_LID_SHUTDOWN)
shutdown_request &= ~VB_SHUTDOWN_REQUEST_LID_CLOSED;
- return !!shutdown_request;
+ return shutdown_request;
}
uint32_t VbTryUsb(struct vb2_context *ctx)
@@ -366,6 +370,124 @@ VbError_t vb2_vendor_data_ui(struct vb2_context *ctx)
return VBERROR_SUCCESS;
}
+/*
+ * User interface for confirming launch of diagnostics rom
+ *
+ * This asks the user to confirm the launch of the diagnostics rom. The user
+ * can press the power button to confirm or press escape. There is a 30-second
+ * timeout which acts the same as escape.
+ */
+VbError_t vb2_diagnostics_ui(struct vb2_context *ctx)
+{
+ int active = 1;
+ int power_button_was_pressed = 0;
+ VbError_t result = VBERROR_REBOOT_REQUIRED;
+ int action_confirmed = 0;
+ uint64_t start_time_us;
+
+ VbDisplayScreen(ctx, VB_SCREEN_CONFIRM_DIAG, 0, NULL);
+
+ start_time_us = VbExGetTimer();
+
+ /* We'll loop until the user decides what to do */
+ do {
+ uint32_t key = VbExKeyboardRead();
+ /*
+ * VbExIsShutdownRequested() is almost an adequate substitute
+ * for adding a new flag to VbExGetSwitches(). The main
+ * issue is that the former doesn't consult the power button
+ * on detachables, and this function wants to see for itself
+ * that the power button isn't currently pressed.
+ */
+ uint32_t power_pressed =
+ VbExGetSwitches(VB_SWITCH_FLAG_PHYS_PRESENCE_PRESSED);
+ /*
+ * TODO(delco): Remove this workaround. On Wilco a button
+ * press is only reported a single time regardless of the
+ * duration of the press. Until it's changed to report the
+ * live/current status of the button we can't ignore when
+ * VbWantShutdown() reports a button press (well, we can
+ * ignore it but the user might have to press the power button
+ * more than once for this code to react).
+ */
+ int shutdown = VbWantShutdown(ctx, 0);
+ if (shutdown & VB_SHUTDOWN_REQUEST_POWER_BUTTON) {
+ power_pressed = 1;
+ }
+
+ if (power_pressed) {
+ power_button_was_pressed = 1;
+ } else if (power_button_was_pressed) {
+ VB2_DEBUG("vb2_diagnostics_ui() - power released\n");
+ action_confirmed = 1;
+ active = 0;
+ break;
+ }
+
+ /* Check the lid and ignore the power button. */
+ if (shutdown & VB_SHUTDOWN_REQUEST_LID_CLOSED) {
+ VB2_DEBUG("vb2_diagnostics_ui() - shutdown request\n");
+ result = VBERROR_SHUTDOWN_REQUESTED;
+ active = 0;
+ break;
+ }
+
+ switch (key) {
+ case 0:
+ /* nothing pressed */
+ break;
+ case VB_KEY_ESC:
+ /* Escape pressed - reboot */
+ VB2_DEBUG("vb2_diagnostics_ui() - user pressed Esc\n");
+ active = 0;
+ break;
+ default:
+ VB2_DEBUG("vb2_diagnostics_ui() - pressed key %d\n",
+ key);
+ VbCheckDisplayKey(ctx, key);
+ break;
+ }
+ if (VbExGetTimer() - start_time_us >= 30 * VB_USEC_PER_SEC) {
+ VB2_DEBUG("vb2_diagnostics_ui() - timeout\n");
+ break;
+ }
+ if (active) {
+ VbExSleepMs(DEV_KEY_DELAY);
+ }
+ } while (active);
+
+ VbDisplayScreen(ctx, VB_SCREEN_BLANK, 0, NULL);
+
+ if (action_confirmed) {
+ VB2_DEBUG("Diagnostic requested, running\n");
+
+ /*
+ * The following helps avoid use of the TPM after
+ * it's disabled (e.g., when vb2_run_altfw() calls
+ * RollbackKernelLock() ).
+ */
+
+ if (RollbackKernelLock(0)) {
+ VB2_DEBUG("Failed to lock TPM PP\n");
+ vb2_fail(ctx, VB2_RECOVERY_TPM_DISABLE_FAILED, 0);
+ } else if (vb2ex_tpm_set_mode(VB2_TPM_MODE_DISABLED) !=
+ VB2_SUCCESS) {
+ VB2_DEBUG("Failed to disable TPM\n");
+ vb2_fail(ctx, VB2_RECOVERY_TPM_DISABLE_FAILED, 0);
+ } else {
+ vb2_run_altfw(ctx, VB_ALTFW_DIAGNOSTIC);
+ VB2_DEBUG("Diagnostic failed to run\n");
+ /*
+ * Assuming failure was due to bad hash, though
+ * the rom could just be missing or invalid.
+ */
+ vb2_fail(ctx, VB2_RECOVERY_ALTFW_HASH_FAILED, 0);
+ }
+ }
+
+ return result;
+}
+
static const char dev_disable_msg[] =
"Developer mode is disabled on this device by system policy.\n"
"For more information, see http://dev.chromium.org/chromium-os/fwmp\n"
@@ -650,6 +772,14 @@ VbError_t VbBootDeveloper(struct vb2_context *ctx)
return retval;
}
+VbError_t VbBootDiagnostic(struct vb2_context *ctx)
+{
+ vb2_init_ui();
+ VbError_t retval = vb2_diagnostics_ui(ctx);
+ VbDisplayScreen(ctx, VB_SCREEN_BLANK, 0, NULL);
+ return retval;
+}
+
/* Delay in recovery mode */
#define REC_DISK_DELAY 1000 /* Check disks every 1s */
#define REC_KEY_DELAY 20 /* Check keys every 20ms */
@@ -786,6 +916,14 @@ static VbError_t recovery_ui(struct vb2_context *ctx)
i = 4;
break;
}
+ } else if (DIAGNOSTIC_UI &&
+ (key == VB_KEY_CTRL('C') ||
+ key == 0x114)) { /* F12 */
+ VB2_DEBUG("Diagnostic requested, rebooting\n");
+ if (shared->flags & VBSD_OPROM_MATTERS)
+ vb2_nv_set(ctx, VB2_NV_OPROM_NEEDED, 1);
+ vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1);
+ return VBERROR_REBOOT_REQUIRED;
} else {
VbCheckDisplayKey(ctx, key);
}