Path: blob/master/arch/x86/boot/compressed/mem_encrypt.S
26481 views
/* SPDX-License-Identifier: GPL-2.0-only */1/*2* AMD Memory Encryption Support3*4* Copyright (C) 2017 Advanced Micro Devices, Inc.5*6* Author: Tom Lendacky <[email protected]>7*/89#include <linux/linkage.h>1011#include <asm/processor-flags.h>12#include <asm/msr.h>13#include <asm/asm-offsets.h>14#include <asm/segment.h>15#include <asm/trapnr.h>1617.text18.code3219SYM_FUNC_START(get_sev_encryption_bit)20push %ebx2122movl $0x80000000, %eax /* CPUID to check the highest leaf */23cpuid24cmpl $0x8000001f, %eax /* See if 0x8000001f is available */25jb .Lno_sev2627/*28* Check for the SEV feature:29* CPUID Fn8000_001F[EAX] - Bit 130* CPUID Fn8000_001F[EBX] - Bits 5:031* Pagetable bit position used to indicate encryption32*/33movl $0x8000001f, %eax34cpuid35bt $1, %eax /* Check if SEV is available */36jnc .Lno_sev3738movl $MSR_AMD64_SEV, %ecx /* Read the SEV MSR */39rdmsr40bt $MSR_AMD64_SEV_ENABLED_BIT, %eax /* Check if SEV is active */41jnc .Lno_sev4243movl %ebx, %eax44andl $0x3f, %eax /* Return the encryption bit location */45jmp .Lsev_exit4647.Lno_sev:48xor %eax, %eax4950.Lsev_exit:51pop %ebx52RET53SYM_FUNC_END(get_sev_encryption_bit)5455/**56* sev_es_req_cpuid - Request a CPUID value from the Hypervisor using57* the GHCB MSR protocol58*59* @%eax: Register to request (0=EAX, 1=EBX, 2=ECX, 3=EDX)60* @%edx: CPUID Function61*62* Returns 0 in %eax on success, non-zero on failure63* %edx returns CPUID value on success64*/65SYM_CODE_START_LOCAL(sev_es_req_cpuid)66shll $30, %eax67orl $0x00000004, %eax68movl $MSR_AMD64_SEV_ES_GHCB, %ecx69wrmsr70rep; vmmcall # VMGEXIT71rdmsr7273/* Check response */74movl %eax, %ecx75andl $0x3ffff000, %ecx # Bits [12-29] MBZ76jnz 2f7778/* Check return code */79andl $0xfff, %eax80cmpl $5, %eax81jne 2f8283/* All good - return success */84xorl %eax, %eax851:86RET872:88movl $-1, %eax89jmp 1b90SYM_CODE_END(sev_es_req_cpuid)9192SYM_CODE_START_LOCAL(startup32_vc_handler)93pushl %eax94pushl %ebx95pushl %ecx96pushl %edx9798/* Keep CPUID function in %ebx */99movl %eax, %ebx100101/* Check if error-code == SVM_EXIT_CPUID */102cmpl $0x72, 16(%esp)103jne .Lfail104105movl $0, %eax # Request CPUID[fn].EAX106movl %ebx, %edx # CPUID fn107call sev_es_req_cpuid # Call helper108testl %eax, %eax # Check return code109jnz .Lfail110movl %edx, 12(%esp) # Store result111112movl $1, %eax # Request CPUID[fn].EBX113movl %ebx, %edx # CPUID fn114call sev_es_req_cpuid # Call helper115testl %eax, %eax # Check return code116jnz .Lfail117movl %edx, 8(%esp) # Store result118119movl $2, %eax # Request CPUID[fn].ECX120movl %ebx, %edx # CPUID fn121call sev_es_req_cpuid # Call helper122testl %eax, %eax # Check return code123jnz .Lfail124movl %edx, 4(%esp) # Store result125126movl $3, %eax # Request CPUID[fn].EDX127movl %ebx, %edx # CPUID fn128call sev_es_req_cpuid # Call helper129testl %eax, %eax # Check return code130jnz .Lfail131movl %edx, 0(%esp) # Store result132133/*134* Sanity check CPUID results from the Hypervisor. See comment in135* do_vc_no_ghcb() for more details on why this is necessary.136*/137138/* Fail if SEV leaf not available in CPUID[0x80000000].EAX */139cmpl $0x80000000, %ebx140jne .Lcheck_sev141cmpl $0x8000001f, 12(%esp)142jb .Lfail143jmp .Ldone144145.Lcheck_sev:146/* Fail if SEV bit not set in CPUID[0x8000001f].EAX[1] */147cmpl $0x8000001f, %ebx148jne .Ldone149btl $1, 12(%esp)150jnc .Lfail151152.Ldone:153popl %edx154popl %ecx155popl %ebx156popl %eax157158/* Remove error code */159addl $4, %esp160161/* Jump over CPUID instruction */162addl $2, (%esp)163164iret165.Lfail:166/* Send terminate request to Hypervisor */167movl $0x100, %eax168xorl %edx, %edx169movl $MSR_AMD64_SEV_ES_GHCB, %ecx170wrmsr171rep; vmmcall172173/* If request fails, go to hlt loop */174hlt175jmp .Lfail176SYM_CODE_END(startup32_vc_handler)177178/*179* Write an IDT entry into boot32_idt180*181* Parameters:182*183* %eax: Handler address184* %edx: Vector number185* %ecx: IDT address186*/187SYM_FUNC_START_LOCAL(startup32_set_idt_entry)188/* IDT entry address to %ecx */189leal (%ecx, %edx, 8), %ecx190191/* Build IDT entry, lower 4 bytes */192movl %eax, %edx193andl $0x0000ffff, %edx # Target code segment offset [15:0]194orl $(__KERNEL32_CS << 16), %edx # Target code segment selector195196/* Store lower 4 bytes to IDT */197movl %edx, (%ecx)198199/* Build IDT entry, upper 4 bytes */200movl %eax, %edx201andl $0xffff0000, %edx # Target code segment offset [31:16]202orl $0x00008e00, %edx # Present, Type 32-bit Interrupt Gate203204/* Store upper 4 bytes to IDT */205movl %edx, 4(%ecx)206207RET208SYM_FUNC_END(startup32_set_idt_entry)209210SYM_FUNC_START(startup32_load_idt)211push %ebp212push %ebx213214call 1f2151: pop %ebp216217leal (boot32_idt - 1b)(%ebp), %ebx218219/* #VC handler */220leal (startup32_vc_handler - 1b)(%ebp), %eax221movl $X86_TRAP_VC, %edx222movl %ebx, %ecx223call startup32_set_idt_entry224225/* Load IDT */226leal (boot32_idt_desc - 1b)(%ebp), %ecx227movl %ebx, 2(%ecx)228lidt (%ecx)229230pop %ebx231pop %ebp232RET233SYM_FUNC_END(startup32_load_idt)234235/*236* Check for the correct C-bit position when the startup_32 boot-path is used.237*238* The check makes use of the fact that all memory is encrypted when paging is239* disabled. The function creates 64 bits of random data using the RDRAND240* instruction. RDRAND is mandatory for SEV guests, so always available. If the241* hypervisor violates that the kernel will crash right here.242*243* The 64 bits of random data are stored to a memory location and at the same244* time kept in the %eax and %ebx registers. Since encryption is always active245* when paging is off the random data will be stored encrypted in main memory.246*247* Then paging is enabled. When the C-bit position is correct all memory is248* still mapped encrypted and comparing the register values with memory will249* succeed. An incorrect C-bit position will map all memory unencrypted, so that250* the compare will use the encrypted random data and fail.251*/252SYM_FUNC_START(startup32_check_sev_cbit)253pushl %ebx254pushl %ebp255256call 0f2570: popl %ebp258259/* Check for non-zero sev_status */260movl (sev_status - 0b)(%ebp), %eax261testl %eax, %eax262jz 4f263264/*265* Get two 32-bit random values - Don't bail out if RDRAND fails266* because it is better to prevent forward progress if no random value267* can be gathered.268*/2691: rdrand %eax270jnc 1b2712: rdrand %ebx272jnc 2b273274/* Store to memory and keep it in the registers */275leal (sev_check_data - 0b)(%ebp), %ebp276movl %eax, 0(%ebp)277movl %ebx, 4(%ebp)278279/* Enable paging to see if encryption is active */280movl %cr0, %edx /* Backup %cr0 in %edx */281movl $(X86_CR0_PG | X86_CR0_PE), %ecx /* Enable Paging and Protected mode */282movl %ecx, %cr0283284cmpl %eax, 0(%ebp)285jne 3f286cmpl %ebx, 4(%ebp)287jne 3f288289movl %edx, %cr0 /* Restore previous %cr0 */290291jmp 4f2922933: /* Check failed - hlt the machine */294hlt295jmp 3b2962974:298popl %ebp299popl %ebx300RET301SYM_FUNC_END(startup32_check_sev_cbit)302303.code64304305#include "../../kernel/sev_verify_cbit.S"306307.data308309.balign 8310SYM_DATA(sme_me_mask, .quad 0)311SYM_DATA(sev_status, .quad 0)312SYM_DATA(sev_check_data, .quad 0)313314SYM_DATA_START_LOCAL(boot32_idt)315.rept 32316.quad 0317.endr318SYM_DATA_END(boot32_idt)319320SYM_DATA_START_LOCAL(boot32_idt_desc)321.word . - boot32_idt - 1322.long 0323SYM_DATA_END(boot32_idt_desc)324325326