summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2012-06-07 04:21:14 -0700
committerGerrit <chrome-bot@google.com>2012-06-08 22:24:05 -0700
commitec8df1628cd9cf236bf912dee7d4365d7977e697 (patch)
treeed2f05416157e5b4f75d85507b2e8150da6b789c
parent1d75e69f3dbc1fecb358b304673ef564460ad131 (diff)
downloadvboot-ec8df1628cd9cf236bf912dee7d4365d7977e697.tar.gz
Support virtual dev-switch (keyboard-based dev-mode)
BUG=chrome-os-partner:9706 TEST=manual Currently, Link is the only platform that enables this feature. To enter dev-mode: Boot into recovery mode using the magic key chord. At the Insert screen, press Ctrl-D. You'll be asked if you want to enter developer mode. If you then press ENTER, it will reboot with dev-mode enabled. If you press SPACE or ESC, it will return to the Insert screen. If you enter recovery mode through any other means, or if dev-mode is already enabled, pressing Ctrl-D at the Insert screen will have no effect. To return to normal mode: Reboot. At the Dev screen, press ENTER or SPACE. It will reboot to recovery mode and ask you if you want to return to normal mode. If you press ESC or power off, you'll still be in dev-mode. Press ENTER or SPACE, and it will reboot into normal mode (of course, if you've messed up your images while in dev-mode, you'll just come right back to recovery mode again). You can also request a direct return to normal mode by running crossystem disable_dev_request=1 and rebooting. Change-Id: I435905855a6c39932ee466cc046bdc4c4c860f98 Reviewed-on: https://gerrit.chromium.org/gerrit/24160 Tested-by: Bill Richardson <wfrichar@chromium.org> Reviewed-by: Bill Richardson <wfrichar@chromium.org> Commit-Ready: Bill Richardson <wfrichar@chromium.org>
-rw-r--r--firmware/include/vboot_api.h4
-rw-r--r--firmware/include/vboot_struct.h2
-rw-r--r--firmware/lib/include/rollback_index.h15
-rw-r--r--firmware/lib/mocked_rollback_index.c5
-rw-r--r--firmware/lib/rollback_index.c68
-rw-r--r--firmware/lib/vboot_api_firmware.c3
-rw-r--r--firmware/lib/vboot_api_init.c55
-rw-r--r--firmware/lib/vboot_api_kernel.c79
-rw-r--r--firmware/lib/vboot_display.c8
-rw-r--r--firmware/linktest/main.c2
-rw-r--r--tests/rollback_index2_tests.c33
-rw-r--r--tests/vboot_api_init_tests.c40
12 files changed, 231 insertions, 83 deletions
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index b6b73928..50d0f816 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -100,7 +100,7 @@ enum VbErrorPredefined_t {
/* VbExBeep() can't make sound in the background */
VBERROR_NO_BACKGROUND_SOUND = 0x10019,
/* Developer has requested a BIOS shell */
- VBERROR_BIOS_SHELL_REQUESTED = 0x10020
+ VBERROR_BIOS_SHELL_REQUESTED = 0x10020,
};
@@ -511,6 +511,8 @@ enum VbScreenType_t {
VB_SCREEN_RECOVERY_REMOVE = 0x201, /* Recovery - remove inserted devices */
VB_SCREEN_RECOVERY_INSERT = 0x202, /* Recovery - insert recovery image */
VB_SCREEN_RECOVERY_NO_GOOD = 0x203, /* Recovery - inserted image invalid */
+ VB_SCREEN_RECOVERY_TO_DEV = 0x204, /* Recovery - confirm dev mode */
+ VB_SCREEN_RECOVERY_TO_NORM = 0x205, /* Recovery - confirm normal mode */
};
/* Initialize and clear the display. Set width and height to the screen
diff --git a/firmware/include/vboot_struct.h b/firmware/include/vboot_struct.h
index 0f6b98d9..d894e23d 100644
--- a/firmware/include/vboot_struct.h
+++ b/firmware/include/vboot_struct.h
@@ -231,6 +231,8 @@ typedef struct VbKernelPreambleHeader {
#define VBSD_BOOT_S3_RESUME 0x00000100
/* Read-only firmware supports the normal/developer code path */
#define VBSD_BOOT_RO_NORMAL_SUPPORT 0x00000200
+/* VbInit was told that the system has a virtual dev-switch */
+#define VBSD_HONOR_VIRT_DEV_SWITCH 0x00000400
/* Result codes for VbSharedDataHeader.check_fw_a_result (and b_result) */
#define VBSD_LF_CHECK_NOT_DONE 0
diff --git a/firmware/lib/include/rollback_index.h b/firmware/lib/include/rollback_index.h
index 5a072446..20df5b31 100644
--- a/firmware/lib/include/rollback_index.h
+++ b/firmware/lib/include/rollback_index.h
@@ -67,11 +67,11 @@ uint32_t RollbackS3Resume(void);
/* These functions are callable from VbSelectFirmware(). They cannot use
* global variables. */
-/* Setup must be called. Pass recovery_mode=nonzero if in recovery mode. Pass
- * *developer_mode=nonzero if in developer mode. Set hw_dev_sw if there's a
- * hardware developer switch. Duh. */
-uint32_t RollbackFirmwareSetup(int recovery_mode, int hw_dev_sw,
- int* dev_mode_ptr, uint32_t* version);
+/* This must be called. */
+uint32_t RollbackFirmwareSetup(int recovery_mode, int is_hw_dev,
+ int disable_dev_request,
+ /* two outputs on success */
+ int *is_virt_dev, uint32_t *tpm_version);
/* Write may be called if the versions change */
uint32_t RollbackFirmwareWrite(uint32_t version);
@@ -118,6 +118,9 @@ uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware* rsf,
/* SetupTPM starts the TPM and establishes the root of trust for the
* anti-rollback mechanism. */
uint32_t SetupTPM(int recovery_mode, int developer_mode,
- RollbackSpaceFirmware* rsf);
+ int disable_dev_request, RollbackSpaceFirmware* rsf);
+
+/* Utility function to turn the virtual dev-mode flag on or off. 0=off, 1=on */
+uint32_t SetVirtualDevMode(int val);
#endif /* VBOOT_REFERENCE_ROLLBACK_INDEX_H_ */
diff --git a/firmware/lib/mocked_rollback_index.c b/firmware/lib/mocked_rollback_index.c
index 32082ddd..f884daec 100644
--- a/firmware/lib/mocked_rollback_index.c
+++ b/firmware/lib/mocked_rollback_index.c
@@ -27,8 +27,9 @@ uint32_t RollbackS3Resume(void) {
}
-uint32_t RollbackFirmwareSetup(int recovery_mode, int hw_dev_sw,
- int* dev_mode_ptr, uint32_t* version) {
+uint32_t RollbackFirmwareSetup(int recovery_mode, int is_hw_dev,
+ int disable_dev_request,
+ int *is_virt_dev, uint32_t *version) {
*version = 0;
return TPM_SUCCESS;
}
diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c
index 5cd13566..668312e6 100644
--- a/firmware/lib/rollback_index.c
+++ b/firmware/lib/rollback_index.c
@@ -131,6 +131,28 @@ uint32_t WriteSpaceFirmware(RollbackSpaceFirmware* rsf) {
return TPM_E_CORRUPTED_STATE;
}
+uint32_t SetVirtualDevMode(int val) {
+ RollbackSpaceFirmware rsf;
+
+ VBDEBUG(("TPM: Entering %s()\n", __func__));
+ if (TPM_SUCCESS != ReadSpaceFirmware(&rsf))
+ return VBERROR_TPM_FIRMWARE_SETUP;
+
+ VBDEBUG(("TPM: flags were 0x%02x\n", rsf.flags));
+ if (val)
+ rsf.flags |= FLAG_VIRTUAL_DEV_MODE_ON;
+ else
+ rsf.flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
+ /* NOTE: This doesn't update the FLAG_LAST_BOOT_DEVELOPER bit */
+ VBDEBUG(("TPM: flags are now 0x%02x\n", rsf.flags));
+
+ if (TPM_SUCCESS != WriteSpaceFirmware(&rsf))
+ return VBERROR_TPM_SET_BOOT_MODE_STATE;
+
+ VBDEBUG(("TPM: Leaving %s()\n", __func__));
+ return VBERROR_SUCCESS;
+}
+
uint32_t ReadSpaceKernel(RollbackSpaceKernel* rsk) {
uint32_t r;
int attempts = 3;
@@ -276,10 +298,9 @@ uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware* rsf,
* the durability of the NVRAM.
*/
uint32_t SetupTPM(int recovery_mode, int developer_mode,
- RollbackSpaceFirmware* rsf) {
+ int disable_dev_request, RollbackSpaceFirmware* rsf) {
- int rsf_dirty = 0;
- uint8_t new_flags = 0;
+ uint8_t in_flags;
uint8_t disable;
uint8_t deactivated;
uint32_t result;
@@ -362,29 +383,36 @@ uint32_t SetupTPM(int recovery_mode, int developer_mode,
}
VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n",
rsf->struct_version, rsf->flags, rsf->fw_versions));
+ in_flags = rsf->flags;
+
+ /* If we've been asked to clear the virtual dev-mode flag, do so now */
+ if (disable_dev_request) {
+ rsf->flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
+ VBDEBUG(("TPM: Clearing virt dev-switch: f%x\n", rsf->flags));
+ }
/* The developer_mode value that's passed in is only set by a hardware
- * dev-switch. We should OR it with any enabled virtual switch. */
+ * dev-switch. We should OR it with the virtual switch, whether or not the
+ * virtual switch is used. If it's not used, it shouldn't change, so it
+ * doesn't matter. */
if (rsf->flags & FLAG_VIRTUAL_DEV_MODE_ON)
developer_mode = 1;
/* Clears ownership if developer flag has toggled */
if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) !=
- (rsf->flags & FLAG_LAST_BOOT_DEVELOPER)) {
+ (in_flags & FLAG_LAST_BOOT_DEVELOPER)) {
VBDEBUG(("TPM: Developer flag changed; clearing owner.\n"));
RETURN_ON_FAILURE(TPMClearAndReenable());
}
- /* Updates flags */
if (developer_mode)
- new_flags |= FLAG_LAST_BOOT_DEVELOPER;
- if (rsf->flags != new_flags) {
- rsf->flags = new_flags;
- rsf_dirty = 1;
- }
+ rsf->flags |= FLAG_LAST_BOOT_DEVELOPER;
+ else
+ rsf->flags &= ~FLAG_LAST_BOOT_DEVELOPER;
+
/* If firmware space is dirty, this flushes it back to the TPM */
- if (rsf_dirty) {
+ if (rsf->flags != in_flags) {
VBDEBUG(("TPM: Updating firmware space.\n"));
RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
}
@@ -411,8 +439,9 @@ uint32_t RollbackS3Resume(void) {
return TPM_SUCCESS;
}
-uint32_t RollbackFirmwareSetup(int recovery_mode, int hw_dev_sw,
- int* developer_mode, uint32_t* version) {
+uint32_t RollbackFirmwareSetup(int recovery_mode, int is_hw_dev,
+ int disable_dev_request,
+ int *is_virt_dev, uint32_t *version) {
#ifndef CHROMEOS_ENVIRONMENT
/* Initialize the TPM, but ignores return codes. In ChromeOS
* environment, don't even talk to the TPM. */
@@ -464,17 +493,18 @@ uint32_t RollbackS3Resume(void) {
return result;
}
-uint32_t RollbackFirmwareSetup(int recovery_mode, int hw_dev_sw,
- int* dev_mode_ptr, uint32_t* version) {
+uint32_t RollbackFirmwareSetup(int recovery_mode, int is_hw_dev,
+ int disable_dev_request,
+ int *is_virt_dev, uint32_t *version) {
RollbackSpaceFirmware rsf;
/* Set version to 0 in case we fail */
*version = 0;
- RETURN_ON_FAILURE(SetupTPM(recovery_mode, *dev_mode_ptr, &rsf));
+ RETURN_ON_FAILURE(SetupTPM(recovery_mode, is_hw_dev,
+ disable_dev_request, &rsf));
*version = rsf.fw_versions;
- if (!hw_dev_sw && (rsf.flags & FLAG_VIRTUAL_DEV_MODE_ON))
- *dev_mode_ptr = 1; /* OR with the TPM's value */
+ *is_virt_dev = (rsf.flags & FLAG_VIRTUAL_DEV_MODE_ON) ? 1 : 0;
VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)rsf.fw_versions));
return TPM_SUCCESS;
}
diff --git a/firmware/lib/vboot_api_firmware.c b/firmware/lib/vboot_api_firmware.c
index faae7dd0..cffc462b 100644
--- a/firmware/lib/vboot_api_firmware.c
+++ b/firmware/lib/vboot_api_firmware.c
@@ -33,8 +33,7 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams,
if (is_rec) {
/* Recovery is requested; go straight to recovery without checking the
* RW firmware. */
- VBDEBUG(("VbSelectFirmware() detected recovery request, reason=%d.\n",
- (int)shared->recovery_reason));
+ VBDEBUG(("VbSelectFirmware() detected recovery request\n"));
/* Go directly to recovery mode */
fparams->selected_firmware = VB_SELECT_FIRMWARE_RECOVERY;
diff --git a/firmware/lib/vboot_api_init.c b/firmware/lib/vboot_api_init.c
index 34323094..bff57bd5 100644
--- a/firmware/lib/vboot_api_init.c
+++ b/firmware/lib/vboot_api_init.c
@@ -25,7 +25,10 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
uint32_t require_official_os = 0;
uint32_t tpm_version = 0;
uint32_t tpm_status = 0;
- int hw_dev_sw = 1;
+ int has_virt_dev_switch = 0;
+ int is_hw_dev = 0;
+ int is_virt_dev = 0;
+ uint32_t disable_dev_request = 0;
int is_dev = 0;
VBDEBUG(("VbInit() input flags 0x%x\n", iparams->flags));
@@ -45,11 +48,8 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
shared->timer_vb_init_enter = VbExGetTimer();
- /* Copy boot switch flags */
+ /* Copy some boot switch flags */
shared->flags = 0;
- if (!(iparams->flags & VB_INIT_FLAG_VIRTUAL_DEV_SWITCH) &&
- (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON))
- is_dev = 1;
if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
shared->flags |= VBSD_BOOT_REC_SWITCH_ON;
if (iparams->flags & VB_INIT_FLAG_WP_ENABLED)
@@ -80,6 +80,7 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
* it so we don't get stuck in recovery mode. */
if (!is_s3_resume) {
VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &recovery);
+ VBDEBUG(("VbInit sees recovery request = %d\n", recovery));
if (VBNV_RECOVERY_NOT_REQUESTED != recovery)
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_NOT_REQUESTED);
}
@@ -101,6 +102,7 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
/* Copy current recovery reason to shared data. If we fail later on, it
* won't matter, since we'll just reboot. */
shared->recovery_reason = (uint8_t)recovery;
+ VBDEBUG(("VbInit now sets shared->recovery_reason = %d\n", recovery));
/* If this is a S3 resume, resume the TPM. */
/* FIXME: I think U-Boot won't ever ask us to do this. Can we remove it? */
@@ -112,25 +114,29 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
retval = VBERROR_TPM_S3_RESUME;
}
} else {
-
- /* We need to know about dev mode now. */
- if (iparams->flags & VB_INIT_FLAG_VIRTUAL_DEV_SWITCH)
- hw_dev_sw = 0;
+ /* Should we pay attention to the TPM's virtual dev-switch? */
+ if (iparams->flags & VB_INIT_FLAG_VIRTUAL_DEV_SWITCH) {
+ shared->flags |= VBSD_HONOR_VIRT_DEV_SWITCH;
+ has_virt_dev_switch = 1;
+ }
+ /* We always believe the HW dev-switch, since there's one attached to servo
+ * which may be active even on systems without a physical switch. The EC
+ * may also implement a fake dev-switch for testing. */
if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON)
- is_dev = 1;
+ is_hw_dev = 1;
+ /* We may be asked to clear the virtual dev-switch at boot. */
+ VbNvGet(&vnc, VBNV_DISABLE_DEV_REQUEST, &disable_dev_request);
+
/* FIXME: How about a GBB flag to force dev-switch on? */
VBPERFSTART("VB_TPMI");
- /* Initialize the TPM. *is_dev is both an input and output. The only time
- * it should be 1 on input is when the hardware dev-switch is enabled
- * (which includes the fake_dev switch from the EC). The only time
- * it's promoted from 0 to 1 on return is when we have a virtual dev-switch
- * and the TPM has a valid rollback space with the virtual switch already
- * enabled (if the TPM space is initialized by this call, its virtual
- * dev-switch will be disabled by default). The TPM just uses the input
- * value to clear ownership if the dev state has changed. */
- tpm_status = RollbackFirmwareSetup(recovery, hw_dev_sw,
- &is_dev, &tpm_version);
+ /* Initialize the TPM. If the developer mode state has changed since the
+ * last boot, we need to clear TPM ownership. If the TPM space is
+ * initialized by this call, the virtual dev-switch will be disabled by
+ * default) */
+ tpm_status = RollbackFirmwareSetup(recovery, is_hw_dev, disable_dev_request,
+ /* two outputs on success */
+ &is_virt_dev, &tpm_version);
VBPERFEND("VB_TPMI");
if (0 != tpm_status) {
VBDEBUG(("Unable to setup TPM and read firmware version.\n"));
@@ -157,10 +163,16 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
goto VbInit_exit;
}
}
+
+ /* TPM setup succeeded. What did we learn? */
shared->fw_version_tpm_start = tpm_version;
shared->fw_version_tpm = tpm_version;
- if (is_dev)
+ if (is_hw_dev || (has_virt_dev_switch && is_virt_dev)) {
+ is_dev = 1;
shared->flags |= VBSD_BOOT_DEV_SWITCH_ON;
+ }
+ if (disable_dev_request && !is_virt_dev)
+ VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 0);
}
/* Allow BIOS to load arbitrary option ROMs? */
@@ -207,5 +219,6 @@ VbInit_exit:
shared->timer_vb_init_exit = VbExGetTimer();
+ VBDEBUG(("VbInit() returning 0x%x\n", retval));
return retval;
}
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index 891807a3..b0a04ac4 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -110,6 +110,7 @@ uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p,
/* Handle a normal boot. */
VbError_t VbBootNormal(VbCommonParams* cparams, LoadKernelParams* p) {
/* Boot from fixed disk only */
+ VBDEBUG(("Entering %s()\n", __func__));
return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED);
}
@@ -118,6 +119,8 @@ VbError_t VbBootDeveloper(VbCommonParams* cparams, LoadKernelParams* p) {
uint32_t allow_usb = 0;
VbAudioContext* audio = 0;
+ VBDEBUG(("Entering %s()\n", __func__));
+
/* Check if USB booting is allowed */
VbNvGet(&vnc, VBNV_DEV_BOOT_USB, &allow_usb);
@@ -202,6 +205,49 @@ fallout:
}
+/* FIXME(crosbug.com/p/9953): The platform BIOS should implement this! */
+/* And not here: somewhere outside of vboot with the other VbEx functions */
+int VbExTrustEC(void) {
+ /* Only return true if the EC is running in its RO firmware *right now*. */
+ return 1;
+}
+
+/* Ask the user to confirm changing the virtual dev-mode switch. If they confirm
+ * we'll change it and return a reason to reboot. */
+static VbError_t VbConfirmChangeDevMode(VbCommonParams* cparams, int to_dev) {
+ uint32_t key;
+
+ VBDEBUG(("Entering %s(%d)\n", __func__, to_dev));
+ /* Show the dev-mode confirmation screen */
+ VbDisplayScreen(cparams, (to_dev ? VB_SCREEN_RECOVERY_TO_DEV
+ : VB_SCREEN_RECOVERY_TO_NORM), 0, &vnc);
+
+ /* Await further instructions */
+ while (1) {
+ if (VbExIsShutdownRequested())
+ return VBERROR_SHUTDOWN_REQUESTED;
+ /* ENTER is always yes, ESC is always no.
+ * SPACE is yes when leaving dev-mode, but is no when entering it. */
+ key = VbExKeyboardRead();
+ if (key == '\r' || (key == ' ' && !to_dev)) {
+ VBDEBUG(("%s() - Yes: virtual dev-mode switch => %d\n",
+ __func__, to_dev));
+ if (TPM_SUCCESS != SetVirtualDevMode(to_dev))
+ return VBERROR_TPM_SET_BOOT_MODE_STATE;
+ VBDEBUG(("%s() - Reboot so it will take effect\n", __func__));
+ return VBERROR_TPM_REBOOT_REQUIRED;
+ } else if (key == 0x1B || (key == ' ' && to_dev)) {
+ VBDEBUG(("%s() - No: don't change virtual dev-mode switch\n", __func__));
+ VbDisplayScreen(cparams, VB_SCREEN_RECOVERY_INSERT, 0, &vnc);
+ return VBERROR_SUCCESS;
+ } else if (key) {
+ /* Anything else, just keep waiting */
+ VbCheckDisplayKey(cparams, key, &vnc);
+ VbExSleepMs(1000);
+ }
+ }
+}
+
/* Delay between disk checks in recovery mode */
#define REC_DELAY_INCREMENT 250
@@ -209,6 +255,7 @@ fallout:
VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) {
VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
uint32_t retval;
+ uint32_t key;
int i;
VBDEBUG(("VbBootRecovery() start\n"));
@@ -224,7 +271,7 @@ VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) {
while (1) {
if (VBERROR_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count,
- VB_DISK_FLAG_REMOVABLE))
+ VB_DISK_FLAG_REMOVABLE))
disk_count = 0;
VbExDiskFreeInfo(disk_info, NULL);
@@ -249,6 +296,18 @@ VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) {
}
}
+ /* See if we should disable the virtual dev-mode switch. */
+ VBDEBUG(("VbBootRecovery() shared->flags=0x%x, recovery_reason=%d\n",
+ shared->flags, shared->recovery_reason));
+ if (shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH &&
+ shared->flags & VBSD_BOOT_DEV_SWITCH_ON &&
+ shared->recovery_reason == VBNV_RECOVERY_RW_DEV_SCREEN) {
+ retval = VbConfirmChangeDevMode(cparams, 0); /* .. so go ask */
+ VBDEBUG(("VbConfirmChangeDevMode() returned %d\n", retval));
+ if (retval != VBERROR_SUCCESS)
+ return retval;
+ }
+
/* Loop and wait for a recovery image */
while (1) {
VBDEBUG(("VbBootRecovery() attempting to load kernel\n"));
@@ -260,7 +319,7 @@ VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) {
VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
if (VBERROR_SUCCESS == retval)
- break; /* Found a recovery kernel */
+ break; /* Found a recovery kernel */
VbDisplayScreen(cparams, VBERROR_NO_DISK_FOUND == retval ?
VB_SCREEN_RECOVERY_INSERT : VB_SCREEN_RECOVERY_NO_GOOD,
@@ -269,7 +328,19 @@ VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) {
/* Scan keyboard more frequently than media, since x86 platforms don't like
* to scan USB too rapidly. */
for (i = 0; i < 4; i++) {
- VbCheckDisplayKey(cparams, VbExKeyboardRead(), &vnc);
+ key = VbExKeyboardRead();
+ /* We might want to enter dev-mode from the Insert screen if... */
+ if (key == 0x04 && /* user pressed Ctrl-D */
+ shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH && /* we can do that */
+ !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) && /* not in dev-mode */
+ (shared->flags & VBSD_BOOT_REC_SWITCH_ON) && /* user forced rec */
+ VbExTrustEC()) { /* EC isn't pwned */
+ retval = VbConfirmChangeDevMode(cparams, 1); /* .. so go ask */
+ VBDEBUG(("VbConfirmChangeDevMode() returned %d\n", retval));
+ if (retval != VBERROR_SUCCESS)
+ return retval;
+ } else
+ VbCheckDisplayKey(cparams, key, &vnc);
if (VbExIsShutdownRequested())
return VBERROR_SHUTDOWN_REQUESTED;
VbExSleepMs(REC_DELAY_INCREMENT);
@@ -287,8 +358,6 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
LoadKernelParams p;
uint32_t tpm_status = 0;
- VBDEBUG(("VbSelectAndLoadKernel() start\n"));
-
/* Start timer */
shared->timer_vb_select_and_load_kernel_enter = VbExGetTimer();
diff --git a/firmware/lib/vboot_display.c b/firmware/lib/vboot_display.c
index 3649fd1f..e48623b5 100644
--- a/firmware/lib/vboot_display.c
+++ b/firmware/lib/vboot_display.c
@@ -219,6 +219,12 @@ VbError_t VbDisplayScreenFromGBB(VbCommonParams* cparams, uint32_t screen,
case VB_SCREEN_RECOVERY_INSERT:
screen_index = 3;
break;
+ case VB_SCREEN_RECOVERY_TO_DEV:
+ screen_index = 4;
+ break;
+ case VB_SCREEN_RECOVERY_TO_NORM:
+ screen_index = 5;
+ break;
case VB_SCREEN_BLANK:
case VB_SCREEN_DEVELOPER_EGG:
default:
@@ -328,6 +334,7 @@ VbError_t VbDisplayScreenFromGBB(VbCommonParams* cparams, uint32_t screen,
VbDisplayScreenFromGBB_exit:
+ VBDEBUG(("leaving VbDisplayScreenFromGBB() with %d\n",retval));
/* Free the bitmap data copy */
VbExFree(bmpfv);
return retval;
@@ -590,7 +597,6 @@ VbError_t VbCheckDisplayKey(VbCommonParams* cparams, uint32_t key,
if ('\t' == key) {
/* Tab = display debug info */
return VbDisplayDebugInfo(cparams, vncptr);
-
} else if (VB_KEY_LEFT == key || VB_KEY_RIGHT == key ||
VB_KEY_DOWN == key || VB_KEY_UP == key) {
/* Arrow keys = change localization */
diff --git a/firmware/linktest/main.c b/firmware/linktest/main.c
index 9c1cf346..020b589a 100644
--- a/firmware/linktest/main.c
+++ b/firmware/linktest/main.c
@@ -29,7 +29,7 @@ int main(void)
/* rollback_index.h */
RollbackS3Resume();
- RollbackFirmwareSetup(0, 0, 0, 0);
+ RollbackFirmwareSetup(0, 0, 0, 0, 0);
RollbackFirmwareWrite(0);
RollbackFirmwareLock();
RollbackKernelRead(0);
diff --git a/tests/rollback_index2_tests.c b/tests/rollback_index2_tests.c
index 98d7dcde..6de33bcf 100644
--- a/tests/rollback_index2_tests.c
+++ b/tests/rollback_index2_tests.c
@@ -558,7 +558,7 @@ static void SetupTpmTest(void) {
/* Complete setup */
ResetMocks(0, 0);
- TEST_EQ(SetupTPM(0, 0, &rsf), 0, "SetupTPM()");
+ TEST_EQ(SetupTPM(0, 0, 0, &rsf), 0, "SetupTPM()");
TEST_STR_EQ(mock_calls,
"TlclLibInit()\n"
"TlclStartup()\n"
@@ -570,7 +570,7 @@ static void SetupTpmTest(void) {
/* If TPM is disabled or deactivated, must enable it */
ResetMocks(0, 0);
mock_pflags.disable = 1;
- TEST_EQ(SetupTPM(0, 0, &rsf), TPM_E_MUST_REBOOT, "SetupTPM() disabled");
+ TEST_EQ(SetupTPM(0, 0, 0, &rsf), TPM_E_MUST_REBOOT, "SetupTPM() disabled");
TEST_STR_EQ(mock_calls,
"TlclLibInit()\n"
"TlclStartup()\n"
@@ -582,7 +582,7 @@ static void SetupTpmTest(void) {
ResetMocks(0, 0);
mock_pflags.deactivated = 1;
- TEST_EQ(SetupTPM(0, 0, &rsf), TPM_E_MUST_REBOOT, "SetupTPM() deactivated");
+ TEST_EQ(SetupTPM(0, 0, 0, &rsf), TPM_E_MUST_REBOOT, "SetupTPM() deactivated");
TEST_STR_EQ(mock_calls,
"TlclLibInit()\n"
"TlclStartup()\n"
@@ -594,7 +594,7 @@ static void SetupTpmTest(void) {
/* If physical presence command isn't enabled, should try to enable it */
ResetMocks(3, TPM_E_IOERROR);
- TEST_EQ(SetupTPM(0, 0, &rsf), 0, "SetupTPM() pp cmd");
+ TEST_EQ(SetupTPM(0, 0, 0, &rsf), 0, "SetupTPM() pp cmd");
TEST_STR_EQ(mock_calls,
"TlclLibInit()\n"
"TlclStartup()\n"
@@ -609,7 +609,7 @@ static void SetupTpmTest(void) {
ResetMocks(5, TPM_E_BADINDEX);
mock_pflags.physicalPresenceLifetimeLock = 1;
mock_pflags.nvLocked = 1;
- TEST_EQ(SetupTPM(0, 0, &rsf), 0, "SetupTPM() no firmware space");
+ TEST_EQ(SetupTPM(0, 0, 0, &rsf), 0, "SetupTPM() no firmware space");
TEST_STR_EQ(mock_calls,
"TlclLibInit()\n"
"TlclStartup()\n"
@@ -632,7 +632,7 @@ static void SetupTpmTest(void) {
/* Other firmware space error is passed through */
ResetMocks(5, TPM_E_IOERROR);
- TEST_EQ(SetupTPM(0, 0, &rsf), TPM_E_CORRUPTED_STATE,
+ TEST_EQ(SetupTPM(0, 0, 0, &rsf), TPM_E_CORRUPTED_STATE,
"SetupTPM() bad firmware space");
TEST_STR_EQ(mock_calls,
"TlclLibInit()\n"
@@ -644,7 +644,7 @@ static void SetupTpmTest(void) {
/* If developer flag has toggled, clear ownership and write new flag */
ResetMocks(0, 0);
- TEST_EQ(SetupTPM(0, 1, &rsf), 0, "SetupTPM() to dev");
+ TEST_EQ(SetupTPM(0, 1, 0, &rsf), 0, "SetupTPM() to dev");
TEST_STR_EQ(mock_calls,
"TlclLibInit()\n"
"TlclStartup()\n"
@@ -657,11 +657,11 @@ static void SetupTpmTest(void) {
"TlclWrite(0x1007, 10)\n"
"TlclRead(0x1007, 10)\n",
"tlcl calls");
- TEST_EQ(mock_rsf.flags, FLAG_LAST_BOOT_DEVELOPER, "fw space flags to dev");
+ TEST_EQ(mock_rsf.flags, FLAG_LAST_BOOT_DEVELOPER, "fw space flags to dev 1");
ResetMocks(0, 0);
mock_rsf.flags = FLAG_LAST_BOOT_DEVELOPER;
- TEST_EQ(SetupTPM(0, 0, &rsf), 0, "SetupTPM() from dev");
+ TEST_EQ(SetupTPM(0, 0, 0, &rsf), 0, "SetupTPM() from dev");
TEST_STR_EQ(mock_calls,
"TlclLibInit()\n"
"TlclStartup()\n"
@@ -674,7 +674,7 @@ static void SetupTpmTest(void) {
"TlclWrite(0x1007, 10)\n"
"TlclRead(0x1007, 10)\n",
"tlcl calls");
- TEST_EQ(mock_rsf.flags, 0, "fw space flags from dev");
+ TEST_EQ(mock_rsf.flags, 0, "fw space flags from dev 1");
/* Note: SetupTPM() recovery_mode parameter sets a global flag in
* rollback_index.c; this is tested along with RollbackKernelLock() below. */
@@ -691,7 +691,7 @@ static void RollbackFirmwareTest(void) {
dev_mode = 0;
version = 123;
mock_rsf.fw_versions = 0x12345678;
- TEST_EQ(RollbackFirmwareSetup(0, 0, &dev_mode, &version), 0,
+ TEST_EQ(RollbackFirmwareSetup(0, 0, dev_mode, &dev_mode, &version), 0,
"RollbackFirmwareSetup()");
TEST_STR_EQ(mock_calls,
"TlclLibInit()\n"
@@ -707,7 +707,8 @@ static void RollbackFirmwareTest(void) {
dev_mode = 0;
version = 123;
mock_rsf.fw_versions = 0x12345678;
- TEST_EQ(RollbackFirmwareSetup(0, 0, &dev_mode, &version), TPM_E_IOERROR,
+ TEST_EQ(RollbackFirmwareSetup(0, 0, dev_mode, &dev_mode, &version),
+ TPM_E_IOERROR,
"RollbackFirmwareSetup() error");
TEST_STR_EQ(mock_calls,
"TlclLibInit()\n",
@@ -717,7 +718,7 @@ static void RollbackFirmwareTest(void) {
/* Developer mode flag gets passed properly */
ResetMocks(0, 0);
dev_mode = 1;
- TEST_EQ(RollbackFirmwareSetup(0, 0, &dev_mode, &version), 0,
+ TEST_EQ(RollbackFirmwareSetup(0, dev_mode, 0, &dev_mode, &version), 0,
"RollbackFirmwareSetup() to dev");
TEST_STR_EQ(mock_calls,
"TlclLibInit()\n"
@@ -731,7 +732,7 @@ static void RollbackFirmwareTest(void) {
"TlclWrite(0x1007, 10)\n"
"TlclRead(0x1007, 10)\n",
"tlcl calls");
- TEST_EQ(mock_rsf.flags, FLAG_LAST_BOOT_DEVELOPER, "fw space flags to dev");
+ TEST_EQ(mock_rsf.flags, FLAG_LAST_BOOT_DEVELOPER, "fw space flags to dev 2");
/* Test write */
ResetMocks(0, 0);
@@ -769,7 +770,7 @@ static void RollbackKernelTest(void) {
/* RollbackKernel*() functions use a global flag inside
* rollback_index.c based on recovery mode, which is set by
* SetupTPM(). Clear the flag for the first set of tests. */
- TEST_EQ(SetupTPM(0, 0, &rsf), 0, "SetupTPM()");
+ TEST_EQ(SetupTPM(0, 0, 0, &rsf), 0, "SetupTPM()");
/* Normal read */
ResetMocks(0, 0);
@@ -830,7 +831,7 @@ static void RollbackKernelTest(void) {
TEST_EQ(RollbackKernelLock(), TPM_E_IOERROR, "RollbackKernelLock() error");
/* Test lock with recovery on; shouldn't lock PP */
- SetupTPM(1, 0, &rsf);
+ SetupTPM(1, 0, 0, &rsf);
ResetMocks(0, 0);
TEST_EQ(RollbackKernelLock(), 0, "RollbackKernelLock() in recovery");
TEST_STR_EQ(mock_calls, "", "no tlcl calls");
diff --git a/tests/vboot_api_init_tests.c b/tests/vboot_api_init_tests.c
index 15907d49..ec1e7fa9 100644
--- a/tests/vboot_api_init_tests.c
+++ b/tests/vboot_api_init_tests.c
@@ -26,7 +26,7 @@ static uint64_t mock_timer;
static int rollback_s3_retval;
static int nv_write_called;
static GoogleBinaryBlockHeader gbb;
-static int mock_dev_mode;
+static int mock_virt_dev_sw;
static uint32_t mock_tpm_version;
static uint32_t mock_rfs_retval;
@@ -55,7 +55,7 @@ static void ResetMocks(void) {
rollback_s3_retval = TPM_SUCCESS;
nv_write_called = 0;
- mock_dev_mode = 0;
+ mock_virt_dev_sw = 0;
mock_tpm_version = 0x10001;
mock_rfs_retval = 0;
}
@@ -87,10 +87,11 @@ uint32_t RollbackS3Resume(void) {
return rollback_s3_retval;
}
-uint32_t RollbackFirmwareSetup(int recovery_mode, int hw_dev_sw,
- int* dev_mode_ptr, uint32_t* version) {
- if (!hw_dev_sw)
- *dev_mode_ptr = mock_dev_mode;
+uint32_t RollbackFirmwareSetup(int recovery_mode, int is_hw_dev,
+ int disable_dev_request,
+ /* two outputs on success */
+ int *is_virt_dev, uint32_t *version) {
+ *is_virt_dev = mock_virt_dev_sw;
*version = mock_tpm_version;
return mock_rfs_retval;
}
@@ -316,16 +317,16 @@ static void VbInitTestTPM(void) {
/* Virtual developer switch, but not enabled. */
ResetMocks();
- iparams.flags = VB_INIT_FLAG_DEV_SWITCH_ON | VB_INIT_FLAG_VIRTUAL_DEV_SWITCH;
+ iparams.flags = VB_INIT_FLAG_VIRTUAL_DEV_SWITCH;
TestVbInit(0, 0, "TPM Dev mode off");
TEST_EQ(shared->recovery_reason, 0, " recovery reason");
TEST_EQ(iparams.out_flags, 0, " out flags");
- TEST_EQ(shared->flags, 0, " shared flags");
+ TEST_EQ(shared->flags, VBSD_HONOR_VIRT_DEV_SWITCH, " shared flags");
/* Virtual developer switch, enabled. */
ResetMocks();
iparams.flags = VB_INIT_FLAG_VIRTUAL_DEV_SWITCH;
- mock_dev_mode = 1;
+ mock_virt_dev_sw = 1;
TestVbInit(0, 0, "TPM Dev mode on");
TEST_EQ(shared->recovery_reason, 0, " recovery reason");
TEST_EQ(iparams.out_flags,
@@ -333,6 +334,27 @@ static void VbInitTestTPM(void) {
VB_INIT_OUT_ENABLE_DISPLAY |
VB_INIT_OUT_ENABLE_USB_STORAGE |
VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
+ TEST_EQ(shared->flags, VBSD_BOOT_DEV_SWITCH_ON | VBSD_HONOR_VIRT_DEV_SWITCH,
+ " shared flags");
+
+ /* Ignore virtual developer switch, even though enabled. */
+ ResetMocks();
+ mock_virt_dev_sw = 1;
+ TestVbInit(0, 0, "TPM Dev mode on but ignored");
+ TEST_EQ(shared->recovery_reason, 0, " recovery reason");
+ TEST_EQ(iparams.out_flags, 0, " out flags");
+ TEST_EQ(shared->flags, 0, " shared flags");
+
+ /* HW dev switch on, no virtual developer switch */
+ ResetMocks();
+ iparams.flags = VB_INIT_FLAG_DEV_SWITCH_ON;
+ TestVbInit(0, 0, "HW Dev mode on");
+ TEST_EQ(shared->recovery_reason, 0, " recovery reason");
+ TEST_EQ(iparams.out_flags,
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE |
+ VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
TEST_EQ(shared->flags, VBSD_BOOT_DEV_SWITCH_ON, " shared flags");
}