1 /* SPDX-License-Identifier: GPL-2.0-only */
3 * AMD Memory Encryption Support
5 * Copyright (C) 2017 Advanced Micro Devices, Inc.
10 #include <linux/linkage.h>
12 #include <asm/processor-flags.h>
14 #include <asm/asm-offsets.h>
15 #include <asm/segment.h>
16 #include <asm/trapnr.h>
20 SYM_FUNC_START(get_sev_encryption_bit)
23 movl $0x80000000, %eax /* CPUID to check the highest leaf */
25 cmpl $0x8000001f, %eax /* See if 0x8000001f is available */
29 * Check for the SEV feature:
30 * CPUID Fn8000_001F[EAX] - Bit 1
31 * CPUID Fn8000_001F[EBX] - Bits 5:0
32 * Pagetable bit position used to indicate encryption
34 movl $0x8000001f, %eax
36 bt $1, %eax /* Check if SEV is available */
39 movl $MSR_AMD64_SEV, %ecx /* Read the SEV MSR */
41 bt $MSR_AMD64_SEV_ENABLED_BIT, %eax /* Check if SEV is active */
45 andl $0x3f, %eax /* Return the encryption bit location */
54 SYM_FUNC_END(get_sev_encryption_bit)
57 * sev_es_req_cpuid - Request a CPUID value from the Hypervisor using
58 * the GHCB MSR protocol
60 * @%eax: Register to request (0=EAX, 1=EBX, 2=ECX, 3=EDX)
61 * @%edx: CPUID Function
63 * Returns 0 in %eax on success, non-zero on failure
64 * %edx returns CPUID value on success
66 SYM_CODE_START_LOCAL(sev_es_req_cpuid)
69 movl $MSR_AMD64_SEV_ES_GHCB, %ecx
71 rep; vmmcall # VMGEXIT
76 andl $0x3ffff000, %ecx # Bits [12-29] MBZ
79 /* Check return code */
84 /* All good - return success */
91 SYM_CODE_END(sev_es_req_cpuid)
93 SYM_CODE_START_LOCAL(startup32_vc_handler)
99 /* Keep CPUID function in %ebx */
102 /* Check if error-code == SVM_EXIT_CPUID */
106 movl $0, %eax # Request CPUID[fn].EAX
107 movl %ebx, %edx # CPUID fn
108 call sev_es_req_cpuid # Call helper
109 testl %eax, %eax # Check return code
111 movl %edx, 12(%esp) # Store result
113 movl $1, %eax # Request CPUID[fn].EBX
114 movl %ebx, %edx # CPUID fn
115 call sev_es_req_cpuid # Call helper
116 testl %eax, %eax # Check return code
118 movl %edx, 8(%esp) # Store result
120 movl $2, %eax # Request CPUID[fn].ECX
121 movl %ebx, %edx # CPUID fn
122 call sev_es_req_cpuid # Call helper
123 testl %eax, %eax # Check return code
125 movl %edx, 4(%esp) # Store result
127 movl $3, %eax # Request CPUID[fn].EDX
128 movl %ebx, %edx # CPUID fn
129 call sev_es_req_cpuid # Call helper
130 testl %eax, %eax # Check return code
132 movl %edx, 0(%esp) # Store result
135 * Sanity check CPUID results from the Hypervisor. See comment in
136 * do_vc_no_ghcb() for more details on why this is necessary.
139 /* Fail if SEV leaf not available in CPUID[0x80000000].EAX */
140 cmpl $0x80000000, %ebx
142 cmpl $0x8000001f, 12(%esp)
147 /* Fail if SEV bit not set in CPUID[0x8000001f].EAX[1] */
148 cmpl $0x8000001f, %ebx
159 /* Remove error code */
162 /* Jump over CPUID instruction */
167 /* Send terminate request to Hypervisor */
170 movl $MSR_AMD64_SEV_ES_GHCB, %ecx
174 /* If request fails, go to hlt loop */
177 SYM_CODE_END(startup32_vc_handler)
180 * Write an IDT entry into boot32_idt
184 * %eax: Handler address
185 * %edx: Vector number
188 SYM_FUNC_START_LOCAL(startup32_set_idt_entry)
189 /* IDT entry address to %ecx */
190 leal (%ecx, %edx, 8), %ecx
192 /* Build IDT entry, lower 4 bytes */
194 andl $0x0000ffff, %edx # Target code segment offset [15:0]
195 orl $(__KERNEL32_CS << 16), %edx # Target code segment selector
197 /* Store lower 4 bytes to IDT */
200 /* Build IDT entry, upper 4 bytes */
202 andl $0xffff0000, %edx # Target code segment offset [31:16]
203 orl $0x00008e00, %edx # Present, Type 32-bit Interrupt Gate
205 /* Store upper 4 bytes to IDT */
209 SYM_FUNC_END(startup32_set_idt_entry)
211 SYM_FUNC_START(startup32_load_idt)
218 leal (boot32_idt - 1b)(%ebp), %ebx
221 leal (startup32_vc_handler - 1b)(%ebp), %eax
222 movl $X86_TRAP_VC, %edx
224 call startup32_set_idt_entry
227 leal (boot32_idt_desc - 1b)(%ebp), %ecx
234 SYM_FUNC_END(startup32_load_idt)
237 * Check for the correct C-bit position when the startup_32 boot-path is used.
239 * The check makes use of the fact that all memory is encrypted when paging is
240 * disabled. The function creates 64 bits of random data using the RDRAND
241 * instruction. RDRAND is mandatory for SEV guests, so always available. If the
242 * hypervisor violates that the kernel will crash right here.
244 * The 64 bits of random data are stored to a memory location and at the same
245 * time kept in the %eax and %ebx registers. Since encryption is always active
246 * when paging is off the random data will be stored encrypted in main memory.
248 * Then paging is enabled. When the C-bit position is correct all memory is
249 * still mapped encrypted and comparing the register values with memory will
250 * succeed. An incorrect C-bit position will map all memory unencrypted, so that
251 * the compare will use the encrypted random data and fail.
253 SYM_FUNC_START(startup32_check_sev_cbit)
260 /* Check for non-zero sev_status */
261 movl (sev_status - 0b)(%ebp), %eax
266 * Get two 32-bit random values - Don't bail out if RDRAND fails
267 * because it is better to prevent forward progress if no random value
275 /* Store to memory and keep it in the registers */
276 leal (sev_check_data - 0b)(%ebp), %ebp
280 /* Enable paging to see if encryption is active */
281 movl %cr0, %edx /* Backup %cr0 in %edx */
282 movl $(X86_CR0_PG | X86_CR0_PE), %ecx /* Enable Paging and Protected mode */
290 movl %edx, %cr0 /* Restore previous %cr0 */
294 3: /* Check failed - hlt the machine */
302 SYM_FUNC_END(startup32_check_sev_cbit)
306 #include "../../kernel/sev_verify_cbit.S"
311 SYM_DATA(sme_me_mask, .quad 0)
312 SYM_DATA(sev_status, .quad 0)
313 SYM_DATA(sev_check_data, .quad 0)
315 SYM_DATA_START_LOCAL(boot32_idt)
319 SYM_DATA_END(boot32_idt)
321 SYM_DATA_START_LOCAL(boot32_idt_desc)
322 .word . - boot32_idt - 1
324 SYM_DATA_END(boot32_idt_desc)