Now that startup32_load_idt() has been refactored into an ordinary callable function, move it into mem-encrypt.S where it belongs. Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Signed-off-by: Borislav Petkov <bp@suse.de> Link: https://lore.kernel.org/r/20221122161017.2426828-13-ardb@kernel.org
268 lines
5.4 KiB
ArmAsm
268 lines
5.4 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* AMD Memory Encryption Support
|
|
*
|
|
* Copyright (C) 2017 Advanced Micro Devices, Inc.
|
|
*
|
|
* Author: Tom Lendacky <thomas.lendacky@amd.com>
|
|
*/
|
|
|
|
#include <linux/linkage.h>
|
|
|
|
#include <asm/processor-flags.h>
|
|
#include <asm/msr.h>
|
|
#include <asm/asm-offsets.h>
|
|
#include <asm/segment.h>
|
|
#include <asm/trapnr.h>
|
|
|
|
.text
|
|
.code32
|
|
SYM_FUNC_START(get_sev_encryption_bit)
|
|
xor %eax, %eax
|
|
|
|
#ifdef CONFIG_AMD_MEM_ENCRYPT
|
|
push %ebx
|
|
push %ecx
|
|
push %edx
|
|
|
|
movl $0x80000000, %eax /* CPUID to check the highest leaf */
|
|
cpuid
|
|
cmpl $0x8000001f, %eax /* See if 0x8000001f is available */
|
|
jb .Lno_sev
|
|
|
|
/*
|
|
* Check for the SEV feature:
|
|
* CPUID Fn8000_001F[EAX] - Bit 1
|
|
* CPUID Fn8000_001F[EBX] - Bits 5:0
|
|
* Pagetable bit position used to indicate encryption
|
|
*/
|
|
movl $0x8000001f, %eax
|
|
cpuid
|
|
bt $1, %eax /* Check if SEV is available */
|
|
jnc .Lno_sev
|
|
|
|
movl $MSR_AMD64_SEV, %ecx /* Read the SEV MSR */
|
|
rdmsr
|
|
bt $MSR_AMD64_SEV_ENABLED_BIT, %eax /* Check if SEV is active */
|
|
jnc .Lno_sev
|
|
|
|
movl %ebx, %eax
|
|
andl $0x3f, %eax /* Return the encryption bit location */
|
|
jmp .Lsev_exit
|
|
|
|
.Lno_sev:
|
|
xor %eax, %eax
|
|
|
|
.Lsev_exit:
|
|
pop %edx
|
|
pop %ecx
|
|
pop %ebx
|
|
|
|
#endif /* CONFIG_AMD_MEM_ENCRYPT */
|
|
|
|
RET
|
|
SYM_FUNC_END(get_sev_encryption_bit)
|
|
|
|
/**
|
|
* sev_es_req_cpuid - Request a CPUID value from the Hypervisor using
|
|
* the GHCB MSR protocol
|
|
*
|
|
* @%eax: Register to request (0=EAX, 1=EBX, 2=ECX, 3=EDX)
|
|
* @%edx: CPUID Function
|
|
*
|
|
* Returns 0 in %eax on success, non-zero on failure
|
|
* %edx returns CPUID value on success
|
|
*/
|
|
SYM_CODE_START_LOCAL(sev_es_req_cpuid)
|
|
shll $30, %eax
|
|
orl $0x00000004, %eax
|
|
movl $MSR_AMD64_SEV_ES_GHCB, %ecx
|
|
wrmsr
|
|
rep; vmmcall # VMGEXIT
|
|
rdmsr
|
|
|
|
/* Check response */
|
|
movl %eax, %ecx
|
|
andl $0x3ffff000, %ecx # Bits [12-29] MBZ
|
|
jnz 2f
|
|
|
|
/* Check return code */
|
|
andl $0xfff, %eax
|
|
cmpl $5, %eax
|
|
jne 2f
|
|
|
|
/* All good - return success */
|
|
xorl %eax, %eax
|
|
1:
|
|
RET
|
|
2:
|
|
movl $-1, %eax
|
|
jmp 1b
|
|
SYM_CODE_END(sev_es_req_cpuid)
|
|
|
|
SYM_CODE_START_LOCAL(startup32_vc_handler)
|
|
pushl %eax
|
|
pushl %ebx
|
|
pushl %ecx
|
|
pushl %edx
|
|
|
|
/* Keep CPUID function in %ebx */
|
|
movl %eax, %ebx
|
|
|
|
/* Check if error-code == SVM_EXIT_CPUID */
|
|
cmpl $0x72, 16(%esp)
|
|
jne .Lfail
|
|
|
|
movl $0, %eax # Request CPUID[fn].EAX
|
|
movl %ebx, %edx # CPUID fn
|
|
call sev_es_req_cpuid # Call helper
|
|
testl %eax, %eax # Check return code
|
|
jnz .Lfail
|
|
movl %edx, 12(%esp) # Store result
|
|
|
|
movl $1, %eax # Request CPUID[fn].EBX
|
|
movl %ebx, %edx # CPUID fn
|
|
call sev_es_req_cpuid # Call helper
|
|
testl %eax, %eax # Check return code
|
|
jnz .Lfail
|
|
movl %edx, 8(%esp) # Store result
|
|
|
|
movl $2, %eax # Request CPUID[fn].ECX
|
|
movl %ebx, %edx # CPUID fn
|
|
call sev_es_req_cpuid # Call helper
|
|
testl %eax, %eax # Check return code
|
|
jnz .Lfail
|
|
movl %edx, 4(%esp) # Store result
|
|
|
|
movl $3, %eax # Request CPUID[fn].EDX
|
|
movl %ebx, %edx # CPUID fn
|
|
call sev_es_req_cpuid # Call helper
|
|
testl %eax, %eax # Check return code
|
|
jnz .Lfail
|
|
movl %edx, 0(%esp) # Store result
|
|
|
|
/*
|
|
* Sanity check CPUID results from the Hypervisor. See comment in
|
|
* do_vc_no_ghcb() for more details on why this is necessary.
|
|
*/
|
|
|
|
/* Fail if SEV leaf not available in CPUID[0x80000000].EAX */
|
|
cmpl $0x80000000, %ebx
|
|
jne .Lcheck_sev
|
|
cmpl $0x8000001f, 12(%esp)
|
|
jb .Lfail
|
|
jmp .Ldone
|
|
|
|
.Lcheck_sev:
|
|
/* Fail if SEV bit not set in CPUID[0x8000001f].EAX[1] */
|
|
cmpl $0x8000001f, %ebx
|
|
jne .Ldone
|
|
btl $1, 12(%esp)
|
|
jnc .Lfail
|
|
|
|
.Ldone:
|
|
popl %edx
|
|
popl %ecx
|
|
popl %ebx
|
|
popl %eax
|
|
|
|
/* Remove error code */
|
|
addl $4, %esp
|
|
|
|
/* Jump over CPUID instruction */
|
|
addl $2, (%esp)
|
|
|
|
iret
|
|
.Lfail:
|
|
/* Send terminate request to Hypervisor */
|
|
movl $0x100, %eax
|
|
xorl %edx, %edx
|
|
movl $MSR_AMD64_SEV_ES_GHCB, %ecx
|
|
wrmsr
|
|
rep; vmmcall
|
|
|
|
/* If request fails, go to hlt loop */
|
|
hlt
|
|
jmp .Lfail
|
|
SYM_CODE_END(startup32_vc_handler)
|
|
|
|
/*
|
|
* Write an IDT entry into boot32_idt
|
|
*
|
|
* Parameters:
|
|
*
|
|
* %eax: Handler address
|
|
* %edx: Vector number
|
|
* %ecx: IDT address
|
|
*/
|
|
SYM_FUNC_START_LOCAL(startup32_set_idt_entry)
|
|
/* IDT entry address to %ecx */
|
|
leal (%ecx, %edx, 8), %ecx
|
|
|
|
/* Build IDT entry, lower 4 bytes */
|
|
movl %eax, %edx
|
|
andl $0x0000ffff, %edx # Target code segment offset [15:0]
|
|
orl $(__KERNEL32_CS << 16), %edx # Target code segment selector
|
|
|
|
/* Store lower 4 bytes to IDT */
|
|
movl %edx, (%ecx)
|
|
|
|
/* Build IDT entry, upper 4 bytes */
|
|
movl %eax, %edx
|
|
andl $0xffff0000, %edx # Target code segment offset [31:16]
|
|
orl $0x00008e00, %edx # Present, Type 32-bit Interrupt Gate
|
|
|
|
/* Store upper 4 bytes to IDT */
|
|
movl %edx, 4(%ecx)
|
|
|
|
RET
|
|
SYM_FUNC_END(startup32_set_idt_entry)
|
|
|
|
SYM_FUNC_START(startup32_load_idt)
|
|
push %ebp
|
|
push %ebx
|
|
|
|
call 1f
|
|
1: pop %ebp
|
|
|
|
leal (boot32_idt - 1b)(%ebp), %ebx
|
|
|
|
/* #VC handler */
|
|
leal (startup32_vc_handler - 1b)(%ebp), %eax
|
|
movl $X86_TRAP_VC, %edx
|
|
movl %ebx, %ecx
|
|
call startup32_set_idt_entry
|
|
|
|
/* Load IDT */
|
|
leal (boot32_idt_desc - 1b)(%ebp), %ecx
|
|
movl %ebx, 2(%ecx)
|
|
lidt (%ecx)
|
|
|
|
pop %ebx
|
|
pop %ebp
|
|
RET
|
|
SYM_FUNC_END(startup32_load_idt)
|
|
|
|
.code64
|
|
|
|
#include "../../kernel/sev_verify_cbit.S"
|
|
|
|
.data
|
|
|
|
#ifdef CONFIG_AMD_MEM_ENCRYPT
|
|
.balign 8
|
|
SYM_DATA(sme_me_mask, .quad 0)
|
|
SYM_DATA(sev_status, .quad 0)
|
|
SYM_DATA(sev_check_data, .quad 0)
|
|
|
|
SYM_DATA_START_LOCAL(boot32_idt)
|
|
.rept 32
|
|
.quad 0
|
|
.endr
|
|
SYM_DATA_END(boot32_idt)
|
|
|
|
SYM_DATA_START_LOCAL(boot32_idt_desc)
|
|
.word . - boot32_idt - 1
|
|
.long 0
|
|
SYM_DATA_END(boot32_idt_desc)
|
|
#endif
|