diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/include/vboot_api.h | 4 | ||||
-rw-r--r-- | firmware/lib/include/rollback_index.h | 21 | ||||
-rw-r--r-- | firmware/lib/mocked_rollback_index.c | 4 | ||||
-rw-r--r-- | firmware/lib/rollback_index.c | 18 | ||||
-rw-r--r-- | firmware/lib/vboot_api_firmware.c | 47 | ||||
-rw-r--r-- | firmware/lib/vboot_api_init.c | 117 | ||||
-rw-r--r-- | firmware/linktest/main.c | 2 |
7 files changed, 122 insertions, 91 deletions
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h index a5b061b7..b6b73928 100644 --- a/firmware/include/vboot_api.h +++ b/firmware/include/vboot_api.h @@ -165,6 +165,10 @@ typedef struct VbCommonParams { /* Calling firmware supports read only firmware for normal/developer * boot path. */ #define VB_INIT_FLAG_RO_NORMAL_SUPPORT 0x00000020 +/* This platform does not have a physical dev-switch, so we must rely on a + * virtual switch (kept in the TPM) instead. When this flag is set, + * VB_INIT_FLAG_DEV_SWITCH_ON is ignored. */ +#define VB_INIT_FLAG_VIRTUAL_DEV_SWITCH 0x00000040 /* Output flags for VbInitParams.out_flags. Used to indicate * potential boot paths and configuration to the calling firmware diff --git a/firmware/lib/include/rollback_index.h b/firmware/lib/include/rollback_index.h index 4d847626..5a072446 100644 --- a/firmware/lib/include/rollback_index.h +++ b/firmware/lib/include/rollback_index.h @@ -37,10 +37,13 @@ typedef struct RollbackSpaceKernel { /* Last boot was developer mode. TPM ownership is cleared when * transitioning to/from developer mode. */ #define FLAG_LAST_BOOT_DEVELOPER 0x01 -/* There have been one or more boots which left PP unlocked, so the - * contents of the kernel space are untrusted and must be restored - * from the backup copy. */ -#define FLAG_KERNEL_SPACE_USE_BACKUP 0x02 +/* Some systems may not have a dedicated dev-mode switch, but enter and leave + * dev-mode through some recovery-mode magic keypresses. For those systems, + * the dev-mode "switch" state is in this bit (0=normal, 1=dev). To make it + * work, a new flag is passed to VbInit(), indicating that the system lacks a + * physical dev-mode switch. If a physical switch is present, this bit is + * ignored. */ +#define FLAG_VIRTUAL_DEV_MODE_ON 0x02 #define ROLLBACK_SPACE_FIRMWARE_VERSION 2 /* Firmware space - FIRMWARE_NV_INDEX, locked with global lock. */ @@ -64,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. */ -uint32_t RollbackFirmwareSetup(int recovery_mode, int developer_mode, - uint32_t* version); +/* 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); /* Write may be called if the versions change */ uint32_t RollbackFirmwareWrite(uint32_t version); diff --git a/firmware/lib/mocked_rollback_index.c b/firmware/lib/mocked_rollback_index.c index f36bed8a..32082ddd 100644 --- a/firmware/lib/mocked_rollback_index.c +++ b/firmware/lib/mocked_rollback_index.c @@ -27,8 +27,8 @@ uint32_t RollbackS3Resume(void) { } -uint32_t RollbackFirmwareSetup(int recovery_mode, int developer_mode, - uint32_t* version) { +uint32_t RollbackFirmwareSetup(int recovery_mode, int hw_dev_sw, + int* dev_mode_ptr, uint32_t* version) { *version = 0; return TPM_SUCCESS; } diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c index 3b4e4665..038188a8 100644 --- a/firmware/lib/rollback_index.c +++ b/firmware/lib/rollback_index.c @@ -363,6 +363,12 @@ 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)); + /* 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, since it + * can only be set by doing the keyboard-based dev-mode dance. */ + 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)) { @@ -406,8 +412,8 @@ uint32_t RollbackS3Resume(void) { return TPM_SUCCESS; } -uint32_t RollbackFirmwareSetup(int recovery_mode, int developer_mode, - uint32_t* version) { +uint32_t RollbackFirmwareSetup(int recovery_mode, int hw_dev_sw, + int* developer_mode, uint32_t* version) { #ifndef CHROMEOS_ENVIRONMENT /* Initialize the TPM, but ignores return codes. In ChromeOS * environment, don't even talk to the TPM. */ @@ -459,15 +465,17 @@ uint32_t RollbackS3Resume(void) { return result; } -uint32_t RollbackFirmwareSetup(int recovery_mode, int developer_mode, - uint32_t* version) { +uint32_t RollbackFirmwareSetup(int recovery_mode, int hw_dev_sw, + int* dev_mode_ptr, uint32_t* version) { RollbackSpaceFirmware rsf; /* Set version to 0 in case we fail */ *version = 0; - RETURN_ON_FAILURE(SetupTPM(recovery_mode, developer_mode, &rsf)); + RETURN_ON_FAILURE(SetupTPM(recovery_mode, *dev_mode_ptr, &rsf)); *version = rsf.fw_versions; + if (!hw_dev_sw) + *dev_mode_ptr = 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 284dff24..faae7dd0 100644 --- a/firmware/lib/vboot_api_firmware.c +++ b/firmware/lib/vboot_api_firmware.c @@ -14,14 +14,6 @@ #include "vboot_common.h" #include "vboot_nvstorage.h" - -/* Set recovery request */ -static void VbSfRequestRecovery(VbNvContext *vnc, uint32_t recovery_request) { - VBDEBUG(("VbSfRequestRecovery(%d)\n", (int)recovery_request)); - VbNvSet(vnc, VBNV_RECOVERY_REQUEST, recovery_request); -} - - VbError_t VbSelectFirmware(VbCommonParams* cparams, VbSelectFirmwareParams* fparams) { VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob; @@ -29,7 +21,6 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, VbError_t retval = VBERROR_UNKNOWN; /* Assume error until proven successful */ int is_rec = (shared->recovery_reason ? 1 : 0); int is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0); - uint32_t tpm_version = 0; uint32_t tpm_status = 0; /* Start timer */ @@ -39,38 +30,6 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, VbExNvStorageRead(vnc.raw); VbNvSetup(&vnc); - /* Initialize the TPM */ - VBPERFSTART("VB_TPMI"); - tpm_status = RollbackFirmwareSetup(is_rec, is_dev, &tpm_version); - VBPERFEND("VB_TPMI"); - if (0 != tpm_status) { - VBDEBUG(("Unable to setup TPM and read firmware version.\n")); - - if (TPM_E_MUST_REBOOT == tpm_status) { - /* TPM wants to reboot into the same mode we're in now */ - VBDEBUG(("TPM requires a reboot.\n")); - if (!is_rec) { - /* Not recovery mode. Just reboot (not into recovery). */ - retval = VBERROR_TPM_REBOOT_REQUIRED; - goto VbSelectFirmware_exit; - } else if (VBNV_RECOVERY_RO_TPM_REBOOT != shared->recovery_reason) { - /* In recovery mode now, and we haven't requested a TPM reboot yet, - * so request one. */ - VbSfRequestRecovery(&vnc, VBNV_RECOVERY_RO_TPM_REBOOT); - retval = VBERROR_TPM_REBOOT_REQUIRED; - goto VbSelectFirmware_exit; - } - } - - if (!is_rec) { - VbSfRequestRecovery(&vnc, VBNV_RECOVERY_RO_TPM_ERROR); - retval = VBERROR_TPM_FIRMWARE_SETUP; - goto VbSelectFirmware_exit; - } - } - shared->fw_version_tpm_start = tpm_version; - shared->fw_version_tpm = tpm_version; - if (is_rec) { /* Recovery is requested; go straight to recovery without checking the * RW firmware. */ @@ -104,7 +63,7 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, VBPERFEND("VB_TPMU"); if (0 != tpm_status) { VBDEBUG(("Unable to write firmware version to TPM.\n")); - VbSfRequestRecovery(&vnc, VBNV_RECOVERY_RO_TPM_ERROR); + VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_ERROR); retval = VBERROR_TPM_WRITE_FIRMWARE; goto VbSelectFirmware_exit; } @@ -116,7 +75,7 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, VBPERFEND("VB_TPML"); if (0 != tpm_status) { VBDEBUG(("Unable to lock firmware version in TPM.\n")); - VbSfRequestRecovery(&vnc, VBNV_RECOVERY_RO_TPM_ERROR); + VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_ERROR); retval = VBERROR_TPM_LOCK_FIRMWARE; goto VbSelectFirmware_exit; } @@ -128,7 +87,7 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, if (0 != tpm_status) { VBDEBUG(("Unable to update the TPM with boot mode information.\n")); if (!is_rec) { - VbSfRequestRecovery(&vnc, VBNV_RECOVERY_RO_TPM_ERROR); + VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_ERROR); retval = VBERROR_TPM_SET_BOOT_MODE_STATE; goto VbSelectFirmware_exit; } diff --git a/firmware/lib/vboot_api_init.c b/firmware/lib/vboot_api_init.c index b03c3d5a..d64590c4 100644 --- a/firmware/lib/vboot_api_init.c +++ b/firmware/lib/vboot_api_init.c @@ -23,6 +23,10 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) { int is_s3_resume = 0; uint32_t s3_debug_boot = 0; uint32_t require_official_os = 0; + uint32_t tpm_version = 0; + uint32_t tpm_status = 0; + int hw_dev_sw = 1; + int is_dev = 0; VBDEBUG(("VbInit() input flags 0x%x\n", iparams->flags)); @@ -43,8 +47,9 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) { /* Copy boot switch flags */ shared->flags = 0; - if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON) - shared->flags |= VBSD_BOOT_DEV_SWITCH_ON; + 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) @@ -62,7 +67,7 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) { if (is_s3_resume) { VBDEBUG(("VbInit() requesting S3 debug boot\n")); iparams->out_flags |= VB_INIT_OUT_S3_DEBUG_BOOT; - is_s3_resume = 0; /* Proceed as if this is a normal boot */ + is_s3_resume = 0; /* Proceed as if this is a normal boot */ } /* Clear the request even if this is a normal boot, since we don't @@ -93,19 +98,91 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) { if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED) recovery = VBNV_RECOVERY_RO_MANUAL; + /* 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; + + /* 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? */ + if (is_s3_resume) { + if (TPM_SUCCESS != RollbackS3Resume()) { + /* If we can't resume, just do a full reboot. No need to go to recovery + * mode here, since if the TPM is really broken we'll catch it on the + * next boot. */ + 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; + else if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON) + is_dev = 1; + + 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 we have a hardware dev-switch and it's + * enabled. 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. */ + tpm_status = RollbackFirmwareSetup(recovery, hw_dev_sw, + &is_dev, &tpm_version); + VBPERFEND("VB_TPMI"); + if (0 != tpm_status) { + VBDEBUG(("Unable to setup TPM and read firmware version.\n")); + + if (TPM_E_MUST_REBOOT == tpm_status) { + /* TPM wants to reboot into the same mode we're in now */ + VBDEBUG(("TPM requires a reboot.\n")); + if (!recovery) { + /* Not recovery mode. Just reboot (not into recovery). */ + retval = VBERROR_TPM_REBOOT_REQUIRED; + goto VbInit_exit; + } else if (VBNV_RECOVERY_RO_TPM_REBOOT != shared->recovery_reason) { + /* In recovery mode now, and we haven't requested a TPM reboot yet, + * so request one. */ + VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_REBOOT); + retval = VBERROR_TPM_REBOOT_REQUIRED; + goto VbInit_exit; + } + } + + if (!recovery) { + VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_ERROR); + retval = VBERROR_TPM_FIRMWARE_SETUP; + goto VbInit_exit; + } + } + shared->fw_version_tpm_start = tpm_version; + shared->fw_version_tpm = tpm_version; + if (is_dev) + shared->flags |= VBSD_BOOT_DEV_SWITCH_ON; + } + + /* FIXME: May need a GBB flag for initial value of virtual dev-switch */ + + /* Allow BIOS to load arbitrary option ROMs? */ + if (gbb->flags & GBB_FLAG_LOAD_OPTION_ROMS) + iparams->out_flags |= VB_INIT_OUT_ENABLE_OPROM; + + /* The factory may need to boot custom OSes whenever the dev-switch is on */ + if (is_dev && (gbb->flags & GBB_FLAG_ENABLE_ALTERNATE_OS)) + iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS; + /* Set output flags */ if (VBNV_RECOVERY_NOT_REQUESTED != recovery) { /* Requesting recovery mode */ iparams->out_flags |= (VB_INIT_OUT_ENABLE_RECOVERY | - VB_INIT_OUT_CLEAR_RAM | - VB_INIT_OUT_ENABLE_DISPLAY | - VB_INIT_OUT_ENABLE_USB_STORAGE); + VB_INIT_OUT_CLEAR_RAM | + VB_INIT_OUT_ENABLE_DISPLAY | + VB_INIT_OUT_ENABLE_USB_STORAGE); } - else if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON) { + else if (is_dev) { /* Developer switch is on, so need to support dev mode */ iparams->out_flags |= (VB_INIT_OUT_CLEAR_RAM | - VB_INIT_OUT_ENABLE_DISPLAY | - VB_INIT_OUT_ENABLE_USB_STORAGE); + VB_INIT_OUT_ENABLE_DISPLAY | + VB_INIT_OUT_ENABLE_USB_STORAGE); /* ... which may or may not include custom OSes */ VbNvGet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os); if (!require_official_os) @@ -118,27 +195,7 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) { VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 0); } - /* Allow BIOS to load arbitrary option ROMs? */ - if (gbb->flags & GBB_FLAG_LOAD_OPTION_ROMS) - iparams->out_flags |= VB_INIT_OUT_ENABLE_OPROM; - - /* The factory may need to boot custom OSes whenever the dev-switch is on */ - if ((gbb->flags & GBB_FLAG_ENABLE_ALTERNATE_OS) && - (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON)) - iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS; - - /* copy current recovery reason to shared data */ - shared->recovery_reason = (uint8_t)recovery; - - /* If this is a S3 resume, resume the TPM */ - if (is_s3_resume) { - if (TPM_SUCCESS != RollbackS3Resume()) { - /* If we can't resume, just do a full reboot. No need to go to recovery - * mode here, since if the TPM is really broken we'll catch it on the - * next boot. */ - retval = VBERROR_TPM_S3_RESUME; - } - } +VbInit_exit: /* Tear down NV storage */ VbNvTeardown(&vnc); diff --git a/firmware/linktest/main.c b/firmware/linktest/main.c index af5d8d65..9c1cf346 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); + RollbackFirmwareSetup(0, 0, 0, 0); RollbackFirmwareWrite(0); RollbackFirmwareLock(); RollbackKernelRead(0); |