mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-12 02:45:33 +00:00
Add LoadFirmware() support for NvStorage API
Change-Id: I19f402904978581eb5ca990ffbdf2f762b48c217 BUG=12282 TEST=make H2C firmware and verify using crossystem utility (set fwb_tries, reboot, verify that mainfw_act is B) Review URL: http://codereview.chromium.org/6597018
This commit is contained in:
@@ -19,10 +19,10 @@
|
||||
|
||||
/* Return codes for LoadFirmware() and S3Resume(). */
|
||||
#define LOAD_FIRMWARE_SUCCESS 0 /* Success */
|
||||
#define LOAD_FIRMWARE_RECOVERY 1 /* Reboot to recovery mode */
|
||||
#define LOAD_FIRMWARE_RECOVERY 1 /* Reboot to recovery mode. The specific
|
||||
* recovery reason has been set in
|
||||
* VbNvContext (VBNV_RECOVERY_REQUEST). */
|
||||
#define LOAD_FIRMWARE_REBOOT 2 /* Reboot to same mode as current boot */
|
||||
#define LOAD_FIRMWARE_RECOVERY_TPM 3 /* Reboot to recovery mode due
|
||||
* to TPM error */
|
||||
|
||||
/* Boot flags for LoadFirmware().boot_flags */
|
||||
#define BOOT_FLAG_DEVELOPER UINT64_C(0x01) /* Developer switch is on */
|
||||
@@ -82,6 +82,12 @@ int GetFirmwareBody(LoadFirmwareParams* params, uint64_t firmware_index);
|
||||
|
||||
/* Functions provided by verified boot library to PEI */
|
||||
|
||||
/* Early setup for LoadFirmware(). This should be called as soon as the TPM
|
||||
* is available in the boot process.
|
||||
*
|
||||
* Returns LOAD_FIRMWARE_SUCCESS if successful, error code on failure. */
|
||||
int LoadFirmwareSetup(void);
|
||||
|
||||
/* Attempts to load the rewritable firmware.
|
||||
*
|
||||
* Returns LOAD_FIRMWARE_SUCCESS if successful, error code on failure. */
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "rollback_index.h"
|
||||
#include "utility.h"
|
||||
#include "vboot_common.h"
|
||||
#include "vboot_nvstorage.h"
|
||||
|
||||
/* Static variables for UpdateFirmwareBodyHash(). It's less than
|
||||
* optimal to have static variables in a library, but in UEFI the
|
||||
@@ -31,32 +32,47 @@ void UpdateFirmwareBodyHash(LoadFirmwareParams* params,
|
||||
}
|
||||
|
||||
|
||||
int LoadFirmwareSetup(void) {
|
||||
/* TODO: start initializing the TPM */
|
||||
return LOAD_FIRMWARE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int LoadFirmware(LoadFirmwareParams* params) {
|
||||
|
||||
VbPublicKey* root_key = (VbPublicKey*)params->firmware_root_key_blob;
|
||||
VbLoadFirmwareInternal* lfi;
|
||||
VbNvContext* vnc = params->nv_context;
|
||||
|
||||
uint32_t try_b_count;
|
||||
uint32_t tpm_version = 0;
|
||||
uint64_t lowest_version = 0xFFFFFFFF;
|
||||
uint32_t status;
|
||||
int good_index = -1;
|
||||
int is_dev;
|
||||
int index;
|
||||
int i;
|
||||
|
||||
int retval = LOAD_FIRMWARE_RECOVERY;
|
||||
int recovery = VBNV_RECOVERY_RO_UNSPECIFIED;
|
||||
|
||||
/* Clear output params in case we fail */
|
||||
params->firmware_index = 0;
|
||||
|
||||
VBDEBUG(("LoadFirmware started...\n"));
|
||||
|
||||
/* Setup NV storage */
|
||||
VbNvSetup(vnc);
|
||||
|
||||
if (params->kernel_sign_key_size < sizeof(VbPublicKey)) {
|
||||
VBDEBUG(("Kernel sign key buffer too small\n"));
|
||||
return LOAD_FIRMWARE_RECOVERY;
|
||||
goto LoadFirmwareExit;
|
||||
}
|
||||
|
||||
/* Must have a root key */
|
||||
if (!root_key) {
|
||||
VBDEBUG(("No root key\n"));
|
||||
return LOAD_FIRMWARE_RECOVERY;
|
||||
goto LoadFirmwareExit;
|
||||
}
|
||||
|
||||
/* Parse flags */
|
||||
@@ -68,11 +84,20 @@ int LoadFirmware(LoadFirmwareParams* params) {
|
||||
if (0 != status) {
|
||||
VBDEBUG(("Unable to setup TPM and read stored versions.\n"));
|
||||
VBPERFEND("VB_TPMI");
|
||||
return (status == TPM_E_MUST_REBOOT ?
|
||||
LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY_TPM);
|
||||
if (status == TPM_E_MUST_REBOOT)
|
||||
retval = LOAD_FIRMWARE_REBOOT;
|
||||
else
|
||||
recovery = VBNV_RECOVERY_RO_TPM_ERROR;
|
||||
goto LoadFirmwareExit;
|
||||
}
|
||||
VBPERFEND("VB_TPMI");
|
||||
|
||||
/* Read try-b count and decrement if necessary */
|
||||
VbNvGet(vnc, VBNV_TRY_B_COUNT, &try_b_count);
|
||||
if (0 != try_b_count)
|
||||
VbNvSet(vnc, VBNV_TRY_B_COUNT, try_b_count - 1);
|
||||
VbNvSet(vnc, VBNV_TRIED_FIRMWARE_B, try_b_count ? 1 : 0);
|
||||
|
||||
/* Allocate our internal data */
|
||||
lfi = (VbLoadFirmwareInternal*)Malloc(sizeof(VbLoadFirmwareInternal));
|
||||
if (!lfi)
|
||||
@@ -81,7 +106,7 @@ int LoadFirmware(LoadFirmwareParams* params) {
|
||||
params->load_firmware_internal = (uint8_t*)lfi;
|
||||
|
||||
/* Loop over indices */
|
||||
for (index = 0; index < 2; index++) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
VbKeyBlockHeader* key_block;
|
||||
uint64_t vblock_size;
|
||||
VbFirmwarePreambleHeader* preamble;
|
||||
@@ -90,6 +115,9 @@ int LoadFirmware(LoadFirmwareParams* params) {
|
||||
uint64_t combined_version;
|
||||
uint8_t* body_digest;
|
||||
|
||||
/* If try B count is non-zero try firmware B first */
|
||||
index = (try_b_count ? i : 1 - i);
|
||||
|
||||
/* Verify the key block */
|
||||
VBPERFSTART("VB_VKB");
|
||||
if (0 == index) {
|
||||
@@ -248,8 +276,11 @@ int LoadFirmware(LoadFirmwareParams* params) {
|
||||
VBPERFEND("VB_TPMU");
|
||||
if (0 != status) {
|
||||
VBDEBUG(("Unable to write stored versions.\n"));
|
||||
return (status == TPM_E_MUST_REBOOT ?
|
||||
LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY_TPM);
|
||||
if (status == TPM_E_MUST_REBOOT)
|
||||
retval = LOAD_FIRMWARE_REBOOT;
|
||||
else
|
||||
recovery = VBNV_RECOVERY_RO_TPM_ERROR;
|
||||
goto LoadFirmwareExit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,18 +290,29 @@ int LoadFirmware(LoadFirmwareParams* params) {
|
||||
VBPERFEND("VB_TPML");
|
||||
if (0 != status) {
|
||||
VBDEBUG(("Unable to lock firmware versions.\n"));
|
||||
return (status == TPM_E_MUST_REBOOT ?
|
||||
LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY_TPM);
|
||||
if (status == TPM_E_MUST_REBOOT)
|
||||
retval = LOAD_FIRMWARE_REBOOT;
|
||||
else
|
||||
recovery = VBNV_RECOVERY_RO_TPM_ERROR;
|
||||
goto LoadFirmwareExit;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
VBDEBUG(("Will boot firmware index %d\n", (int)params->firmware_index));
|
||||
return LOAD_FIRMWARE_SUCCESS;
|
||||
retval = LOAD_FIRMWARE_SUCCESS;
|
||||
} else {
|
||||
/* No good firmware, so go to recovery mode. */
|
||||
VBDEBUG(("Alas, no good firmware.\n"));
|
||||
recovery = VBNV_RECOVERY_RO_INVALID_RW;
|
||||
}
|
||||
|
||||
/* If we're still here, no good firmware, so go to recovery mode. */
|
||||
VBDEBUG(("Alas, no good firmware.\n"));
|
||||
return LOAD_FIRMWARE_RECOVERY;
|
||||
LoadFirmwareExit:
|
||||
/* Store recovery request, if any, then tear down non-volatile storage */
|
||||
VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_FIRMWARE_RECOVERY == retval ?
|
||||
recovery : VBNV_RECOVERY_NOT_REQUESTED);
|
||||
VbNvTeardown(vnc);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@@ -278,10 +320,11 @@ int S3Resume(void) {
|
||||
/* Resume the TPM */
|
||||
uint32_t status = 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. */
|
||||
if (status == TPM_SUCCESS)
|
||||
return LOAD_FIRMWARE_SUCCESS;
|
||||
else if (status == TPM_E_MUST_REBOOT)
|
||||
return LOAD_FIRMWARE_REBOOT;
|
||||
else
|
||||
return LOAD_FIRMWARE_RECOVERY_TPM;
|
||||
return LOAD_FIRMWARE_REBOOT;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,11 @@ int VerifyFirmwareDriver_stub(uint8_t* root_key_blob,
|
||||
|
||||
CallerInternal ci;
|
||||
LoadFirmwareParams p;
|
||||
VbNvContext vnc;
|
||||
|
||||
/* TODO: YOU SHOULD CALL LoadFirmwareSetup() AS SOON AS THE TPM
|
||||
* INTERFACE IS AVAILABLE */
|
||||
LoadFirmwareSetup();
|
||||
|
||||
/* Copy the firmware volume pointers to our global variables. */
|
||||
ci.firmwareA = firmwareA;
|
||||
@@ -82,11 +87,14 @@ int VerifyFirmwareDriver_stub(uint8_t* root_key_blob,
|
||||
ci.firmwareA_size = 0;
|
||||
ci.firmwareB_size = 0;
|
||||
|
||||
/* TODO: YOU NEED TO LOAD vnc.raw[] FROM NON-VOLATILE STORAGE */
|
||||
|
||||
/* Set up the params for LoadFirmware() */
|
||||
p.caller_internal = &ci;
|
||||
p.firmware_root_key_blob = root_key_blob;
|
||||
p.verification_block_0 = verification_headerA;
|
||||
p.verification_block_1 = verification_headerB;
|
||||
p.nv_context = &vnc;
|
||||
|
||||
/* Allocate a key blob buffer */
|
||||
p.kernel_sign_key_blob = Malloc(LOAD_FIRMWARE_KEY_BLOB_REC_SIZE);
|
||||
@@ -97,6 +105,11 @@ int VerifyFirmwareDriver_stub(uint8_t* root_key_blob,
|
||||
|
||||
/* Call LoadFirmware() */
|
||||
rv = LoadFirmware(&p);
|
||||
|
||||
if (vnc.raw_changed) {
|
||||
/* TODO: YOU NEED TO SAVE vnc.raw TO NON-VOLATILE STORAGE */
|
||||
}
|
||||
|
||||
if (LOAD_FIRMWARE_SUCCESS == rv) {
|
||||
/* TODO: YOU NEED TO KEEP TRACK OF p.kernel_sign_key_blob AND
|
||||
* p.kernel_sign_key_size SO YOU CAN PASS THEM TO LoadKernel(). */
|
||||
|
||||
@@ -225,8 +225,6 @@ const char* status_string(int status) {
|
||||
return "LOAD_FIRMWARE_RECOVERY";
|
||||
case LOAD_FIRMWARE_REBOOT:
|
||||
return "LOAD_FIRMWARE_REBOOT";
|
||||
case LOAD_FIRMWARE_RECOVERY_TPM:
|
||||
return "LOAD_FIRMWARE_RECOVERY_TPM";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user