summaryrefslogtreecommitdiff
path: root/src/security
diff options
context:
space:
mode:
Diffstat (limited to 'src/security')
-rw-r--r--src/security/intel/txt/Makefile.inc2
-rw-r--r--src/security/intel/txt/common.c42
-rw-r--r--src/security/intel/txt/romstage.c125
-rw-r--r--src/security/intel/txt/txt.h3
-rw-r--r--src/security/intel/txt/txt_register.h10
5 files changed, 182 insertions, 0 deletions
diff --git a/src/security/intel/txt/Makefile.inc b/src/security/intel/txt/Makefile.inc
index 762256f6e3..eab47b95f9 100644
--- a/src/security/intel/txt/Makefile.inc
+++ b/src/security/intel/txt/Makefile.inc
@@ -1,6 +1,8 @@
ifeq ($(CONFIG_INTEL_TXT),y)
+romstage-y += romstage.c
romstage-y += getsec_sclean.S
+romstage-y += getsec.c
romstage-y += common.c
romstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c
diff --git a/src/security/intel/txt/common.c b/src/security/intel/txt/common.c
index 88e2b5dddb..4dd4ad3ddf 100644
--- a/src/security/intel/txt/common.c
+++ b/src/security/intel/txt/common.c
@@ -290,6 +290,48 @@ static void *intel_txt_prepare_bios_acm(struct region_device *acm, size_t *acm_l
return acm_data;
}
+#define MCU_BASE_ADDR (TXT_BASE + 0x278)
+#define BIOACM_ADDR (TXT_BASE + 0x27c)
+#define APINIT_ADDR (TXT_BASE + 0x290)
+#define SEMAPHORE (TXT_BASE + 0x294)
+
+/* Returns on failure, resets the computer on success */
+void intel_txt_run_sclean(void)
+{
+ struct region_device acm;
+ size_t acm_len;
+
+ void *acm_data = intel_txt_prepare_bios_acm(&acm, &acm_len);
+
+ if (!acm_data)
+ return;
+
+ /* FIXME: Do we need to program these two? */
+ //write32((void *)MCU_BASE_ADDR, 0xffe1a990);
+ //write32((void *)APINIT_ADDR, 0xfffffff0);
+
+ write32((void *)BIOACM_ADDR, (uintptr_t)acm_data);
+ write32((void *)SEMAPHORE, 0);
+
+ /*
+ * The time SCLEAN will take depends on the installed RAM size.
+ * On Haswell with 8 GiB of DDR3, it takes five or ten minutes. (rough estimate)
+ */
+ printk(BIOS_ALERT, "TEE-TXT: Invoking SCLEAN. This can take several minutes.\n");
+
+ /*
+ * Invoke the BIOS ACM. If successful, the system will reset with memory unlocked.
+ */
+ getsec_sclean((uintptr_t)acm_data, acm_len);
+
+ /*
+ * However, if this function returns, the BIOS ACM could not be invoked. This is bad.
+ */
+ printk(BIOS_CRIT, "TEE-TXT: getsec_sclean could not launch the BIOS ACM.\n");
+
+ rdev_munmap(&acm, acm_data);
+}
+
/*
* Test all bits for TXT execution.
*
diff --git a/src/security/intel/txt/romstage.c b/src/security/intel/txt/romstage.c
new file mode 100644
index 0000000000..7a12debd6d
--- /dev/null
+++ b/src/security/intel/txt/romstage.c
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <arch/mmio.h>
+#include <cf9_reset.h>
+#include <console/console.h>
+#include <cpu/intel/common/common.h>
+#include <cpu/x86/msr.h>
+#include <southbridge/intel/common/pmbase.h>
+#include <timer.h>
+#include <types.h>
+
+#include <security/tpm/tis.h>
+
+#include "txt.h"
+#include "txt_register.h"
+#include "txt_getsec.h"
+
+static bool is_establishment_bit_asserted(void)
+{
+ struct stopwatch timer;
+ uint8_t access;
+
+ /* Spec says no less than 30 milliseconds */
+ stopwatch_init_msecs_expire(&timer, 50);
+
+ while (true) {
+ access = read8((void *)TPM_ACCESS_REG);
+
+ /* Register returns all ones if TPM is missing */
+ if (access == 0xff)
+ return false;
+
+ if (access & TPM_ACCESS_VALID)
+ break;
+
+ /* On timeout, assume that the TPM is not working */
+ if (stopwatch_expired(&timer))
+ return false;
+ }
+
+ /* This bit uses inverted logic: if cleared, establishment is asserted */
+ return !(access & TPM_ACCESS_ESTABLISHMENT);
+}
+
+static bool is_txt_cpu(void)
+{
+ const uint32_t ecx = cpu_get_feature_flags_ecx();
+
+ return (ecx & (CPUID_SMX | CPUID_VMX)) == (CPUID_SMX | CPUID_VMX);
+}
+
+static bool is_txt_chipset(void)
+{
+ uint32_t eax;
+
+ const bool success = getsec_capabilities(&eax);
+
+ return success && eax & 1;
+}
+
+/* Print the bad news */
+static void print_memory_is_locked(void)
+{
+ if (!CONFIG(INTEL_TXT_LOGGING))
+ return;
+
+ printk(BIOS_EMERG, "FATAL: Cannot run SCLEAN. Memory will remain locked.\n");
+ printk(BIOS_EMERG, "\n");
+ printk(BIOS_EMERG, "If you still want to boot, your options are:\n");
+ printk(BIOS_EMERG, "\n");
+ printk(BIOS_EMERG, " 1. Flash a coreboot image with a valid BIOS ACM.\n");
+ printk(BIOS_EMERG, " Then, try again and hope it works this time.\n");
+ printk(BIOS_EMERG, "\n");
+ printk(BIOS_EMERG, " 2. If possible, remove the TPM from the system.\n");
+ printk(BIOS_EMERG, " Reinstalling the TPM might lock memory again.\n");
+ printk(BIOS_EMERG, "\n");
+ printk(BIOS_EMERG, " 3. Disconnect all power sources, and RTC battery.\n");
+ printk(BIOS_EMERG, " This may not work on all TXT-enabled platforms.\n");
+ printk(BIOS_EMERG, "\n");
+}
+
+void intel_txt_romstage_init(void)
+{
+ /* Bail early if the CPU doesn't support TXT */
+ if (!is_txt_cpu())
+ return;
+
+ /* We need to use GETSEC here, so enable it */
+ enable_getsec_or_reset();
+
+ if (!is_txt_chipset())
+ return;
+
+ const uint8_t txt_ests = read8((void *)TXT_ESTS);
+
+ const bool establishment = is_establishment_bit_asserted();
+ const bool is_wake_error = !!(txt_ests & TXT_ESTS_WAKE_ERROR_STS);
+
+ if (CONFIG(INTEL_TXT_LOGGING)) {
+
+ printk(BIOS_INFO, "TEE-TXT: TPM established: %s\n",
+ establishment ? "true" : "false");
+ }
+
+ if (establishment && is_wake_error) {
+
+ printk(BIOS_ERR, "TEE-TXT: Secrets remain in memory. SCLEAN is required.\n");
+
+ if (txt_ests & TXT_ESTS_TXT_RESET_STS) {
+ printk(BIOS_ERR, "TEE-TXT: TXT_RESET bit set, doing full reset!\n");
+ full_reset();
+ }
+
+ /* FIXME: Clear SLP_TYP# */
+ write_pmbase32(4, read_pmbase32(4) & ~(0x7 << 10));
+
+ intel_txt_run_sclean();
+
+ /* If running the BIOS ACM is impossible, manual intervention is required */
+ print_memory_is_locked();
+
+ /* FIXME: vboot A/B could be used to recover, but has not been tested */
+ die("Could not execute BIOS ACM to unlock the memory.\n");
+ }
+}
diff --git a/src/security/intel/txt/txt.h b/src/security/intel/txt/txt.h
index fc5c49e67e..976cc7458e 100644
--- a/src/security/intel/txt/txt.h
+++ b/src/security/intel/txt/txt.h
@@ -17,10 +17,13 @@
#define ACM_E_UUID_NOT_MATCH 0x09
#define ACM_E_PLATFORM_IS_NOT_PROD 0x10
+void intel_txt_romstage_init(void);
+
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);
+void intel_txt_run_sclean(void);
int intel_txt_run_bios_acm(const u8 input_params);
bool intel_txt_prepare_txt_env(void);
diff --git a/src/security/intel/txt/txt_register.h b/src/security/intel/txt/txt_register.h
index c19ec13799..bb735b6cfd 100644
--- a/src/security/intel/txt/txt_register.h
+++ b/src/security/intel/txt/txt_register.h
@@ -99,6 +99,16 @@
#define TXT_E2STS_SECRET_STS (1ull << 1)
/*
+ * TCG PC Client Platform TPM Profile (PTP) Specification
+ *
+ * Note: Only locality 0 registers are publicly accessible.
+ */
+
+#define TPM_BASE 0xfed40000UL
+
+#define TPM_ACCESS_REG (TPM_BASE + 0x00)
+
+/*
* TXT Memory regions
* Chapter 5.3
* Intel Trusted Execution Technology Lab Handout