1d2912cb1SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */ 21958b5fcSTom Lendacky/* 31958b5fcSTom Lendacky * AMD Memory Encryption Support 41958b5fcSTom Lendacky * 51958b5fcSTom Lendacky * Copyright (C) 2017 Advanced Micro Devices, Inc. 61958b5fcSTom Lendacky * 71958b5fcSTom Lendacky * Author: Tom Lendacky <thomas.lendacky@amd.com> 81958b5fcSTom Lendacky */ 91958b5fcSTom Lendacky 101958b5fcSTom Lendacky#include <linux/linkage.h> 111958b5fcSTom Lendacky 121958b5fcSTom Lendacky#include <asm/processor-flags.h> 131958b5fcSTom Lendacky#include <asm/msr.h> 141958b5fcSTom Lendacky#include <asm/asm-offsets.h> 159ea813beSArd Biesheuvel#include <asm/segment.h> 169ea813beSArd Biesheuvel#include <asm/trapnr.h> 171958b5fcSTom Lendacky 181958b5fcSTom Lendacky .text 191958b5fcSTom Lendacky .code32 206dcc5627SJiri SlabySYM_FUNC_START(get_sev_encryption_bit) 211958b5fcSTom Lendacky push %ebx 221958b5fcSTom Lendacky 231958b5fcSTom Lendacky movl $0x80000000, %eax /* CPUID to check the highest leaf */ 241958b5fcSTom Lendacky cpuid 251958b5fcSTom Lendacky cmpl $0x8000001f, %eax /* See if 0x8000001f is available */ 261958b5fcSTom Lendacky jb .Lno_sev 271958b5fcSTom Lendacky 281958b5fcSTom Lendacky /* 291958b5fcSTom Lendacky * Check for the SEV feature: 301958b5fcSTom Lendacky * CPUID Fn8000_001F[EAX] - Bit 1 311958b5fcSTom Lendacky * CPUID Fn8000_001F[EBX] - Bits 5:0 321958b5fcSTom Lendacky * Pagetable bit position used to indicate encryption 331958b5fcSTom Lendacky */ 341958b5fcSTom Lendacky movl $0x8000001f, %eax 351958b5fcSTom Lendacky cpuid 361958b5fcSTom Lendacky bt $1, %eax /* Check if SEV is available */ 371958b5fcSTom Lendacky jnc .Lno_sev 381958b5fcSTom Lendacky 391958b5fcSTom Lendacky movl $MSR_AMD64_SEV, %ecx /* Read the SEV MSR */ 401958b5fcSTom Lendacky rdmsr 411958b5fcSTom Lendacky bt $MSR_AMD64_SEV_ENABLED_BIT, %eax /* Check if SEV is active */ 421958b5fcSTom Lendacky jnc .Lno_sev 431958b5fcSTom Lendacky 441958b5fcSTom Lendacky movl %ebx, %eax 451958b5fcSTom Lendacky andl $0x3f, %eax /* Return the encryption bit location */ 461958b5fcSTom Lendacky jmp .Lsev_exit 471958b5fcSTom Lendacky 481958b5fcSTom Lendacky.Lno_sev: 491958b5fcSTom Lendacky xor %eax, %eax 501958b5fcSTom Lendacky 511958b5fcSTom Lendacky.Lsev_exit: 521958b5fcSTom Lendacky pop %ebx 53f94909ceSPeter Zijlstra RET 546dcc5627SJiri SlabySYM_FUNC_END(get_sev_encryption_bit) 551958b5fcSTom Lendacky 561ccdbf74SJoerg Roedel/** 571ccdbf74SJoerg Roedel * sev_es_req_cpuid - Request a CPUID value from the Hypervisor using 581ccdbf74SJoerg Roedel * the GHCB MSR protocol 591ccdbf74SJoerg Roedel * 601ccdbf74SJoerg Roedel * @%eax: Register to request (0=EAX, 1=EBX, 2=ECX, 3=EDX) 611ccdbf74SJoerg Roedel * @%edx: CPUID Function 621ccdbf74SJoerg Roedel * 631ccdbf74SJoerg Roedel * Returns 0 in %eax on success, non-zero on failure 641ccdbf74SJoerg Roedel * %edx returns CPUID value on success 651ccdbf74SJoerg Roedel */ 661ccdbf74SJoerg RoedelSYM_CODE_START_LOCAL(sev_es_req_cpuid) 671ccdbf74SJoerg Roedel shll $30, %eax 681ccdbf74SJoerg Roedel orl $0x00000004, %eax 691ccdbf74SJoerg Roedel movl $MSR_AMD64_SEV_ES_GHCB, %ecx 701ccdbf74SJoerg Roedel wrmsr 711ccdbf74SJoerg Roedel rep; vmmcall # VMGEXIT 721ccdbf74SJoerg Roedel rdmsr 731ccdbf74SJoerg Roedel 741ccdbf74SJoerg Roedel /* Check response */ 751ccdbf74SJoerg Roedel movl %eax, %ecx 761ccdbf74SJoerg Roedel andl $0x3ffff000, %ecx # Bits [12-29] MBZ 771ccdbf74SJoerg Roedel jnz 2f 781ccdbf74SJoerg Roedel 791ccdbf74SJoerg Roedel /* Check return code */ 801ccdbf74SJoerg Roedel andl $0xfff, %eax 811ccdbf74SJoerg Roedel cmpl $5, %eax 821ccdbf74SJoerg Roedel jne 2f 831ccdbf74SJoerg Roedel 841ccdbf74SJoerg Roedel /* All good - return success */ 851ccdbf74SJoerg Roedel xorl %eax, %eax 861ccdbf74SJoerg Roedel1: 87f94909ceSPeter Zijlstra RET 881ccdbf74SJoerg Roedel2: 891ccdbf74SJoerg Roedel movl $-1, %eax 901ccdbf74SJoerg Roedel jmp 1b 911ccdbf74SJoerg RoedelSYM_CODE_END(sev_es_req_cpuid) 921ccdbf74SJoerg Roedel 939ea813beSArd BiesheuvelSYM_CODE_START_LOCAL(startup32_vc_handler) 941ccdbf74SJoerg Roedel pushl %eax 951ccdbf74SJoerg Roedel pushl %ebx 961ccdbf74SJoerg Roedel pushl %ecx 971ccdbf74SJoerg Roedel pushl %edx 981ccdbf74SJoerg Roedel 991ccdbf74SJoerg Roedel /* Keep CPUID function in %ebx */ 1001ccdbf74SJoerg Roedel movl %eax, %ebx 1011ccdbf74SJoerg Roedel 1021ccdbf74SJoerg Roedel /* Check if error-code == SVM_EXIT_CPUID */ 1031ccdbf74SJoerg Roedel cmpl $0x72, 16(%esp) 1041ccdbf74SJoerg Roedel jne .Lfail 1051ccdbf74SJoerg Roedel 1061ccdbf74SJoerg Roedel movl $0, %eax # Request CPUID[fn].EAX 1071ccdbf74SJoerg Roedel movl %ebx, %edx # CPUID fn 1081ccdbf74SJoerg Roedel call sev_es_req_cpuid # Call helper 1091ccdbf74SJoerg Roedel testl %eax, %eax # Check return code 1101ccdbf74SJoerg Roedel jnz .Lfail 1111ccdbf74SJoerg Roedel movl %edx, 12(%esp) # Store result 1121ccdbf74SJoerg Roedel 1131ccdbf74SJoerg Roedel movl $1, %eax # Request CPUID[fn].EBX 1141ccdbf74SJoerg Roedel movl %ebx, %edx # CPUID fn 1151ccdbf74SJoerg Roedel call sev_es_req_cpuid # Call helper 1161ccdbf74SJoerg Roedel testl %eax, %eax # Check return code 1171ccdbf74SJoerg Roedel jnz .Lfail 1181ccdbf74SJoerg Roedel movl %edx, 8(%esp) # Store result 1191ccdbf74SJoerg Roedel 1201ccdbf74SJoerg Roedel movl $2, %eax # Request CPUID[fn].ECX 1211ccdbf74SJoerg Roedel movl %ebx, %edx # CPUID fn 1221ccdbf74SJoerg Roedel call sev_es_req_cpuid # Call helper 1231ccdbf74SJoerg Roedel testl %eax, %eax # Check return code 1241ccdbf74SJoerg Roedel jnz .Lfail 1251ccdbf74SJoerg Roedel movl %edx, 4(%esp) # Store result 1261ccdbf74SJoerg Roedel 1271ccdbf74SJoerg Roedel movl $3, %eax # Request CPUID[fn].EDX 1281ccdbf74SJoerg Roedel movl %ebx, %edx # CPUID fn 1291ccdbf74SJoerg Roedel call sev_es_req_cpuid # Call helper 1301ccdbf74SJoerg Roedel testl %eax, %eax # Check return code 1311ccdbf74SJoerg Roedel jnz .Lfail 1321ccdbf74SJoerg Roedel movl %edx, 0(%esp) # Store result 1331ccdbf74SJoerg Roedel 134e927e62dSJoerg Roedel /* 135e927e62dSJoerg Roedel * Sanity check CPUID results from the Hypervisor. See comment in 136e927e62dSJoerg Roedel * do_vc_no_ghcb() for more details on why this is necessary. 137e927e62dSJoerg Roedel */ 138e927e62dSJoerg Roedel 139e927e62dSJoerg Roedel /* Fail if SEV leaf not available in CPUID[0x80000000].EAX */ 140e927e62dSJoerg Roedel cmpl $0x80000000, %ebx 141e927e62dSJoerg Roedel jne .Lcheck_sev 142e927e62dSJoerg Roedel cmpl $0x8000001f, 12(%esp) 143e927e62dSJoerg Roedel jb .Lfail 144e927e62dSJoerg Roedel jmp .Ldone 145e927e62dSJoerg Roedel 146e927e62dSJoerg Roedel.Lcheck_sev: 147e927e62dSJoerg Roedel /* Fail if SEV bit not set in CPUID[0x8000001f].EAX[1] */ 148e927e62dSJoerg Roedel cmpl $0x8000001f, %ebx 149e927e62dSJoerg Roedel jne .Ldone 150e927e62dSJoerg Roedel btl $1, 12(%esp) 151e927e62dSJoerg Roedel jnc .Lfail 152e927e62dSJoerg Roedel 153e927e62dSJoerg Roedel.Ldone: 1541ccdbf74SJoerg Roedel popl %edx 1551ccdbf74SJoerg Roedel popl %ecx 1561ccdbf74SJoerg Roedel popl %ebx 1571ccdbf74SJoerg Roedel popl %eax 1581ccdbf74SJoerg Roedel 1591ccdbf74SJoerg Roedel /* Remove error code */ 1601ccdbf74SJoerg Roedel addl $4, %esp 1611ccdbf74SJoerg Roedel 1621ccdbf74SJoerg Roedel /* Jump over CPUID instruction */ 1631ccdbf74SJoerg Roedel addl $2, (%esp) 1641ccdbf74SJoerg Roedel 1651ccdbf74SJoerg Roedel iret 1661ccdbf74SJoerg Roedel.Lfail: 167e927e62dSJoerg Roedel /* Send terminate request to Hypervisor */ 168e927e62dSJoerg Roedel movl $0x100, %eax 169e927e62dSJoerg Roedel xorl %edx, %edx 170e927e62dSJoerg Roedel movl $MSR_AMD64_SEV_ES_GHCB, %ecx 171e927e62dSJoerg Roedel wrmsr 172e927e62dSJoerg Roedel rep; vmmcall 173e927e62dSJoerg Roedel 174e927e62dSJoerg Roedel /* If request fails, go to hlt loop */ 1751ccdbf74SJoerg Roedel hlt 1761ccdbf74SJoerg Roedel jmp .Lfail 1771ccdbf74SJoerg RoedelSYM_CODE_END(startup32_vc_handler) 1781ccdbf74SJoerg Roedel 1799ea813beSArd Biesheuvel/* 1809ea813beSArd Biesheuvel * Write an IDT entry into boot32_idt 1819ea813beSArd Biesheuvel * 1829ea813beSArd Biesheuvel * Parameters: 1839ea813beSArd Biesheuvel * 1849ea813beSArd Biesheuvel * %eax: Handler address 1859ea813beSArd Biesheuvel * %edx: Vector number 1869ea813beSArd Biesheuvel * %ecx: IDT address 1879ea813beSArd Biesheuvel */ 1889ea813beSArd BiesheuvelSYM_FUNC_START_LOCAL(startup32_set_idt_entry) 1899ea813beSArd Biesheuvel /* IDT entry address to %ecx */ 1909ea813beSArd Biesheuvel leal (%ecx, %edx, 8), %ecx 1919ea813beSArd Biesheuvel 1929ea813beSArd Biesheuvel /* Build IDT entry, lower 4 bytes */ 1939ea813beSArd Biesheuvel movl %eax, %edx 1949ea813beSArd Biesheuvel andl $0x0000ffff, %edx # Target code segment offset [15:0] 1959ea813beSArd Biesheuvel orl $(__KERNEL32_CS << 16), %edx # Target code segment selector 1969ea813beSArd Biesheuvel 1979ea813beSArd Biesheuvel /* Store lower 4 bytes to IDT */ 1989ea813beSArd Biesheuvel movl %edx, (%ecx) 1999ea813beSArd Biesheuvel 2009ea813beSArd Biesheuvel /* Build IDT entry, upper 4 bytes */ 2019ea813beSArd Biesheuvel movl %eax, %edx 2029ea813beSArd Biesheuvel andl $0xffff0000, %edx # Target code segment offset [31:16] 2039ea813beSArd Biesheuvel orl $0x00008e00, %edx # Present, Type 32-bit Interrupt Gate 2049ea813beSArd Biesheuvel 2059ea813beSArd Biesheuvel /* Store upper 4 bytes to IDT */ 2069ea813beSArd Biesheuvel movl %edx, 4(%ecx) 2079ea813beSArd Biesheuvel 2089ea813beSArd Biesheuvel RET 2099ea813beSArd BiesheuvelSYM_FUNC_END(startup32_set_idt_entry) 2109ea813beSArd Biesheuvel 2119ea813beSArd BiesheuvelSYM_FUNC_START(startup32_load_idt) 2129ea813beSArd Biesheuvel push %ebp 2139ea813beSArd Biesheuvel push %ebx 2149ea813beSArd Biesheuvel 2159ea813beSArd Biesheuvel call 1f 2169ea813beSArd Biesheuvel1: pop %ebp 2179ea813beSArd Biesheuvel 2189ea813beSArd Biesheuvel leal (boot32_idt - 1b)(%ebp), %ebx 2199ea813beSArd Biesheuvel 2209ea813beSArd Biesheuvel /* #VC handler */ 2219ea813beSArd Biesheuvel leal (startup32_vc_handler - 1b)(%ebp), %eax 2229ea813beSArd Biesheuvel movl $X86_TRAP_VC, %edx 2239ea813beSArd Biesheuvel movl %ebx, %ecx 2249ea813beSArd Biesheuvel call startup32_set_idt_entry 2259ea813beSArd Biesheuvel 2269ea813beSArd Biesheuvel /* Load IDT */ 2279ea813beSArd Biesheuvel leal (boot32_idt_desc - 1b)(%ebp), %ecx 2289ea813beSArd Biesheuvel movl %ebx, 2(%ecx) 2299ea813beSArd Biesheuvel lidt (%ecx) 2309ea813beSArd Biesheuvel 2319ea813beSArd Biesheuvel pop %ebx 2329ea813beSArd Biesheuvel pop %ebp 2339ea813beSArd Biesheuvel RET 2349ea813beSArd BiesheuvelSYM_FUNC_END(startup32_load_idt) 2359ea813beSArd Biesheuvel 236*9d7eaae6SArd Biesheuvel/* 237*9d7eaae6SArd Biesheuvel * Check for the correct C-bit position when the startup_32 boot-path is used. 238*9d7eaae6SArd Biesheuvel * 239*9d7eaae6SArd Biesheuvel * The check makes use of the fact that all memory is encrypted when paging is 240*9d7eaae6SArd Biesheuvel * disabled. The function creates 64 bits of random data using the RDRAND 241*9d7eaae6SArd Biesheuvel * instruction. RDRAND is mandatory for SEV guests, so always available. If the 242*9d7eaae6SArd Biesheuvel * hypervisor violates that the kernel will crash right here. 243*9d7eaae6SArd Biesheuvel * 244*9d7eaae6SArd Biesheuvel * The 64 bits of random data are stored to a memory location and at the same 245*9d7eaae6SArd Biesheuvel * time kept in the %eax and %ebx registers. Since encryption is always active 246*9d7eaae6SArd Biesheuvel * when paging is off the random data will be stored encrypted in main memory. 247*9d7eaae6SArd Biesheuvel * 248*9d7eaae6SArd Biesheuvel * Then paging is enabled. When the C-bit position is correct all memory is 249*9d7eaae6SArd Biesheuvel * still mapped encrypted and comparing the register values with memory will 250*9d7eaae6SArd Biesheuvel * succeed. An incorrect C-bit position will map all memory unencrypted, so that 251*9d7eaae6SArd Biesheuvel * the compare will use the encrypted random data and fail. 252*9d7eaae6SArd Biesheuvel */ 253*9d7eaae6SArd BiesheuvelSYM_FUNC_START(startup32_check_sev_cbit) 254*9d7eaae6SArd Biesheuvel pushl %ebx 255*9d7eaae6SArd Biesheuvel pushl %ebp 256*9d7eaae6SArd Biesheuvel 257*9d7eaae6SArd Biesheuvel call 0f 258*9d7eaae6SArd Biesheuvel0: popl %ebp 259*9d7eaae6SArd Biesheuvel 260*9d7eaae6SArd Biesheuvel /* Check for non-zero sev_status */ 261*9d7eaae6SArd Biesheuvel movl (sev_status - 0b)(%ebp), %eax 262*9d7eaae6SArd Biesheuvel testl %eax, %eax 263*9d7eaae6SArd Biesheuvel jz 4f 264*9d7eaae6SArd Biesheuvel 265*9d7eaae6SArd Biesheuvel /* 266*9d7eaae6SArd Biesheuvel * Get two 32-bit random values - Don't bail out if RDRAND fails 267*9d7eaae6SArd Biesheuvel * because it is better to prevent forward progress if no random value 268*9d7eaae6SArd Biesheuvel * can be gathered. 269*9d7eaae6SArd Biesheuvel */ 270*9d7eaae6SArd Biesheuvel1: rdrand %eax 271*9d7eaae6SArd Biesheuvel jnc 1b 272*9d7eaae6SArd Biesheuvel2: rdrand %ebx 273*9d7eaae6SArd Biesheuvel jnc 2b 274*9d7eaae6SArd Biesheuvel 275*9d7eaae6SArd Biesheuvel /* Store to memory and keep it in the registers */ 276*9d7eaae6SArd Biesheuvel leal (sev_check_data - 0b)(%ebp), %ebp 277*9d7eaae6SArd Biesheuvel movl %eax, 0(%ebp) 278*9d7eaae6SArd Biesheuvel movl %ebx, 4(%ebp) 279*9d7eaae6SArd Biesheuvel 280*9d7eaae6SArd Biesheuvel /* Enable paging to see if encryption is active */ 281*9d7eaae6SArd Biesheuvel movl %cr0, %edx /* Backup %cr0 in %edx */ 282*9d7eaae6SArd Biesheuvel movl $(X86_CR0_PG | X86_CR0_PE), %ecx /* Enable Paging and Protected mode */ 283*9d7eaae6SArd Biesheuvel movl %ecx, %cr0 284*9d7eaae6SArd Biesheuvel 285*9d7eaae6SArd Biesheuvel cmpl %eax, 0(%ebp) 286*9d7eaae6SArd Biesheuvel jne 3f 287*9d7eaae6SArd Biesheuvel cmpl %ebx, 4(%ebp) 288*9d7eaae6SArd Biesheuvel jne 3f 289*9d7eaae6SArd Biesheuvel 290*9d7eaae6SArd Biesheuvel movl %edx, %cr0 /* Restore previous %cr0 */ 291*9d7eaae6SArd Biesheuvel 292*9d7eaae6SArd Biesheuvel jmp 4f 293*9d7eaae6SArd Biesheuvel 294*9d7eaae6SArd Biesheuvel3: /* Check failed - hlt the machine */ 295*9d7eaae6SArd Biesheuvel hlt 296*9d7eaae6SArd Biesheuvel jmp 3b 297*9d7eaae6SArd Biesheuvel 298*9d7eaae6SArd Biesheuvel4: 299*9d7eaae6SArd Biesheuvel popl %ebp 300*9d7eaae6SArd Biesheuvel popl %ebx 301*9d7eaae6SArd Biesheuvel RET 302*9d7eaae6SArd BiesheuvelSYM_FUNC_END(startup32_check_sev_cbit) 303*9d7eaae6SArd Biesheuvel 3041958b5fcSTom Lendacky .code64 30586ce43f7SJoerg Roedel 30686ce43f7SJoerg Roedel#include "../../kernel/sev_verify_cbit.S" 3071958b5fcSTom Lendacky 3081958b5fcSTom Lendacky .data 30907344b15STom Lendacky 31007344b15STom Lendacky .balign 8 311b8c3f9b5SJiri SlabySYM_DATA(sme_me_mask, .quad 0) 3123ad84246SJoerg RoedelSYM_DATA(sev_status, .quad 0) 31386ce43f7SJoerg RoedelSYM_DATA(sev_check_data, .quad 0) 3149ea813beSArd Biesheuvel 3159ea813beSArd BiesheuvelSYM_DATA_START_LOCAL(boot32_idt) 3169ea813beSArd Biesheuvel .rept 32 3179ea813beSArd Biesheuvel .quad 0 3189ea813beSArd Biesheuvel .endr 3199ea813beSArd BiesheuvelSYM_DATA_END(boot32_idt) 3209ea813beSArd Biesheuvel 3219ea813beSArd BiesheuvelSYM_DATA_START_LOCAL(boot32_idt_desc) 3229ea813beSArd Biesheuvel .word . - boot32_idt - 1 3239ea813beSArd Biesheuvel .long 0 3249ea813beSArd BiesheuvelSYM_DATA_END(boot32_idt_desc) 325