xref: /openbmc/linux/arch/x86/boot/compressed/mem_encrypt.S (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
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