Hello Philipp Deppenwiese,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/42712
to review the following change.
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
security/intel/txt: Add Intel TXT support
* Add TXT ramstage driver ** Show startup errors ** Check for TXT reset ** Check for Secrets-in-memory ** Add assembly for GETSEC instruction ** Check platform state if GETSEC instruction is supported ** Configure TXT memory regions ** Lock TXT ** Protect TSEG using DMA protected regions ** Place SINIT ACM ** Print information about ACMs
* Extend security_clear_dram_request() ** To clear all DRAM if secrets are in memory
Tested on OCP Wedge100s and Facebook Watson * Able to enter a Measure Launch Environment using SINIT ACM and TBOOT * Secrets in Memory bit is set on ungraceful shutdown * Memory is cleared after ungraceful shutdown
Change-Id: Iaf4be7f016cc12d3971e1e1fe171e6665e44c284 Signed-off-by: Philipp Deppenwiese zaolin.daisuki@gmail.com --- M src/security/intel/txt/Kconfig M src/security/intel/txt/Makefile.inc A src/security/intel/txt/common.c A src/security/intel/txt/getsec.c A src/security/intel/txt/getsec_enteraccs.S A src/security/intel/txt/logging.c A src/security/intel/txt/ramstage.c A src/security/intel/txt/txt.h A src/security/intel/txt/txt_getsec.h A src/security/intel/txt/txt_register.h M src/security/memory/memory.c 11 files changed, 1,990 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/42712/1
diff --git a/src/security/intel/txt/Kconfig b/src/security/intel/txt/Kconfig index 97d24fd..140312a 100644 --- a/src/security/intel/txt/Kconfig +++ b/src/security/intel/txt/Kconfig @@ -22,7 +22,7 @@ depends on (TPM1 || TPM2) depends on CPU_INTEL_FIRMWARE_INTERFACE_TABLE depends on PLATFORM_HAS_DRAM_CLEAR - depends on SOC_INTEL_FSP_BROADWELL_DE || SOC_INTEL_COMMON_BLOCK_SA + depends on SOC_INTEL_FSP_BROADWELL_DE
if INTEL_TXT
@@ -46,6 +46,12 @@ access to Intel resources. Or for some platforms found inside the blob repository.
+config INTEL_TXT_LOGGING + bool "Enable verbose logging" + help + Print more TXT related debug output. + Use in preproduction environments only. + config INTEL_TXT_BIOSACM_ALIGNMENT hex default 0x20000 # 128KB diff --git a/src/security/intel/txt/Makefile.inc b/src/security/intel/txt/Makefile.inc index 38eb65d..4ecde3e 100644 --- a/src/security/intel/txt/Makefile.inc +++ b/src/security/intel/txt/Makefile.inc @@ -1,5 +1,13 @@ ifeq ($(CONFIG_INTEL_TXT),y)
+romstage-y += common.c +ramstage-y += common.c +ramstage-y += ramstage.c +ramstage-y += getsec_enteraccs.S +ramstage-y += getsec.c +ramstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c +romstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c + cbfs-files-y += txt_bios_acm.bin txt_bios_acm.bin-file := $(CONFIG_INTEL_TXT_BIOSACM_FILE) txt_bios_acm.bin-type := raw diff --git a/src/security/intel/txt/common.c b/src/security/intel/txt/common.c new file mode 100644 index 0000000..61f2034 --- /dev/null +++ b/src/security/intel/txt/common.c @@ -0,0 +1,506 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 9elements Agency GmbH + * Copyright (C) 2019 Facebook Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/mmio.h> +#include <string.h> +#include <console/console.h> +#include <stdint.h> +#include <cbfs.h> +#include <cpu/x86/lapic.h> +#include <cpu/x86/cr.h> +#include <cpu/x86/mp.h> +#include <lib.h> + +#include "txt.h" +#include "txt_register.h" +#include "txt_getsec.h" + +/** + * Dump the ACM error status bits. + * + * @param acm_error The status register to dump + * @return -1 on error (register is not valid) + * 0 on error (Class > 0 and Major > 0) + * 1 on success (Class == 0 and Major == 0 and progress > 0) + */ +int intel_txt_log_acm_error(const uint32_t acm_error) +{ + if (acm_error & ACMERROR_TXT_VALID) { + const uint8_t type = (acm_error & ACMERROR_TXT_TYPE_CODE) + >> ACMERROR_TXT_TYPE_SHIFT; + + switch (type) { + case ACMERROR_TXT_AC_MODULE_TYPE_BIOS: + printk(BIOS_ERR, "BIOSACM"); + break; + case ACMERROR_TXT_AC_MODULE_TYPE_SINIT: + printk(BIOS_ERR, "SINIT"); + break; + default: + printk(BIOS_ERR, "ACM"); + break; + } + printk(BIOS_ERR, ": Error code valid\n"); + + if (acm_error & ACMERROR_TXT_EXTERNAL) + printk(BIOS_ERR, " Caused by: External\n"); + else + printk(BIOS_ERR, " Caused by: Processor\n"); + + const uint32_t class = (acm_error & ACMERROR_TXT_CLASS_CODE) + >> ACMERROR_TXT_CLASS_SHIFT; + const uint32_t major = (acm_error & ACMERROR_TXT_MAJOR_CODE) + >> ACMERROR_TXT_MAJOR_SHIFT; + const uint32_t minor = (acm_error & ACMERROR_TXT_MINOR_CODE) + >> ACMERROR_TXT_MINOR_SHIFT; + const uint32_t progress = (acm_error & ACMERROR_TXT_PROGRESS_CODE) + >> ACMERROR_TXT_PROGRESS_SHIFT; + + if (!minor) { + if (class == 0 && major == 0 && progress > 0) { + printk(BIOS_ERR, " Execution successful\n"); + printk(BIOS_ERR, " Progress code 0x%x\n", + progress); + } else { + printk(BIOS_ERR, " Error Class: %x\n", class); + printk(BIOS_ERR, " Error: %x.%x\n", major, progress); + } + } else { + printk(BIOS_ERR, " ACM didn't start\n"); + printk(BIOS_ERR, " Error Type: 0x%x\n", acm_error & 0xffffff); + return -1; + } + + return (acm_error & ACMERROR_TXT_EXTERNAL) && + class == 0 && + major == 0 && + progress > 0; + } + + return -1; +} + +void intel_txt_log_spad(void) +{ + const uint64_t acm_status = read64((void *)TXT_SPAD); + + printk(BIOS_INFO, "TXT-STS: ACM verification "); + + if (acm_status & ACMSTS_VERIFICATION_ERROR) + printk(BIOS_INFO, "error\n"); + else + printk(BIOS_INFO, "successful\n"); + + printk(BIOS_INFO, "TXT-STS: IBB "); + + if (!(acm_status & ACMSTS_IBB_MEASURED)) + printk(BIOS_INFO, "not measured\n"); + else + printk(BIOS_INFO, "measured\n"); + + printk(BIOS_INFO, "TXT-STS: TXT is "); + + if (acm_status & ACMSTS_TXT_DISABLED) + printk(BIOS_INFO, "disabled\n"); + else + printk(BIOS_INFO, "not disabled\n"); + + printk(BIOS_INFO, "TXT-STS: BIOS is "); + + if (acm_status & ACMSTS_BIOS_TRUSTED) + printk(BIOS_INFO, "trusted\n"); + else + printk(BIOS_INFO, "not trusted\n"); +} + +/* Returns true if secrets might be in memory */ +bool intel_txt_memory_has_secrets(void) +{ + bool ret; + if (!CONFIG(INTEL_TXT)) + return false; + + ret = (read8((void *)TXT_ESTS) & TXT_ESTS_WAKE_ERROR_STS) || + (read64((void *)TXT_E2STS) & TXT_E2STS_SECRET_STS); + + if (ret) + printk(BIOS_CRIT, "TXT-STS: Secrets in memory!\n"); + return ret; +} + +static struct acm_info_table *find_info_table(const void *ptr) +{ + const struct acm_header_v0 *acm_header = (struct acm_header_v0*)ptr; + + return (struct acm_info_table *)(ptr + + (acm_header->header_len + acm_header->scratch_size) * 4); +} + +/** + * Validate that the provided ACM is useable on this platform. + */ +static int validate_acm(const void *ptr) +{ + const struct acm_header_v0 *acm_header = (struct acm_header_v0*)ptr; + uint32_t max_size_acm_area = 0; + + if (acm_header->module_type != CHIPSET_ACM) + return -1; + + /* Seems inconsistent accross generations. */ + if (acm_header->module_sub_type != 0 && acm_header->module_sub_type != 1) + return -2; + + if (acm_header->module_vendor != INTEL_ACM_VENDOR) + return -3; + + if (((acm_header->header_len + acm_header->scratch_size) * 4 + + sizeof(struct acm_info_table)) > (acm_header->size & 0xffffff) * 4) { + return -4; + } + + if (!getsec_parameter(NULL, NULL, &max_size_acm_area, NULL, NULL, NULL)) + return -5; + + /* + * Causes #GP if acm_header->size > processor internal authenticated + * code area capacity. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + */ + const size_t acm_len = 1UL << log2_ceil((acm_header->size & 0xffffff) << 2); + if (max_size_acm_area < acm_len) { + printk(BIOS_ERR, "TEE-TXT: BIOS ACM doesn't fit into AC execution region\n"); + return -6; + } + + struct acm_info_table *info = find_info_table(ptr); + if (!info) + return -7; + if (info->chipset_acm_type != BIOS) + return -8; + + static const u8 acm_uuid[] = { + 0xaa, 0x3a, 0xc0, 0x7f, 0xa7, 0x46, 0xdb, 0x18, 0x2e, 0xac, 0x69, 0x8f, 0x8d, + 0x41, 0x7f, 0x5a + }; + if (memcmp(acm_uuid, info->uuid, sizeof(acm_uuid)) != 0) + return -9; + + if ((acm_header->flags & ACM_FORMAT_FLAGS_DEBUG) == + (read64((void *)TXT_VER_FSBIF) & TXT_VER_PRODUCTION_FUSED)) + return -10; + + return 0; +} + +/* + * Test all bits for TXT execution. + * + * @return 0 on success + */ +int intel_txt_run_bios_acm(const u8 input_params) +{ + struct cbfsf file; + void *acm_data; + struct region_device acm; + size_t acm_len; + int ret; + + if (cbfs_boot_locate(&file, TXT_FILE_BIOS_ACM, NULL)) { + printk(BIOS_ERR, "TEE-TXT: Couldn't locate BIOS ACM in CBFS.\n"); + return -1; + } + + cbfs_file_data(&acm, &file); + acm_data = rdev_mmap_full(&acm); + acm_len = region_device_sz(&acm); + if (!acm_data || acm_len == 0) { + printk(BIOS_ERR, "TEE-TXT: Couldn't map BIOS ACM from CBFS.\n"); + return -1; + } + + /* + * CPU enforces only 4KiB alignment. + * Chapter A.1.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + if (((uintptr_t)acm_data) % 4096 != 0) { + printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't mapped at page boundary.\n"); + rdev_munmap(&acm, acm_data); + return -1; + } + + /* + * Causes #GP if not multiple of 64. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + */ + if (acm_len % 64 != 0) { + printk(BIOS_ERR, "TEE-TXT: BIOS ACM size isn't multiple of 64.\n"); + rdev_munmap(&acm, acm_data); + return -1; + } + + /* + * The ACM should be aligned to it's size, but that's not possible, as + * some ACMs are not power of two. Use the next power of two for verification. + */ + if ((uintptr_t)acm_data & ((1UL << log2_ceil(acm_len)) - 1)) { + printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't aligned to its size.\n"); + rdev_munmap(&acm, acm_data); + return -1; + } + + if (CONFIG(INTEL_TXT_LOGGING)) + txt_dump_acm_info(acm_data); + + ret = validate_acm(acm_data); + if (ret < 0) { + printk(BIOS_ERR, "TEE-TXT: Validation of ACM failed with: %d\n", ret); + rdev_munmap(&acm, acm_data); + return ret; + } + + /* Call into assembly which invokes the referenced ACM */ + getsec_enteraccs(input_params, (uintptr_t)acm_data, acm_len); + + rdev_munmap(&acm, acm_data); + + const uint64_t acm_status = read64((void *)TXT_SPAD); + if (acm_status & ACMERROR_TXT_VALID) { + printk(BIOS_ERR, "TEE-TXT: FATAL ACM launch error !\n"); + /* + * WARNING ! + * To clear TXT.BIOSACM.ERRORCODE you must issue a cold reboot ! + */ + intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)); + return -1; + } + if (intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)) != 1) + return -1; + + return 0; +} + +/* + * Test all bits that are required TXT in general. + * Enables SMX if available. + * + * @return 0 on success + */ +bool intel_txt_prepare_txt_env(void) +{ + bool failure = false; + uint32_t txt_feature_flags = 0; + + unsigned int ecx = cpuid_ecx(1); + + printk(BIOS_DEBUG, "TEE-TXT: CPU supports SMX: "); + if (ecx & CPUID_SMX) { + printk(BIOS_DEBUG, "true\n"); + } else { + printk(BIOS_DEBUG, "false\n"); + failure = true; + } + + printk(BIOS_DEBUG, "TEE-TXT: CPU supports VMX: "); + if (ecx & CPUID_VMX) { + printk(BIOS_DEBUG, "true\n"); + } else { + printk(BIOS_DEBUG, "false\n"); + failure = true; + } + + msr_t msr = rdmsr(IA32_FEATURE_CONTROL); + if (!(msr.lo & (1 << 0))) { + printk(BIOS_ERR, "TEE-TXT: IA32_FEATURE_CONTROL is not locked\n"); + + msr.lo |= FEATURE_ENABLE_VMX; + msr.lo |= (1 << 1); + msr.lo |= 0xff00; + msr.lo |= 1; + + wrmsr(IA32_FEATURE_CONTROL, msr); + msr = rdmsr(IA32_FEATURE_CONTROL); + } + + printk(BIOS_DEBUG, "TEE-TXT: IA32_FEATURE_CONTROL\n"); + printk(BIOS_DEBUG, " VMXON in SMX enable: "); + + if (msr.lo & (1 << 1)) { + printk(BIOS_DEBUG, "true\n"); + } else { + printk(BIOS_DEBUG, "false\n"); + failure = true; + } + + printk(BIOS_DEBUG, " VMXON outside SMX enable: "); + if (msr.lo & FEATURE_ENABLE_VMX) { + printk(BIOS_DEBUG, "true\n"); + } else { + printk(BIOS_DEBUG, "false\n"); + failure = true; + } + + printk(BIOS_DEBUG, " register is locked: "); + if (msr.lo & (1 << 0)) { + printk(BIOS_DEBUG, "true\n"); + } else { + printk(BIOS_DEBUG, "false\n"); + failure = true; + } + + /* IA32_FEATURE_CONTROL enables getsec instructions */ + printk(BIOS_DEBUG, " GETSEC (all instructions) is enabled: "); + if ((msr.lo & 0xff00) == 0xff00) { + printk(BIOS_DEBUG, "true\n"); + } else { + printk(BIOS_DEBUG, "false\n"); + failure = true; + } + + /* Prevent crash and opt out early */ + if (!(ecx & CPUID_SMX) || failure) + return true; + + uint32_t eax = 0; + /* + * GetSec[CAPABILITIES] + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * Must check BIT0 of TXT chipset has been detected by CPU. + */ + if (!getsec_capabilities(&eax)) + return true; + + printk(BIOS_DEBUG, "TEE-TXT: GETSEC[CAPABILITIES] returned: \n"); + printk(BIOS_DEBUG, " TXT capabable chipset present: "); + if (eax & (1 << 0)) { + printk(BIOS_DEBUG, "true\n"); + } else { + printk(BIOS_DEBUG, "false\n"); + } + + printk(BIOS_DEBUG, " ENTERACCS available: "); + if (eax & (1 << 2)) { + printk(BIOS_DEBUG, "true\n"); + } else { + printk(BIOS_DEBUG, "false\n"); + } + + printk(BIOS_DEBUG, " EXITAC available: "); + if (eax & (1 << 3)) { + printk(BIOS_DEBUG, "true\n"); + } else { + printk(BIOS_DEBUG, "false\n"); + } + + printk(BIOS_DEBUG, " SENTER available: "); + if (eax & (1 << 4)) { + printk(BIOS_DEBUG, "true\n"); + } else { + printk(BIOS_DEBUG, "false\n"); + } + + printk(BIOS_DEBUG, " SEXIT available: "); + if (eax & (1 << 5)) { + printk(BIOS_DEBUG, "true\n"); + } else { + printk(BIOS_DEBUG, "false\n"); + } + + printk(BIOS_DEBUG, " PARAMETERS available: "); + if (eax & (1 << 6)) { + printk(BIOS_DEBUG, "true\n"); + } else { + printk(BIOS_DEBUG, "false\n"); + } + + /* + * Causes #GP if function is not supported by getsec. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * Order Number: 325383-060US + */ + if ((eax & 0x7d) != 0x7d) + failure = true; + + const uint64_t status = read64((void *)TXT_SPAD); + + if (status & ACMSTS_TXT_DISABLED) { + printk(BIOS_INFO, "TEE-TXT: TXT disabled by policy.\n"); + failure = true; + } + + /* + * Only the BSP must call getsec[ENTERACCS]. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * Order Number: 325383-060US + */ + msr = rdmsr(LAPIC_BASE_MSR); + if (!(msr.lo & LAPIC_BASE_MSR_BOOTSTRAP_PROCESSOR)) { + printk(BIOS_ERR, "TEE-TXT: BSP flag not set in APICBASE_MSR.\n"); + failure = true; + } + + /* + * There must be no MCEs pending. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * Order Number: 325383-060US + */ + msr = rdmsr(0x17a); + if (msr.lo & 0x4) { + printk(BIOS_ERR, "TEE-TXT: IA32_MCG_STATUS.MCIP is set.\n"); + failure = true; + } + + if (!getsec_parameter(NULL, NULL, NULL, NULL, NULL, &txt_feature_flags)) { + failure = true; + } else { + printk(BIOS_DEBUG, "TEE-TXT: Machine Check Register: "); + if (txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK) { + printk(BIOS_DEBUG, "preserved\n"); + } else { + printk(BIOS_DEBUG, "must be clear\n"); + } + } + + if (!(txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK)) { + /* + * Make sure there are no uncorrectable MCE errors. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + */ + msr = rdmsr(IA32_MCG_CAP); + size_t max_mc_msr = msr.lo & MCA_BANKS_MASK; + for (size_t i = 0; i < max_mc_msr; i++) { + msr = rdmsr(IA32_MC0_STATUS + 4 * i); + if (!(msr.hi & MCA_STATUS_HI_UC)) + continue; + + printk(BIOS_ERR, "TEE-TXT: IA32_MC%zd_STATUS.UC is set.\n", i); + failure = true; + break; + } + } + + /* Need to park all APs. */ + if (CONFIG(PARALLEL_MP) && CONFIG(PARALLEL_MP_AP_WORK)) + mp_park_aps(); + + return failure; +} diff --git a/src/security/intel/txt/getsec.c b/src/security/intel/txt/getsec.c new file mode 100644 index 0000000..9378e84 --- /dev/null +++ b/src/security/intel/txt/getsec.c @@ -0,0 +1,131 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 9elements Agency GmbH + * Copyright (C) 2019 Facebook Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdint.h> +#include <cpu/x86/lapic.h> +#include <cpu/x86/cr.h> +#include <cpu/x86/cache.h> +#include <cpu/x86/mp.h> + +#include "txt_register.h" +#include "txt_getsec.h" + +/** + * Check for SMX support and enable it if possible. + * + * Returns false on error, true on success. + */ +static bool getsec_enabled(void) +{ + unsigned int ecx = cpuid_ecx(1); + /* + * Check if SMX and VMX is supported by CPU. + */ + if (!(ecx & CPUID_SMX) || !(ecx & CPUID_VMX)) + return false; + + /* + * Check if SMX, VMX and GetSec instructions havn't been disabled. + */ + msr_t msr = rdmsr(IA32_FEATURE_CONTROL); + if ((msr.lo & 0xff07) != 0xff07) + return false; + + /* + * Enable SMX. Required to execute GetSec instruction. + * Chapter 2.2.4.3 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + write_cr4(read_cr4() | CR4_SMXE); + + return true; +} + +/** + * Get information as returned by getsec[PARAMETER]. + * Arguments can be set to NULL if not needed. + * + * Returns false on error, true on success. + */ +bool getsec_parameter(uint32_t *version_mask, + uint32_t *version_numbers_supported, + uint32_t *max_size_acm_area, + uint32_t *memory_type_mask, + uint32_t *senter_function_disable, + uint32_t *txt_feature_flags) +{ + uint32_t i, eax, ebx, ecx; + + if (!getsec_enabled()) + return false; + + /* + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + */ + for(i = 0; i < 0x1f; i++) { + /* Getsec[PARAMETERS] */ + asm volatile ("getsec\n" + : "=a" (eax), "=b" (ebx), "=c" (ecx) + : "a" (IA32_GETSEC_PARAMETERS), "b" (i) :); + switch (eax & 0x1f) { + case 0: /* NULL - Exit marker */ + return true; + case 1: /* Supported AC module versions */ + if (version_mask) + *version_mask = ebx; + if (version_numbers_supported) + *version_numbers_supported = ecx; + break; + case 2: /* Max size of authenticated code execution area */ + if (max_size_acm_area) + *max_size_acm_area = eax & ~0x1f; + break; + case 3: /* External memory types supported during AC mode */ + if (memory_type_mask) + *memory_type_mask = eax; + break; + case 4: /* Selective SENTER functionality control */ + if (senter_function_disable) + *senter_function_disable = eax & (0x3f00); + break; + case 5: /* TXT extensions support */ + if (txt_feature_flags) + *txt_feature_flags = eax & (0x60); + break; + } + } + + return true; +} + +/** + * Get capabilities as returned by getsec[CAPABILITIES]. + * + * Returns false on error, true on success. + */ + +bool getsec_capabilities(uint32_t *eax) +{ + if (!getsec_enabled()) + return false; + + asm volatile ("getsec\n" + : "=a" (*eax) + : "a" (IA32_GETSEC_CAPABILITIES), "b" (0) :); + + return true; +} diff --git a/src/security/intel/txt/getsec_enteraccs.S b/src/security/intel/txt/getsec_enteraccs.S new file mode 100644 index 0000000..82d3ec7 --- /dev/null +++ b/src/security/intel/txt/getsec_enteraccs.S @@ -0,0 +1,322 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 9elements Agency GmbH + * Copyright (C) 2019 Facebook Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <cpu/x86/mtrr.h> +#include <cpu/x86/cr.h> +#include <cpu/x86/msr.h> + +#define MTRR_HIGH_MASK $((1 << (CONFIG_CPU_ADDR_BITS-32)) - 1) + +.macro PUSH_MSR x + movl $(\x), %ecx + rdmsr + push %eax + push %edx +.endm + +.macro POP_MSR x + movl $(\x), %ecx + pop %edx + pop %eax + wrmsr +.endm + +.macro CLEAR_MSR x + movl $(\x), %ecx + movl $0, %edx + movl $0, %eax + wrmsr +.endm + +.macro PUSH_VAR_MTTR x + movl $(MTRR_CAP_MSR), %ecx + rdmsr + andl $(0xff), %eax + cmp $(\x), %eax + jl 1f + PUSH_MSR (0x200 + 2 * (\x)) + PUSH_MSR (0x200 + 2 * (\x) + 1) + 1: +.endm + +.macro POP_VAR_MTTR x + movl $(MTRR_CAP_MSR), %ecx + rdmsr + andl $(0xff), %eax + cmp $(\x), %eax + jl 1f + POP_MSR (0x200 + 2 * (\x) + 1) + POP_MSR (0x200 + 2 * (\x)) + 1: +.endm + +.macro CLEAR_VAR_MTTR x + movl $(MTRR_CAP_MSR), %ecx + rdmsr + andl $(0xff), %eax + cmp $(\x), %eax + jl 1f + CLEAR_MSR (0x200 + 2 * (\x)) + CLEAR_MSR (0x200 + 2 * (\x) + 1) + 1: +.endm + +.align 4 +.text + + +/* + * See "SAFER MODE EXTENSIONS REFERENCE." + * Chapter "GETSEC[ENTERACCS] - Execute Authenticated Chipset Code" for reference. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * + * void getsec_enteraccs(uint32_t esi, + * uint32_t acm_base, + * uint32_t acm_size); + */ +.global getsec_enteraccs +getsec_enteraccs: + + /* Backup current register state */ + pushl %ebp + movl %esp, %ebp + + pushal + + movl %cr0, %eax + pushl %eax + movl %cr4, %eax + pushl %eax + + /* Pushed 10 32bit registers */ + + /* Reserve space on stack for GDT */ + subl $8, %esp + + PUSH_MSR IA32_MISC_ENABLE + PUSH_MSR MTRR_FIX_64K_00000 + PUSH_MSR MTRR_FIX_16K_80000 + PUSH_MSR MTRR_FIX_16K_A0000 + PUSH_MSR MTRR_FIX_4K_C0000 + PUSH_MSR MTRR_FIX_4K_C8000 + PUSH_MSR MTRR_FIX_4K_D0000 + PUSH_MSR MTRR_FIX_4K_D8000 + PUSH_MSR MTRR_FIX_4K_E0000 + PUSH_MSR MTRR_FIX_4K_F0000 + PUSH_MSR MTRR_FIX_4K_F8000 + + PUSH_VAR_MTTR 0 + PUSH_VAR_MTTR 1 + PUSH_VAR_MTTR 2 + PUSH_VAR_MTTR 3 + PUSH_VAR_MTTR 4 + PUSH_VAR_MTTR 5 + PUSH_VAR_MTTR 6 + PUSH_VAR_MTTR 7 + PUSH_VAR_MTTR 8 + PUSH_VAR_MTTR 9 + +1: + /* + * Disable cache. + * Chapter 2.2.4.3 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + movl %cr0, %eax + orl $(CR0_CD | CR0_NW), %eax + movl %eax, %cr0 + + /* Disable fixed MTRRs */ + movl $(MTRR_DEF_TYPE_MSR), %ecx + rdmsr + andl $(~MTRR_DEF_TYPE_FIX_EN), %eax + wrmsr + + /* + * Clear fixed MTRRs. + * Chapter 2.2.5.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + CLEAR_MSR MTRR_FIX_64K_00000 + CLEAR_MSR MTRR_FIX_16K_80000 + CLEAR_MSR MTRR_FIX_16K_A0000 + CLEAR_MSR MTRR_FIX_4K_C0000 + CLEAR_MSR MTRR_FIX_4K_C8000 + CLEAR_MSR MTRR_FIX_4K_D0000 + CLEAR_MSR MTRR_FIX_4K_D8000 + CLEAR_MSR MTRR_FIX_4K_E0000 + CLEAR_MSR MTRR_FIX_4K_F0000 + CLEAR_MSR MTRR_FIX_4K_F8000 + + /* + * Clear variable MTRRs + * Chapter 2.2.5.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + CLEAR_VAR_MTTR 0 + CLEAR_VAR_MTTR 1 + CLEAR_VAR_MTTR 2 + CLEAR_VAR_MTTR 3 + CLEAR_VAR_MTTR 4 + CLEAR_VAR_MTTR 5 + CLEAR_VAR_MTTR 6 + CLEAR_VAR_MTTR 7 + CLEAR_VAR_MTTR 8 + CLEAR_VAR_MTTR 9 + + /* + * Setup BIOS ACM as WB + * Chapter A.1.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + movl $(0x200), %ecx + movl 12(%ebp), %eax /* %eax = acmbase */ + orl $(6), %eax /* MTRR_TYPE_WB */ + movl $0, %edx + wrmsr + + /* Round acmsize to next power of two. Required for MTRR programming. */ + movl $1, %ebx + movl 16(%ebp), %ecx /* %ebx = acmsize */ + dec %ecx + bsr %ecx, %ecx /* find MSB */ + inc %ecx + shl %cl, %ebx + movl $(0x201), %ecx + xorl %eax, %eax + subl %ebx, %eax /* %eax = 4GIB - log2_ceil(ACM SIZE) */ + orl $((1 << 11)), %eax /* MTRR_PHYS_MASK_VALID */ + movl MTRR_HIGH_MASK, %edx + wrmsr + +1: + /* Enable cache - GPE# if not done */ + movl %cr0, %eax + andl $(~(CR0_CD | CR0_NW)), %eax + movl %eax, %cr0 + + /* Enable Numeric error - GPE# if not done */ + movl %cr0, %eax + orl $(CR0_NE), %eax + movl %eax, %cr0 + + /* Enable SMX and FXSTORE - for getsec */ + movl %cr4, %eax + orl $(CR4_SMXE | CR4_OSFXSR), %eax + movl %eax, %cr4 + + /* + * Save GDT + * Chapter A.1.2 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + sgdt -48(%ebp) + + /* Backup stack pointer */ + movd %esp, %xmm0 + movd %ebp, %xmm1 + + /* + * Get function arguments. + * It's important to pass the exact ACM size as it's used by getsec to verify + * the integrity of ACM. Unlike the size for MTRR programming, which needs to + * be power of two. + * + * The following assembly code is based on tboot's tboot/include/txt/smx.h. + */ + movl 8(%ebp), %esi /* flags */ + movl 12(%ebp), %ebx /* acm_base */ + movl 16(%ebp), %ecx /* acm_size */ + + movl $0, %edx /* reserved, must be zero */ + movl $0, %edi /* must be zero */ + movl $2, %eax /* GetSec[ENTERACCS] */ + + getsec + + /* Restore stack pointer */ + movd %xmm0, %esp + movd %xmm1, %ebp + + /* Reload GDT */ + lgdt -48(%ebp) + + /* Set cs */ + ljmp $0x10, $1f +1: + /* Fix segment registers */ + movl $0x18, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %ss + movl %eax, %fs + movl %eax, %gs + + /* Disable cache */ + movl %cr0, %eax + orl $(CR0_CD | CR0_NW), %eax + movl %eax, %cr0 + + /* Restore MTTRs */ + POP_VAR_MTTR 9 + POP_VAR_MTTR 8 + POP_VAR_MTTR 7 + POP_VAR_MTTR 6 + POP_VAR_MTTR 5 + POP_VAR_MTTR 4 + POP_VAR_MTTR 3 + POP_VAR_MTTR 2 + POP_VAR_MTTR 1 + POP_VAR_MTTR 0 + +1: + POP_MSR MTRR_FIX_4K_F8000 + POP_MSR MTRR_FIX_4K_F0000 + POP_MSR MTRR_FIX_4K_E0000 + POP_MSR MTRR_FIX_4K_D8000 + POP_MSR MTRR_FIX_4K_D0000 + POP_MSR MTRR_FIX_4K_C8000 + POP_MSR MTRR_FIX_4K_C0000 + POP_MSR MTRR_FIX_16K_A0000 + POP_MSR MTRR_FIX_16K_80000 + POP_MSR MTRR_FIX_64K_00000 + POP_MSR IA32_MISC_ENABLE + + /* Enable fixed MTRRs */ + movl $(MTRR_DEF_TYPE_MSR), %ecx + rdmsr + orl $(MTRR_DEF_TYPE_FIX_EN), %eax + wrmsr + + /* Enable cache */ + movl %cr0, %eax + andl $(~(CR0_CD | CR0_NW)), %eax + movl %eax, %cr0 + + /* Pop GDT */ + addl $8, %esp + + popl %eax + movl %eax, %cr4 + popl %eax + movl %eax, %cr0 + + popal + + movl %ebp,%esp + popl %ebp + + ret diff --git a/src/security/intel/txt/logging.c b/src/security/intel/txt/logging.c new file mode 100644 index 0000000..db1c792 --- /dev/null +++ b/src/security/intel/txt/logging.c @@ -0,0 +1,270 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 9elements Agency GmbH + * Copyright (C) 2019 Facebook Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <console/console.h> +#if CONFIG(SOC_INTEL_FSP_BROADWELL_DE) +#include <soc/broadwell_de.h> +#endif +#if CONFIG(SOC_INTEL_COMMON_BLOCK_SA) +#include <intelblocks/systemagent.h> +#endif + +#include <arch/mmio.h> +#include <string.h> + +#include "txt.h" +#include "txt_register.h" + +/** + * Logs microcode or SINIT ACM errors. + * Does not log SBIOS ACM errors. + */ +static void log_txt_error(const char *phase) +{ + const uint64_t txt_error = read64((void *)TXT_ERROR); + + if (txt_error & ACMERROR_TXT_VALID) { + printk(BIOS_ERR, "%s: Error occured\n", phase); + + if (txt_error & ACMERROR_TXT_EXTERNAL) + printk(BIOS_ERR, " Caused by: External\n"); + else + printk(BIOS_ERR, " Caused by: Processor\n"); + + printk(BIOS_ERR, " Type: "); + + switch(txt_error & TXT_ERROR_MASK) { + case 0: + printk(BIOS_ERR, "Legacy Shutdown\n"); + break; + case 5: + printk(BIOS_ERR, "Load memory type error in ACM area\n"); + break; + case 6: + printk(BIOS_ERR, "Unrecognized ACM format\n"); + break; + case 7: + printk(BIOS_ERR, "Failure to authenticate\n"); + break; + case 8: + printk(BIOS_ERR, "Invalid ACM format\n"); + break; + case 9: + printk(BIOS_ERR, "Unexpected Snoop hit\n"); + break; + case 10: + printk(BIOS_ERR, "Invalid event\n"); + break; + case 11: + printk(BIOS_ERR, "Invalid MLE\n"); + break; + case 12: + printk(BIOS_ERR, "Machine check event\n"); + break; + case 13: + printk(BIOS_ERR, "VMXAbort\n"); + break; + case 14: + printk(BIOS_ERR, "AC memory corruption\n"); + break; + case 15: + printk(BIOS_ERR, "Illegal voltage/bus ratio\n"); + break; + default: + printk(BIOS_ERR, "unknown\n"); + break; + } + } +} + +/** + * Dump useful informaation about the BIOS ACM state. + * Should run right after console_init() in romstage. + * Resets the platform if TXT reset is active and MLE cannot be established. + **/ +void intel_txt_log_bios_acm_error(void) +{ + uint32_t bios_acm_error; + uint64_t acm_status; + uint64_t txt_error; + + printk(BIOS_INFO, "TEE-TXT: State of ACM and ucode update:\n"); + + bios_acm_error = read32((void *)TXT_BIOSACM_ERRORCODE); + acm_status = read64((void *)TXT_SPAD); + txt_error = read64((void *)TXT_ERROR); + + /* Errors by BIOS ACM or FIT */ + if ((txt_error & ACMERROR_TXT_VALID) && + (acm_status & ACMERROR_TXT_VALID)) { + intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)); + log_txt_error("FIT MICROCODE"); + } + /* Errors by SINIT */ + if ((txt_error & ACMERROR_TXT_VALID) && + !(acm_status & ACMERROR_TXT_VALID)) { + intel_txt_log_acm_error(txt_error); + log_txt_error("SINIT"); + } + + /* Check for fatal ACM error and TXT reset */ + uint8_t error = read8((void *)TXT_ESTS); + if (error & TXT_ESTS_TXT_RESET_STS) { + printk(BIOS_CRIT, "TXT-STS: Intel TXT reset detected\n"); + intel_txt_log_acm_error(read32((void *)TXT_ERROR)); + } +} + +/** + * Dump information about the provided ACM. + */ +void txt_dump_acm_info(const struct acm_header_v0 *acm_header) +{ + const struct acm_info_table *info = NULL; + if (!acm_header) + return; + + printk(BIOS_INFO, "ACM @ %p\n", acm_header); + + const size_t acm_size = (acm_header->size & 0xffffff) << 2; + const size_t info_off = (acm_header->header_len + acm_header->scratch_size) * 4; + + if (acm_size > (info_off + sizeof(struct acm_info_table))) + info = (const struct acm_info_table *) + ((const unsigned char *)acm_header + info_off); + + printk(BIOS_INFO, " ACM: Binary Info\n"); + if (acm_header->module_type == CHIPSET_ACM) + printk(BIOS_INFO, " Type: Chipset ACM\n"); + + if (acm_header->module_sub_type == 0) + printk(BIOS_INFO, " Subtype: undefined\n"); + else if (acm_header->module_sub_type == 1) + printk(BIOS_INFO, " Subtype: Run at reset\n"); + + printk(BIOS_INFO, " Header: v%u.%u\n", acm_header->header_version[0], + acm_header->header_version[1]); + + printk(BIOS_INFO, " Chipset: %u\n", acm_header->chipset_id); + printk(BIOS_INFO, " Size: %u\n", + (acm_header->size & 0xffffff) << 2); + + switch(acm_header->flags) { + case ACM_FORMAT_FLAGS_PW: + printk(BIOS_INFO, " Flags: PW signed (Production Worthy)\n"); + break; + case ACM_FORMAT_FLAGS_NPW: + printk(BIOS_INFO, " Flags: NPW signed (Non Production Worthy)\n"); + break; + case ACM_FORMAT_FLAGS_DEBUG: + printk(BIOS_INFO, " Flags: Debug signed\n"); + break; + } + + if (acm_header->module_vendor == INTEL_ACM_VENDOR) + printk(BIOS_INFO, " Vendor: Intel Cooperation\n"); + + printk(BIOS_INFO, " Date: %x\n", acm_header->date); + + switch (acm_header->size) { + case ACM_FORMAT_SIZE_64KB: + printk(BIOS_INFO, " Size: 64KB\n"); + printk(BIOS_INFO, " CBnT: no\n"); + break; + case ACM_FORMAT_SIZE_128KB: + printk(BIOS_INFO, " Size: 128KB\n"); + printk(BIOS_INFO, " CBnT: no\n"); + break; + case ACM_FORMAT_SIZE_256KB: + printk(BIOS_INFO, " Size: 256KB\n"); + printk(BIOS_INFO, " CBnT: yes\n"); + break; + default: + printk(BIOS_INFO, " Size: 0x%08x\n", acm_header->size); + + break; + } + + printk(BIOS_INFO, " TXT SVN: %u\n", acm_header->txt_svn); + printk(BIOS_INFO, " SE SVN: %u\n", acm_header->se_svn); + + if (!info) + return; + printk(BIOS_INFO, " Table info:\n"); + printk(BIOS_INFO, " UUID: "); + for (size_t i = 0; i < sizeof(info->uuid); i++) + printk(BIOS_INFO, "%02X ", info->uuid[i]); + printk(BIOS_INFO, "\n"); + printk(BIOS_INFO, " Chipset acm type: 0x%x\n", info->chipset_acm_type); + printk(BIOS_INFO, " Capabilities: 0x%x\n", info->capabilities); +} + +/** + * Dump information about the chipset's TXT capabilities. + */ +void txt_dump_chipset_info(void) +{ + printk(BIOS_INFO, "TEE-TXT: Chipset Key Hash 0x"); + for (int i = 0; i < TXT_ACM_KEY_HASH_LEN; i++) { + printk(BIOS_INFO, "%llx", read64((void *)TXT_ACM_KEY_HASH + + (i * sizeof(uint64_t)))); + } + printk(BIOS_INFO, "\n"); + + printk(BIOS_INFO, "TEE-TXT: DIDVID 0x%x\n", read32((void *)TXT_DIDVID)); + printk(BIOS_INFO, "TEE-TXT: production fused chipset: %s\n", + (read64((void *)TXT_VER_FSBIF) & TXT_VER_PRODUCTION_FUSED) ? "true" : "false"); +} + +void txt_dump_regions(void) +{ + struct txt_biosdataregion *bdr = NULL; + uintptr_t tseg = 0; + uint64_t reg64; + + if (CONFIG(SOC_INTEL_FSP_BROADWELL_DE) || + CONFIG(SOC_INTEL_COMMON_BLOCK_SA)) + tseg = sa_get_tseg_base() >> 20; + + + reg64 = read64((void *)TXT_HEAP_BASE); + if ((reg64 != 0 && reg64 != ~0UL) && + (read64((void *)(uintptr_t)reg64) >= (sizeof(*bdr) + sizeof(uint64_t)))) + bdr = (void *)((uintptr_t)reg64 + sizeof(uint64_t)); + + printk(BIOS_DEBUG, "TEE-TXT: TSEG 0x%lx\n", tseg * MiB); + printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.SIZE 0x%llx\n", + read64((void *)TXT_HEAP_SIZE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.BASE 0x%llx\n", + read64((void *)TXT_HEAP_BASE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.SIZE 0x%llx\n", + read64((void *)TXT_SINIT_SIZE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.BASE 0x%llx\n", + read64((void *)TXT_SINIT_BASE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.BASE 0x%llx\n", + read64((void *)TXT_MSEG_BASE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.SIZE 0x%llx\n", + read64((void *)TXT_MSEG_SIZE)); + + if (bdr) { + printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.bios_sinit_size 0x%x\n", + bdr->bios_sinit_size); + printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_size 0x%llx\n", + bdr->lcp_pd_size); + printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_base 0x%llx\n", + bdr->lcp_pd_base); + } +} diff --git a/src/security/intel/txt/ramstage.c b/src/security/intel/txt/ramstage.c new file mode 100644 index 0000000..2fe45df --- /dev/null +++ b/src/security/intel/txt/ramstage.c @@ -0,0 +1,394 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 9elements Agency GmbH + * Copyright (C) 2019 Facebook Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/mmio.h> +#include <arch/acpi.h> +#include <bootstate.h> +#include <bootmem.h> +#include <console/console.h> +#include <stdint.h> +#include <cbfs.h> +#include <cpu/intel/common/common.h> +#include <cpu/x86/msr.h> + +#include <lib.h> +#if CONFIG(SOC_INTEL_FSP_BROADWELL_DE) +#include <soc/broadwell_de.h> +#include <soc/ramstage.h> +#endif +#include <device/pci_ops.h> + +#include "txt.h" +#include "txt_register.h" +#include "txt_getsec.h" + +/* FIXME: Seems to work only on some platforms */ +static void log_ibb_measurements(void) +{ + const uint64_t mseg_size = read64((void *)TXT_MSEG_SIZE); + uint64_t mseg_base = read64((void *)TXT_MSEG_BASE); + + if (!mseg_size || !mseg_base || mseg_size <= mseg_base) + return; + /* MSEG SIZE and MSEG BASE might contain random values. + * Assume below 4GiB and 8byte aligned. + */ + if (mseg_base & ~0xfffffff8ULL || mseg_size & ~0xfffffff8ULL) + return; + + printk(BIOS_INFO, "TEE-TXT: IBB Hash 0x"); + for (; mseg_base < mseg_size; mseg_base++) { + printk(BIOS_INFO, "%02X", read8((void *)(uintptr_t)mseg_base)); + } + printk(BIOS_INFO, "\n"); +} + +void bootmem_platform_add_ranges(void) +{ + uint64_t status = read64((void *)TXT_SPAD); + + if (status & ACMSTS_TXT_DISABLED) + return; + + /* Chapter 5.5.5 Intel TXT reserved memory */ + bootmem_add_range(TXT_RESERVED_SPACE, + TXT_RESERVED_SPACE_SIZE, + BM_MEM_RESERVED); + + /* Intel TPM decode memory */ + bootmem_add_range(TXT_TPM_DECODE_AREA, + TXT_RESERVED_SPACE - TXT_TPM_DECODE_AREA, + BM_MEM_RESERVED); + + /* Intel TXT public space memory */ + bootmem_add_range(TXT_PUBLIC_SPACE, + TXT_TPM_DECODE_AREA - TXT_PUBLIC_SPACE, + BM_MEM_RESERVED); + + /* Intel TXT private space memory */ + bootmem_add_range(TXT_PRIVATE_SPACE, + TXT_PUBLIC_SPACE - TXT_PRIVATE_SPACE, + BM_MEM_RESERVED); + + const uint32_t txt_dev_memory = read32((void *)TXT_DPR) & + (TXT_DPR_TOP_ADDR_MASK << TXT_DPR_TOP_ADDR_SHIFT); + const uint32_t txt_dev_size = + (read32((void *)TXT_DPR) >> TXT_DPR_LOCK_SIZE_SHIFT) & + TXT_DPR_LOCK_SIZE_MASK; + + /* Chapter 5.5.6 Intel TXT Device Memory */ + bootmem_add_range(txt_dev_memory - txt_dev_size * MiB, + txt_dev_size * MiB, + BM_MEM_RESERVED); +} + +static bool get_wake_error_status(void) +{ + const uint8_t error = read8((void *)TXT_ESTS); + return !!(error & TXT_ESTS_WAKE_ERROR_STS); +} + +static void check_secrets_txt(void *unused) +{ + uint64_t status = read64((void *)TXT_SPAD); + + if (status & ACMSTS_TXT_DISABLED) + return; + + /* Check for fatal ACM error and TXT reset */ + if (get_wake_error_status()) { + /* + * Check if secrets bit needs to be reset. Only platforms that support + * CONFIG_PLATFORM_HAS_DRAM_CLEAR will be able to run this code. + * Assume all memory really was cleared. + * + * TXT will issue a platform reset to come up sobber. + */ + if (intel_txt_memory_has_secrets()) { + printk(BIOS_INFO, "TEE-TXT: Wiping TEE...\n"); + intel_txt_run_bios_acm(ACMINPUT_CLEAR_SECRETS); + + /* Should never reach this point ... */ + intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)); + die("Waiting for platform reset...\n"); + } + } +} + +BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_ENTRY, check_secrets_txt, NULL); + +/** + * Log TXT startup errors, check all bits for TXT, run BIOSACM using + * GETSEC[ENTERACCS]. + * + * If a "TXT reset" is detected or "memory had secrets" is set, then do nothing as + * 1. Running ACMs will cause a TXT-RESET + * 2. Memory will be scrubbed in BS_DEV_INIT + * 3. TXT-RESET will be issued by code above later + * + */ +static void init_intel_txt(void *unused) +{ + const uint64_t status = read64((void *)TXT_SPAD); + + if (status & ACMSTS_TXT_DISABLED) + return; + + printk(BIOS_INFO, "TEE-TXT: Initializing TEE...\n"); + + intel_txt_log_spad(); + + if (CONFIG(INTEL_TXT_LOGGING)) { + intel_txt_log_bios_acm_error(); + txt_dump_chipset_info(); + } + + printk(BIOS_INFO, "TEE-TXT: Validate TEE...\n"); + + if (intel_txt_prepare_txt_env()) { + printk(BIOS_ERR, "TEE-TXT: Failed to prepare TXT environment\n"); + return; + } + + /* Check for fatal ACM error and TXT reset */ + if (get_wake_error_status()) { + /* Can't run ACMs with TXT_ESTS_WAKE_ERROR_STS set */ + printk(BIOS_ERR, "TEE-TXT: Failed to prepare TXT environment\n"); + return; + } + + printk(BIOS_INFO, "TEE-TXT: Testing BIOS ACM calling code...\n"); + + /* + * Test BIOS ACM code. + * ACM should do nothing on reserved functions, and return an error code + * in TXT_BIOSACM_ERRORCODE. Tested show that this is not true. + * Use special function "NOP" that does 'nothing'. + */ + if (intel_txt_run_bios_acm(ACMINPUT_NOP) < 0) { + printk(BIOS_ERR, "TEE-TXT: Error calling BIOS ACM.\n"); + return; + } + + if (status & (ACMSTS_BIOS_TRUSTED | ACMSTS_IBB_MEASURED)) { + log_ibb_measurements(); + + int s3resume = acpi_is_wakeup_s3(); + if (!s3resume) { + printk(BIOS_INFO, "TEE-TXT: Scheck...\n"); + if (intel_txt_run_bios_acm(ACMINPUT_SCHECK) < 0) { + printk(BIOS_ERR, "TEE-TXT: Error calling BIOS ACM.\n"); + return; + } + } + } +} + +BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, init_intel_txt, NULL); + +static void push_sinit_heap(u8 **heap_ptr, void *data, size_t data_length) +{ + /* Push size */ + const uint64_t tmp = data_length + 8; + memcpy(*heap_ptr, &tmp, 8); + *heap_ptr += 8; + + if (data_length) { + /* Push data */ + memcpy(*heap_ptr, data, data_length); + *heap_ptr += data_length; + } +} + +/** + * Finalize the TXT device. + * + * - Lock TXT register. + * - Protect TSEG using DMA protected regions. + * - Setup TXT regions. + * - Place SINIT ACM in TXT_SINIT memory segment. + * - Fill TXT BIOSDATA region. + */ +static void lockdown_intel_txt(void *unused) +{ + const uint64_t status = read64((void *)TXT_SPAD); + uintptr_t tseg = 0; + + if (status & ACMSTS_TXT_DISABLED) + return; + + printk(BIOS_INFO, "TEE-TXT: Locking TEE...\n"); + + /* Lock TXT config, unlocks TXT_HEAP_BASE */ + if (intel_txt_run_bios_acm(ACMINPUT_LOCK_CONFIG) < 0) { + printk(BIOS_ERR, "TEE-TXT: Failed to lock registers.\n"); + printk(BIOS_ERR, "TEE-TXT: SINIT won't be supported.\n"); + return; + } + + if (CONFIG(SOC_INTEL_FSP_BROADWELL_DE)) + tseg = sa_get_tseg_base() >> 20; + + /* + * Document Number: 558294 + * Chapter 5.5.6.1 DMA Protection Memory Region + */ + + const u8 dpr_capable = !!(read64((void *)TXT_CAPABILITIES) & + TXT_CAPABILITIES_DPR); + printk(BIOS_INFO, "TEE-TXT: DPR capable %x\n", dpr_capable); + if (dpr_capable) { + + /* Protect 3 MiB below TSEG and lock register */ + write64((void *)TXT_DPR, (TXT_DPR_TOP_ADDR(tseg) | + TXT_DPR_LOCK_SIZE(3) | + TXT_DPR_LOCK_MASK)); + +#if CONFIG(SOC_INTEL_FSP_BROADWELL_DE) + broadwell_de_set_dpr(tseg, 3 * MiB); + broadwell_de_lock_dpr(); +#endif + printk(BIOS_INFO, "TEE-TXT: TXT.DPR 0x%08x\n", + read32((void *)TXT_DPR)); + } + + /* + * Document Number: 558294 + * Chapter 5.5.6.3 Intel TXT Heap Memory Region + */ + write64((void *)TXT_HEAP_SIZE, 0xE0000); + write64((void *)TXT_HEAP_BASE, + ALIGN_DOWN((tseg * MiB) - read64((void *)TXT_HEAP_SIZE), 4096)); + + /* + * Document Number: 558294 + * Chapter 5.5.6.2 SINIT Memory Region + */ + write64((void *)TXT_SINIT_SIZE, 0x20000); + write64((void *)TXT_SINIT_BASE, + ALIGN_DOWN(read64((void *)TXT_HEAP_BASE) - + read64((void *)TXT_SINIT_SIZE), 4096)); + + /* + * BIOS Data Format + * Chapter C.2 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + struct { + struct txt_biosdataregion bdr; + struct txt_heap_acm_element heap_acm; + struct txt_extended_data_element_header end; + } __packed data = {0}; + + /* TPM2.0 requires version 6 of BDT */ + if (CONFIG(TPM2)) + data.bdr.version = 6; + else + data.bdr.version = 5; + + data.bdr.no_logical_procs = dev_count_cpu(); + + void *sinit_base = (void *)(uintptr_t)read64((void *)TXT_SINIT_BASE); + data.bdr.bios_sinit_size = cbfs_boot_load_file(TXT_FILE_SINIT_ACM, + sinit_base, + read64((void *)TXT_SINIT_SIZE), CBFS_TYPE_RAW); + + if (data.bdr.bios_sinit_size) { + printk(BIOS_INFO, "TEE-TXT: Placing SINIT ACM in memory.\n"); + if (CONFIG(INTEL_TXT_LOGGING)) + txt_dump_acm_info(sinit_base); + } else { + printk(BIOS_ERR, "TEE-TXT: Couldn't locate SINIT ACM in" + "CBFS.\n"); + /* Clear memory */ + memset(sinit_base, 0, read64((void *)TXT_SINIT_SIZE)); + } + + struct cbfsf file; + /* The following have been removed from BIOS Data Table in version 6 */ + if (!cbfs_boot_locate(&file, TXT_FILE_LCP_PD_ACM, NULL)) { + struct region_device policy; + + cbfs_file_data(&policy, &file); + void *policy_data = rdev_mmap_full(&policy); + size_t policy_len = region_device_sz(&policy); + + if (policy_data && policy_len) { + /* Point to FIT Type 9 entry in flash */ + data.bdr.lcp_pd_base = (uintptr_t)policy_data; + data.bdr.lcp_pd_size = (uint64_t)policy_len; + rdev_munmap(&policy, policy_data); + } else { + printk(BIOS_ERR, "TEE-TXT: Couldn't map LCP PD Policy from CBFS.\n"); + } + } else { + printk(BIOS_ERR, "TEE-TXT: Couldn't locate LCP PD Policy in CBFS.\n"); + } + + data.bdr.support_acpi_ppi = 0; + data.bdr.platform_type = 0; + + /* Extended elements - ACM addresses */ + data.heap_acm.header.type = HEAP_EXTDATA_TYPE_ACM; + data.heap_acm.header.size = sizeof(data.heap_acm); + if (data.bdr.bios_sinit_size) { + data.heap_acm.num_acms = 2; + data.heap_acm.acm_addrs[1] = (uintptr_t)sinit_base; + } else { + data.heap_acm.num_acms = 1; + } + data.heap_acm.acm_addrs[0] = + (uintptr_t)cbfs_boot_map_with_leak(TXT_FILE_BIOS_ACM, + CBFS_TYPE_RAW, + NULL); + /* Extended elements - End marker */ + data.end.type = HEAP_EXTDATA_TYPE_END; + data.end.size = sizeof(data.end); + + /* Fill TXT.HEAP.BASE with 4 subregions */ + u8 *heap_struct = (void *)((uintptr_t)read64((void *)TXT_HEAP_BASE)); + + /* BiosData */ + push_sinit_heap(&heap_struct, &data, sizeof(data)); + + /* OsMLEData */ + /* FIXME: Does firmware need to write this? */ + push_sinit_heap(&heap_struct, NULL, 0); + + /* OsSinitData */ + /* FIXME: Does firmware need to write this? */ + push_sinit_heap(&heap_struct, NULL, 0); + + /* SinitMLEData */ + /* FIXME: Does firmware need to write this? */ + push_sinit_heap(&heap_struct, NULL, 0); + + /* + * FIXME: Server-TXT capable platforms need to install an STM in SMM and set up MSEG. + */ + + /** + * Chapter 5.10.1 SMM in the Intel TXT for Servers Environment + * Disable MSEG. + */ + write64((void *)TXT_MSEG_SIZE, 0); + write64((void *)TXT_MSEG_BASE, 0); + + if (CONFIG(INTEL_TXT_LOGGING)) + txt_dump_regions(); +} + +BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, lockdown_intel_txt, NULL); diff --git a/src/security/intel/txt/txt.h b/src/security/intel/txt/txt.h new file mode 100644 index 0000000..5daab5a --- /dev/null +++ b/src/security/intel/txt/txt.h @@ -0,0 +1,30 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018-2019 Facebook Inc. + * Copyright (C) 2018-2019 9elements Agency GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SECURITY_INTEL_TXT_H_ +#define SECURITY_INTEL_TXT_H_ + +#include <types.h> +#include <stddef.h> + +void intel_txt_log_bios_acm_error(void); +int intel_txt_log_acm_error(const uint32_t acm_error); +void intel_txt_log_spad(void); +bool intel_txt_memory_has_secrets(void); +int intel_txt_run_bios_acm(const u8 input_params); +bool intel_txt_prepare_txt_env(void); + +#endif /* SECURITY_INTEL_TXT_H_ */ diff --git a/src/security/intel/txt/txt_getsec.h b/src/security/intel/txt/txt_getsec.h new file mode 100644 index 0000000..aae13d7 --- /dev/null +++ b/src/security/intel/txt/txt_getsec.h @@ -0,0 +1,34 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018-2019 Facebook Inc. + * Copyright (C) 2018-2019 9elements Agency GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SECURITY_INTEL_TXT_GETSEC_H_ +#define SECURITY_INTEL_TXT_GETSEC_H_ + + +bool getsec_parameter(uint32_t *version_mask, + uint32_t *version_numbers_supported, + uint32_t *max_size_acm_area, + uint32_t *memory_type_mask, + uint32_t *senter_function_disable, + uint32_t *txt_feature_flags); + +bool getsec_capabilities(uint32_t *eax); + +void getsec_enteraccs(const uint32_t esi, + const uint32_t acm_base, + const uint32_t acm_size); + +#endif /* SECURITY_INTEL_TXT_REGISTER_H_ */ diff --git a/src/security/intel/txt/txt_register.h b/src/security/intel/txt/txt_register.h new file mode 100644 index 0000000..fefdfec --- /dev/null +++ b/src/security/intel/txt/txt_register.h @@ -0,0 +1,283 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018-2019 Facebook Inc. + * Copyright (C) 2018-2019 9elements Agency GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SECURITY_INTEL_TXT_REGISTER_H_ +#define SECURITY_INTEL_TXT_REGISTER_H_ + +#include <types.h> +#include <stddef.h> + +/* + * Document: 315168-016 + * Intel Trusted Execution Technology (Intel TXT) + * Software Development Guide + * Chapter B + */ +#define TXT_BASE 0xfed30000UL + +#define TXT_STS (TXT_BASE + 0) +#define TXT_ESTS (TXT_BASE + 8) +#define TXT_ESTS_TXT_RESET_STS (1 << 0) +/* + * Chapter 6 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_ESTS_WAKE_ERROR_STS (1 << 6) + +#define TXT_ERROR (TXT_BASE + 0x30) +#define ACMERROR_TXT_VALID (1ul << 31) +#define ACMERROR_TXT_EXTERNAL (1ul << 30) + +#define ACMERROR_TXT_PROGRESS_SHIFT 16 +#define ACMERROR_TXT_MINOR_SHIFT 15 +#define ACMERROR_TXT_MAJOR_SHIFT 10 +#define ACMERROR_TXT_CLASS_SHIFT 4 +#define ACMERROR_TXT_TYPE_SHIFT 0 + +#define ACMERROR_TXT_PROGRESS_CODE (0xffull << ACMERROR_TXT_PROGRESS_SHIFT) +#define ACMERROR_TXT_MINOR_CODE (1ull << ACMERROR_TXT_MINOR_SHIFT) +#define ACMERROR_TXT_MAJOR_CODE (0x1full << ACMERROR_TXT_MAJOR_SHIFT) +#define ACMERROR_TXT_CLASS_CODE (0x3full << ACMERROR_TXT_CLASS_SHIFT) +#define ACMERROR_TXT_TYPE_CODE (0xfull << ACMERROR_TXT_TYPE_SHIFT) + +#define ACMERROR_TXT_AC_MODULE_TYPE_BIOS 0 +#define ACMERROR_TXT_AC_MODULE_TYPE_SINIT 1 + +#define TXT_ERROR_MASK (0x3ff << 0) + +#define TXT_CMD_RESET (TXT_BASE + 0x38) +#define TXT_CMD_CLOSE_PRIVATE (TXT_BASE + 0x48) + +/* Present in Document Number: 315168-016. */ +#define TXT_SPAD (TXT_BASE + 0xa0) +#define ACMSTS_IBB_MEASURED (1ull << 63) +#define ACMSTS_VERIFICATION_ERROR (1ull << 62) +#define ACMSTS_BG_STARTUP_ERROR (1ull << 61) /* CBnT platforms only */ +#define ACMSTS_TXT_DISABLED (1ull << 60) /* disabled by FIT type 0xA record */ +#define ACMSTS_BIOS_TRUSTED (1ull << 59) +#define ACMSTS_MEM_CLEAR_POWER_DOWN (1ull << 47) +#define ACMSTS_TXT_STARTUP_SUCCESS (1ull << 30) + +#define TXT_VER_FSBIF (TXT_BASE + 0x100) +#define TXT_VER_PRODUCTION_FUSED (1ull << 31) + +#define TXT_DIDVID (TXT_BASE + 0x110) + +/* + * Chapter 6 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_CAPABILITIES (TXT_BASE + 0x200) +#define TXT_CAPABILITIES_DPR (1ull << 26) +#define TXT_CAPABILITIES_PMRC (1ull << 19) + +/* Only present in Document Number: 315168-010 and 315168-016 */ +#define TXT_VER_QPIIF (TXT_BASE + 0x200) + +#define TXT_SINIT_BASE (TXT_BASE + 0x270) +#define TXT_SINIT_SIZE (TXT_BASE + 0x278) +#define TXT_MLE_JOIN (TXT_BASE + 0x290) + +#define TXT_HEAP_BASE (TXT_BASE + 0x300) +#define TXT_HEAP_SIZE (TXT_BASE + 0x308) +/* + * Chapter 6 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_MSEG_BASE (TXT_BASE + 0x310) +#define TXT_MSEG_SIZE (TXT_BASE + 0x318) + +/* + * Chapter 5.4.2.1 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_BIOSACM_ERRORCODE (TXT_BASE + 0x328) + +#define TXT_DPR (TXT_BASE + 0x330) +#define TXT_DPR_LOCK_SHIFT 0 +#define TXT_DPR_LOCK_SIZE_SHIFT 4 +#define TXT_DPR_LOCK_SIZE_MASK 0xff +#define TXT_DPR_TOP_ADDR_SHIFT 20 +#define TXT_DPR_TOP_ADDR_MASK 0xfff + +#define TXT_DPR_LOCK_MASK (1 << TXT_DPR_LOCK_SHIFT) +#define TXT_DPR_LOCK_SIZE(x) ((x) << TXT_DPR_LOCK_SIZE_SHIFT) +#define TXT_DPR_TOP_ADDR(x) ((x) << TXT_DPR_TOP_ADDR_SHIFT) + +#define TXT_ACM_KEY_HASH (TXT_BASE + 0x400) +#define TXT_ACM_KEY_HASH_LEN 0x4 + +#define TXT_E2STS (TXT_BASE + 0x8f0) +#define TXT_E2STS_SECRET_STS (1ull << 1) + +/* + * TXT Memory regions + * Chapter 5.3 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_PRIVATE_SPACE 0xfed20000UL +#define TXT_PUBLIC_SPACE 0xfed30000UL +#define TXT_TPM_DECODE_AREA 0xfed40000UL +#define TXT_RESERVED_SPACE 0xfed50000UL +#define TXT_RESERVED_SPACE_SIZE 0x3ffff + +/* ESI flags for GETSEC[ENTERACCS] see Reference Number: 323372-017 */ +#define ACMINPUT_RESET_TPM_AUXILIARY_INDICIES 2 +#define ACMINPUT_NOP 3 +#define ACMINPUT_SCHECK 4 +#define ACMINPUT_CLEAR_SECRETS 5 +#define ACMINPUT_LOCK_CONFIG 6 + +/* CBFS file names */ +#define TXT_FILE_LCP_PD_ACM "txt_bios_policy.bin" +#define TXT_FILE_BIOS_ACM "txt_bios_acm.bin" +#define TXT_FILE_SINIT_ACM "txt_sinit_acm.bin" + +/* + * GetSec EAX value. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2 + * Order Number: 325383-060US + */ +#define IA32_GETSEC_CAPABILITIES 0 +#define IA32_GETSEC_ENTERACCS 2 +#define IA32_GETSEC_SENTER 4 +#define IA32_GETSEC_SEXIT 5 +#define IA32_GETSEC_PARAMETERS 6 +#define IA32_GETSEC_SMCTRL 7 +#define IA32_GETSEC_WAKEUP 8 + +#define GETSEC_PARAMS_TXT_EXT (1ul << 5) +#define GETSEC_PARAMS_TXT_EXT_CRTM_SUPPORT (1ul << 1) +#define GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK (1ul << 6) + +/* ACM defines */ +#define INTEL_ACM_VENDOR 0x00008086 + +#define ACM_FORMAT_FLAGS_PW 0x00000000 +#define ACM_FORMAT_FLAGS_NPW (1 << 14) +#define ACM_FORMAT_FLAGS_DEBUG (1 << 15) + +/* Old ACMs are power of two aligned, newer ACMs are not */ +#define ACM_FORMAT_SIZE_64KB (64*KiB / 4) +#define ACM_FORMAT_SIZE_128KB (128*KiB / 4) +#define ACM_FORMAT_SIZE_256KB (256*KiB / 4) + +typedef enum { + CHIPSET_ACM = 2, +} acm_module_type; + +typedef enum { + BIOS = 0, + SINIT = 1, +} acm_module_sub_type; + +/* + * ACM Header v0.0 without dynamic part + * Chapter A.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ +struct acm_header_v0 { + uint16_t module_type; + uint16_t module_sub_type; + uint32_t header_len; + uint16_t header_version[2]; + uint16_t chipset_id; + uint16_t flags; + uint32_t module_vendor; + uint32_t date; + uint32_t size; + uint16_t txt_svn; + uint16_t se_svn; + uint32_t code_control; + uint32_t error_entry_point; + uint32_t gdt_limit; + uint32_t gdt_ptr; + uint32_t seg_sel; + uint32_t entry_point; + uint8_t reserved2[64]; + uint32_t key_size; + uint32_t scratch_size; + uint8_t rsa2048_pubkey[256]; + uint32_t pub_exp; + uint8_t rsa2048_sig[256]; + uint32_t scratch[143]; + uint8_t user_area[]; +} __packed; + +struct acm_info_table { + uint8_t uuid[16]; + uint8_t chipset_acm_type; + uint8_t version; + uint16_t length; + uint32_t chipset_id_list; + uint32_t os_sinit_data_ver; + uint32_t min_mle_hdr_ver; + uint32_t capabilities; + uint8_t acm_ver; + uint8_t reserved[3]; +} __packed; + +/* + * Extended Data Elements + * Chapter C.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ +struct txt_extended_data_element_header { + uint32_t type; + uint32_t size; + uint8_t data[0]; +} __packed; + +#define HEAP_EXTDATA_TYPE_END 0 +#define HEAP_EXTDATA_TYPE_BIOS_SPEC_VER 1 +#define HEAP_EXTDATA_TYPE_ACM 2 +#define HEAP_EXTDATA_TYPE_CUSTOM 4 + +struct txt_heap_acm_element { + struct txt_extended_data_element_header header; + uint32_t num_acms; // must greater 0, smaller than 3 + uint64_t acm_addrs[2]; +} __packed; + +/* + * BIOS Data Format + * Chapter C.2 + * Intel TXT Software Development Guide (Document: 315168-015) + */ +struct txt_biosdataregion { + uint32_t version; + uint32_t bios_sinit_size; + uint64_t lcp_pd_base; + uint64_t lcp_pd_size; + uint32_t no_logical_procs; + uint32_t sinit_flags; + union { + uint32_t mle_flags; + struct { + uint32_t support_acpi_ppi : 1; + uint32_t platform_type : 2; + }; + }; + u8 extended_data_elements[0]; +} __packed; + + +void txt_dump_regions(void); +void txt_dump_chipset_info(void); +void txt_dump_acm_info(const struct acm_header_v0 *acm_header); + +#endif /* SECURITY_INTEL_TXT_REGISTER_H_ */ diff --git a/src/security/memory/memory.c b/src/security/memory/memory.c index c815236..ad00857a 100644 --- a/src/security/memory/memory.c +++ b/src/security/memory/memory.c @@ -15,6 +15,8 @@ */
#include <types.h> +#include <stdint.h> +#include <security/intel/txt/txt.h> #include "memory.h"
/** @@ -27,6 +29,9 @@ if (CONFIG(SECURITY_CLEAR_DRAM_ON_REGULAR_BOOT)) return true;
+ if (CONFIG(INTEL_TXT) && intel_txt_memory_has_secrets()) + return true; + /* TODO: Add TEE environments here */
return false;
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 1:
(18 comments)
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/comm... File src/security/intel/txt/common.c:
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/comm... PS1, Line 146: const struct acm_header_v0 *acm_header = (struct acm_header_v0*)ptr; "(foo*)" should be "(foo *)"
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/comm... PS1, Line 157: const struct acm_header_v0 *acm_header = (struct acm_header_v0*)ptr; "(foo*)" should be "(foo *)"
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/comm... PS1, Line 163: /* Seems inconsistent accross generations. */ 'accross' may be misspelled - perhaps 'across'?
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/comm... PS1, Line 390: printk(BIOS_DEBUG, "TEE-TXT: GETSEC[CAPABILITIES] returned: \n"); unnecessary whitespace before a quoted newline
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/comm... PS1, Line 392: if (eax & (1 << 0)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/comm... PS1, Line 399: if (eax & (1 << 2)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/comm... PS1, Line 406: if (eax & (1 << 3)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/comm... PS1, Line 413: if (eax & (1 << 4)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/comm... PS1, Line 420: if (eax & (1 << 5)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/comm... PS1, Line 427: if (eax & (1 << 6)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/comm... PS1, Line 476: if (txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/gets... File src/security/intel/txt/getsec.c:
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/gets... PS1, Line 79: for(i = 0; i < 0x1f; i++) { space required before the open parenthesis '('
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/logg... File src/security/intel/txt/logging.c:
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/logg... PS1, Line 40: printk(BIOS_ERR, "%s: Error occured\n", phase); 'occured' may be misspelled - perhaps 'occurred'?
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/logg... PS1, Line 49: switch(txt_error & TXT_ERROR_MASK) { space required before the open parenthesis '('
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/logg... PS1, Line 165: switch(acm_header->flags) { switch and case should be at the same indent
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/logg... PS1, Line 165: switch(acm_header->flags) { space required before the open parenthesis '('
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/logg... PS1, Line 182: switch (acm_header->size) { switch and case should be at the same indent
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/rams... File src/security/intel/txt/ramstage.c:
https://review.coreboot.org/c/coreboot/+/42712/1/src/security/intel/txt/rams... PS1, Line 53: for (; mseg_base < mseg_size; mseg_base++) { braces {} are not necessary for single statement blocks
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 2:
(18 comments)
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/comm... File src/security/intel/txt/common.c:
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/comm... PS2, Line 146: const struct acm_header_v0 *acm_header = (struct acm_header_v0*)ptr; "(foo*)" should be "(foo *)"
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/comm... PS2, Line 157: const struct acm_header_v0 *acm_header = (struct acm_header_v0*)ptr; "(foo*)" should be "(foo *)"
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/comm... PS2, Line 163: /* Seems inconsistent accross generations. */ 'accross' may be misspelled - perhaps 'across'?
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/comm... PS2, Line 390: printk(BIOS_DEBUG, "TEE-TXT: GETSEC[CAPABILITIES] returned: \n"); unnecessary whitespace before a quoted newline
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/comm... PS2, Line 392: if (eax & (1 << 0)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/comm... PS2, Line 399: if (eax & (1 << 2)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/comm... PS2, Line 406: if (eax & (1 << 3)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/comm... PS2, Line 413: if (eax & (1 << 4)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/comm... PS2, Line 420: if (eax & (1 << 5)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/comm... PS2, Line 427: if (eax & (1 << 6)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/comm... PS2, Line 476: if (txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/gets... File src/security/intel/txt/getsec.c:
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/gets... PS2, Line 79: for(i = 0; i < 0x1f; i++) { space required before the open parenthesis '('
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/logg... File src/security/intel/txt/logging.c:
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/logg... PS2, Line 40: printk(BIOS_ERR, "%s: Error occured\n", phase); 'occured' may be misspelled - perhaps 'occurred'?
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/logg... PS2, Line 49: switch(txt_error & TXT_ERROR_MASK) { space required before the open parenthesis '('
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/logg... PS2, Line 165: switch(acm_header->flags) { switch and case should be at the same indent
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/logg... PS2, Line 165: switch(acm_header->flags) { space required before the open parenthesis '('
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/logg... PS2, Line 182: switch (acm_header->size) { switch and case should be at the same indent
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/rams... File src/security/intel/txt/ramstage.c:
https://review.coreboot.org/c/coreboot/+/42712/2/src/security/intel/txt/rams... PS2, Line 53: for (; mseg_base < mseg_size; mseg_base++) { braces {} are not necessary for single statement blocks
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 3:
(18 comments)
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/comm... File src/security/intel/txt/common.c:
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/comm... PS3, Line 146: const struct acm_header_v0 *acm_header = (struct acm_header_v0*)ptr; "(foo*)" should be "(foo *)"
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/comm... PS3, Line 157: const struct acm_header_v0 *acm_header = (struct acm_header_v0*)ptr; "(foo*)" should be "(foo *)"
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/comm... PS3, Line 163: /* Seems inconsistent accross generations. */ 'accross' may be misspelled - perhaps 'across'?
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/comm... PS3, Line 390: printk(BIOS_DEBUG, "TEE-TXT: GETSEC[CAPABILITIES] returned: \n"); unnecessary whitespace before a quoted newline
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/comm... PS3, Line 392: if (eax & (1 << 0)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/comm... PS3, Line 399: if (eax & (1 << 2)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/comm... PS3, Line 406: if (eax & (1 << 3)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/comm... PS3, Line 413: if (eax & (1 << 4)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/comm... PS3, Line 420: if (eax & (1 << 5)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/comm... PS3, Line 427: if (eax & (1 << 6)) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/comm... PS3, Line 476: if (txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK) { braces {} are not necessary for any arm of this statement
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/gets... File src/security/intel/txt/getsec.c:
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/gets... PS3, Line 79: for(i = 0; i < 0x1f; i++) { space required before the open parenthesis '('
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/logg... File src/security/intel/txt/logging.c:
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/logg... PS3, Line 40: printk(BIOS_ERR, "%s: Error occured\n", phase); 'occured' may be misspelled - perhaps 'occurred'?
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/logg... PS3, Line 49: switch(txt_error & TXT_ERROR_MASK) { space required before the open parenthesis '('
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/logg... PS3, Line 165: switch(acm_header->flags) { switch and case should be at the same indent
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/logg... PS3, Line 165: switch(acm_header->flags) { space required before the open parenthesis '('
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/logg... PS3, Line 182: switch (acm_header->size) { switch and case should be at the same indent
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/rams... File src/security/intel/txt/ramstage.c:
https://review.coreboot.org/c/coreboot/+/42712/3/src/security/intel/txt/rams... PS3, Line 53: for (; mseg_base < mseg_size; mseg_base++) { braces {} are not necessary for single statement blocks
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 3: Code-Review+1
Philipp Deppenwiese has uploaded a new patch set (#4) to the change originally created by Jonathan Zhang. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
security/intel/txt: Add Intel TXT support
Add TXT ramstage driver: * Show startup errors * Check for TXT reset * Check for Secrets-in-memory * Add assembly for GETSEC instruction * Check platform state if GETSEC instruction is supported * Configure TXT memory regions * Lock TXT * Protect TSEG using DMA protected regions * Place SINIT ACM * Print information about ACMs
Extend the `security_clear_dram_request()` function: * Clear all DRAM if secrets are in memory
Add a config so that the code gets build-tested. Since BIOS and SINIT ACM binaries are not available, use the STM binary as a placeholder.
Tested on OCP Wedge100s and Facebook Watson * Able to enter a Measured Launch Environment using SINIT ACM and TBOOT * Secrets in Memory bit is set on ungraceful shutdown * Memory is cleared after ungraceful shutdown
Change-Id: Iaf4be7f016cc12d3971e1e1fe171e6665e44c284 Signed-off-by: Philipp Deppenwiese zaolin@das-labor.org Reviewed-on: https://review.coreboot.org/c/coreboot/+/37016 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Christian Walter christian.walter@9elements.com (cherry picked from commit 5f9f77672d096a013094f3cad63cb138167dbf1b) --- A configs/config.purism_librem15_v4.txt_build_test M src/security/intel/txt/Kconfig M src/security/intel/txt/Makefile.inc A src/security/intel/txt/common.c A src/security/intel/txt/getsec.c A src/security/intel/txt/getsec_enteraccs.S A src/security/intel/txt/logging.c A src/security/intel/txt/ramstage.c A src/security/intel/txt/txt.h A src/security/intel/txt/txt_getsec.h A src/security/intel/txt/txt_register.h M src/security/memory/memory.c 12 files changed, 1,837 insertions(+), 9 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/42712/4
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 4:
(1 comment)
https://review.coreboot.org/c/coreboot/+/42712/4/src/security/intel/txt/comm... File src/security/intel/txt/common.c:
https://review.coreboot.org/c/coreboot/+/42712/4/src/security/intel/txt/comm... PS4, Line 390: } else { else is not generally useful after a break or return
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 4: Code-Review+1
Jonathan Zhang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 4: Code-Review+2
LGTM. This is cheery-pick of "5f9f77672d security/intel/txt: Add Intel TXT support" to master branch.
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 4:
Patch Set 4: Code-Review+2
LGTM. This is cheery-pick of "5f9f77672d security/intel/txt: Add Intel TXT support" to master branch.
There were updates (most notably, refactoring of the assembly code for getsec) so it would be good to test the current patchset to make sure nothing has broken.
Jonathan Zhang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 4:
Patch Set 4:
Patch Set 4: Code-Review+2
LGTM. This is cheery-pick of "5f9f77672d security/intel/txt: Add Intel TXT support" to master branch.
There were updates (most notably, refactoring of the assembly code for getsec) so it would be good to test the current patchset to make sure nothing has broken.
I will test now, and report back.
Jonathan Zhang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 4: Code-Review-1
Mark at "-1" as some more work is needed.
Philipp Deppenwiese has uploaded a new patch set (#5) to the change originally created by Jonathan Zhang. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
security/intel/txt: Add Intel TXT support
Add TXT ramstage driver: * Show startup errors * Check for TXT reset * Check for Secrets-in-memory * Add assembly for GETSEC instruction * Check platform state if GETSEC instruction is supported * Configure TXT memory regions * Lock TXT * Protect TSEG using DMA protected regions * Place SINIT ACM * Print information about ACMs
Extend the `security_clear_dram_request()` function: * Clear all DRAM if secrets are in memory
Add a config so that the code gets build-tested. Since BIOS and SINIT ACM binaries are not available, use the STM binary as a placeholder.
Tested on OCP Wedge100s and Facebook Watson * Able to enter a Measured Launch Environment using SINIT ACM and TBOOT * Secrets in Memory bit is set on ungraceful shutdown * Memory is cleared after ungraceful shutdown
Change-Id: Iaf4be7f016cc12d3971e1e1fe171e6665e44c284 Signed-off-by: Philipp Deppenwiese zaolin@das-labor.org Reviewed-on: https://review.coreboot.org/c/coreboot/+/37016 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Christian Walter christian.walter@9elements.com (cherry picked from commit 5f9f77672d096a013094f3cad63cb138167dbf1b) --- A configs/config.purism_librem15_v4.txt_build_test M src/security/intel/txt/Kconfig M src/security/intel/txt/Makefile.inc A src/security/intel/txt/common.c A src/security/intel/txt/getsec.c A src/security/intel/txt/getsec_enteraccs.S A src/security/intel/txt/logging.c A src/security/intel/txt/ramstage.c A src/security/intel/txt/txt.h A src/security/intel/txt/txt_getsec.h A src/security/intel/txt/txt_register.h M src/security/memory/memory.c 12 files changed, 1,837 insertions(+), 9 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/42712/5
Philipp Deppenwiese has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 5:
Issues should be fixed now. Please review again
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 5:
(1 comment)
https://review.coreboot.org/c/coreboot/+/42712/5/src/security/intel/txt/comm... File src/security/intel/txt/common.c:
https://review.coreboot.org/c/coreboot/+/42712/5/src/security/intel/txt/comm... PS5, Line 390: } else { else is not generally useful after a break or return
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 5: Code-Review+1
Angel Pons has uploaded a new patch set (#6) to the change originally created by Jonathan Zhang. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
security/intel/txt: Add Intel TXT support
Add TXT ramstage driver: * Show startup errors * Check for TXT reset * Check for Secrets-in-memory * Add assembly for GETSEC instruction * Check platform state if GETSEC instruction is supported * Configure TXT memory regions * Lock TXT * Protect TSEG using DMA protected regions * Place SINIT ACM * Print information about ACMs
Extend the `security_clear_dram_request()` function: * Clear all DRAM if secrets are in memory
Add a config so that the code gets build-tested. Since BIOS and SINIT ACM binaries are not available, use the STM binary as a placeholder.
Tested on OCP Wedge100s and Facebook Watson * Able to enter a Measured Launch Environment using SINIT ACM and TBOOT * Secrets in Memory bit is set on ungraceful shutdown * Memory is cleared after ungraceful shutdown
Change-Id: Iaf4be7f016cc12d3971e1e1fe171e6665e44c284 Signed-off-by: Philipp Deppenwiese zaolin@das-labor.org Reviewed-on: https://review.coreboot.org/c/coreboot/+/37016 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Christian Walter christian.walter@9elements.com (cherry picked from commit 5f9f77672d096a013094f3cad63cb138167dbf1b) --- A configs/config.purism_librem15_v4.txt_build_test M src/security/intel/txt/Kconfig M src/security/intel/txt/Makefile.inc A src/security/intel/txt/common.c A src/security/intel/txt/getsec.c A src/security/intel/txt/getsec_enteraccs.S A src/security/intel/txt/logging.c A src/security/intel/txt/ramstage.c A src/security/intel/txt/txt.h A src/security/intel/txt/txt_getsec.h A src/security/intel/txt/txt_register.h M src/security/memory/memory.c 12 files changed, 1,842 insertions(+), 9 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/42712/6
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 6:
(1 comment)
https://review.coreboot.org/c/coreboot/+/42712/6/src/security/intel/txt/comm... File src/security/intel/txt/common.c:
https://review.coreboot.org/c/coreboot/+/42712/6/src/security/intel/txt/comm... PS6, Line 390: } else { else is not generally useful after a break or return
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 6:
Patch Set 4: Code-Review-1
Mark at "-1" as some more work is needed.
Hi Jonathan,
Looks like I messed up the assembly part of the change... Sorry for the inconvenience, the latest patchset should work. I've also made CB:44183 to fix the same problem on master. I was able to reproduce the problem on a Haswell board and saw the hang is actually an exception:
CPU Index 0 - APIC 0 Unexpected Exception:13 @ 10:7f781080 - Halting Code: 0 eflags: 00010006 cr2: 00000000 eax: 0000000a ebx: 00000000 ecx: 03020100 edx: 00000000 edi: 7f7c4f10 esi: ffe40000 ebp: 7f7c4ee8 esp: 7f7c4e600x7f781040: 00 0f 32 50 52 b9 6a 02 0x7f781048: 00 00 0f 32 50 52 b9 6b 0x7f781050: 02 00 00 0f 32 50 52 b9 0x7f781058: 6c 02 00 00 0f 32 50 52 0x7f781060: b9 6e 02 00 00 0f 32 50 0x7f781068: 52 b9 6f 02 00 00 0f 32 0x7f781070: 50 52 31 db eb 14 89 d9 0x7f781078: d1 e1 03 0d 00 02 00 00 0x7f781080: 0f 32 50 52 41 0f 32 50 0x7f781088: 52 43 b9 fe 00 00 00 0f 0x7f781090: 32 25 ff 00 00 00 39 d8 0x7f781098: 7d dc 0f 20 c0 0d 00 00 0x7f7810a0: 00 60 0f 22 c0 b9 ff 02 0x7f7810a8: 00 00 0f 32 25 ff fb ff 0x7f7810b0: ff 0f 30 b9 50 02 00 00 0x7f7810b8: 31 d2 31 c0 0f 30 b9 58 0x7f7c4edc: 0x0027b68e 0x7f7c4ed8: 0x00000003 0x7f7c4ed4: 0x7f7c4ee8 0x7f7c4ed0: 0x7f7c4ee8 0x7f7c4ecc: 0xffe40000 0x7f7c4ec8: 0x7f7c4f10 0x7f7c4ec4: 0x00000011 0x7f7c4ec0: 0x00004200 0x7f7c4ebc: 0x00000003 0x7f7c4eb8: 0x7f7c4ed8 0x7f7c4eb4: 0x00850089 0x7f7c4eb0: 0x00000000 0x7f7c4eac: 0x06060606 0x7f7c4ea8: 0x06060606 0x7f7c4ea4: 0x06060606 0x7f7c4ea0: 0x06060606 0x7f7c4e9c: 0x00000000 0x7f7c4e98: 0x00000000 0x7f7c4e94: 0x06060606 0x7f7c4e90: 0x06060606 0x7f7c4e8c: 0x06060606 0x7f7c4e88: 0x06060606 0x7f7c4e84: 0x06060606 0x7f7c4e80: 0x06060606 0x7f7c4e7c: 0x06060606 0x7f7c4e78: 0x06060606 0x7f7c4e74: 0x06060606 0x7f7c4e70: 0x06060606 0x7f7c4e6c: 0x06060606 0x7f7c4e68: 0x06060606 0x7f7c4e64: 0x06060606 0x7f7c4e60: 0x06060606 <-esp
Angel Pons has uploaded a new patch set (#7) to the change originally created by Jonathan Zhang. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
security/intel/txt: Add Intel TXT support
Add TXT ramstage driver: * Show startup errors * Check for TXT reset * Check for Secrets-in-memory * Add assembly for GETSEC instruction * Check platform state if GETSEC instruction is supported * Configure TXT memory regions * Lock TXT * Protect TSEG using DMA protected regions * Place SINIT ACM * Print information about ACMs
Extend the `security_clear_dram_request()` function: * Clear all DRAM if secrets are in memory
Add a config so that the code gets build-tested. Since BIOS and SINIT ACM binaries are not available, use the STM binary as a placeholder.
Tested on OCP Wedge100s and Facebook Watson * Able to enter a Measured Launch Environment using SINIT ACM and TBOOT * Secrets in Memory bit is set on ungraceful shutdown * Memory is cleared after ungraceful shutdown
Change-Id: Iaf4be7f016cc12d3971e1e1fe171e6665e44c284 Signed-off-by: Philipp Deppenwiese zaolin@das-labor.org Reviewed-on: https://review.coreboot.org/c/coreboot/+/37016 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Christian Walter christian.walter@9elements.com (cherry picked from commit 5f9f77672d096a013094f3cad63cb138167dbf1b) --- A configs/config.purism_librem15_v4.txt_build_test M src/security/intel/txt/Kconfig M src/security/intel/txt/Makefile.inc A src/security/intel/txt/common.c A src/security/intel/txt/getsec.c A src/security/intel/txt/getsec_enteraccs.S A src/security/intel/txt/logging.c A src/security/intel/txt/ramstage.c A src/security/intel/txt/txt.h A src/security/intel/txt/txt_getsec.h A src/security/intel/txt/txt_register.h M src/security/memory/memory.c 12 files changed, 1,836 insertions(+), 9 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/42712/7
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 7:
(1 comment)
https://review.coreboot.org/c/coreboot/+/42712/7/src/security/intel/txt/comm... File src/security/intel/txt/common.c:
https://review.coreboot.org/c/coreboot/+/42712/7/src/security/intel/txt/comm... PS7, Line 390: } else { else is not generally useful after a break or return
Philipp Deppenwiese has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 7: Code-Review+2
Philipp Deppenwiese has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 7: -Code-Review
Philipp Deppenwiese has uploaded a new patch set (#8) to the change originally created by Jonathan Zhang. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
security/intel/txt: Add Intel TXT support
Add TXT ramstage driver: * Show startup errors * Check for TXT reset * Check for Secrets-in-memory * Add assembly for GETSEC instruction * Check platform state if GETSEC instruction is supported * Configure TXT memory regions * Lock TXT * Protect TSEG using DMA protected regions * Place SINIT ACM * Print information about ACMs
Extend the `security_clear_dram_request()` function: * Clear all DRAM if secrets are in memory
Add a config so that the code gets build-tested. Since BIOS and SINIT ACM binaries are not available, use the STM binary as a placeholder.
Tested on OCP Wedge100s and Facebook Watson * Able to enter a Measured Launch Environment using SINIT ACM and TBOOT * Secrets in Memory bit is set on ungraceful shutdown * Memory is cleared after ungraceful shutdown
Change-Id: Iaf4be7f016cc12d3971e1e1fe171e6665e44c284 Signed-off-by: Philipp Deppenwiese zaolin@das-labor.org Reviewed-on: https://review.coreboot.org/c/coreboot/+/37016 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Christian Walter christian.walter@9elements.com (cherry picked from commit 5f9f77672d096a013094f3cad63cb138167dbf1b) --- A configs/config.purism_librem15_v4.txt_build_test M src/security/intel/txt/Kconfig M src/security/intel/txt/Makefile.inc A src/security/intel/txt/common.c A src/security/intel/txt/getsec.c A src/security/intel/txt/getsec_enteraccs.S A src/security/intel/txt/logging.c A src/security/intel/txt/ramstage.c A src/security/intel/txt/txt.h A src/security/intel/txt/txt_getsec.h A src/security/intel/txt/txt_register.h M src/security/memory/memory.c 12 files changed, 1,846 insertions(+), 9 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/42712/8
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 8: Code-Review+1
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 8:
(1 comment)
https://review.coreboot.org/c/coreboot/+/42712/8/src/security/intel/txt/comm... File src/security/intel/txt/common.c:
https://review.coreboot.org/c/coreboot/+/42712/8/src/security/intel/txt/comm... PS8, Line 390: } else { else is not generally useful after a break or return
Jonathan Zhang has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 8: Code-Review+2
Tried on WatsonV2, ran tboot and then kexec, worked well!
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
Patch Set 8:
Patch Set 8: Code-Review+2
Tried on WatsonV2, ran tboot and then kexec, worked well!
Nice!
Philipp Deppenwiese has submitted this change. ( https://review.coreboot.org/c/coreboot/+/42712 )
Change subject: security/intel/txt: Add Intel TXT support ......................................................................
security/intel/txt: Add Intel TXT support
Add TXT ramstage driver: * Show startup errors * Check for TXT reset * Check for Secrets-in-memory * Add assembly for GETSEC instruction * Check platform state if GETSEC instruction is supported * Configure TXT memory regions * Lock TXT * Protect TSEG using DMA protected regions * Place SINIT ACM * Print information about ACMs
Extend the `security_clear_dram_request()` function: * Clear all DRAM if secrets are in memory
Add a config so that the code gets build-tested. Since BIOS and SINIT ACM binaries are not available, use the STM binary as a placeholder.
Tested on OCP Wedge100s and Facebook Watson * Able to enter a Measured Launch Environment using SINIT ACM and TBOOT * Secrets in Memory bit is set on ungraceful shutdown * Memory is cleared after ungraceful shutdown
Change-Id: Iaf4be7f016cc12d3971e1e1fe171e6665e44c284 Signed-off-by: Philipp Deppenwiese zaolin@das-labor.org Reviewed-on: https://review.coreboot.org/c/coreboot/+/37016 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Christian Walter christian.walter@9elements.com (cherry picked from commit 5f9f77672d096a013094f3cad63cb138167dbf1b) Reviewed-on: https://review.coreboot.org/c/coreboot/+/42712 Reviewed-by: Angel Pons th3fanbus@gmail.com Reviewed-by: Jonathan Zhang jonzhang@fb.com --- A configs/config.purism_librem15_v4.txt_build_test M src/security/intel/txt/Kconfig M src/security/intel/txt/Makefile.inc A src/security/intel/txt/common.c A src/security/intel/txt/getsec.c A src/security/intel/txt/getsec_enteraccs.S A src/security/intel/txt/logging.c A src/security/intel/txt/ramstage.c A src/security/intel/txt/txt.h A src/security/intel/txt/txt_getsec.h A src/security/intel/txt/txt_register.h M src/security/memory/memory.c 12 files changed, 1,846 insertions(+), 9 deletions(-)
Approvals: build bot (Jenkins): Verified Angel Pons: Looks good to me, but someone else must approve Jonathan Zhang: Looks good to me, approved
diff --git a/configs/config.purism_librem15_v4.txt_build_test b/configs/config.purism_librem15_v4.txt_build_test new file mode 100644 index 0000000..f2de8bc --- /dev/null +++ b/configs/config.purism_librem15_v4.txt_build_test @@ -0,0 +1,8 @@ +# Not meant for actual use. Exercises Intel TXT code. Since BIOS +# and SINIT ACM blobs are missing, use something else as placeholder. +CONFIG_VENDOR_PURISM=y +CONFIG_BOARD_PURISM_LIBREM15_V4=y +CONFIG_INTEL_TXT=y +CONFIG_INTEL_TXT_BIOSACM_FILE="3rdparty/blobs/cpu/intel/stm/stm.bin" +CONFIG_INTEL_TXT_SINITACM_FILE="3rdparty/blobs/cpu/intel/stm/stm.bin" +CONFIG_INTEL_TXT_LOGGING=y diff --git a/src/security/intel/txt/Kconfig b/src/security/intel/txt/Kconfig index 97d24fd..d828a9d 100644 --- a/src/security/intel/txt/Kconfig +++ b/src/security/intel/txt/Kconfig @@ -33,7 +33,7 @@ default "3rdparty/blobs/soc/intel/fsp_broadwell_de/biosacm.bin" if SOC_INTEL_FSP_BROADWELL_DE default "3rdparty/blobs/soc/intel/skylake/biosacm.bin" if SOC_INTEL_COMMON_SKYLAKE_BASE help - Intel TXT BIOS ACM file. This file can be obtained by privileged + Intel TXT BIOS ACM file. This file can be obtained through privileged access to Intel resources. Or for some platforms found inside the blob repository.
@@ -42,16 +42,34 @@ default "3rdparty/blobs/soc/intel/fsp_broadwell_de/sinitacm.bin" if SOC_INTEL_FSP_BROADWELL_DE default "3rdparty/blobs/soc/intel/skylake/sinitacm.bin" if SOC_INTEL_COMMON_SKYLAKE_BASE help - Intel TXT SINIT ACM file. This file can be obtained by privileged + Intel TXT SINIT ACM file. This file can be obtained through privileged access to Intel resources. Or for some platforms found inside the blob repository.
+config INTEL_TXT_LOGGING + bool "Enable verbose logging" + help + Print more TXT related debug output. + Use in pre-production environments only! + config INTEL_TXT_BIOSACM_ALIGNMENT hex - default 0x20000 # 128KB + default 0x20000 # 128 KiB help - Exceptions are Ivy- and Sandy Bridge with 64KB and Purely with 256KB - alignment size. Please overwrite it SoC specific. + Exceptions are Ivy and Sandy Bridge with 64 KiB and Purley with 256 KiB + alignment size. If necessary, override from platform-specific Kconfig. + +config INTEL_TXT_CBFS_BIOS_POLICY + string + default "txt_bios_policy.bin" + +config INTEL_TXT_CBFS_BIOS_ACM + string + default "txt_bios_acm.bin" + +config INTEL_TXT_CBFS_SINIT_ACM + string + default "txt_sinit_acm.bin"
endmenu # Intel
diff --git a/src/security/intel/txt/Makefile.inc b/src/security/intel/txt/Makefile.inc index 38eb65d..39c3ad1 100644 --- a/src/security/intel/txt/Makefile.inc +++ b/src/security/intel/txt/Makefile.inc @@ -1,5 +1,14 @@ ifeq ($(CONFIG_INTEL_TXT),y)
+romstage-y += common.c +romstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c + +ramstage-y += common.c +ramstage-y += getsec.c +ramstage-y += getsec_enteraccs.S +ramstage-y += ramstage.c +ramstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c + cbfs-files-y += txt_bios_acm.bin txt_bios_acm.bin-file := $(CONFIG_INTEL_TXT_BIOSACM_FILE) txt_bios_acm.bin-type := raw @@ -13,6 +22,8 @@ txt_sinit_acm.bin-compression := lzma endif
+ifeq ($(CONFIG_CPU_INTEL_FIRMWARE_INTERFACE_TABLE),y) + INTERMEDIATE+=add_acm_fit add_acm_fit: $(obj)/coreboot.pre $(IFITTOOL) $(IFITTOOL) -r COREBOOT -a -n txt_bios_acm.bin -t 2 -s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) -f $< @@ -26,7 +37,9 @@
INTERMEDIATE+=add_ibb_fit add_ibb_fit: $(obj)/coreboot.pre $(IFITTOOL) - $(foreach file, $(ibb-files), $(shell $(IFITTOOL) -f $< -a -n $(file) -t 7 -s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) \ - -r COREBOOT)) true + $(foreach file, $(ibb-files), $(shell $(IFITTOOL) -f $< -a -n $(file) -t 7 \ + -s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) -r COREBOOT)) true
-endif +endif # CPU_INTEL_FIRMWARE_INTERFACE_TABLE + +endif # INTEL_TXT diff --git a/src/security/intel/txt/common.c b/src/security/intel/txt/common.c new file mode 100644 index 0000000..32350b7 --- /dev/null +++ b/src/security/intel/txt/common.c @@ -0,0 +1,421 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/mmio.h> +#include <string.h> +#include <console/console.h> +#include <types.h> +#include <cbfs.h> +#include <cpu/x86/lapic.h> +#include <cpu/x86/cr.h> +#include <cpu/x86/mp.h> +#include <lib.h> +#include <smp/node.h> +#include <cf9_reset.h> +#include "txt.h" +#include "txt_register.h" +#include "txt_getsec.h" + +/** + * Dump the ACM error status bits. + * + * @param acm_error The status register to dump + * @return -1 on error (register is not valid) + * 0 on error (Class > 0 and Major > 0) + * 1 on success (Class == 0 and Major == 0 and progress > 0) + */ +int intel_txt_log_acm_error(const uint32_t acm_error) +{ + if (!(acm_error & ACMERROR_TXT_VALID)) + return -1; + + const uint8_t type = (acm_error & ACMERROR_TXT_TYPE_CODE) + >> ACMERROR_TXT_TYPE_SHIFT; + + switch (type) { + case ACMERROR_TXT_AC_MODULE_TYPE_BIOS: + printk(BIOS_ERR, "BIOSACM"); + break; + case ACMERROR_TXT_AC_MODULE_TYPE_SINIT: + printk(BIOS_ERR, "SINIT"); + break; + default: + printk(BIOS_ERR, "ACM"); + break; + } + printk(BIOS_ERR, ": Error code valid\n"); + + if (acm_error & ACMERROR_TXT_EXTERNAL) + printk(BIOS_ERR, " Caused by: External\n"); + else + printk(BIOS_ERR, " Caused by: Processor\n"); + + const uint32_t class = (acm_error & ACMERROR_TXT_CLASS_CODE) + >> ACMERROR_TXT_CLASS_SHIFT; + const uint32_t major = (acm_error & ACMERROR_TXT_MAJOR_CODE) + >> ACMERROR_TXT_MAJOR_SHIFT; + const uint32_t minor = (acm_error & ACMERROR_TXT_MINOR_CODE) + >> ACMERROR_TXT_MINOR_SHIFT; + const uint32_t progress = (acm_error & ACMERROR_TXT_PROGRESS_CODE) + >> ACMERROR_TXT_PROGRESS_SHIFT; + + if (!minor) { + if (class == 0 && major == 0 && progress > 0) { + printk(BIOS_ERR, " Execution successful\n"); + printk(BIOS_ERR, " Progress code 0x%x\n", progress); + } else { + printk(BIOS_ERR, " Error Class: %x\n", class); + printk(BIOS_ERR, " Error: %x.%x\n", major, progress); + } + } else { + printk(BIOS_ERR, " ACM didn't start\n"); + printk(BIOS_ERR, " Error Type: 0x%x\n", acm_error & 0xffffff); + return -1; + } + + return (acm_error & ACMERROR_TXT_EXTERNAL) && class == 0 && major == 0 && progress > 0; +} + +void intel_txt_log_spad(void) +{ + const uint64_t acm_status = read64((void *)TXT_SPAD); + + printk(BIOS_INFO, "TXT-STS: ACM verification "); + + if (acm_status & ACMSTS_VERIFICATION_ERROR) + printk(BIOS_INFO, "error\n"); + else + printk(BIOS_INFO, "successful\n"); + + printk(BIOS_INFO, "TXT-STS: IBB "); + + if (acm_status & ACMSTS_IBB_MEASURED) + printk(BIOS_INFO, "measured\n"); + else + printk(BIOS_INFO, "not measured\n"); + + printk(BIOS_INFO, "TXT-STS: TXT is "); + + if (acm_status & ACMSTS_TXT_DISABLED) + printk(BIOS_INFO, "disabled\n"); + else + printk(BIOS_INFO, "not disabled\n"); + + printk(BIOS_INFO, "TXT-STS: BIOS is "); + + if (acm_status & ACMSTS_BIOS_TRUSTED) + printk(BIOS_INFO, "trusted\n"); + else + printk(BIOS_INFO, "not trusted\n"); +} + +/* Returns true if secrets might be in memory */ +bool intel_txt_memory_has_secrets(void) +{ + bool ret; + if (!CONFIG(INTEL_TXT)) + return false; + + ret = (read8((void *)TXT_ESTS) & TXT_ESTS_WAKE_ERROR_STS) || + (read64((void *)TXT_E2STS) & TXT_E2STS_SECRET_STS); + + if (ret) + printk(BIOS_CRIT, "TXT-STS: Secrets in memory!\n"); + return ret; +} + +static struct acm_info_table *find_info_table(const void *ptr) +{ + const struct acm_header_v0 *acm_header = (struct acm_header_v0 *)ptr; + + return (struct acm_info_table *)(ptr + + (acm_header->header_len + acm_header->scratch_size) * sizeof(uint32_t)); +} + +/** + * Validate that the provided ACM is useable on this platform. + */ +static int validate_acm(const void *ptr) +{ + const struct acm_header_v0 *acm_header = (struct acm_header_v0 *)ptr; + uint32_t max_size_acm_area = 0; + + if (acm_header->module_type != CHIPSET_ACM) + return ACM_E_TYPE_NOT_MATCH; + + /* Seems inconsistent across generations. */ + if (acm_header->module_sub_type != 0 && acm_header->module_sub_type != 1) + return ACM_E_MODULE_SUB_TYPE_WRONG; + + if (acm_header->module_vendor != INTEL_ACM_VENDOR) + return ACM_E_MODULE_VENDOR_NOT_INTEL; + + if (((acm_header->header_len + acm_header->scratch_size) * sizeof(uint32_t) + + sizeof(struct acm_info_table)) > (acm_header->size & 0xffffff) * sizeof(uint32_t)) { + return ACM_E_SIZE_INCORRECT; + } + + if (!getsec_parameter(NULL, NULL, &max_size_acm_area, NULL, NULL, NULL)) + return ACM_E_CANT_CALL_GETSEC; + + /* + * Causes #GP if acm_header->size > processor internal authenticated + * code area capacity. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + */ + const size_t acm_len = 1UL << log2_ceil((acm_header->size & 0xffffff) << 2); + if (max_size_acm_area < acm_len) { + printk(BIOS_ERR, "TEE-TXT: BIOS ACM doesn't fit into AC execution region\n"); + return ACM_E_NOT_FIT_INTO_CPU_ACM_MEM; + } + + struct acm_info_table *info = find_info_table(ptr); + if (!info) + return ACM_E_NO_INFO_TABLE; + if (info->chipset_acm_type != BIOS) + return ACM_E_NOT_BIOS_ACM; + + static const u8 acm_uuid[] = { + 0xaa, 0x3a, 0xc0, 0x7f, 0xa7, 0x46, 0xdb, 0x18, + 0x2e, 0xac, 0x69, 0x8f, 0x8d, 0x41, 0x7f, 0x5a, + }; + if (memcmp(acm_uuid, info->uuid, sizeof(acm_uuid)) != 0) + return ACM_E_UUID_NOT_MATCH; + + if ((acm_header->flags & ACM_FORMAT_FLAGS_DEBUG) == + (read64((void *)TXT_VER_FSBIF) & TXT_VER_PRODUCTION_FUSED)) + return ACM_E_PLATFORM_IS_NOT_PROD; + + return 0; +} + +/* + * Test all bits for TXT execution. + * + * @return 0 on success + */ +int intel_txt_run_bios_acm(const u8 input_params) +{ + struct cbfsf file; + void *acm_data; + struct region_device acm; + size_t acm_len; + int ret; + + if (cbfs_boot_locate(&file, CONFIG_INTEL_TXT_CBFS_BIOS_ACM, NULL)) { + printk(BIOS_ERR, "TEE-TXT: Couldn't locate BIOS ACM in CBFS.\n"); + return -1; + } + + cbfs_file_data(&acm, &file); + acm_data = rdev_mmap_full(&acm); + acm_len = region_device_sz(&acm); + if (!acm_data || acm_len == 0) { + printk(BIOS_ERR, "TEE-TXT: Couldn't map BIOS ACM from CBFS.\n"); + return -1; + } + + /* + * CPU enforces only 4KiB alignment. + * Chapter A.1.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + if (!IS_ALIGNED((uintptr_t)acm_data, 4096)) { + printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't mapped at page boundary.\n"); + rdev_munmap(&acm, acm_data); + return -1; + } + + /* + * Causes #GP if not multiple of 64. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + */ + if (!IS_ALIGNED(acm_len, 64)) { + printk(BIOS_ERR, "TEE-TXT: BIOS ACM size isn't multiple of 64.\n"); + rdev_munmap(&acm, acm_data); + return -1; + } + + /* + * The ACM should be aligned to it's size, but that's not possible, as + * some ACMs are not power of two. Use the next power of two for verification. + */ + if (!IS_ALIGNED((uintptr_t)acm_data, (1UL << log2_ceil(acm_len)))) { + printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't aligned to its size.\n"); + rdev_munmap(&acm, acm_data); + return -1; + } + + if (CONFIG(INTEL_TXT_LOGGING)) + txt_dump_acm_info(acm_data); + + ret = validate_acm(acm_data); + if (ret < 0) { + printk(BIOS_ERR, "TEE-TXT: Validation of ACM failed with: %d\n", ret); + rdev_munmap(&acm, acm_data); + return ret; + } + + /* Call into assembly which invokes the referenced ACM */ + getsec_enteraccs(input_params, (uintptr_t)acm_data, acm_len); + + rdev_munmap(&acm, acm_data); + + const uint64_t acm_status = read64((void *)TXT_SPAD); + if (acm_status & ACMERROR_TXT_VALID) { + printk(BIOS_ERR, "TEE-TXT: FATAL ACM launch error !\n"); + /* + * WARNING ! + * To clear TXT.BIOSACM.ERRORCODE you must issue a cold reboot! + */ + intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)); + return -1; + } + if (intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)) != 1) + return -1; + + return 0; +} + + /* Returns true if cond is not met */ +static bool check_precondition(const int cond) +{ + printk(BIOS_DEBUG, "%s\n", cond ? "true" : "false"); + return !cond; +} + +/* + * Test all bits that are required for Intel TXT. + * Enable SMX if available. + * + * @return 0 on success + */ +bool intel_txt_prepare_txt_env(void) +{ + bool failure = false; + uint32_t txt_feature_flags = 0; + + unsigned int ecx = cpuid_ecx(1); + + printk(BIOS_DEBUG, "TEE-TXT: CPU supports SMX: "); + failure |= check_precondition(ecx & CPUID_SMX); + + printk(BIOS_DEBUG, "TEE-TXT: CPU supports VMX: "); + failure |= check_precondition(ecx & CPUID_VMX); + + msr_t msr = rdmsr(IA32_FEATURE_CONTROL); + if (!(msr.lo & BIT(0))) { + printk(BIOS_ERR, "TEE-TXT: IA32_FEATURE_CONTROL is not locked\n"); + full_reset(); + } + + printk(BIOS_DEBUG, "TEE-TXT: IA32_FEATURE_CONTROL\n"); + printk(BIOS_DEBUG, " VMXON in SMX enable: "); + failure |= check_precondition(msr.lo & BIT(1)); + + printk(BIOS_DEBUG, " VMXON outside SMX enable: "); + failure |= check_precondition(msr.lo & FEATURE_ENABLE_VMX); + + printk(BIOS_DEBUG, " register is locked: "); + failure |= check_precondition(msr.lo & BIT(0)); + + /* IA32_FEATURE_CONTROL enables getsec instructions */ + printk(BIOS_DEBUG, " GETSEC (all instructions) is enabled: "); + failure |= check_precondition((msr.lo & 0xff00) == 0xff00); + + /* Prevent crash and opt out early */ + if (failure) + return true; + + uint32_t eax = 0; + /* + * GetSec[CAPABILITIES] + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * Must check BIT0 of TXT chipset has been detected by CPU. + */ + if (!getsec_capabilities(&eax)) + return true; + + printk(BIOS_DEBUG, "TEE-TXT: GETSEC[CAPABILITIES] returned:\n"); + printk(BIOS_DEBUG, " TXT capable chipset: %s\n", (eax & BIT(0)) ? "true" : "false"); + + printk(BIOS_DEBUG, " ENTERACCS available: %s\n", (eax & BIT(2)) ? "true" : "false"); + printk(BIOS_DEBUG, " EXITAC available: %s\n", (eax & BIT(3)) ? "true" : "false"); + printk(BIOS_DEBUG, " SENTER available: %s\n", (eax & BIT(4)) ? "true" : "false"); + printk(BIOS_DEBUG, " SEXIT available: %s\n", (eax & BIT(5)) ? "true" : "false"); + printk(BIOS_DEBUG, " PARAMETERS available: %s\n", (eax & BIT(6)) ? "true" : "false"); + + /* + * Causes #GP if function is not supported by getsec. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * Order Number: 325383-060US + */ + if ((eax & 0x7d) != 0x7d) + failure = true; + + const uint64_t status = read64((void *)TXT_SPAD); + + if (status & ACMSTS_TXT_DISABLED) { + printk(BIOS_INFO, "TEE-TXT: TXT disabled by BIOS policy in FIT.\n"); + failure = true; + } + + /* + * Only the BSP must call getsec[ENTERACCS]. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * Order Number: 325383-060US + */ + if (!boot_cpu()) { + printk(BIOS_ERR, "TEE-TXT: BSP flag not set in APICBASE_MSR.\n"); + failure = true; + } + + /* + * There must be no MCEs pending. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * Order Number: 325383-060US + */ + msr = rdmsr(IA32_MCG_STATUS); + if (msr.lo & 0x4) { + printk(BIOS_ERR, "TEE-TXT: IA32_MCG_STATUS.MCIP is set.\n"); + failure = true; + } + + if (!getsec_parameter(NULL, NULL, NULL, NULL, NULL, &txt_feature_flags)) { + return true; + } else { + printk(BIOS_DEBUG, "TEE-TXT: Machine Check Register: "); + if (txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK) + printk(BIOS_DEBUG, "preserved\n"); + else + printk(BIOS_DEBUG, "must be clear\n"); + } + + if (!(txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK)) { + /* + * Make sure there are no uncorrectable MCE errors. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + */ + msr = rdmsr(IA32_MCG_CAP); + size_t max_mc_msr = msr.lo & MCA_BANKS_MASK; + for (size_t i = 0; i < max_mc_msr; i++) { + msr = rdmsr(IA32_MC0_STATUS + 4 * i); + if (!(msr.hi & MCA_STATUS_HI_UC)) + continue; + + printk(BIOS_ERR, "TEE-TXT: IA32_MC%zd_STATUS.UC is set.\n", i); + failure = true; + break; + } + } + + /* Need to park all APs. */ + if (CONFIG(PARALLEL_MP_AP_WORK)) + mp_park_aps(); + + return failure; +} diff --git a/src/security/intel/txt/getsec.c b/src/security/intel/txt/getsec.c new file mode 100644 index 0000000..a42607d --- /dev/null +++ b/src/security/intel/txt/getsec.c @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <stdint.h> +#include <cpu/x86/lapic.h> +#include <cpu/x86/cr.h> +#include <cpu/x86/cache.h> +#include <cpu/x86/mp.h> + +#include "txt_register.h" +#include "txt_getsec.h" + +/** + * Check for SMX support and enable it if possible. + * + * Returns false on error, true on success. + */ +static bool getsec_enabled(void) +{ + unsigned int ecx = cpuid_ecx(1); + /* + * Check if SMX and VMX is supported by CPU. + */ + if (!(ecx & CPUID_SMX) || !(ecx & CPUID_VMX)) + return false; + + /* + * Check if SMX, VMX and GetSec instructions haven't been disabled. + */ + msr_t msr = rdmsr(IA32_FEATURE_CONTROL); + if ((msr.lo & 0xff07) != 0xff07) + return false; + + /* + * Enable SMX. Required to execute GetSec instruction. + * Chapter 2.2.4.3 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + write_cr4(read_cr4() | CR4_SMXE); + + return true; +} + +/** + * Get information as returned by getsec[PARAMETER]. + * Arguments can be set to NULL if not needed. + * + * Returns false on error, true on success. + */ +bool getsec_parameter(uint32_t *version_mask, + uint32_t *version_numbers_supported, + uint32_t *max_size_acm_area, + uint32_t *memory_type_mask, + uint32_t *senter_function_disable, + uint32_t *txt_feature_flags) +{ + uint32_t i, eax, ebx, ecx; + + if (!getsec_enabled()) + return false; + + /* + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + */ + for (i = 0; i < 0x1f; i++) { + /* Getsec[PARAMETERS] */ + asm volatile ("getsec\n" + : "=a" (eax), "=b" (ebx), "=c" (ecx) + : "a" (IA32_GETSEC_PARAMETERS), "b" (i) :); + switch (eax & 0x1f) { + case 0: /* NULL - Exit marker */ + return true; + case 1: /* Supported AC module versions */ + if (version_mask) + *version_mask = ebx; + if (version_numbers_supported) + *version_numbers_supported = ecx; + break; + case 2: /* Max size of authenticated code execution area */ + if (max_size_acm_area) + *max_size_acm_area = eax & ~0x1f; + break; + case 3: /* External memory types supported during AC mode */ + if (memory_type_mask) + *memory_type_mask = eax; + break; + case 4: /* Selective SENTER functionality control */ + if (senter_function_disable) + *senter_function_disable = eax & (0x3f00); + break; + case 5: /* TXT extensions support */ + if (txt_feature_flags) + *txt_feature_flags = eax & (0x60); + break; + } + } + + return true; +} + +/** + * Get capabilities as returned by getsec[CAPABILITIES]. + * + * Returns false on error, true on success. + */ + +bool getsec_capabilities(uint32_t *eax) +{ + if (!getsec_enabled()) + return false; + + asm volatile ("getsec\n" + : "=a" (*eax) + : "a" (IA32_GETSEC_CAPABILITIES), "b" (0) :); + + return true; +} diff --git a/src/security/intel/txt/getsec_enteraccs.S b/src/security/intel/txt/getsec_enteraccs.S new file mode 100644 index 0000000..3135de7 --- /dev/null +++ b/src/security/intel/txt/getsec_enteraccs.S @@ -0,0 +1,318 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <cpu/x86/mtrr.h> +#include <cpu/x86/cr.h> +#include <cpu/x86/msr.h> + +#define MTRR_HIGH_MASK $((1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1) + +.macro PUSH_MSR x + movl $(\x), %ecx + rdmsr + push %eax + push %edx +.endm + +.macro POP_MSR x + movl $(\x), %ecx + pop %edx + pop %eax + wrmsr +.endm + +.macro CLEAR_MSR x + movl $(\x), %ecx + xorl %edx, %edx + xorl %eax, %eax + wrmsr +.endm + +.align 4 +.text + +/* + * See "SAFER MODE EXTENSIONS REFERENCE." + * Chapter "GETSEC[ENTERACCS] - Execute Authenticated Chipset Code" for reference. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D + * + * void getsec_enteraccs(uint32_t esi, + * uint32_t acm_base, + * uint32_t acm_size); + */ +.global getsec_enteraccs +getsec_enteraccs: + + /* Backup current register state */ + pushl %ebp + movl %esp, %ebp + + pushal + + movl %cr0, %eax + pushl %eax + movl %cr4, %eax + pushl %eax + + /* Pushed 10 32bit registers */ + + /* Reserve space on stack for GDT */ + subl $8, %esp + + PUSH_MSR IA32_MISC_ENABLE + PUSH_MSR MTRR_FIX_64K_00000 + PUSH_MSR MTRR_FIX_16K_80000 + PUSH_MSR MTRR_FIX_16K_A0000 + PUSH_MSR MTRR_FIX_4K_C0000 + PUSH_MSR MTRR_FIX_4K_C8000 + PUSH_MSR MTRR_FIX_4K_D0000 + PUSH_MSR MTRR_FIX_4K_D8000 + PUSH_MSR MTRR_FIX_4K_E0000 + PUSH_MSR MTRR_FIX_4K_F0000 + PUSH_MSR MTRR_FIX_4K_F8000 + + /* Push variable MTRRs in ascending order */ + + xorl %ebx, %ebx + jmp cond_push_var_mtrrs + +body_push_var_mtrrs: + + movl %ebx, %ecx + shll %ecx + addl $(MTRR_PHYS_BASE(0)), %ecx + rdmsr + push %eax + push %edx + incl %ecx /* MTRR_PHYS_MASK */ + rdmsr + push %eax + push %edx + + incl %ebx + +cond_push_var_mtrrs: + + movl $(MTRR_CAP_MSR), %ecx + rdmsr + andl $(0xff), %eax + cmp %ebx, %eax + jg body_push_var_mtrrs + + /* + * Disable cache. + * Chapter 2.2.4.3 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + movl %cr0, %eax + orl $(CR0_CD | CR0_NW), %eax + movl %eax, %cr0 + + /* Disable fixed MTRRs */ + movl $(MTRR_DEF_TYPE_MSR), %ecx + rdmsr + andl $(~MTRR_DEF_TYPE_FIX_EN), %eax + wrmsr + + /* + * Clear fixed MTRRs. + * Chapter 2.2.5.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + CLEAR_MSR MTRR_FIX_64K_00000 + CLEAR_MSR MTRR_FIX_16K_80000 + CLEAR_MSR MTRR_FIX_16K_A0000 + CLEAR_MSR MTRR_FIX_4K_C0000 + CLEAR_MSR MTRR_FIX_4K_C8000 + CLEAR_MSR MTRR_FIX_4K_D0000 + CLEAR_MSR MTRR_FIX_4K_D8000 + CLEAR_MSR MTRR_FIX_4K_E0000 + CLEAR_MSR MTRR_FIX_4K_F0000 + CLEAR_MSR MTRR_FIX_4K_F8000 + + /* + * Clear variable MTRRs + * Chapter 2.2.5.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + movl $(MTRR_CAP_MSR), %ecx + rdmsr + andl $(0xff), %eax + movl %eax, %ebx + + xorl %eax, %eax + xorl %edx, %edx + + jmp cond_clear_var_mtrrs + +body_clear_var_mtrrs: + + decl %ebx + movl %ebx, %ecx + shll %ecx + addl $(MTRR_PHYS_BASE(0)), %ecx + wrmsr + incl %ecx /* MTRR_PHYS_MASK */ + wrmsr + +cond_clear_var_mtrrs: + + cmpl $0, %ebx + jnz body_clear_var_mtrrs + + /* + * Setup BIOS ACM as WB + * Chapter A.1.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + movl $(MTRR_PHYS_BASE(0)), %ecx + movl 12(%ebp), %eax /* %eax = acmbase */ + orl $(6), %eax /* MTRR_TYPE_WB */ + movl $0, %edx + wrmsr + + /* Round acmsize to next power of two. Required for MTRR programming. */ + movl $1, %ebx + movl 16(%ebp), %ecx /* %ebx = acmsize */ + dec %ecx + bsr %ecx, %ecx /* find MSB */ + inc %ecx + shl %cl, %ebx + movl $(MTRR_PHYS_MASK(0)), %ecx + xorl %eax, %eax + subl %ebx, %eax /* %eax = 4GIB - log2_ceil(ACM SIZE) */ + orl $((1 << 11)), %eax /* MTRR_PHYS_MASK_VALID */ + movl MTRR_HIGH_MASK, %edx + wrmsr + + /* Enable cache - GPF# if not done */ + movl %cr0, %eax + andl $(~(CR0_CD | CR0_NW)), %eax + movl %eax, %cr0 + + /* Enable Numeric error - GPE# if not done */ + movl %cr0, %eax + orl $(CR0_NE), %eax + movl %eax, %cr0 + + /* Enable SMX and FXSTORE - for getsec */ + movl %cr4, %eax + orl $(CR4_SMXE | CR4_OSFXSR), %eax + movl %eax, %cr4 + + /* + * Save GDT + * Chapter A.1.2 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + sgdt -48(%ebp) + + /* Backup stack pointer */ + movd %esp, %xmm0 + movd %ebp, %xmm1 + + /* + * Get function arguments. + * It's important to pass the exact ACM size as it's used by getsec to verify + * the integrity of ACM. Unlike the size for MTRR programming, which needs to + * be power of two. + * + * The following assembly code is based on tboot's tboot/include/txt/smx.h. + */ + movl 8(%ebp), %esi /* flags */ + movl 12(%ebp), %ebx /* acm_base */ + movl 16(%ebp), %ecx /* acm_size */ + + movl $0, %edx /* reserved, must be zero */ + movl $0, %edi /* must be zero */ + movl $2, %eax /* GetSec[ENTERACCS] */ + + getsec + + /* Restore stack pointer */ + movd %xmm0, %esp + movd %xmm1, %ebp + + /* Reload GDT */ + lgdt -48(%ebp) + + /* Set cs */ + ljmp $0x10, $1f +1: + /* Fix segment registers */ + movl $0x18, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %ss + movl %eax, %fs + movl %eax, %gs + + /* Disable cache */ + movl %cr0, %eax + orl $(CR0_CD | CR0_NW), %eax + movl %eax, %cr0 + + /* Pop variable MTRRs in descending order */ + + movl $(MTRR_CAP_MSR), %ecx + rdmsr + andl $(0xff), %eax + movl %eax, %ebx + + jmp cond_pop_var_mtrrs + +body_pop_var_mtrrs: + + decl %ebx + movl %ebx, %ecx + shll %ecx + addl $(MTRR_PHYS_MASK(0)), %ecx + pop %edx + pop %eax + wrmsr + decl %ecx /* MTRR_PHYS_BASE */ + pop %edx + pop %eax + wrmsr + +cond_pop_var_mtrrs: + + cmpl $0, %ebx + jne body_pop_var_mtrrs + + POP_MSR MTRR_FIX_4K_F8000 + POP_MSR MTRR_FIX_4K_F0000 + POP_MSR MTRR_FIX_4K_E0000 + POP_MSR MTRR_FIX_4K_D8000 + POP_MSR MTRR_FIX_4K_D0000 + POP_MSR MTRR_FIX_4K_C8000 + POP_MSR MTRR_FIX_4K_C0000 + POP_MSR MTRR_FIX_16K_A0000 + POP_MSR MTRR_FIX_16K_80000 + POP_MSR MTRR_FIX_64K_00000 + POP_MSR IA32_MISC_ENABLE + + /* Enable fixed MTRRs */ + movl $(MTRR_DEF_TYPE_MSR), %ecx + rdmsr + orl $(MTRR_DEF_TYPE_FIX_EN), %eax + wrmsr + + /* Enable cache */ + movl %cr0, %eax + andl $(~(CR0_CD | CR0_NW)), %eax + movl %eax, %cr0 + + /* Pop GDT */ + addl $8, %esp + + popl %eax + movl %eax, %cr4 + popl %eax + movl %eax, %cr0 + + popal + + movl %ebp, %esp + popl %ebp + + ret diff --git a/src/security/intel/txt/logging.c b/src/security/intel/txt/logging.c new file mode 100644 index 0000000..cf14b55 --- /dev/null +++ b/src/security/intel/txt/logging.c @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#if CONFIG(SOC_INTEL_COMMON_BLOCK_SA) +#include <intelblocks/systemagent.h> +#endif + +#include <arch/mmio.h> +#include <string.h> + +#include "txt.h" +#include "txt_register.h" + +/** + * Logs microcode or SINIT ACM errors. + * Does not log SBIOS ACM errors. + */ +static void log_txt_error(const char *phase) +{ + const uint64_t txt_error = read64((void *)TXT_ERROR); + + if (txt_error & ACMERROR_TXT_VALID) { + printk(BIOS_ERR, "%s: Error occurred\n", phase); + + if (txt_error & ACMERROR_TXT_EXTERNAL) + printk(BIOS_ERR, " Caused by: External\n"); + else + printk(BIOS_ERR, " Caused by: Processor\n"); + + printk(BIOS_ERR, " Type: "); + + switch (txt_error & TXT_ERROR_MASK) { + case 0: + printk(BIOS_ERR, "Legacy Shutdown\n"); + break; + case 5: + printk(BIOS_ERR, "Load memory type error in ACM area\n"); + break; + case 6: + printk(BIOS_ERR, "Unrecognized ACM format\n"); + break; + case 7: + printk(BIOS_ERR, "Failure to authenticate\n"); + break; + case 8: + printk(BIOS_ERR, "Invalid ACM format\n"); + break; + case 9: + printk(BIOS_ERR, "Unexpected Snoop hit\n"); + break; + case 10: + printk(BIOS_ERR, "Invalid event\n"); + break; + case 11: + printk(BIOS_ERR, "Invalid MLE\n"); + break; + case 12: + printk(BIOS_ERR, "Machine check event\n"); + break; + case 13: + printk(BIOS_ERR, "VMXAbort\n"); + break; + case 14: + printk(BIOS_ERR, "AC memory corruption\n"); + break; + case 15: + printk(BIOS_ERR, "Illegal voltage/bus ratio\n"); + break; + default: + printk(BIOS_ERR, "unknown\n"); + break; + } + } +} + +/** + * Dump useful informaation about the BIOS ACM state. + * Should run right after console_init() in romstage. + * Resets the platform if TXT reset is active and MLE cannot be established. + **/ +void intel_txt_log_bios_acm_error(void) +{ + uint32_t bios_acm_error; + uint64_t acm_status; + uint64_t txt_error; + + printk(BIOS_INFO, "TEE-TXT: State of ACM and ucode update:\n"); + + bios_acm_error = read32((void *)TXT_BIOSACM_ERRORCODE); + acm_status = read64((void *)TXT_SPAD); + txt_error = read64((void *)TXT_ERROR); + + /* Errors by BIOS ACM or FIT */ + if ((txt_error & ACMERROR_TXT_VALID) && + (acm_status & ACMERROR_TXT_VALID)) { + intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)); + log_txt_error("FIT MICROCODE"); + } + /* Errors by SINIT */ + if ((txt_error & ACMERROR_TXT_VALID) && + !(acm_status & ACMERROR_TXT_VALID)) { + intel_txt_log_acm_error(txt_error); + log_txt_error("SINIT"); + } + + /* Check for fatal ACM error and TXT reset */ + uint8_t error = read8((void *)TXT_ESTS); + if (error & TXT_ESTS_TXT_RESET_STS) { + printk(BIOS_CRIT, "TXT-STS: Intel TXT reset detected\n"); + intel_txt_log_acm_error(read32((void *)TXT_ERROR)); + } +} + +/** + * Dump information about the provided ACM. + */ +void txt_dump_acm_info(const struct acm_header_v0 *acm_header) +{ + const struct acm_info_table *info = NULL; + if (!acm_header) + return; + + printk(BIOS_INFO, "ACM @ %p\n", acm_header); + + const size_t acm_size = (acm_header->size & 0xffffff) << 2; + const size_t info_off = (acm_header->header_len + acm_header->scratch_size) * 4; + + if (acm_size > (info_off + sizeof(struct acm_info_table))) + info = (const struct acm_info_table *) + ((const unsigned char *)acm_header + info_off); + + printk(BIOS_INFO, " ACM: Binary Info\n"); + if (acm_header->module_type == CHIPSET_ACM) + printk(BIOS_INFO, " Type: Chipset ACM\n"); + + if (acm_header->module_sub_type == 0) + printk(BIOS_INFO, " Subtype: undefined\n"); + else if (acm_header->module_sub_type == 1) + printk(BIOS_INFO, " Subtype: Run at reset\n"); + + printk(BIOS_INFO, " Header: v%u.%u\n", acm_header->header_version[0], + acm_header->header_version[1]); + + printk(BIOS_INFO, " Chipset: %u\n", acm_header->chipset_id); + printk(BIOS_INFO, " Size: %zu\n", acm_size); + + switch (acm_header->flags) { + case ACM_FORMAT_FLAGS_PW: + printk(BIOS_INFO, " Flags: PW signed (Production Worthy)\n"); + break; + case ACM_FORMAT_FLAGS_NPW: + printk(BIOS_INFO, " Flags: NPW signed (Non Production Worthy)\n"); + break; + case ACM_FORMAT_FLAGS_DEBUG: + printk(BIOS_INFO, " Flags: Debug signed\n"); + break; + } + + if (acm_header->module_vendor == INTEL_ACM_VENDOR) + printk(BIOS_INFO, " Vendor: Intel Corporation\n"); + + printk(BIOS_INFO, " Date: %x\n", acm_header->date); + + switch (acm_header->size) { + case ACM_FORMAT_SIZE_64KB: + printk(BIOS_INFO, " Size: 64KB\n"); + printk(BIOS_INFO, " CBnT: no\n"); + break; + case ACM_FORMAT_SIZE_128KB: + printk(BIOS_INFO, " Size: 128KB\n"); + printk(BIOS_INFO, " CBnT: no\n"); + break; + case ACM_FORMAT_SIZE_256KB: + printk(BIOS_INFO, " Size: 256KB\n"); + printk(BIOS_INFO, " CBnT: yes\n"); + break; + default: + printk(BIOS_INFO, " Size: 0x%08x\n", acm_header->size); + + break; + } + + printk(BIOS_INFO, " TXT SVN: %u\n", acm_header->txt_svn); + printk(BIOS_INFO, " SE SVN: %u\n", acm_header->se_svn); + + if (!info) + return; + printk(BIOS_INFO, " Table info:\n"); + printk(BIOS_INFO, " UUID: "); + for (size_t i = 0; i < sizeof(info->uuid); i++) + printk(BIOS_INFO, "%02X ", info->uuid[i]); + printk(BIOS_INFO, "\n"); + printk(BIOS_INFO, " Chipset acm type: 0x%x\n", info->chipset_acm_type); + printk(BIOS_INFO, " Capabilities: 0x%x\n", info->capabilities); +} + +/** + * Dump information about the chipset's TXT capabilities. + */ +void txt_dump_chipset_info(void) +{ + printk(BIOS_INFO, "TEE-TXT: Chipset Key Hash 0x"); + for (int i = 0; i < TXT_ACM_KEY_HASH_LEN; i++) { + printk(BIOS_INFO, "%llx", read64((void *)TXT_ACM_KEY_HASH + + (i * sizeof(uint64_t)))); + } + printk(BIOS_INFO, "\n"); + + printk(BIOS_INFO, "TEE-TXT: DIDVID 0x%x\n", read32((void *)TXT_DIDVID)); + printk(BIOS_INFO, "TEE-TXT: production fused chipset: %s\n", + (read64((void *)TXT_VER_FSBIF) & TXT_VER_PRODUCTION_FUSED) ? "true" : "false"); +} + +void txt_dump_regions(void) +{ + struct txt_biosdataregion *bdr = NULL; + uintptr_t tseg = 0; + uint64_t reg64; + + reg64 = read64((void *)TXT_HEAP_BASE); + if ((reg64 != 0 && reg64 != ~0UL) && + (read64((void *)(uintptr_t)reg64) >= (sizeof(*bdr) + sizeof(uint64_t)))) + bdr = (void *)((uintptr_t)reg64 + sizeof(uint64_t)); + + printk(BIOS_DEBUG, "TEE-TXT: TSEG 0x%lx\n", tseg * MiB); + printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.BASE 0x%llx\n", read64((void *)TXT_HEAP_BASE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.SIZE 0x%llx\n", read64((void *)TXT_HEAP_SIZE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.BASE 0x%llx\n", read64((void *)TXT_SINIT_BASE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.SIZE 0x%llx\n", read64((void *)TXT_SINIT_SIZE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.BASE 0x%llx\n", read64((void *)TXT_MSEG_BASE)); + printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.SIZE 0x%llx\n", read64((void *)TXT_MSEG_SIZE)); + + if (bdr) { + printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.bios_sinit_size 0x%x\n", + bdr->bios_sinit_size); + printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_size 0x%llx\n", + bdr->lcp_pd_size); + printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_base 0x%llx\n", + bdr->lcp_pd_base); + } +} diff --git a/src/security/intel/txt/ramstage.c b/src/security/intel/txt/ramstage.c new file mode 100644 index 0000000..76efa96 --- /dev/null +++ b/src/security/intel/txt/ramstage.c @@ -0,0 +1,382 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/mmio.h> +#include <arch/acpi.h> +#include <bootstate.h> +#include <bootmem.h> +#include <console/console.h> +#include <stdint.h> +#include <cbfs.h> +#include <cpu/intel/common/common.h> +#include <cpu/x86/msr.h> + +#include <lib.h> +#include <device/pci_ops.h> + +#if CONFIG(SOC_INTEL_FSP_BROADWELL_DE) +#include <soc/broadwell_de.h> +#include <soc/ramstage.h> +#endif + +#include "txt.h" +#include "txt_register.h" +#include "txt_getsec.h" + +/* FIXME: Seems to work only on some platforms */ +static void log_ibb_measurements(void) +{ + const uint64_t mseg_size = read64((void *)TXT_MSEG_SIZE); + uint64_t mseg_base = read64((void *)TXT_MSEG_BASE); + + if (!mseg_size || !mseg_base || mseg_size <= mseg_base) + return; + /* + * MSEG SIZE and MSEG BASE might contain random values. + * Assume below 4GiB and 8byte aligned. + */ + if (mseg_base & ~0xfffffff8ULL || mseg_size & ~0xfffffff8ULL) + return; + + printk(BIOS_INFO, "TEE-TXT: IBB Hash 0x"); + for (; mseg_base < mseg_size; mseg_base++) + printk(BIOS_INFO, "%02X", read8((void *)(uintptr_t)mseg_base)); + + printk(BIOS_INFO, "\n"); +} + +void bootmem_platform_add_ranges(void) +{ + uint64_t status = read64((void *)TXT_SPAD); + + if (status & ACMSTS_TXT_DISABLED) + return; + + /* Chapter 5.5.5 Intel TXT reserved memory */ + bootmem_add_range(TXT_RESERVED_SPACE, + TXT_RESERVED_SPACE_SIZE, + BM_MEM_RESERVED); + + /* Intel TPM decode memory */ + bootmem_add_range(TXT_TPM_DECODE_AREA, + TXT_RESERVED_SPACE - TXT_TPM_DECODE_AREA, + BM_MEM_RESERVED); + + /* Intel TXT public space memory */ + bootmem_add_range(TXT_PUBLIC_SPACE, + TXT_TPM_DECODE_AREA - TXT_PUBLIC_SPACE, + BM_MEM_RESERVED); + + /* Intel TXT private space memory */ + bootmem_add_range(TXT_PRIVATE_SPACE, + TXT_PUBLIC_SPACE - TXT_PRIVATE_SPACE, + BM_MEM_RESERVED); + + const uint32_t txt_dev_memory = read32((void *)TXT_DPR) & + (TXT_DPR_TOP_ADDR_MASK << TXT_DPR_TOP_ADDR_SHIFT); + const uint32_t txt_dev_size = + (read32((void *)TXT_DPR) >> TXT_DPR_LOCK_SIZE_SHIFT) & + TXT_DPR_LOCK_SIZE_MASK; + + /* Chapter 5.5.6 Intel TXT Device Memory */ + bootmem_add_range(txt_dev_memory - txt_dev_size * MiB, + txt_dev_size * MiB, + BM_MEM_RESERVED); +} + +static bool get_wake_error_status(void) +{ + const uint8_t error = read8((void *)TXT_ESTS); + return !!(error & TXT_ESTS_WAKE_ERROR_STS); +} + +static void check_secrets_txt(void *unused) +{ + uint64_t status = read64((void *)TXT_SPAD); + + if (status & ACMSTS_TXT_DISABLED) + return; + + /* Check for fatal ACM error and TXT reset */ + if (get_wake_error_status()) { + /* + * Check if secrets bit needs to be reset. Only platforms that support + * CONFIG(PLATFORM_HAS_DRAM_CLEAR) will be able to run this code. + * Assume all memory really was cleared. + * + * TXT will issue a platform reset to come up sober. + */ + if (intel_txt_memory_has_secrets()) { + printk(BIOS_INFO, "TEE-TXT: Wiping TEE...\n"); + intel_txt_run_bios_acm(ACMINPUT_CLEAR_SECRETS); + + /* Should never reach this point ... */ + intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)); + die("Waiting for platform reset...\n"); + } + } +} + +BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_ENTRY, check_secrets_txt, NULL); + +/** + * Log TXT startup errors, check all bits for TXT, run BIOSACM using + * GETSEC[ENTERACCS]. + * + * If a "TXT reset" is detected or "memory had secrets" is set, then do nothing as + * 1. Running ACMs will cause a TXT-RESET + * 2. Memory will be scrubbed in BS_DEV_INIT + * 3. TXT-RESET will be issued by code above later + * + */ +static void init_intel_txt(void *unused) +{ + const uint64_t status = read64((void *)TXT_SPAD); + + if (status & ACMSTS_TXT_DISABLED) + return; + + printk(BIOS_INFO, "TEE-TXT: Initializing TEE...\n"); + + intel_txt_log_spad(); + + if (CONFIG(INTEL_TXT_LOGGING)) { + intel_txt_log_bios_acm_error(); + txt_dump_chipset_info(); + } + + printk(BIOS_INFO, "TEE-TXT: Validate TEE...\n"); + + if (intel_txt_prepare_txt_env()) { + printk(BIOS_ERR, "TEE-TXT: Failed to prepare TXT environment\n"); + return; + } + + /* Check for fatal ACM error and TXT reset */ + if (get_wake_error_status()) { + /* Can't run ACMs with TXT_ESTS_WAKE_ERROR_STS set */ + printk(BIOS_ERR, "TEE-TXT: Fatal BIOS ACM error reported\n"); + return; + } + + printk(BIOS_INFO, "TEE-TXT: Testing BIOS ACM calling code...\n"); + + /* + * Test BIOS ACM code. + * ACM should do nothing on reserved functions, and return an error code + * in TXT_BIOSACM_ERRORCODE. Tests showed that this is not true. + * Use special function "NOP" that does 'nothing'. + */ + if (intel_txt_run_bios_acm(ACMINPUT_NOP) < 0) { + printk(BIOS_ERR, "TEE-TXT: Error calling BIOS ACM with NOP function.\n"); + return; + } + + if (status & (ACMSTS_BIOS_TRUSTED | ACMSTS_IBB_MEASURED)) { + log_ibb_measurements(); + + int s3resume = acpi_is_wakeup_s3(); + if (!s3resume) { + printk(BIOS_INFO, "TEE-TXT: Scheck...\n"); + if (intel_txt_run_bios_acm(ACMINPUT_SCHECK) < 0) { + printk(BIOS_ERR, "TEE-TXT: Error calling BIOS ACM.\n"); + return; + } + } + } +} + +BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, init_intel_txt, NULL); + +static void push_sinit_heap(u8 **heap_ptr, void *data, size_t data_length) +{ + /* Push size */ + const uint64_t tmp = data_length + 8; + memcpy(*heap_ptr, &tmp, 8); + *heap_ptr += 8; + + if (data_length) { + /* Push data */ + memcpy(*heap_ptr, data, data_length); + *heap_ptr += data_length; + } +} + +/** + * Finalize the TXT device. + * + * - Lock TXT register. + * - Protect TSEG using DMA protected regions. + * - Setup TXT regions. + * - Place SINIT ACM in TXT_SINIT memory segment. + * - Fill TXT BIOSDATA region. + */ +static void lockdown_intel_txt(void *unused) +{ + const uint64_t status = read64((void *)TXT_SPAD); + uintptr_t tseg = 0; + + if (status & ACMSTS_TXT_DISABLED) + return; + + printk(BIOS_INFO, "TEE-TXT: Locking TEE...\n"); + + /* Lock TXT config, unlocks TXT_HEAP_BASE */ + if (intel_txt_run_bios_acm(ACMINPUT_LOCK_CONFIG) < 0) { + printk(BIOS_ERR, "TEE-TXT: Failed to lock registers.\n"); + printk(BIOS_ERR, "TEE-TXT: SINIT won't be supported.\n"); + return; + } + + if (CONFIG(SOC_INTEL_FSP_BROADWELL_DE)) + tseg = sa_get_tseg_base() >> 20; + + /* + * Document Number: 558294 + * Chapter 5.5.6.1 DMA Protection Memory Region + */ + + const u8 dpr_capable = !!(read64((void *)TXT_CAPABILITIES) & + TXT_CAPABILITIES_DPR); + printk(BIOS_INFO, "TEE-TXT: DPR capable %x\n", dpr_capable); + if (dpr_capable) { + + /* Protect 3 MiB below TSEG and lock register */ + write64((void *)TXT_DPR, (TXT_DPR_TOP_ADDR(tseg) | + TXT_DPR_LOCK_SIZE(3) | + TXT_DPR_LOCK_MASK)); + +#if CONFIG(SOC_INTEL_FSP_BROADWELL_DE) + broadwell_de_set_dpr(tseg, 3 * MiB); + broadwell_de_lock_dpr(); +#endif + printk(BIOS_INFO, "TEE-TXT: TXT.DPR 0x%08x\n", + read32((void *)TXT_DPR)); + } + + /* + * Document Number: 558294 + * Chapter 5.5.6.3 Intel TXT Heap Memory Region + */ + write64((void *)TXT_HEAP_SIZE, 0xE0000); + write64((void *)TXT_HEAP_BASE, + ALIGN_DOWN((tseg * MiB) - read64((void *)TXT_HEAP_SIZE), 4096)); + + /* + * Document Number: 558294 + * Chapter 5.5.6.2 SINIT Memory Region + */ + write64((void *)TXT_SINIT_SIZE, 0x20000); + write64((void *)TXT_SINIT_BASE, + ALIGN_DOWN(read64((void *)TXT_HEAP_BASE) - + read64((void *)TXT_SINIT_SIZE), 4096)); + + /* + * BIOS Data Format + * Chapter C.2 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + struct { + struct txt_biosdataregion bdr; + struct txt_heap_acm_element heap_acm; + struct txt_extended_data_element_header end; + } __packed data = {0}; + + /* TPM2.0 requires version 6 of BDT */ + if (CONFIG(TPM2)) + data.bdr.version = 6; + else + data.bdr.version = 5; + + data.bdr.no_logical_procs = dev_count_cpu(); + + void *sinit_base = (void *)(uintptr_t)read64((void *)TXT_SINIT_BASE); + data.bdr.bios_sinit_size = cbfs_boot_load_file(CONFIG_INTEL_TXT_CBFS_SINIT_ACM, + sinit_base, + read64((void *)TXT_SINIT_SIZE), + CBFS_TYPE_RAW); + + if (data.bdr.bios_sinit_size) { + printk(BIOS_INFO, "TEE-TXT: Placing SINIT ACM in memory.\n"); + if (CONFIG(INTEL_TXT_LOGGING)) + txt_dump_acm_info(sinit_base); + } else { + printk(BIOS_ERR, "TEE-TXT: Couldn't locate SINIT ACM in CBFS.\n"); + /* Clear memory */ + memset(sinit_base, 0, read64((void *)TXT_SINIT_SIZE)); + } + + struct cbfsf file; + /* The following have been removed from BIOS Data Table in version 6 */ + if (!cbfs_boot_locate(&file, CONFIG_INTEL_TXT_CBFS_BIOS_POLICY, NULL)) { + struct region_device policy; + + cbfs_file_data(&policy, &file); + void *policy_data = rdev_mmap_full(&policy); + size_t policy_len = region_device_sz(&policy); + + if (policy_data && policy_len) { + /* Point to FIT Type 9 entry in flash */ + data.bdr.lcp_pd_base = (uintptr_t)policy_data; + data.bdr.lcp_pd_size = (uint64_t)policy_len; + rdev_munmap(&policy, policy_data); + } else { + printk(BIOS_ERR, "TEE-TXT: Couldn't map LCP PD Policy from CBFS.\n"); + } + } else { + printk(BIOS_ERR, "TEE-TXT: Couldn't locate LCP PD Policy in CBFS.\n"); + } + + data.bdr.support_acpi_ppi = 0; + data.bdr.platform_type = 0; + + /* Extended elements - ACM addresses */ + data.heap_acm.header.type = HEAP_EXTDATA_TYPE_ACM; + data.heap_acm.header.size = sizeof(data.heap_acm); + if (data.bdr.bios_sinit_size) { + data.heap_acm.num_acms = 2; + data.heap_acm.acm_addrs[1] = (uintptr_t)sinit_base; + } else { + data.heap_acm.num_acms = 1; + } + data.heap_acm.acm_addrs[0] = + (uintptr_t)cbfs_boot_map_with_leak(CONFIG_INTEL_TXT_CBFS_BIOS_ACM, + CBFS_TYPE_RAW, + NULL); + /* Extended elements - End marker */ + data.end.type = HEAP_EXTDATA_TYPE_END; + data.end.size = sizeof(data.end); + + /* Fill TXT.HEAP.BASE with 4 subregions */ + u8 *heap_struct = (void *)((uintptr_t)read64((void *)TXT_HEAP_BASE)); + + /* BiosData */ + push_sinit_heap(&heap_struct, &data, sizeof(data)); + + /* OsMLEData */ + /* FIXME: Does firmware need to write this? */ + push_sinit_heap(&heap_struct, NULL, 0); + + /* OsSinitData */ + /* FIXME: Does firmware need to write this? */ + push_sinit_heap(&heap_struct, NULL, 0); + + /* SinitMLEData */ + /* FIXME: Does firmware need to write this? */ + push_sinit_heap(&heap_struct, NULL, 0); + + /* + * FIXME: Server-TXT capable platforms need to install an STM in SMM and set up MSEG. + */ + + /** + * Chapter 5.10.1 SMM in the Intel TXT for Servers Environment + * Disable MSEG. + */ + write64((void *)TXT_MSEG_SIZE, 0); + write64((void *)TXT_MSEG_BASE, 0); + + if (CONFIG(INTEL_TXT_LOGGING)) + txt_dump_regions(); +} + +BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, lockdown_intel_txt, NULL); diff --git a/src/security/intel/txt/txt.h b/src/security/intel/txt/txt.h new file mode 100644 index 0000000..fc5c49e --- /dev/null +++ b/src/security/intel/txt/txt.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SECURITY_INTEL_TXT_H_ +#define SECURITY_INTEL_TXT_H_ + +#include <types.h> + +/* Error codes */ +#define ACM_E_TYPE_NOT_MATCH 0x01 +#define ACM_E_MODULE_SUB_TYPE_WRONG 0x02 +#define ACM_E_MODULE_VENDOR_NOT_INTEL 0x03 +#define ACM_E_SIZE_INCORRECT 0x04 +#define ACM_E_CANT_CALL_GETSEC 0x05 +#define ACM_E_NOT_FIT_INTO_CPU_ACM_MEM 0x06 +#define ACM_E_NO_INFO_TABLE 0x07 +#define ACM_E_NOT_BIOS_ACM 0x08 +#define ACM_E_UUID_NOT_MATCH 0x09 +#define ACM_E_PLATFORM_IS_NOT_PROD 0x10 + +void intel_txt_log_bios_acm_error(void); +int intel_txt_log_acm_error(const uint32_t acm_error); +void intel_txt_log_spad(void); +bool intel_txt_memory_has_secrets(void); +int intel_txt_run_bios_acm(const u8 input_params); +bool intel_txt_prepare_txt_env(void); + +#endif /* SECURITY_INTEL_TXT_H_ */ diff --git a/src/security/intel/txt/txt_getsec.h b/src/security/intel/txt/txt_getsec.h new file mode 100644 index 0000000..7c4a1a4 --- /dev/null +++ b/src/security/intel/txt/txt_getsec.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SECURITY_INTEL_TXT_GETSEC_H_ +#define SECURITY_INTEL_TXT_GETSEC_H_ + +#include <stdint.h> + +bool getsec_parameter(uint32_t *version_mask, + uint32_t *version_numbers_supported, + uint32_t *max_size_acm_area, + uint32_t *memory_type_mask, + uint32_t *senter_function_disable, + uint32_t *txt_feature_flags); + +bool getsec_capabilities(uint32_t *eax); + +void getsec_enteraccs(const uint32_t esi, + const uint32_t acm_base, + const uint32_t acm_size); + +#endif /* SECURITY_INTEL_TXT_REGISTER_H_ */ diff --git a/src/security/intel/txt/txt_register.h b/src/security/intel/txt/txt_register.h new file mode 100644 index 0000000..70bb309 --- /dev/null +++ b/src/security/intel/txt/txt_register.h @@ -0,0 +1,267 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SECURITY_INTEL_TXT_REGISTER_H_ +#define SECURITY_INTEL_TXT_REGISTER_H_ + +#include <types.h> +#include <stddef.h> + +/* + * Document: 315168-016 + * Intel Trusted Execution Technology (Intel TXT) + * Software Development Guide + * Chapter B + */ +#define TXT_BASE 0xfed30000UL + +#define TXT_STS (TXT_BASE + 0) +#define TXT_ESTS (TXT_BASE + 8) +#define TXT_ESTS_TXT_RESET_STS (1 << 0) +/* + * Chapter 6 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_ESTS_WAKE_ERROR_STS (1 << 6) + +#define TXT_ERROR (TXT_BASE + 0x30) +#define ACMERROR_TXT_VALID (1ul << 31) +#define ACMERROR_TXT_EXTERNAL (1ul << 30) + +#define ACMERROR_TXT_PROGRESS_SHIFT 16 +#define ACMERROR_TXT_MINOR_SHIFT 15 +#define ACMERROR_TXT_MAJOR_SHIFT 10 +#define ACMERROR_TXT_CLASS_SHIFT 4 +#define ACMERROR_TXT_TYPE_SHIFT 0 + +#define ACMERROR_TXT_PROGRESS_CODE (0xffull << ACMERROR_TXT_PROGRESS_SHIFT) +#define ACMERROR_TXT_MINOR_CODE (0x01ull << ACMERROR_TXT_MINOR_SHIFT) +#define ACMERROR_TXT_MAJOR_CODE (0x1full << ACMERROR_TXT_MAJOR_SHIFT) +#define ACMERROR_TXT_CLASS_CODE (0x3full << ACMERROR_TXT_CLASS_SHIFT) +#define ACMERROR_TXT_TYPE_CODE (0x0full << ACMERROR_TXT_TYPE_SHIFT) + +#define ACMERROR_TXT_AC_MODULE_TYPE_BIOS 0 +#define ACMERROR_TXT_AC_MODULE_TYPE_SINIT 1 + +#define TXT_ERROR_MASK (0x3ff << 0) + +#define TXT_CMD_RESET (TXT_BASE + 0x38) +#define TXT_CMD_CLOSE_PRIVATE (TXT_BASE + 0x48) + +/* Present in Document Number: 315168-016. */ +#define TXT_SPAD (TXT_BASE + 0xa0) +#define ACMSTS_IBB_MEASURED (1ull << 63) +#define ACMSTS_VERIFICATION_ERROR (1ull << 62) +#define ACMSTS_BG_STARTUP_ERROR (1ull << 61) /* CBnT platforms only */ +#define ACMSTS_TXT_DISABLED (1ull << 60) /* disabled by FIT type 0xA record */ +#define ACMSTS_BIOS_TRUSTED (1ull << 59) +#define ACMSTS_MEM_CLEAR_POWER_DOWN (1ull << 47) +#define ACMSTS_TXT_STARTUP_SUCCESS (1ull << 30) + +#define TXT_VER_FSBIF (TXT_BASE + 0x100) +#define TXT_VER_PRODUCTION_FUSED (1ull << 31) + +#define TXT_DIDVID (TXT_BASE + 0x110) + +/* + * Chapter 6 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_CAPABILITIES (TXT_BASE + 0x200) +#define TXT_CAPABILITIES_DPR (1ull << 26) +#define TXT_CAPABILITIES_PMRC (1ull << 19) + +#define TXT_VER_QPIIF (TXT_BASE + 0x200) + +#define TXT_SINIT_BASE (TXT_BASE + 0x270) +#define TXT_SINIT_SIZE (TXT_BASE + 0x278) +#define TXT_MLE_JOIN (TXT_BASE + 0x290) + +#define TXT_HEAP_BASE (TXT_BASE + 0x300) +#define TXT_HEAP_SIZE (TXT_BASE + 0x308) +/* + * Chapter 6 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_MSEG_BASE (TXT_BASE + 0x310) +#define TXT_MSEG_SIZE (TXT_BASE + 0x318) + +/* + * Chapter 5.4.2.1 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_BIOSACM_ERRORCODE (TXT_BASE + 0x328) + +#define TXT_DPR (TXT_BASE + 0x330) +#define TXT_DPR_LOCK_SHIFT 0 +#define TXT_DPR_LOCK_SIZE_SHIFT 4 +#define TXT_DPR_LOCK_SIZE_MASK 0xff +#define TXT_DPR_TOP_ADDR_SHIFT 20 +#define TXT_DPR_TOP_ADDR_MASK 0xfff + +#define TXT_DPR_LOCK_MASK (1 << TXT_DPR_LOCK_SHIFT) +#define TXT_DPR_LOCK_SIZE(x) ((x) << TXT_DPR_LOCK_SIZE_SHIFT) +#define TXT_DPR_TOP_ADDR(x) ((x) << TXT_DPR_TOP_ADDR_SHIFT) + +#define TXT_ACM_KEY_HASH (TXT_BASE + 0x400) +#define TXT_ACM_KEY_HASH_LEN 0x4 + +#define TXT_E2STS (TXT_BASE + 0x8f0) +#define TXT_E2STS_SECRET_STS (1ull << 1) + +/* + * TXT Memory regions + * Chapter 5.3 + * Intel Trusted Execution Technology Lab Handout + */ +#define TXT_PRIVATE_SPACE 0xfed20000UL +#define TXT_PUBLIC_SPACE 0xfed30000UL +#define TXT_TPM_DECODE_AREA 0xfed40000UL +#define TXT_RESERVED_SPACE 0xfed50000UL + +#define TXT_RESERVED_SPACE_SIZE 0x3ffff + +/* ESI flags for GETSEC[ENTERACCS] see Reference Number: 323372-017 */ +#define ACMINPUT_RESET_TPM_AUXILIARY_INDICIES 2 +#define ACMINPUT_NOP 3 +#define ACMINPUT_SCHECK 4 +#define ACMINPUT_CLEAR_SECRETS 5 +#define ACMINPUT_LOCK_CONFIG 6 + +/* + * GetSec EAX value. + * SAFER MODE EXTENSIONS REFERENCE. + * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2 + * Order Number: 325383-060US + */ +#define IA32_GETSEC_CAPABILITIES 0 +#define IA32_GETSEC_ENTERACCS 2 +#define IA32_GETSEC_SENTER 4 +#define IA32_GETSEC_SEXIT 5 +#define IA32_GETSEC_PARAMETERS 6 +#define IA32_GETSEC_SMCTRL 7 +#define IA32_GETSEC_WAKEUP 8 + +#define GETSEC_PARAMS_TXT_EXT (1ul << 5) +#define GETSEC_PARAMS_TXT_EXT_CRTM_SUPPORT (1ul << 1) +#define GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK (1ul << 6) + +/* ACM defines */ +#define INTEL_ACM_VENDOR 0x00008086 + +#define ACM_FORMAT_FLAGS_PW 0x00000000 +#define ACM_FORMAT_FLAGS_NPW (1 << 14) +#define ACM_FORMAT_FLAGS_DEBUG (1 << 15) + +/* Old ACMs are power of two aligned, newer ACMs are not */ +#define ACM_FORMAT_SIZE_64KB (64 * KiB / 4) +#define ACM_FORMAT_SIZE_128KB (128 * KiB / 4) +#define ACM_FORMAT_SIZE_256KB (256 * KiB / 4) + +/* MSRs */ +#define IA32_MCG_STATUS 0x17a + +typedef enum { + CHIPSET_ACM = 2, +} acm_module_type; + +typedef enum { + BIOS = 0, + SINIT = 1, +} acm_module_sub_type; + +/* + * ACM Header v0.0 without dynamic part + * Chapter A.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ +struct __packed acm_header_v0 { + uint16_t module_type; + uint16_t module_sub_type; + uint32_t header_len; + uint16_t header_version[2]; + uint16_t chipset_id; + uint16_t flags; + uint32_t module_vendor; + uint32_t date; + uint32_t size; + uint16_t txt_svn; + uint16_t se_svn; + uint32_t code_control; + uint32_t error_entry_point; + uint32_t gdt_limit; + uint32_t gdt_ptr; + uint32_t seg_sel; + uint32_t entry_point; + uint8_t reserved2[64]; + uint32_t key_size; + uint32_t scratch_size; + uint8_t rsa2048_pubkey[256]; + uint32_t pub_exp; + uint8_t rsa2048_sig[256]; + uint32_t scratch[143]; + uint8_t user_area[]; +}; + +struct __packed acm_info_table { + uint8_t uuid[16]; + uint8_t chipset_acm_type; + uint8_t version; + uint16_t length; + uint32_t chipset_id_list; + uint32_t os_sinit_data_ver; + uint32_t min_mle_hdr_ver; + uint32_t capabilities; + uint8_t acm_ver; + uint8_t reserved[3]; +}; + +/* + * Extended Data Elements + * Chapter C.1 + * Intel TXT Software Development Guide (Document: 315168-015) + */ +struct __packed txt_extended_data_element_header { + uint32_t type; + uint32_t size; + uint8_t data[0]; +}; + +#define HEAP_EXTDATA_TYPE_END 0 +#define HEAP_EXTDATA_TYPE_BIOS_SPEC_VER 1 +#define HEAP_EXTDATA_TYPE_ACM 2 +#define HEAP_EXTDATA_TYPE_CUSTOM 4 + +struct __packed txt_heap_acm_element { + struct txt_extended_data_element_header header; + uint32_t num_acms; // must greater 0, smaller than 3 + uint64_t acm_addrs[2]; +}; + +/* + * BIOS Data Format + * Chapter C.2 + * Intel TXT Software Development Guide (Document: 315168-015) + */ +struct __packed txt_biosdataregion { + uint32_t version; + uint32_t bios_sinit_size; + uint64_t lcp_pd_base; + uint64_t lcp_pd_size; + uint32_t no_logical_procs; + uint32_t sinit_flags; + union { + uint32_t mle_flags; + struct { + uint32_t support_acpi_ppi : 1; + uint32_t platform_type : 2; + }; + }; + u8 extended_data_elements[0]; +}; + + +void txt_dump_regions(void); +void txt_dump_chipset_info(void); +void txt_dump_acm_info(const struct acm_header_v0 *acm_header); + +#endif /* SECURITY_INTEL_TXT_REGISTER_H_ */ diff --git a/src/security/memory/memory.c b/src/security/memory/memory.c index c815236..a1bc663 100644 --- a/src/security/memory/memory.c +++ b/src/security/memory/memory.c @@ -14,7 +14,8 @@ * GNU General Public License for more details. */
-#include <types.h> +#include <stdint.h> +#include <security/intel/txt/txt.h> #include "memory.h"
/** @@ -27,6 +28,9 @@ if (CONFIG(SECURITY_CLEAR_DRAM_ON_REGULAR_BOOT)) return true;
+ if (CONFIG(INTEL_TXT) && intel_txt_memory_has_secrets()) + return true; + /* TODO: Add TEE environments here */
return false;