1/*
2 * AMD Memory Encryption Support
3 *
4 * Copyright (C) 2017 Advanced Micro Devices, Inc.
5 *
6 * Author: Tom Lendacky <thomas.lendacky@amd.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/linkage.h>
14
15#include <asm/processor-flags.h>
16#include <asm/msr.h>
17#include <asm/asm-offsets.h>
18
19	.text
20	.code32
21ENTRY(get_sev_encryption_bit)
22	xor	%eax, %eax
23
24#ifdef CONFIG_AMD_MEM_ENCRYPT
25	push	%ebx
26	push	%ecx
27	push	%edx
28	push	%edi
29
30	/*
31	 * RIP-relative addressing is needed to access the encryption bit
32	 * variable. Since we are running in 32-bit mode we need this call/pop
33	 * sequence to get the proper relative addressing.
34	 */
35	call	1f
361:	popl	%edi
37	subl	$1b, %edi
38
39	movl	enc_bit(%edi), %eax
40	cmpl	$0, %eax
41	jge	.Lsev_exit
42
43	/* Check if running under a hypervisor */
44	movl	$1, %eax
45	cpuid
46	bt	$31, %ecx		/* Check the hypervisor bit */
47	jnc	.Lno_sev
48
49	movl	$0x80000000, %eax	/* CPUID to check the highest leaf */
50	cpuid
51	cmpl	$0x8000001f, %eax	/* See if 0x8000001f is available */
52	jb	.Lno_sev
53
54	/*
55	 * Check for the SEV feature:
56	 *   CPUID Fn8000_001F[EAX] - Bit 1
57	 *   CPUID Fn8000_001F[EBX] - Bits 5:0
58	 *     Pagetable bit position used to indicate encryption
59	 */
60	movl	$0x8000001f, %eax
61	cpuid
62	bt	$1, %eax		/* Check if SEV is available */
63	jnc	.Lno_sev
64
65	movl	$MSR_AMD64_SEV, %ecx	/* Read the SEV MSR */
66	rdmsr
67	bt	$MSR_AMD64_SEV_ENABLED_BIT, %eax	/* Check if SEV is active */
68	jnc	.Lno_sev
69
70	movl	%ebx, %eax
71	andl	$0x3f, %eax		/* Return the encryption bit location */
72	movl	%eax, enc_bit(%edi)
73	jmp	.Lsev_exit
74
75.Lno_sev:
76	xor	%eax, %eax
77	movl	%eax, enc_bit(%edi)
78
79.Lsev_exit:
80	pop	%edi
81	pop	%edx
82	pop	%ecx
83	pop	%ebx
84
85#endif	/* CONFIG_AMD_MEM_ENCRYPT */
86
87	ret
88ENDPROC(get_sev_encryption_bit)
89
90	.code64
91ENTRY(set_sev_encryption_mask)
92#ifdef CONFIG_AMD_MEM_ENCRYPT
93	push	%rbp
94	push	%rdx
95
96	movq	%rsp, %rbp		/* Save current stack pointer */
97
98	call	get_sev_encryption_bit	/* Get the encryption bit position */
99	testl	%eax, %eax
100	jz	.Lno_sev_mask
101
102	bts	%rax, sme_me_mask(%rip)	/* Create the encryption mask */
103
104.Lno_sev_mask:
105	movq	%rbp, %rsp		/* Restore original stack pointer */
106
107	pop	%rdx
108	pop	%rbp
109#endif
110
111	xor	%rax, %rax
112	ret
113ENDPROC(set_sev_encryption_mask)
114
115	.data
116enc_bit:
117	.int	0xffffffff
118
119#ifdef CONFIG_AMD_MEM_ENCRYPT
120	.balign	8
121GLOBAL(sme_me_mask)
122	.quad	0
123#endif
124