blob: e240a2faaa364d5f08fb7088f70a670fb0c53197 [file] [log] [blame]
/* 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