summaryrefslogtreecommitdiffstats
path: root/src/security
diff options
context:
space:
mode:
authorAngel Pons <th3fanbus@gmail.com>2020-10-21 00:23:29 +0200
committerAngel Pons <th3fanbus@gmail.com>2020-11-04 23:31:11 +0000
commit5725ee4f9f056b4ea62efe205d823a6132b56971 (patch)
treebcf22473ca47d439afe139d106f03fd4a6320906 /src/security
parent527647677a8da418bf4854eada32d9090393ee5f (diff)
downloadcoreboot-5725ee4f9f056b4ea62efe205d823a6132b56971.tar.gz
coreboot-5725ee4f9f056b4ea62efe205d823a6132b56971.tar.bz2
coreboot-5725ee4f9f056b4ea62efe205d823a6132b56971.zip
sec/intel/txt: Add support for running SCLEAN in romstage
SCLEAN has specific requirements and needs to run in early romstage, since the DRAM would be locked when SCLEAN needs to be executed. Change-Id: I77b237342e0c98eda974f87944f1948d197714db Signed-off-by: Angel Pons <th3fanbus@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/46607 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Diffstat (limited to 'src/security')
-rw-r--r--src/security/intel/txt/Makefile.inc2
-rw-r--r--src/security/intel/txt/getsec_sclean.S181
-rw-r--r--src/security/intel/txt/txt_getsec.h3
3 files changed, 186 insertions, 0 deletions
diff --git a/src/security/intel/txt/Makefile.inc b/src/security/intel/txt/Makefile.inc
index 712ab589d55d..762256f6e37a 100644
--- a/src/security/intel/txt/Makefile.inc
+++ b/src/security/intel/txt/Makefile.inc
@@ -1,5 +1,7 @@
ifeq ($(CONFIG_INTEL_TXT),y)
+romstage-y += getsec_sclean.S
+
romstage-y += common.c
romstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c
diff --git a/src/security/intel/txt/getsec_sclean.S b/src/security/intel/txt/getsec_sclean.S
new file mode 100644
index 000000000000..e240a2faaa36
--- /dev/null
+++ b/src/security/intel/txt/getsec_sclean.S
@@ -0,0 +1,181 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <cpu/x86/cr.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/msr.h>
+
+#include "getsec_mtrr_setup.inc"
+
+#define MTRR_HIGH_MASK $((1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1)
+
+#define NO_EVICT_MODE 0x2e0
+
+.align 4
+.text
+
+/*
+ * void getsec_sclean(const uint32_t acm_base, const uint32_t acm_size);
+ */
+.global getsec_sclean
+getsec_sclean:
+ /*
+ * At this point, it is certain that the BIOS ACM will be run.
+ * This requires tearing down CAR, which cannot be undone.
+ *
+ * From here onwards, the only way out is to reset the system.
+ */
+
+ /* Enable SMXE, SSE and debug extensions */
+ movl %cr4, %eax
+ orl $(CR4_OSFXSR | CR4_DE | CR4_SMXE), %eax
+ movl %eax, %cr4
+
+ /*
+ * Save arguments into SSE registers. We need to tear down CAR
+ * before launching the BIOS ACM, which will destroy the stack.
+ */
+ movd 4(%esp), %xmm2 /* acm_base */
+ movd 8(%esp), %xmm3 /* acm_size */
+
+ /* Disable cache */
+ movl %cr0, %eax
+ orl $(CR0_CD | CR0_NE), %eax
+ andl $(~(CR0_NW)), %eax
+ movl %eax, %cr0
+
+ /* Invalidate the cache */
+ invd
+
+ /* Disable MTRRs */
+ movl $(MTRR_DEF_TYPE_MSR), %ecx
+ xorl %eax, %eax
+ xorl %edx, %edx
+ wrmsr
+
+ /* Disable NEM, needs to be done in two steps */
+ movl $NO_EVICT_MODE, %ecx
+ rdmsr
+ andl $~2, %eax /* Clear NEM Run bit */
+ wrmsr
+ andl $~1, %eax /* Clear NEM Setup bit */
+ wrmsr
+
+ /* Invalidate the cache, again */
+ invd
+
+ /*
+ * Clear variable MTRRs
+ * Chapter 2.2.5.1
+ * Intel TXT Software Development Guide (Document: 315168-015)
+ */
+ movl $(MTRR_CAP_MSR), %ecx
+ rdmsr
+ andl $(0xff), %eax
+ movl %eax, %ebx
+
+ xorl %eax, %eax
+ xorl %edx, %edx
+
+ jmp cond_clear_var_mtrrs
+
+body_clear_var_mtrrs:
+
+ decl %ebx
+ movl %ebx, %ecx
+ shll %ecx
+ addl $(MTRR_PHYS_BASE(0)), %ecx
+ wrmsr
+ incl %ecx /* MTRR_PHYS_MASK */
+ wrmsr
+
+cond_clear_var_mtrrs:
+
+ cmpl $0, %ebx
+ jnz body_clear_var_mtrrs
+
+ /*
+ * Setup BIOS ACM as WB
+ * Chapter A.1.1
+ * Intel TXT Software Development Guide (Document: 315168-015)
+ */
+
+ /* Determine size of AC module */
+ movd %xmm2, %eax /* acm_base */
+ movd %xmm3, %ebx /* acm_size */
+
+ /* Round up to page size */
+ addl $(0xfff), %ebx
+ andl $(~0xfff), %ebx /* Aligned to a page (4 KiB) */
+
+ /* Use SSE registers to store local variables */
+ movd %eax, %xmm0
+ movd %ebx, %xmm1
+
+ /*
+ * Important note: The MTRRs must cache less than a page (4 KiB)
+ * of unused memory after the BIOS ACM. Not doing so on Haswell
+ * will cause a TXT reset with Class Code 5, Major Error Code 2.
+ *
+ * The caller must have checked that there are enough variable
+ * MTRRs to cache the ACM size prior to invoking this routine.
+ */
+ SET_UP_MTRRS_FOR_BIOS_ACM
+
+ /* Enable variable MTRRs */
+ movl $MTRR_DEF_TYPE_MSR, %ecx
+ rdmsr
+ orl $MTRR_DEF_TYPE_EN, %eax
+ wrmsr
+
+ /* Enable cache - CR0_NW is and stays clear */
+ movl %cr0, %eax
+ andl $~(CR0_CD), %eax
+ movl %eax, %cr0
+
+ /*
+ * 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.
+ *
+ * Note: Do not forget that CAR has been torn down, so the stack doesn't exist.
+ */
+ movl $2, %eax /* GETSEC[ENTERACCS] */
+ movd %xmm2, %ebx /* acm_base */
+ movd %xmm3, %ecx /* acm_size */
+ movl $0, %edx /* reserved, must be zero */
+ movl $0, %edi /* must be zero */
+ movl $0, %esi /* SCLEAN */
+
+ getsec
+
+ /*
+ * The platform state after SCLEAN is undefined. The only sane
+ * thing to do afterwards is to reset the platform. Note that
+ * the BIOS ACM should already reset the platform, so this code
+ * may not always be reached, but keep it here just to be sure.
+ */
+#if 1
+ movw $0xcf8, %dx
+ movl $0x8000F8AC, %eax
+ outl %eax, %dx
+
+ movw $0xcfc, %dx
+ inl %dx, %eax
+ andl $~(1 << 20), %eax
+ outl %eax, %dx
+#endif
+
+ movw $0xcf9, %dx
+ movb $0, %al
+ outb %al, %dx
+
+ movw $0xcf9, %dx
+ movb $0x0e, %al
+ outb %al, %dx
+
+ cli
+
+ hlt
+
+ ret
diff --git a/src/security/intel/txt/txt_getsec.h b/src/security/intel/txt/txt_getsec.h
index 78171a7d5ac2..f949c7d3613d 100644
--- a/src/security/intel/txt/txt_getsec.h
+++ b/src/security/intel/txt/txt_getsec.h
@@ -20,4 +20,7 @@ void getsec_enteraccs(const uint32_t esi,
const uint32_t acm_base,
const uint32_t acm_size);
+void getsec_sclean(const uint32_t acm_base,
+ const uint32_t acm_size);
+
#endif /* SECURITY_INTEL_TXT_REGISTER_H_ */