summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configs/config.purism_librem15_v4.txt_build_test8
-rw-r--r--src/security/intel/txt/Kconfig28
-rw-r--r--src/security/intel/txt/Makefile.inc19
-rw-r--r--src/security/intel/txt/common.c421
-rw-r--r--src/security/intel/txt/getsec.c117
-rw-r--r--src/security/intel/txt/getsec_enteraccs.S319
-rw-r--r--src/security/intel/txt/logging.c241
-rw-r--r--src/security/intel/txt/ramstage.c372
-rw-r--r--src/security/intel/txt/txt.h27
-rw-r--r--src/security/intel/txt/txt_getsec.h21
-rw-r--r--src/security/intel/txt/txt_register.h267
-rw-r--r--src/security/memory/memory.c6
12 files changed, 1837 insertions, 9 deletions
diff --git a/configs/config.purism_librem15_v4.txt_build_test b/configs/config.purism_librem15_v4.txt_build_test
new file mode 100644
index 0000000000..f2de8bc59f
--- /dev/null
+++ b/configs/config.purism_librem15_v4.txt_build_test
@@ -0,0 +1,8 @@
+# Not meant for actual use. Exercises Intel TXT code. Since BIOS
+# and SINIT ACM blobs are missing, use something else as placeholder.
+CONFIG_VENDOR_PURISM=y
+CONFIG_BOARD_PURISM_LIBREM15_V4=y
+CONFIG_INTEL_TXT=y
+CONFIG_INTEL_TXT_BIOSACM_FILE="3rdparty/blobs/cpu/intel/stm/stm.bin"
+CONFIG_INTEL_TXT_SINITACM_FILE="3rdparty/blobs/cpu/intel/stm/stm.bin"
+CONFIG_INTEL_TXT_LOGGING=y
diff --git a/src/security/intel/txt/Kconfig b/src/security/intel/txt/Kconfig
index 732f3d3c67..edb13a51b5 100644
--- a/src/security/intel/txt/Kconfig
+++ b/src/security/intel/txt/Kconfig
@@ -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
diff --git a/src/security/intel/txt/Makefile.inc b/src/security/intel/txt/Makefile.inc
index 38eb65d69c..39c3ad1dff 100644
--- a/src/security/intel/txt/Makefile.inc
+++ b/src/security/intel/txt/Makefile.inc
@@ -1,5 +1,14 @@
ifeq ($(CONFIG_INTEL_TXT),y)
+romstage-y += common.c
+romstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c
+
+ramstage-y += common.c
+ramstage-y += getsec.c
+ramstage-y += getsec_enteraccs.S
+ramstage-y += ramstage.c
+ramstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c
+
cbfs-files-y += txt_bios_acm.bin
txt_bios_acm.bin-file := $(CONFIG_INTEL_TXT_BIOSACM_FILE)
txt_bios_acm.bin-type := raw
@@ -13,6 +22,8 @@ txt_sinit_acm.bin-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
diff --git a/src/security/intel/txt/common.c b/src/security/intel/txt/common.c
new file mode 100644
index 0000000000..d3e18376a5
--- /dev/null
+++ b/src/security/intel/txt/common.c
@@ -0,0 +1,421 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <arch/mmio.h>
+#include <string.h>
+#include <console/console.h>
+#include <types.h>
+#include <cbfs.h>
+#include <cpu/x86/lapic.h>
+#include <cpu/x86/cr.h>
+#include <cpu/x86/mp.h>
+#include <lib.h>
+#include <smp/node.h>
+#include <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;
+}
diff --git a/src/security/intel/txt/getsec.c b/src/security/intel/txt/getsec.c
new file mode 100644
index 0000000000..a42607dccc
--- /dev/null
+++ b/src/security/intel/txt/getsec.c
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <stdint.h>
+#include <cpu/x86/lapic.h>
+#include <cpu/x86/cr.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/mp.h>
+
+#include "txt_register.h"
+#include "txt_getsec.h"
+
+/**
+ * Check for SMX support and enable it if possible.
+ *
+ * Returns false on error, true on success.
+ */
+static bool getsec_enabled(void)
+{
+ unsigned int ecx = cpuid_ecx(1);
+ /*
+ * Check if SMX and VMX is supported by CPU.
+ */
+ if (!(ecx & CPUID_SMX) || !(ecx & CPUID_VMX))
+ return false;
+
+ /*
+ * Check if SMX, VMX and GetSec instructions haven't been disabled.
+ */
+ msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
+ if ((msr.lo & 0xff07) != 0xff07)
+ return false;
+
+ /*
+ * Enable SMX. Required to execute GetSec instruction.
+ * Chapter 2.2.4.3
+ * Intel TXT Software Development Guide (Document: 315168-015)
+ */
+ write_cr4(read_cr4() | CR4_SMXE);
+
+ return true;
+}
+
+/**
+ * Get information as returned by getsec[PARAMETER].
+ * Arguments can be set to NULL if not needed.
+ *
+ * Returns false on error, true on success.
+ */
+bool getsec_parameter(uint32_t *version_mask,
+ uint32_t *version_numbers_supported,
+ uint32_t *max_size_acm_area,
+ uint32_t *memory_type_mask,
+ uint32_t *senter_function_disable,
+ uint32_t *txt_feature_flags)
+{
+ uint32_t i, eax, ebx, ecx;
+
+ if (!getsec_enabled())
+ return false;
+
+ /*
+ * SAFER MODE EXTENSIONS REFERENCE.
+ * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
+ */
+ for (i = 0; i < 0x1f; i++) {
+ /* Getsec[PARAMETERS] */
+ asm volatile ("getsec\n"
+ : "=a" (eax), "=b" (ebx), "=c" (ecx)
+ : "a" (IA32_GETSEC_PARAMETERS), "b" (i) :);
+ switch (eax & 0x1f) {
+ case 0: /* NULL - Exit marker */
+ return true;
+ case 1: /* Supported AC module versions */
+ if (version_mask)
+ *version_mask = ebx;
+ if (version_numbers_supported)
+ *version_numbers_supported = ecx;
+ break;
+ case 2: /* Max size of authenticated code execution area */
+ if (max_size_acm_area)
+ *max_size_acm_area = eax & ~0x1f;
+ break;
+ case 3: /* External memory types supported during AC mode */
+ if (memory_type_mask)
+ *memory_type_mask = eax;
+ break;
+ case 4: /* Selective SENTER functionality control */
+ if (senter_function_disable)
+ *senter_function_disable = eax & (0x3f00);
+ break;
+ case 5: /* TXT extensions support */
+ if (txt_feature_flags)
+ *txt_feature_flags = eax & (0x60);
+ break;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Get capabilities as returned by getsec[CAPABILITIES].
+ *
+ * Returns false on error, true on success.
+ */
+
+bool getsec_capabilities(uint32_t *eax)
+{
+ if (!getsec_enabled())
+ return false;
+
+ asm volatile ("getsec\n"
+ : "=a" (*eax)
+ : "a" (IA32_GETSEC_CAPABILITIES), "b" (0) :);
+
+ return true;
+}
diff --git a/src/security/intel/txt/getsec_enteraccs.S b/src/security/intel/txt/getsec_enteraccs.S
new file mode 100644
index 0000000000..0dd5237e7a
--- /dev/null
+++ b/src/security/intel/txt/getsec_enteraccs.S
@@ -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
diff --git a/src/security/intel/txt/logging.c b/src/security/intel/txt/logging.c
new file mode 100644
index 0000000000..cf14b55df9
--- /dev/null
+++ b/src/security/intel/txt/logging.c
@@ -0,0 +1,241 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#if CONFIG(SOC_INTEL_COMMON_BLOCK_SA)
+#include <intelblocks/systemagent.h>
+#endif
+
+#include <arch/mmio.h>
+#include <string.h>
+
+#include "txt.h"
+#include "txt_register.h"
+
+/**
+ * Logs microcode or SINIT ACM errors.
+ * Does not log SBIOS ACM errors.
+ */
+static void log_txt_error(const char *phase)
+{
+ const uint64_t txt_error = read64((void *)TXT_ERROR);
+
+ if (txt_error & ACMERROR_TXT_VALID) {
+ printk(BIOS_ERR, "%s: Error occurred\n", phase);
+
+ if (txt_error & ACMERROR_TXT_EXTERNAL)
+ printk(BIOS_ERR, " Caused by: External\n");
+ else
+ printk(BIOS_ERR, " Caused by: Processor\n");
+
+ printk(BIOS_ERR, " Type: ");
+
+ switch (txt_error & TXT_ERROR_MASK) {
+ case 0:
+ printk(BIOS_ERR, "Legacy Shutdown\n");
+ break;
+ case 5:
+ printk(BIOS_ERR, "Load memory type error in ACM area\n");
+ break;
+ case 6:
+ printk(BIOS_ERR, "Unrecognized ACM format\n");
+ break;
+ case 7:
+ printk(BIOS_ERR, "Failure to authenticate\n");
+ break;
+ case 8:
+ printk(BIOS_ERR, "Invalid ACM format\n");
+ break;
+ case 9:
+ printk(BIOS_ERR, "Unexpected Snoop hit\n");
+ break;
+ case 10:
+ printk(BIOS_ERR, "Invalid event\n");
+ break;
+ case 11:
+ printk(BIOS_ERR, "Invalid MLE\n");
+ break;
+ case 12:
+ printk(BIOS_ERR, "Machine check event\n");
+ break;
+ case 13:
+ printk(BIOS_ERR, "VMXAbort\n");
+ break;
+ case 14:
+ printk(BIOS_ERR, "AC memory corruption\n");
+ break;
+ case 15:
+ printk(BIOS_ERR, "Illegal voltage/bus ratio\n");
+ break;
+ default:
+ printk(BIOS_ERR, "unknown\n");
+ break;
+ }
+ }
+}
+
+/**
+ * Dump useful informaation about the BIOS ACM state.
+ * Should run right after console_init() in romstage.
+ * Resets the platform if TXT reset is active and MLE cannot be established.
+ **/
+void intel_txt_log_bios_acm_error(void)
+{
+ uint32_t bios_acm_error;
+ uint64_t acm_status;
+ uint64_t txt_error;
+
+ printk(BIOS_INFO, "TEE-TXT: State of ACM and ucode update:\n");
+
+ bios_acm_error = read32((void *)TXT_BIOSACM_ERRORCODE);
+ acm_status = read64((void *)TXT_SPAD);
+ txt_error = read64((void *)TXT_ERROR);
+
+ /* Errors by BIOS ACM or FIT */
+ if ((txt_error & ACMERROR_TXT_VALID) &&
+ (acm_status & ACMERROR_TXT_VALID)) {
+ intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE));
+ log_txt_error("FIT MICROCODE");
+ }
+ /* Errors by SINIT */
+ if ((txt_error & ACMERROR_TXT_VALID) &&
+ !(acm_status & ACMERROR_TXT_VALID)) {
+ intel_txt_log_acm_error(txt_error);
+ log_txt_error("SINIT");
+ }
+
+ /* Check for fatal ACM error and TXT reset */
+ uint8_t error = read8((void *)TXT_ESTS);
+ if (error & TXT_ESTS_TXT_RESET_STS) {
+ printk(BIOS_CRIT, "TXT-STS: Intel TXT reset detected\n");
+ intel_txt_log_acm_error(read32((void *)TXT_ERROR));
+ }
+}
+
+/**
+ * Dump information about the provided ACM.
+ */
+void txt_dump_acm_info(const struct acm_header_v0 *acm_header)
+{
+ const struct acm_info_table *info = NULL;
+ if (!acm_header)
+ return;
+
+ printk(BIOS_INFO, "ACM @ %p\n", acm_header);
+
+ const size_t acm_size = (acm_header->size & 0xffffff) << 2;
+ const size_t info_off = (acm_header->header_len + acm_header->scratch_size) * 4;
+
+ if (acm_size > (info_off + sizeof(struct acm_info_table)))
+ info = (const struct acm_info_table *)
+ ((const unsigned char *)acm_header + info_off);
+
+ printk(BIOS_INFO, " ACM: Binary Info\n");
+ if (acm_header->module_type == CHIPSET_ACM)
+ printk(BIOS_INFO, " Type: Chipset ACM\n");
+
+ if (acm_header->module_sub_type == 0)
+ printk(BIOS_INFO, " Subtype: undefined\n");
+ else if (acm_header->module_sub_type == 1)
+ printk(BIOS_INFO, " Subtype: Run at reset\n");
+
+ printk(BIOS_INFO, " Header: v%u.%u\n", acm_header->header_version[0],
+ acm_header->header_version[1]);
+
+ printk(BIOS_INFO, " Chipset: %u\n", acm_header->chipset_id);
+ printk(BIOS_INFO, " Size: %zu\n", acm_size);
+
+ switch (acm_header->flags) {
+ case ACM_FORMAT_FLAGS_PW:
+ printk(BIOS_INFO, " Flags: PW signed (Production Worthy)\n");
+ break;
+ case ACM_FORMAT_FLAGS_NPW:
+ printk(BIOS_INFO, " Flags: NPW signed (Non Production Worthy)\n");
+ break;
+ case ACM_FORMAT_FLAGS_DEBUG:
+ printk(BIOS_INFO, " Flags: Debug signed\n");
+ break;
+ }
+
+ if (acm_header->module_vendor == INTEL_ACM_VENDOR)
+ printk(BIOS_INFO, " Vendor: Intel Corporation\n");
+
+ printk(BIOS_INFO, " Date: %x\n", acm_header->date);
+
+ switch (acm_header->size) {
+ case ACM_FORMAT_SIZE_64KB:
+ printk(BIOS_INFO, " Size: 64KB\n");
+ printk(BIOS_INFO, " CBnT: no\n");
+ break;
+ case ACM_FORMAT_SIZE_128KB:
+ printk(BIOS_INFO, " Size: 128KB\n");
+ printk(BIOS_INFO, " CBnT: no\n");
+ break;
+ case ACM_FORMAT_SIZE_256KB:
+ printk(BIOS_INFO, " Size: 256KB\n");
+ printk(BIOS_INFO, " CBnT: yes\n");
+ break;
+ default:
+ printk(BIOS_INFO, " Size: 0x%08x\n", acm_header->size);
+
+ break;
+ }
+
+ printk(BIOS_INFO, " TXT SVN: %u\n", acm_header->txt_svn);
+ printk(BIOS_INFO, " SE SVN: %u\n", acm_header->se_svn);
+
+ if (!info)
+ return;
+ printk(BIOS_INFO, " Table info:\n");
+ printk(BIOS_INFO, " UUID: ");
+ for (size_t i = 0; i < sizeof(info->uuid); i++)
+ printk(BIOS_INFO, "%02X ", info->uuid[i]);
+ printk(BIOS_INFO, "\n");
+ printk(BIOS_INFO, " Chipset acm type: 0x%x\n", info->chipset_acm_type);
+ printk(BIOS_INFO, " Capabilities: 0x%x\n", info->capabilities);
+}
+
+/**
+ * Dump information about the chipset's TXT capabilities.
+ */
+void txt_dump_chipset_info(void)
+{
+ printk(BIOS_INFO, "TEE-TXT: Chipset Key Hash 0x");
+ for (int i = 0; i < TXT_ACM_KEY_HASH_LEN; i++) {
+ printk(BIOS_INFO, "%llx", read64((void *)TXT_ACM_KEY_HASH +
+ (i * sizeof(uint64_t))));
+ }
+ printk(BIOS_INFO, "\n");
+
+ printk(BIOS_INFO, "TEE-TXT: DIDVID 0x%x\n", read32((void *)TXT_DIDVID));
+ printk(BIOS_INFO, "TEE-TXT: production fused chipset: %s\n",
+ (read64((void *)TXT_VER_FSBIF) & TXT_VER_PRODUCTION_FUSED) ? "true" : "false");
+}
+
+void txt_dump_regions(void)
+{
+ struct txt_biosdataregion *bdr = NULL;
+ uintptr_t tseg = 0;
+ uint64_t reg64;
+
+ reg64 = read64((void *)TXT_HEAP_BASE);
+ if ((reg64 != 0 && reg64 != ~0UL) &&
+ (read64((void *)(uintptr_t)reg64) >= (sizeof(*bdr) + sizeof(uint64_t))))
+ bdr = (void *)((uintptr_t)reg64 + sizeof(uint64_t));
+
+ printk(BIOS_DEBUG, "TEE-TXT: TSEG 0x%lx\n", tseg * MiB);
+ printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.BASE 0x%llx\n", read64((void *)TXT_HEAP_BASE));
+ printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.SIZE 0x%llx\n", read64((void *)TXT_HEAP_SIZE));
+ printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.BASE 0x%llx\n", read64((void *)TXT_SINIT_BASE));
+ printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.SIZE 0x%llx\n", read64((void *)TXT_SINIT_SIZE));
+ printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.BASE 0x%llx\n", read64((void *)TXT_MSEG_BASE));
+ printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.SIZE 0x%llx\n", read64((void *)TXT_MSEG_SIZE));
+
+ if (bdr) {
+ printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.bios_sinit_size 0x%x\n",
+ bdr->bios_sinit_size);
+ printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_size 0x%llx\n",
+ bdr->lcp_pd_size);
+ printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_base 0x%llx\n",
+ bdr->lcp_pd_base);
+ }
+}
diff --git a/src/security/intel/txt/ramstage.c b/src/security/intel/txt/ramstage.c
new file mode 100644
index 0000000000..8627a2b5c9
--- /dev/null
+++ b/src/security/intel/txt/ramstage.c
@@ -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);
diff --git a/src/security/intel/txt/txt.h b/src/security/intel/txt/txt.h
new file mode 100644
index 0000000000..fc5c49e67e
--- /dev/null
+++ b/src/security/intel/txt/txt.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef SECURITY_INTEL_TXT_H_
+#define SECURITY_INTEL_TXT_H_
+
+#include <types.h>
+
+/* Error codes */
+#define ACM_E_TYPE_NOT_MATCH 0x01
+#define ACM_E_MODULE_SUB_TYPE_WRONG 0x02
+#define ACM_E_MODULE_VENDOR_NOT_INTEL 0x03
+#define ACM_E_SIZE_INCORRECT 0x04
+#define ACM_E_CANT_CALL_GETSEC 0x05
+#define ACM_E_NOT_FIT_INTO_CPU_ACM_MEM 0x06
+#define ACM_E_NO_INFO_TABLE 0x07
+#define ACM_E_NOT_BIOS_ACM 0x08
+#define ACM_E_UUID_NOT_MATCH 0x09
+#define ACM_E_PLATFORM_IS_NOT_PROD 0x10
+
+void intel_txt_log_bios_acm_error(void);
+int intel_txt_log_acm_error(const uint32_t acm_error);
+void intel_txt_log_spad(void);
+bool intel_txt_memory_has_secrets(void);
+int intel_txt_run_bios_acm(const u8 input_params);
+bool intel_txt_prepare_txt_env(void);
+
+#endif /* SECURITY_INTEL_TXT_H_ */
diff --git a/src/security/intel/txt/txt_getsec.h b/src/security/intel/txt/txt_getsec.h
new file mode 100644
index 0000000000..7c4a1a4283
--- /dev/null
+++ b/src/security/intel/txt/txt_getsec.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef SECURITY_INTEL_TXT_GETSEC_H_
+#define SECURITY_INTEL_TXT_GETSEC_H_
+
+#include <stdint.h>
+
+bool getsec_parameter(uint32_t *version_mask,
+ uint32_t *version_numbers_supported,
+ uint32_t *max_size_acm_area,
+ uint32_t *memory_type_mask,
+ uint32_t *senter_function_disable,
+ uint32_t *txt_feature_flags);
+
+bool getsec_capabilities(uint32_t *eax);
+
+void getsec_enteraccs(const uint32_t esi,
+ const uint32_t acm_base,
+ const uint32_t acm_size);
+
+#endif /* SECURITY_INTEL_TXT_REGISTER_H_ */
diff --git a/src/security/intel/txt/txt_register.h b/src/security/intel/txt/txt_register.h
new file mode 100644
index 0000000000..70bb309f15
--- /dev/null
+++ b/src/security/intel/txt/txt_register.h
@@ -0,0 +1,267 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef SECURITY_INTEL_TXT_REGISTER_H_
+#define SECURITY_INTEL_TXT_REGISTER_H_
+
+#include <types.h>
+#include <stddef.h>
+
+/*
+ * Document: 315168-016
+ * Intel Trusted Execution Technology (Intel TXT)
+ * Software Development Guide
+ * Chapter B
+ */
+#define TXT_BASE 0xfed30000UL
+
+#define TXT_STS (TXT_BASE + 0)
+#define TXT_ESTS (TXT_BASE + 8)
+#define TXT_ESTS_TXT_RESET_STS (1 << 0)
+/*
+ * Chapter 6
+ * Intel Trusted Execution Technology Lab Handout
+ */
+#define TXT_ESTS_WAKE_ERROR_STS (1 << 6)
+
+#define TXT_ERROR (TXT_BASE + 0x30)
+#define ACMERROR_TXT_VALID (1ul << 31)
+#define ACMERROR_TXT_EXTERNAL (1ul << 30)
+
+#define ACMERROR_TXT_PROGRESS_SHIFT 16
+#define ACMERROR_TXT_MINOR_SHIFT 15
+#define ACMERROR_TXT_MAJOR_SHIFT 10
+#define ACMERROR_TXT_CLASS_SHIFT 4
+#define ACMERROR_TXT_TYPE_SHIFT 0
+
+#define ACMERROR_TXT_PROGRESS_CODE (0xffull << ACMERROR_TXT_PROGRESS_SHIFT)
+#define ACMERROR_TXT_MINOR_CODE (0x01ull << ACMERROR_TXT_MINOR_SHIFT)
+#define ACMERROR_TXT_MAJOR_CODE (0x1full << ACMERROR_TXT_MAJOR_SHIFT)
+#define ACMERROR_TXT_CLASS_CODE (0x3full << ACMERROR_TXT_CLASS_SHIFT)
+#define ACMERROR_TXT_TYPE_CODE (0x0full << ACMERROR_TXT_TYPE_SHIFT)
+
+#define ACMERROR_TXT_AC_MODULE_TYPE_BIOS 0
+#define ACMERROR_TXT_AC_MODULE_TYPE_SINIT 1
+
+#define TXT_ERROR_MASK (0x3ff << 0)
+
+#define TXT_CMD_RESET (TXT_BASE + 0x38)
+#define TXT_CMD_CLOSE_PRIVATE (TXT_BASE + 0x48)
+
+/* Present in Document Number: 315168-016. */
+#define TXT_SPAD (TXT_BASE + 0xa0)
+#define ACMSTS_IBB_MEASURED (1ull << 63)
+#define ACMSTS_VERIFICATION_ERROR (1ull << 62)
+#define ACMSTS_BG_STARTUP_ERROR (1ull << 61) /* CBnT platforms only */
+#define ACMSTS_TXT_DISABLED (1ull << 60) /* disabled by FIT type 0xA record */
+#define ACMSTS_BIOS_TRUSTED (1ull << 59)
+#define ACMSTS_MEM_CLEAR_POWER_DOWN (1ull << 47)
+#define ACMSTS_TXT_STARTUP_SUCCESS (1ull << 30)
+
+#define TXT_VER_FSBIF (TXT_BASE + 0x100)
+#define TXT_VER_PRODUCTION_FUSED (1ull << 31)
+
+#define TXT_DIDVID (TXT_BASE + 0x110)
+
+/*
+ * Chapter 6
+ * Intel Trusted Execution Technology Lab Handout
+ */
+#define TXT_CAPABILITIES (TXT_BASE + 0x200)
+#define TXT_CAPABILITIES_DPR (1ull << 26)
+#define TXT_CAPABILITIES_PMRC (1ull << 19)
+
+#define TXT_VER_QPIIF (TXT_BASE + 0x200)
+
+#define TXT_SINIT_BASE (TXT_BASE + 0x270)
+#define TXT_SINIT_SIZE (TXT_BASE + 0x278)
+#define TXT_MLE_JOIN (TXT_BASE + 0x290)
+
+#define TXT_HEAP_BASE (TXT_BASE + 0x300)
+#define TXT_HEAP_SIZE (TXT_BASE + 0x308)
+/*
+ * Chapter 6
+ * Intel Trusted Execution Technology Lab Handout
+ */
+#define TXT_MSEG_BASE (TXT_BASE + 0x310)
+#define TXT_MSEG_SIZE (TXT_BASE + 0x318)
+
+/*
+ * Chapter 5.4.2.1
+ * Intel Trusted Execution Technology Lab Handout
+ */
+#define TXT_BIOSACM_ERRORCODE (TXT_BASE + 0x328)
+
+#define TXT_DPR (TXT_BASE + 0x330)
+#define TXT_DPR_LOCK_SHIFT 0
+#define TXT_DPR_LOCK_SIZE_SHIFT 4
+#define TXT_DPR_LOCK_SIZE_MASK 0xff
+#define TXT_DPR_TOP_ADDR_SHIFT 20
+#define TXT_DPR_TOP_ADDR_MASK 0xfff
+
+#define TXT_DPR_LOCK_MASK (1 << TXT_DPR_LOCK_SHIFT)
+#define TXT_DPR_LOCK_SIZE(x) ((x) << TXT_DPR_LOCK_SIZE_SHIFT)
+#define TXT_DPR_TOP_ADDR(x) ((x) << TXT_DPR_TOP_ADDR_SHIFT)
+
+#define TXT_ACM_KEY_HASH (TXT_BASE + 0x400)
+#define TXT_ACM_KEY_HASH_LEN 0x4
+
+#define TXT_E2STS (TXT_BASE + 0x8f0)
+#define TXT_E2STS_SECRET_STS (1ull << 1)
+
+/*
+ * TXT Memory regions
+ * Chapter 5.3
+ * Intel Trusted Execution Technology Lab Handout
+ */
+#define TXT_PRIVATE_SPACE 0xfed20000UL
+#define TXT_PUBLIC_SPACE 0xfed30000UL
+#define TXT_TPM_DECODE_AREA 0xfed40000UL
+#define TXT_RESERVED_SPACE 0xfed50000UL
+
+#define TXT_RESERVED_SPACE_SIZE 0x3ffff
+
+/* ESI flags for GETSEC[ENTERACCS] see Reference Number: 323372-017 */
+#define ACMINPUT_RESET_TPM_AUXILIARY_INDICIES 2
+#define ACMINPUT_NOP 3
+#define ACMINPUT_SCHECK 4
+#define ACMINPUT_CLEAR_SECRETS 5
+#define ACMINPUT_LOCK_CONFIG 6
+
+/*
+ * GetSec EAX value.
+ * SAFER MODE EXTENSIONS REFERENCE.
+ * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2
+ * Order Number: 325383-060US
+ */
+#define IA32_GETSEC_CAPABILITIES 0
+#define IA32_GETSEC_ENTERACCS 2
+#define IA32_GETSEC_SENTER 4
+#define IA32_GETSEC_SEXIT 5
+#define IA32_GETSEC_PARAMETERS 6
+#define IA32_GETSEC_SMCTRL 7
+#define IA32_GETSEC_WAKEUP 8
+
+#define GETSEC_PARAMS_TXT_EXT (1ul << 5)
+#define GETSEC_PARAMS_TXT_EXT_CRTM_SUPPORT (1ul << 1)
+#define GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK (1ul << 6)
+
+/* ACM defines */
+#define INTEL_ACM_VENDOR 0x00008086
+
+#define ACM_FORMAT_FLAGS_PW 0x00000000
+#define ACM_FORMAT_FLAGS_NPW (1 << 14)
+#define ACM_FORMAT_FLAGS_DEBUG (1 << 15)
+
+/* Old ACMs are power of two aligned, newer ACMs are not */
+#define ACM_FORMAT_SIZE_64KB (64 * KiB / 4)
+#define ACM_FORMAT_SIZE_128KB (128 * KiB / 4)
+#define ACM_FORMAT_SIZE_256KB (256 * KiB / 4)
+
+/* MSRs */
+#define IA32_MCG_STATUS 0x17a
+
+typedef enum {
+ CHIPSET_ACM = 2,
+} acm_module_type;
+
+typedef enum {
+ BIOS = 0,
+ SINIT = 1,
+} acm_module_sub_type;
+
+/*
+ * ACM Header v0.0 without dynamic part
+ * Chapter A.1
+ * Intel TXT Software Development Guide (Document: 315168-015)
+ */
+struct __packed acm_header_v0 {
+ uint16_t module_type;
+ uint16_t module_sub_type;
+ uint32_t header_len;
+ uint16_t header_version[2];
+ uint16_t chipset_id;
+ uint16_t flags;
+ uint32_t module_vendor;
+ uint32_t date;
+ uint32_t size;
+ uint16_t txt_svn;
+ uint16_t se_svn;
+ uint32_t code_control;
+ uint32_t error_entry_point;
+ uint32_t gdt_limit;
+ uint32_t gdt_ptr;
+ uint32_t seg_sel;
+ uint32_t entry_point;
+ uint8_t reserved2[64];
+ uint32_t key_size;
+ uint32_t scratch_size;
+ uint8_t rsa2048_pubkey[256];
+ uint32_t pub_exp;
+ uint8_t rsa2048_sig[256];
+ uint32_t scratch[143];
+ uint8_t user_area[];
+};
+
+struct __packed acm_info_table {
+ uint8_t uuid[16];
+ uint8_t chipset_acm_type;
+ uint8_t version;
+ uint16_t length;
+ uint32_t chipset_id_list;
+ uint32_t os_sinit_data_ver;
+ uint32_t min_mle_hdr_ver;
+ uint32_t capabilities;
+ uint8_t acm_ver;
+ uint8_t reserved[3];
+};
+
+/*
+ * Extended Data Elements
+ * Chapter C.1
+ * Intel TXT Software Development Guide (Document: 315168-015)
+ */
+struct __packed txt_extended_data_element_header {
+ uint32_t type;
+ uint32_t size;
+ uint8_t data[0];
+};
+
+#define HEAP_EXTDATA_TYPE_END 0
+#define HEAP_EXTDATA_TYPE_BIOS_SPEC_VER 1
+#define HEAP_EXTDATA_TYPE_ACM 2
+#define HEAP_EXTDATA_TYPE_CUSTOM 4
+
+struct __packed txt_heap_acm_element {
+ struct txt_extended_data_element_header header;
+ uint32_t num_acms; // must greater 0, smaller than 3
+ uint64_t acm_addrs[2];
+};
+
+/*
+ * BIOS Data Format
+ * Chapter C.2
+ * Intel TXT Software Development Guide (Document: 315168-015)
+ */
+struct __packed txt_biosdataregion {
+ uint32_t version;
+ uint32_t bios_sinit_size;
+ uint64_t lcp_pd_base;
+ uint64_t lcp_pd_size;
+ uint32_t no_logical_procs;
+ uint32_t sinit_flags;
+ union {
+ uint32_t mle_flags;
+ struct {
+ uint32_t support_acpi_ppi : 1;
+ uint32_t platform_type : 2;
+ };
+ };
+ u8 extended_data_elements[0];
+};
+
+
+void txt_dump_regions(void);
+void txt_dump_chipset_info(void);
+void txt_dump_acm_info(const struct acm_header_v0 *acm_header);
+
+#endif /* SECURITY_INTEL_TXT_REGISTER_H_ */
diff --git a/src/security/memory/memory.c b/src/security/memory/memory.c
index 664e7c17a3..ff4cd1581b 100644
--- a/src/security/memory/memory.c
+++ b/src/security/memory/memory.c
@@ -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;