From c5322ba116003017deab926f5d1e9bdd16f649b8 Mon Sep 17 00:00:00 2001 From: Namyoon Woo Date: Fri, 6 Dec 2019 13:40:18 -0800 Subject: read EC Firmware hash from kernel secdata during board init Cr50 reads EC Firmware hash from kernel secdata. This data shall be used for EC-EFS (Early Firmware Selection) procedure. BUG=chromium:1020578, b:148489182 BRANCH=cr50 TEST=none Change-Id: Id8942b5b49dd5b0412d198a12ee0bf87fd59d47f Signed-off-by: Namyoon Woo Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1956159 Reviewed-by: Vadim Bendebury --- board/cr50/ec_comm.h | 4 ++++ board/cr50/ec_efs.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++- board/cr50/tpm2/NVMem.c | 9 ++++++++ include/common.h | 2 ++ include/tpm_nvmem.h | 3 ++- include/vboot.h | 18 +++++++++++++++ 6 files changed, 95 insertions(+), 2 deletions(-) diff --git a/board/cr50/ec_comm.h b/board/cr50/ec_comm.h index 9e84a715e1..bec2deb57b 100644 --- a/board/cr50/ec_comm.h +++ b/board/cr50/ec_comm.h @@ -36,4 +36,8 @@ void ec_efs_reset(void); uint16_t ec_efs_set_boot_mode(const char *data, const uint8_t size); /* Verify the given hash data against the EC-FW hash from kernel secdata */ uint16_t ec_efs_verify_hash(const char *hash_data, const uint8_t size); + +/* Re-load EC Hash code from TPM Kernel Secdata */ +void ec_efs_refresh(void); + #endif /* __CROS_EC_COMM_H */ diff --git a/board/cr50/ec_efs.c b/board/cr50/ec_efs.c index da5a31f019..677fb7d7f9 100644 --- a/board/cr50/ec_efs.c +++ b/board/cr50/ec_efs.c @@ -7,10 +7,13 @@ #include "common.h" #include "console.h" #include "ec_comm.h" +#include "crc8.h" #include "ec_commands.h" #include "hooks.h" #include "registers.h" #include "system.h" +#include "tpm_nvmem.h" +#include "tpm_nvmem_ops.h" #include "vboot.h" #ifdef CR50_DEV @@ -48,6 +51,44 @@ static void set_boot_mode_(uint8_t mode_val) GREG32(PMU, PWRDN_SCRATCH20) |= mode_val; } +static int load_ec_hash_(uint8_t * const ec_hash) +{ + struct vb2_secdata_kernel secdata; + const uint8_t secdata_size = sizeof(struct vb2_secdata_kernel); + uint8_t size_to_crc; + uint8_t struct_size; + uint8_t crc; + + if (read_tpm_nvmem(KERNEL_NV_INDEX, secdata_size, + (void *)&secdata) != tpm_read_success) + return EC_ERROR_VBOOT_DATA_UNDERSIZED; + + /* + * Check struct version. CRC offset may be different with old struct + * version + */ + if (secdata.struct_version < VB2_SECDATA_KERNEL_STRUCT_VERSION_MIN) + return EC_ERROR_VBOOT_DATA_INCOMPATIBLE; + + /* Check struct size. */ + struct_size = secdata.struct_size; + if (struct_size != secdata_size) + return EC_ERROR_VBOOT_DATA; + + /* Check CRC */ + size_to_crc = struct_size - + offsetof(struct vb2_secdata_kernel, crc8) - + sizeof(secdata.crc8); + crc = crc8((uint8_t *)&secdata.reserved0, size_to_crc); + if (crc != secdata.crc8) + return EC_ERROR_CRC; + + /* Read hash and copy to hash */ + memcpy(ec_hash, secdata.ec_hash, sizeof(secdata.ec_hash)); + + return EC_SUCCESS; +} + /* * Initialize EC-EFS context. */ @@ -66,7 +107,11 @@ static void ec_efs_init_(void) else ec_efs_reset(); - /* TODO(crbug/1020578): Read Hash from Kernel NV Index */ + /* Read an EC hash in kernel secdata (TPM kernel NV index). */ + if (ec_efs_ctx.hash_is_loaded) + return; + + ec_efs_refresh(); } DECLARE_HOOK(HOOK_INIT, ec_efs_init_, HOOK_PRIO_DEFAULT); @@ -74,3 +119,17 @@ void ec_efs_reset(void) { set_boot_mode_(EC_EFS_BOOT_MODE_NORMAL); } + +void ec_efs_refresh(void) +{ + int rv; + + rv = load_ec_hash_(ec_efs_ctx.hash); + if (rv == EC_SUCCESS) { + ec_efs_ctx.hash_is_loaded = 1; + } else { + ec_efs_ctx.hash_is_loaded = 0; + cprints(CC_SYSTEM, "load_ec_hash error: 0x%x\n", rv); + } + ec_efs_ctx.secdata_error_code = rv; +} diff --git a/board/cr50/tpm2/NVMem.c b/board/cr50/tpm2/NVMem.c index e1a14b4536..052165d5b6 100644 --- a/board/cr50/tpm2/NVMem.c +++ b/board/cr50/tpm2/NVMem.c @@ -14,9 +14,12 @@ #include "Platform.h" #include "PlatformData.h" +#include "TPM_Types.h" #include "TpmError.h" #include "assert.h" +#include "ec_comm.h" #include "nvmem.h" +#include "tpm_nvmem.h" /* Local state */ static struct { @@ -188,3 +191,9 @@ void _plat__ClearNvAvail(void) local_state.s_NvIsAvailable = FALSE; return; } + +void _plat__NvInformIndexDataChanged(unsigned int handle) +{ + if (handle == (HR_NV_INDEX + KERNEL_NV_INDEX)) + ec_efs_refresh(); +} diff --git a/include/common.h b/include/common.h index 99e9ad91c9..62f7d438d0 100644 --- a/include/common.h +++ b/include/common.h @@ -239,6 +239,8 @@ enum ec_error_list { /* Verified boot data errors */ EC_ERROR_VBOOT_DATA = 0x1200, EC_ERROR_VBOOT_DATA_VERIFY = 0x1201, + EC_ERROR_VBOOT_DATA_INCOMPATIBLE = 0x1202, + EC_ERROR_VBOOT_DATA_UNDERSIZED = 0x1203, /* Module-internal error codes may use this range. */ EC_ERROR_INTERNAL_FIRST = 0x10000, diff --git a/include/tpm_nvmem.h b/include/tpm_nvmem.h index 2508c9ae65..3315148323 100644 --- a/include/tpm_nvmem.h +++ b/include/tpm_nvmem.h @@ -8,6 +8,7 @@ #define __CROS_EC_TPM_NVMEM_H #define FIRMWARE_NV_INDEX 0x1007 -#define FWMP_NV_INDEX 0x100a +#define KERNEL_NV_INDEX 0x1008 +#define FWMP_NV_INDEX 0x100a #endif /* __CROS_EC_TPM_NVMEM_H */ diff --git a/include/vboot.h b/include/vboot.h index 195db31a54..ba924508c7 100644 --- a/include/vboot.h +++ b/include/vboot.h @@ -72,6 +72,24 @@ enum ec_efs_boot_mode { EC_EFS_BOOT_MODE_LIMIT = 255, }; +/**************************************************************************** + * This is quoted from 2secdata_struct.h in the directory, + * src/platform/vboot_reference/firmware/2lib/include/. + ****************************************************************************/ + +/* Kernel secure storage space */ +#define VB2_SECDATA_KERNEL_STRUCT_VERSION_MIN 0x10 +#define VB2_SECDATA_KERNEL_UID 0x4752574c /* 'LWRG' */ +struct vb2_secdata_kernel { + uint8_t struct_version; /* top-half:major. bottom-half:minor. */ + uint8_t struct_size; /* Whole structure size */ + uint8_t crc8; /* CRC for everything below */ + uint8_t reserved0; + + uint32_t kernel_versions; /* Kernel versions */ + uint8_t ec_hash[SHA256_DIGEST_SIZE]; +} __packed; + /** * Validate key contents. * -- cgit v1.2.1