ec_sync: Run EFS2 in romstage
EFS2 allows EC RO to enable PD for special cases. When doing so, it sets NO_BOOT flag to avoid booting the OS. AP needs to get NO_BOOT flag from Cr50 and enforce that. This patch makes verstage get a boot mode and a mirrored hash stored in kernel secdata from Cr50. This patch also makes romstage write an expected EC hash (a.k.a. Hexp) to Cr50 (if there is an update). BUG=b:147298634, chromium:1045217, b:148259137 BRANCH=none TEST=Verify software sync succeeds on Puff. Signed-off-by: dnojiri <dnojiri@chromium.org> Change-Id: I1f387b6e920205b9cc4c8536561f2a279c36413d Reviewed-on: https://review.coreboot.org/c/coreboot/+/40389 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
parent
622c6b84ab
commit
dff56a056c
|
@ -71,6 +71,12 @@ uint32_t antirollback_read_space_firmware(struct vb2_context *ctx);
|
|||
*/
|
||||
uint32_t antirollback_write_space_firmware(struct vb2_context *ctx);
|
||||
|
||||
/**
|
||||
* Read and write kernel space in TPM.
|
||||
*/
|
||||
uint32_t antirollback_read_space_kernel(struct vb2_context *ctx);
|
||||
uint32_t antirollback_write_space_kernel(struct vb2_context *ctx);
|
||||
|
||||
/**
|
||||
* Lock must be called.
|
||||
*/
|
||||
|
|
|
@ -50,7 +50,7 @@ void vboot_sync_ec(void)
|
|||
ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED;
|
||||
|
||||
retval = vb2api_ec_sync(ctx);
|
||||
vboot_save_nvdata_only(ctx);
|
||||
vboot_save_data(ctx);
|
||||
|
||||
switch (retval) {
|
||||
case VB2_SUCCESS:
|
||||
|
|
|
@ -53,6 +53,17 @@ vb2_error_t antirollback_write_space_firmware(struct vb2_context *ctx)
|
|||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
vb2_error_t antirollback_read_space_kernel(struct vb2_context *ctx)
|
||||
{
|
||||
vb2api_secdata_kernel_create(ctx);
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
vb2_error_t antirollback_write_space_kernel(struct vb2_context *ctx)
|
||||
{
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
vb2_error_t antirollback_lock_space_firmware(void)
|
||||
{
|
||||
return VB2_SUCCESS;
|
||||
|
|
|
@ -80,6 +80,22 @@ static uint32_t read_space_firmware(struct vb2_context *ctx)
|
|||
return TPM_E_CORRUPTED_STATE;
|
||||
}
|
||||
|
||||
uint32_t antirollback_read_space_kernel(struct vb2_context *ctx)
|
||||
{
|
||||
uint8_t size = VB2_SECDATA_KERNEL_MIN_SIZE;
|
||||
|
||||
RETURN_ON_FAILURE(tlcl_read(KERNEL_NV_INDEX, ctx->secdata_kernel,
|
||||
size));
|
||||
|
||||
if (vb2api_secdata_kernel_check(ctx, &size)
|
||||
== VB2_ERROR_SECDATA_KERNEL_INCOMPLETE)
|
||||
/* Re-read. vboot will run the check and handle errors. */
|
||||
RETURN_ON_FAILURE(tlcl_read(KERNEL_NV_INDEX,
|
||||
ctx->secdata_kernel, size));
|
||||
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t read_space_rec_hash(uint8_t *data)
|
||||
{
|
||||
RETURN_ON_FAILURE(tlcl_read(REC_HASH_NV_INDEX, data,
|
||||
|
@ -440,6 +456,15 @@ uint32_t antirollback_write_space_firmware(struct vb2_context *ctx)
|
|||
VB2_SECDATA_FIRMWARE_SIZE);
|
||||
}
|
||||
|
||||
uint32_t antirollback_write_space_kernel(struct vb2_context *ctx)
|
||||
{
|
||||
/* Learn the expected size. */
|
||||
uint8_t size = VB2_SECDATA_KERNEL_MIN_SIZE;
|
||||
vb2api_secdata_kernel_check(ctx, &size);
|
||||
|
||||
return write_secdata(KERNEL_NV_INDEX, ctx->secdata_kernel, size);
|
||||
}
|
||||
|
||||
uint32_t antirollback_read_space_rec_hash(uint8_t *data, uint32_t size)
|
||||
{
|
||||
if (size != REC_HASH_NV_SIZE) {
|
||||
|
|
|
@ -61,7 +61,6 @@ static inline void vboot_run_logic(void) {}
|
|||
static inline int vboot_locate_cbfs(struct region_device *rdev) { return -1; }
|
||||
#endif
|
||||
|
||||
void vboot_save_nvdata_only(struct vb2_context *ctx);
|
||||
void vboot_save_data(struct vb2_context *ctx);
|
||||
|
||||
/*
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <cbmem.h>
|
||||
#include <fmap.h>
|
||||
#include <security/tpm/tspi/crtm.h>
|
||||
#include <security/tpm/tss/vendor/cr50/cr50.h>
|
||||
#include <security/vboot/misc.h>
|
||||
#include <security/vboot/vbnv.h>
|
||||
#include <security/vboot/tpm_common.h>
|
||||
|
@ -207,10 +208,21 @@ static vb2_error_t hash_body(struct vb2_context *ctx,
|
|||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
void vboot_save_nvdata_only(struct vb2_context *ctx)
|
||||
void vboot_save_data(struct vb2_context *ctx)
|
||||
{
|
||||
assert(!(ctx->flags & (VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED |
|
||||
VB2_CONTEXT_SECDATA_KERNEL_CHANGED)));
|
||||
if (ctx->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED &&
|
||||
(CONFIG(VBOOT_MOCK_SECDATA) || tlcl_lib_init() == VB2_SUCCESS)) {
|
||||
printk(BIOS_INFO, "Saving secdata firmware\n");
|
||||
antirollback_write_space_firmware(ctx);
|
||||
ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED;
|
||||
}
|
||||
|
||||
if (ctx->flags & VB2_CONTEXT_SECDATA_KERNEL_CHANGED &&
|
||||
(CONFIG(VBOOT_MOCK_SECDATA) || tlcl_lib_init() == VB2_SUCCESS)) {
|
||||
printk(BIOS_INFO, "Saving secdata kernel\n");
|
||||
antirollback_write_space_kernel(ctx);
|
||||
ctx->flags &= ~VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
|
||||
}
|
||||
|
||||
if (ctx->flags & VB2_CONTEXT_NVDATA_CHANGED) {
|
||||
printk(BIOS_INFO, "Saving nvdata\n");
|
||||
|
@ -219,23 +231,57 @@ void vboot_save_nvdata_only(struct vb2_context *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
void vboot_save_data(struct vb2_context *ctx)
|
||||
{
|
||||
if (ctx->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED) {
|
||||
printk(BIOS_INFO, "Saving secdata\n");
|
||||
antirollback_write_space_firmware(ctx);
|
||||
ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED;
|
||||
}
|
||||
|
||||
vboot_save_nvdata_only(ctx);
|
||||
}
|
||||
|
||||
static uint32_t extend_pcrs(struct vb2_context *ctx)
|
||||
{
|
||||
return vboot_extend_pcr(ctx, 0, BOOT_MODE_PCR) ||
|
||||
vboot_extend_pcr(ctx, 1, HWID_DIGEST_PCR);
|
||||
}
|
||||
|
||||
#define EC_EFS_BOOT_MODE_NORMAL 0x00
|
||||
#define EC_EFS_BOOT_MODE_NO_BOOT 0x01
|
||||
|
||||
static const char *get_boot_mode_string(uint8_t boot_mode)
|
||||
{
|
||||
if (boot_mode == EC_EFS_BOOT_MODE_NORMAL)
|
||||
return "NORMAL";
|
||||
else if (boot_mode == EC_EFS_BOOT_MODE_NO_BOOT)
|
||||
return "NO_BOOT";
|
||||
else
|
||||
return "UNDEFINED";
|
||||
}
|
||||
|
||||
static void check_boot_mode(struct vb2_context *ctx)
|
||||
{
|
||||
uint8_t boot_mode;
|
||||
int rv;
|
||||
|
||||
rv = tlcl_cr50_get_boot_mode(&boot_mode);
|
||||
switch (rv) {
|
||||
case TPM_E_NO_SUCH_COMMAND:
|
||||
printk(BIOS_WARNING, "Cr50 does not support GET_BOOT_MODE.\n");
|
||||
/* Proceed to legacy boot model. */
|
||||
return;
|
||||
case TPM_SUCCESS:
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_ERR,
|
||||
"Communication error in getting Cr50 boot mode.\n");
|
||||
if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE)
|
||||
/* Continue to boot in recovery mode */
|
||||
return;
|
||||
vb2api_fail(ctx, VB2_RECOVERY_CR50_BOOT_MODE, rv);
|
||||
vboot_save_data(ctx);
|
||||
vboot_reboot();
|
||||
return;
|
||||
}
|
||||
|
||||
printk(BIOS_INFO, "Cr50 says boot_mode is %s(0x%02x).\n",
|
||||
get_boot_mode_string(boot_mode), boot_mode);
|
||||
|
||||
if (boot_mode == EC_EFS_BOOT_MODE_NO_BOOT)
|
||||
ctx->flags |= VB2_CONTEXT_NO_BOOT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify and select the firmware in the RW image
|
||||
*
|
||||
|
@ -268,8 +314,10 @@ void verstage_main(void)
|
|||
* check the return value here because vb2api_fw_phase1 will catch
|
||||
* invalid secdata and tell us what to do (=reboot). */
|
||||
timestamp_add_now(TS_START_TPMINIT);
|
||||
if (vboot_setup_tpm(ctx) == TPM_SUCCESS)
|
||||
if (vboot_setup_tpm(ctx) == TPM_SUCCESS) {
|
||||
antirollback_read_space_firmware(ctx);
|
||||
antirollback_read_space_kernel(ctx);
|
||||
}
|
||||
timestamp_add_now(TS_END_TPMINIT);
|
||||
|
||||
if (get_recovery_mode_switch()) {
|
||||
|
@ -359,6 +407,9 @@ void verstage_main(void)
|
|||
timestamp_add_now(TS_END_TPMPCR);
|
||||
}
|
||||
|
||||
if (CONFIG(TPM_CR50))
|
||||
check_boot_mode(ctx);
|
||||
|
||||
/* Lock TPM */
|
||||
|
||||
timestamp_add_now(TS_START_TPMLOCK);
|
||||
|
|
Loading…
Reference in New Issue