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>
This commit is contained in:
Philipp Deppenwiese 2018-11-20 14:22:15 +01:00
parent a9eec2cc2f
commit 5f9f77672d
12 changed files with 1837 additions and 9 deletions

View File

@ -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

View File

@ -19,7 +19,7 @@ config INTEL_TXT_BIOSACM_FILE
string "BIOS ACM file"
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.
@ -27,16 +27,34 @@ config INTEL_TXT_SINITACM_FILE
string "SINIT ACM file"
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

View File

@ -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-align := 0x10
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 @@ ibb-files += bootblock
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

View File

@ -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 <soc/intel/common/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");
global_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;
}

View File

@ -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;
}

View File

@ -0,0 +1,319 @@
/* 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
/* Variable MTRR index is passed through %ebx */
.macro PUSH_VAR_MTRR
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
.endm
.macro POP_VAR_MTRR
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
.endm
.macro CLEAR_VAR_MTRR
movl %ebx, %ecx
shll %ecx
addl MTRR_PHYS_BASE(0), %ecx
xorl %edx, %edx
xorl %eax, %eax
wrmsr
incl %ecx /* MTRR_PHYS_MASK */
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:
PUSH_VAR_MTRR
incl %ebx
cond_push_var_mtrrs:
movl $(MTRR_CAP_MSR), %ecx
rdmsr
andl $(0xff), %eax
cmp %ebx, %eax
jge 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
body_clear_var_mtrrs:
CLEAR_VAR_MTRR
decl %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
/* Restore MTTRs */
/* Pop variable MTRRs in descending order */
movl $(MTRR_CAP_MSR), %ecx
rdmsr
andl $(0xff), %eax
movl %eax, %ebx
body_pop_var_mtrrs:
POP_VAR_MTRR
decl %ebx
jnz 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

View File

@ -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);
}
}

View File

@ -0,0 +1,372 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/mmio.h>
#include <acpi/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>
#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;
}
/*
* 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));
// DPR TODO: implement SA_ENABLE_DPR in the intelblocks
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);

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <types.h>
#include <stdint.h>
#include <security/intel/txt/txt.h>
#include "memory.h"
/**
@ -13,6 +14,9 @@ bool security_clear_dram_request(void)
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;