| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #include <cpu/x86/mtrr.h> |
| #include <cpu/x86/cr.h> |
| #include <cpu/x86/msr.h> |
| #include <arch/ram_segs.h> |
| |
| #include "getsec_mtrr_setup.inc" |
| |
| .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 all MTRRs */ |
| movl $(MTRR_DEF_TYPE_MSR), %ecx |
| xorl %eax, %eax |
| xorl %edx, %edx |
| 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) |
| */ |
| |
| /* Determine size of AC module */ |
| movl 12(%ebp), %eax /* %eax = acmbase */ |
| movl $1, %ebx |
| movl 16(%ebp), %ebx /* %ebx = acmsize */ |
| |
| /* Round up to page size */ |
| addl $(0xfff), %ebx |
| andl $(~0xfff), %ebx /* Aligned to a page (4 KiB) */ |
| |
| /* |
| * Use XMM to store local variables. This code will need to be |
| * used in romstage, and CAR will have been torn down by then. |
| */ |
| movd %eax, %xmm0 /* XMM0: Base address of next MTRR */ |
| movd %ebx, %xmm1 /* XMM1: Remaining size to cache */ |
| |
| /* |
| * Important note: The MTRRs must cache less than a page (4 KiB) |
| * of unused memory after the BIOS ACM. Failure to do so will |
| * result in 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 |
| |
| /* |
| * Now that the variable MTRRs have been set up, enable them. |
| */ |
| movl $(MTRR_DEF_TYPE_MSR), %ecx |
| rdmsr |
| orl $(MTRR_DEF_TYPE_EN), %eax |
| 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 |
| |
| /* Backup %gs used by CPU_INFO_V2 */ |
| movl %gs, %eax |
| movd %eax, %xmm2 |
| |
| /* |
| * 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 $RAM_CODE_SEG, $1f |
| 1: |
| /* Fix segment registers */ |
| movl $RAM_DATA_SEG, %eax |
| movl %eax, %ds |
| movl %eax, %es |
| movl %eax, %ss |
| movl %eax, %fs |
| /* Restore %gs used by CPU_INFO_V2 */ |
| movd %xmm2, %eax |
| 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 |