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>
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index b6b7392..50d0f81 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -100,7 +100,7 @@
/* 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 @@
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 0f6b98d..d894e23 100644
--- a/firmware/include/vboot_struct.h
+++ b/firmware/include/vboot_struct.h
@@ -231,6 +231,8 @@
#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 5a07244..20df5b3 100644
--- a/firmware/lib/include/rollback_index.h
+++ b/firmware/lib/include/rollback_index.h
@@ -67,11 +67,11 @@
/* 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 @@
/* 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 32082dd..f884dae 100644
--- a/firmware/lib/mocked_rollback_index.c
+++ b/firmware/lib/mocked_rollback_index.c
@@ -27,8 +27,9 @@
}
-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 5cd1356..668312e 100644
--- a/firmware/lib/rollback_index.c
+++ b/firmware/lib/rollback_index.c
@@ -131,6 +131,28 @@
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 @@
* 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 @@
}
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 @@
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 @@
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 faae7dd..cffc462 100644
--- a/firmware/lib/vboot_api_firmware.c
+++ b/firmware/lib/vboot_api_firmware.c
@@ -33,8 +33,7 @@
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 3432309..bff57bd 100644
--- a/firmware/lib/vboot_api_init.c
+++ b/firmware/lib/vboot_api_init.c
@@ -25,7 +25,10 @@
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 @@
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 @@
* 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 @@
/* 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 @@
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 @@
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 @@
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 891807a..b0a04ac 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -110,6 +110,7 @@
/* 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 @@
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 @@
}
+/* 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 @@
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 @@
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 @@
}
}
+ /* 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 @@
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 @@
/* 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 @@
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 3649fd1..e48623b 100644
--- a/firmware/lib/vboot_display.c
+++ b/firmware/lib/vboot_display.c
@@ -219,6 +219,12 @@
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 @@
VbDisplayScreenFromGBB_exit:
+ VBDEBUG(("leaving VbDisplayScreenFromGBB() with %d\n",retval));
/* Free the bitmap data copy */
VbExFree(bmpfv);
return retval;
@@ -590,7 +597,6 @@
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 9c1cf34..020b589 100644
--- a/firmware/linktest/main.c
+++ b/firmware/linktest/main.c
@@ -29,7 +29,7 @@
/* 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 98d7dcd..6de33bc 100644
--- a/tests/rollback_index2_tests.c
+++ b/tests/rollback_index2_tests.c
@@ -558,7 +558,7 @@
/* 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 @@
/* 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 @@
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 @@
/* 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 @@
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 @@
/* 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 @@
/* 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 @@
"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 @@
"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 @@
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 @@
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 @@
/* 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 @@
"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 @@
/* 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 @@
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 15907d4..ec1e7fa 100644
--- a/tests/vboot_api_init_tests.c
+++ b/tests/vboot_api_init_tests.c
@@ -26,7 +26,7 @@
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 @@
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 @@
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 @@
/* 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 @@
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");
}