/* SPDX-License-Identifier: GPL-2.0-only */ #include #include #include #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 .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 MTRR_DEF_TYPE_MSR 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: 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 incl %ebx cond_push_var_mtrrs: movl $(MTRR_CAP_MSR), %ecx rdmsr andl $(0xff), %eax cmp %ebx, %eax jg 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 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) */ 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 /* Pop variable MTRRs in descending order */ movl $(MTRR_CAP_MSR), %ecx rdmsr andl $(0xff), %eax movl %eax, %ebx jmp cond_pop_var_mtrrs body_pop_var_mtrrs: decl %ebx 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 cond_pop_var_mtrrs: cmpl $0, %ebx jne 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 POP_MSR MTRR_DEF_TYPE_MSR /* 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