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:
parent
a9eec2cc2f
commit
5f9f77672d
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue