From 5725ee4f9f056b4ea62efe205d823a6132b56971 Mon Sep 17 00:00:00 2001 From: Angel Pons Date: Wed, 21 Oct 2020 00:23:29 +0200 Subject: 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 Reviewed-on: https://review.coreboot.org/c/coreboot/+/46607 Tested-by: build bot (Jenkins) Reviewed-by: Arthur Heymans --- src/security/intel/txt/Makefile.inc | 2 + src/security/intel/txt/getsec_sclean.S | 181 +++++++++++++++++++++++++++++++++ src/security/intel/txt/txt_getsec.h | 3 + 3 files changed, 186 insertions(+) create mode 100644 src/security/intel/txt/getsec_sclean.S (limited to 'src') diff --git a/src/security/intel/txt/Makefile.inc b/src/security/intel/txt/Makefile.inc index 712ab589d5..762256f6e3 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 0000000000..e240a2faaa --- /dev/null +++ b/src/security/intel/txt/getsec_sclean.S @@ -0,0 +1,181 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include + +#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 78171a7d5a..f949c7d361 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_ */ -- cgit v1.2.3