diff options
author | Randall Spangler <rspangler@chromium.org> | 2011-07-13 16:31:08 -0700 |
---|---|---|
committer | Randall Spangler <rspangler@chromium.org> | 2011-07-14 17:07:10 -0700 |
commit | 8bf0d5ff0ff77aaf496507bbe8d65a5f3027c80c (patch) | |
tree | 326c2e1495b7c82946a9faba33d93c012a6c7c96 | |
parent | 3a6e2f10b279b9b285ae4b832d2df92a05dacd52 (diff) | |
download | vboot-8bf0d5ff0ff77aaf496507bbe8d65a5f3027c80c.tar.gz |
Add vboot support for RO-normal code path.
BUG=chromium-os:17304
TEST=make && make runtests
Change-Id: I4d0f8afd516649fba67119845ec1c4479ba54c43
Reviewed-on: http://gerrit.chromium.org/gerrit/4065
Reviewed-by: Stefan Reinauer <reinauer@chromium.org>
Tested-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r-- | firmware/include/load_firmware_fw.h | 10 | ||||
-rw-r--r-- | firmware/include/vboot_api.h | 8 | ||||
-rw-r--r-- | firmware/include/vboot_struct.h | 8 | ||||
-rw-r--r-- | firmware/lib/vboot_api_firmware.c | 11 | ||||
-rw-r--r-- | firmware/lib/vboot_api_init.c | 2 | ||||
-rw-r--r-- | firmware/lib/vboot_firmware.c | 89 | ||||
-rw-r--r-- | utility/load_firmware_test.c | 12 |
7 files changed, 78 insertions, 62 deletions
diff --git a/firmware/include/load_firmware_fw.h b/firmware/include/load_firmware_fw.h index 98beabd3..8f0f20db 100644 --- a/firmware/include/load_firmware_fw.h +++ b/firmware/include/load_firmware_fw.h @@ -20,9 +20,6 @@ * VbNvContext (VBNV_RECOVERY_REQUEST). */ #define LOAD_FIRMWARE_REBOOT 2 /* Reboot to same mode as current boot */ -/* Boot flags for LoadFirmware().boot_flags */ -#define BOOT_FLAG_DEVELOPER UINT64_C(0x01) /* Developer switch is on */ - typedef struct LoadFirmwareParams { /* Inputs to LoadFirmware() */ void* gbb_data; /* Pointer to GBB data */ @@ -38,13 +35,12 @@ typedef struct LoadFirmwareParams { void* shared_data_blob; /* Shared data blob buffer. Pass this * data to LoadKernel() in * LoadKernelParams.shared_data_blob. */ - uint64_t shared_data_size; /* On input, set to size of shared data blob + uint32_t shared_data_size; /* On input, set to size of shared data blob * buffer, in bytes. On output, this will * contain the actual data size placed into * the buffer. Caller need only pass that * much data to LoadKernel().*/ - uint64_t boot_flags; /* Boot flags */ VbNvContext* nv_context; /* Context for NV storage. nv_context->raw * must be filled before calling * LoadFirmware(). On output, check @@ -52,10 +48,6 @@ typedef struct LoadFirmwareParams { * nv_context->raw has been modified and * needs saving. */ - /* Outputs from LoadFirmware(); valid only if LoadFirmware() returns - * LOAD_FIRMWARE_SUCCESS. */ - uint64_t firmware_index; /* Firmware index to run. */ - /* Internal data for LoadFirmware() / UpdateFirmwareBodyHash(). */ void* load_firmware_internal; diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h index a97f0e8f..55a0332c 100644 --- a/firmware/include/vboot_api.h +++ b/firmware/include/vboot_api.h @@ -100,6 +100,9 @@ typedef struct VbCommonParams { /* TODO: add a field to VbInitParams which holds a reason code, and report * that via VbSharedData. */ #define VB_INIT_FLAG_PREVIOUS_BOOT_FAIL 0x00000010 +/* Calling firmware supports read only firmware for normal/developer + * boot path. */ +#define VB_INIT_FLAG_RO_NORMAL_SUPPORT 0x00000020 /* Output flags for VbInitParams.out_flags. Used to indicate * potential boot paths and configuration to the calling firmware @@ -143,7 +146,7 @@ enum VbSelectFirmware_t { /* Rewritable firmware A/B for normal or developer path */ VB_SELECT_FIRMWARE_A = 1, VB_SELECT_FIRMWARE_B = 2, - /* Read only firmware for normal or developer path */ + /* Read only firmware for normal or developer path. */ VB_SELECT_FIRMWARE_READONLY = 3 }; @@ -157,7 +160,8 @@ typedef struct VbSelectFirmwareParams { uint32_t verification_size_B; /* Verification block B size in bytes */ /* Outputs from VbSelectFirmware(); valid only if it returns success. */ - uint32_t selected_firmware; /* Main firmware to run; see VB_SELECT_*. */ + uint32_t selected_firmware; /* Main firmware to run; see + * VB_SELECT_FIRMWARE_*. */ } VbSelectFirmwareParams; diff --git a/firmware/include/vboot_struct.h b/firmware/include/vboot_struct.h index dd6a4155..408ca2fe 100644 --- a/firmware/include/vboot_struct.h +++ b/firmware/include/vboot_struct.h @@ -180,6 +180,8 @@ typedef struct VbKernelPreambleHeader { #define VBSD_KERNEL_KEY_VERIFIED 0x00000002 /* LoadFirmware() was told the developer switch was on */ #define VBSD_LF_DEV_SWITCH_ON 0x00000004 +/* LoadFirmware() is requesting the read only normal/dev code path */ +#define VBSD_LF_USE_RO_NORMAL 0x00000008 /* Developer switch was enabled at boot time */ #define VBSD_BOOT_DEV_SWITCH_ON 0x00000010 /* Recovery switch was enabled at boot time */ @@ -188,7 +190,8 @@ typedef struct VbKernelPreambleHeader { #define VBSD_BOOT_FIRMWARE_WP_ENABLED 0x00000040 /* Boot is a S3->S0 resume, not a S5->S0 normal boot */ #define VBSD_BOOT_S3_RESUME 0x00000100 - +/* Read-only firmware supports the normal/developer code path */ +#define VBSD_BOOT_RO_NORMAL_SUPPORT 0x00000200 /* Result codes for VbSharedDataHeader.check_fw_a_result (and b_result) */ #define VBSD_LF_CHECK_NOT_DONE 0 @@ -204,6 +207,9 @@ typedef struct VbKernelPreambleHeader { #define VBSD_LF_CHECK_HASH_WRONG_SIZE 10 #define VBSD_LF_CHECK_VERIFY_BODY 11 #define VBSD_LF_CHECK_VALID 12 +/* Read-only normal path requested by firmware preamble, but + * unsupported by firmware. */ +#define VBSD_LF_CHECK_NO_RO_NORMAL 13 /* Boot mode for VbSharedDataHeader.lk_boot_mode */ #define VBSD_LK_BOOT_MODE_RECOVERY 0 diff --git a/firmware/lib/vboot_api_firmware.c b/firmware/lib/vboot_api_firmware.c index e4e4af02..091d6dd1 100644 --- a/firmware/lib/vboot_api_firmware.c +++ b/firmware/lib/vboot_api_firmware.c @@ -40,11 +40,6 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, p.shared_data_size = cparams->shared_data_size; p.nv_context = &vnc; - /* TODO: LoadFirmware() should use VbSharedDataHeader.flags directly. */ - p.boot_flags = 0; - if (shared->flags & VBSD_BOOT_DEV_SWITCH_ON) - p.boot_flags |= BOOT_FLAG_DEVELOPER; - p.verification_block_0 = fparams->verification_block_A; p.verification_block_1 = fparams->verification_block_B; p.verification_size_0 = fparams->verification_size_A; @@ -75,8 +70,10 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, /* Translate return codes */ if (LOAD_FIRMWARE_SUCCESS == rv) { - /* Found good firmware in either A or B */ - if (0 == p.firmware_index) + if (shared->flags & VBSD_LF_USE_RO_NORMAL) { + /* Request the read-only normal/dev code path */ + fparams->selected_firmware = VB_SELECT_FIRMWARE_READONLY; + } else if (0 == shared->firmware_index) fparams->selected_firmware = VB_SELECT_FIRMWARE_A; else fparams->selected_firmware = VB_SELECT_FIRMWARE_B; diff --git a/firmware/lib/vboot_api_init.c b/firmware/lib/vboot_api_init.c index 890b5768..df831291 100644 --- a/firmware/lib/vboot_api_init.c +++ b/firmware/lib/vboot_api_init.c @@ -49,6 +49,8 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) { shared->flags |= VBSD_BOOT_FIRMWARE_WP_ENABLED; if (iparams->flags & VB_INIT_FLAG_S3_RESUME) shared->flags |= VBSD_BOOT_S3_RESUME; + if (iparams->flags & VB_INIT_FLAG_RO_NORMAL_SUPPORT) + shared->flags |= VBSD_BOOT_RO_NORMAL_SUPPORT; is_s3_resume = (iparams->flags & VB_INIT_FLAG_S3_RESUME ? 1 : 0); diff --git a/firmware/lib/vboot_firmware.c b/firmware/lib/vboot_firmware.c index 1e989a4d..da8ef553 100644 --- a/firmware/lib/vboot_firmware.c +++ b/firmware/lib/vboot_firmware.c @@ -57,7 +57,7 @@ int LoadFirmware(LoadFirmwareParams* params) { int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; /* Clear output params in case we fail */ - params->firmware_index = 0; + shared->firmware_index = 0xFF; VBDEBUG(("LoadFirmware started...\n")); @@ -93,7 +93,7 @@ int LoadFirmware(LoadFirmwareParams* params) { root_key = (VbPublicKey*)((uint8_t*)gbb + gbb->rootkey_offset); /* Parse flags */ - is_dev = (params->boot_flags & BOOT_FLAG_DEVELOPER ? 1 : 0); + is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0); if (is_dev) shared->flags |= VBSD_LF_DEV_SWITCH_ON; @@ -231,44 +231,60 @@ int LoadFirmware(LoadFirmwareParams* params) { if (-1 != good_index) continue; - /* Read the firmware data */ - VBPERFSTART("VB_RFD"); - DigestInit(&lfi->body_digest_context, data_key->algorithm); - lfi->body_size_accum = 0; - if (0 != GetFirmwareBody(params, index)) { - VBDEBUG(("GetFirmwareBody() failed for index %d\n", index)); - *check_result = VBSD_LF_CHECK_GET_FW_BODY; - RSAPublicKeyFree(data_key); - VBPERFEND("VB_RFD"); - continue; - } - if (lfi->body_size_accum != preamble->body_signature.data_size) { - VBDEBUG(("Hash updated %d bytes but expected %d\n", - (int)lfi->body_size_accum, - (int)preamble->body_signature.data_size)); - *check_result = VBSD_LF_CHECK_HASH_WRONG_SIZE; - RSAPublicKeyFree(data_key); + /* Handle preamble flag for using the RO normal/dev code path */ + if (VbGetFirmwarePreambleFlags(preamble) & + VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) { + + /* Fail if calling firmware doesn't support RO normal */ + if (!(shared->flags & VBSD_BOOT_RO_NORMAL_SUPPORT)) { + *check_result = VBSD_LF_CHECK_NO_RO_NORMAL; + RSAPublicKeyFree(data_key); + continue; + } + + /* Indicate that we should use the RO normal code path */ + shared->flags |= VBSD_LF_USE_RO_NORMAL; + + } else { + /* Read the firmware data */ + VBPERFSTART("VB_RFD"); + DigestInit(&lfi->body_digest_context, data_key->algorithm); + lfi->body_size_accum = 0; + if (0 != GetFirmwareBody(params, index)) { + VBDEBUG(("GetFirmwareBody() failed for index %d\n", index)); + *check_result = VBSD_LF_CHECK_GET_FW_BODY; + RSAPublicKeyFree(data_key); + VBPERFEND("VB_RFD"); + continue; + } + if (lfi->body_size_accum != preamble->body_signature.data_size) { + VBDEBUG(("Hash updated %d bytes but expected %d\n", + (int)lfi->body_size_accum, + (int)preamble->body_signature.data_size)); + *check_result = VBSD_LF_CHECK_HASH_WRONG_SIZE; + RSAPublicKeyFree(data_key); + VBPERFEND("VB_RFD"); + continue; + } VBPERFEND("VB_RFD"); - continue; - } - VBPERFEND("VB_RFD"); - - /* Verify firmware data */ - VBPERFSTART("VB_VFD"); - body_digest = DigestFinal(&lfi->body_digest_context); - if (0 != VerifyDigest(body_digest, &preamble->body_signature, data_key)) { - VBDEBUG(("Firmware body verification failed.\n")); - *check_result = VBSD_LF_CHECK_VERIFY_BODY; - RSAPublicKeyFree(data_key); + + /* Verify firmware data */ + VBPERFSTART("VB_VFD"); + body_digest = DigestFinal(&lfi->body_digest_context); + if (0 != VerifyDigest(body_digest, &preamble->body_signature, data_key)) { + VBDEBUG(("Firmware body verification failed.\n")); + *check_result = VBSD_LF_CHECK_VERIFY_BODY; + RSAPublicKeyFree(data_key); + VbExFree(body_digest); + VBPERFEND("VB_VFD"); + continue; + } VbExFree(body_digest); VBPERFEND("VB_VFD"); - continue; } - VBPERFEND("VB_VFD"); - /* Done with the digest and data key, so can free them now */ + /* Done with the data key, so can free it now */ RSAPublicKeyFree(data_key); - VbExFree(body_digest); /* If we're still here, the firmware is valid. */ VBDEBUG(("Firmware %d is valid.\n", index)); @@ -284,7 +300,7 @@ int LoadFirmware(LoadFirmwareParams* params) { /* Save the good index, now that we're sure we can actually use * this firmware. That's the one we'll boot. */ good_index = index; - params->firmware_index = index; + shared->firmware_index = index; /* Since we now know which firmware to boot, we can update the * bootable firmware key block mode. */ boot_fw_keyblock_flags = key_block->key_block_flags; @@ -349,8 +365,7 @@ int LoadFirmware(LoadFirmwareParams* params) { } /* Success */ - VBDEBUG(("Will boot firmware index %d\n", (int)params->firmware_index)); - shared->firmware_index = (uint8_t)params->firmware_index; + VBDEBUG(("Will boot firmware index %d\n", (int)shared->firmware->index)); retval = LOAD_FIRMWARE_SUCCESS; } else { uint8_t a = shared->check_fw_a_result; diff --git a/utility/load_firmware_test.c b/utility/load_firmware_test.c index 872bb4ca..5b5bd9f7 100644 --- a/utility/load_firmware_test.c +++ b/utility/load_firmware_test.c @@ -189,10 +189,12 @@ int DriveLoadFirmware(const void* base_of_rom, const void* fmap, lfp.shared_data_blob = malloc(VB_SHARED_DATA_MIN_SIZE); lfp.shared_data_size = VB_SHARED_DATA_MIN_SIZE; - printf("shared data size 0x%08" PRIx64 "\n", lfp.shared_data_size); - - lfp.boot_flags = boot_flags; - printf("boot flags is 0x%08" PRIx64 "\n", lfp.boot_flags); + printf("shared data size 0x%08" PRIx32 "\n", lfp.shared_data_size); + /* TODO: load_firmware_test was broken in the wrapper API rewrite. + * Nothing uses it, so we haven't noticed yet. Need to fix it. See + * crosbug.com/17564. LoadFirmware() now assumes that VbInit() has + * been called to set up the shared data structure, but that isn't + * happening here. */ status = LoadFirmware(&lfp); status_str = status_string(status); @@ -200,8 +202,6 @@ int DriveLoadFirmware(const void* base_of_rom, const void* fmap, printf("LoadFirmware returns %s\n", status_str); else printf("LoadFirmware returns unknown status code: %d\n", status); - if (status == LOAD_FIRMWARE_SUCCESS) - printf("firmwiare index is %" PRIu64 "\n", lfp.firmware_index); free(lfp.shared_data_blob); |