1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* |
3 | * AMD Encrypted Register State Support |
4 | * |
5 | * Author: Joerg Roedel <jroedel@suse.de> |
6 | */ |
7 | |
8 | #ifndef __ASM_ENCRYPTED_STATE_H |
9 | #define __ASM_ENCRYPTED_STATE_H |
10 | |
11 | #include <linux/types.h> |
12 | #include <linux/sev-guest.h> |
13 | |
14 | #include <asm/insn.h> |
15 | #include <asm/sev-common.h> |
16 | #include <asm/bootparam.h> |
17 | #include <asm/coco.h> |
18 | |
19 | #define GHCB_PROTOCOL_MIN 1ULL |
20 | #define GHCB_PROTOCOL_MAX 2ULL |
21 | #define GHCB_DEFAULT_USAGE 0ULL |
22 | |
23 | #define VMGEXIT() { asm volatile("rep; vmmcall\n\r"); } |
24 | |
25 | enum es_result { |
26 | ES_OK, /* All good */ |
27 | ES_UNSUPPORTED, /* Requested operation not supported */ |
28 | ES_VMM_ERROR, /* Unexpected state from the VMM */ |
29 | ES_DECODE_FAILED, /* Instruction decoding failed */ |
30 | ES_EXCEPTION, /* Instruction caused exception */ |
31 | ES_RETRY, /* Retry instruction emulation */ |
32 | }; |
33 | |
34 | struct es_fault_info { |
35 | unsigned long vector; |
36 | unsigned long error_code; |
37 | unsigned long cr2; |
38 | }; |
39 | |
40 | struct pt_regs; |
41 | |
42 | /* ES instruction emulation context */ |
43 | struct es_em_ctxt { |
44 | struct pt_regs *regs; |
45 | struct insn insn; |
46 | struct es_fault_info fi; |
47 | }; |
48 | |
49 | /* |
50 | * AMD SEV Confidential computing blob structure. The structure is |
51 | * defined in OVMF UEFI firmware header: |
52 | * https://github.com/tianocore/edk2/blob/master/OvmfPkg/Include/Guid/ConfidentialComputingSevSnpBlob.h |
53 | */ |
54 | #define CC_BLOB_SEV_HDR_MAGIC 0x45444d41 |
55 | struct cc_blob_sev_info { |
56 | u32 magic; |
57 | u16 version; |
58 | u16 reserved; |
59 | u64 secrets_phys; |
60 | u32 secrets_len; |
61 | u32 rsvd1; |
62 | u64 cpuid_phys; |
63 | u32 cpuid_len; |
64 | u32 rsvd2; |
65 | } __packed; |
66 | |
67 | void do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code); |
68 | |
69 | static inline u64 lower_bits(u64 val, unsigned int bits) |
70 | { |
71 | u64 mask = (1ULL << bits) - 1; |
72 | |
73 | return (val & mask); |
74 | } |
75 | |
76 | struct ; |
77 | enum stack_type; |
78 | |
79 | /* Early IDT entry points for #VC handler */ |
80 | extern void vc_no_ghcb(void); |
81 | extern void vc_boot_ghcb(void); |
82 | extern bool handle_vc_boot_ghcb(struct pt_regs *regs); |
83 | |
84 | /* PVALIDATE return codes */ |
85 | #define PVALIDATE_FAIL_SIZEMISMATCH 6 |
86 | |
87 | /* Software defined (when rFlags.CF = 1) */ |
88 | #define PVALIDATE_FAIL_NOUPDATE 255 |
89 | |
90 | /* RMP page size */ |
91 | #define RMP_PG_SIZE_4K 0 |
92 | #define RMP_PG_SIZE_2M 1 |
93 | |
94 | #define RMPADJUST_VMSA_PAGE_BIT BIT(16) |
95 | |
96 | /* SNP Guest message request */ |
97 | struct snp_req_data { |
98 | unsigned long req_gpa; |
99 | unsigned long resp_gpa; |
100 | unsigned long data_gpa; |
101 | unsigned int data_npages; |
102 | }; |
103 | |
104 | struct sev_guest_platform_data { |
105 | u64 secrets_gpa; |
106 | }; |
107 | |
108 | /* |
109 | * The secrets page contains 96-bytes of reserved field that can be used by |
110 | * the guest OS. The guest OS uses the area to save the message sequence |
111 | * number for each VMPCK. |
112 | * |
113 | * See the GHCB spec section Secret page layout for the format for this area. |
114 | */ |
115 | struct secrets_os_area { |
116 | u32 msg_seqno_0; |
117 | u32 msg_seqno_1; |
118 | u32 msg_seqno_2; |
119 | u32 msg_seqno_3; |
120 | u64 ap_jump_table_pa; |
121 | u8 rsvd[40]; |
122 | u8 guest_usage[32]; |
123 | } __packed; |
124 | |
125 | #define VMPCK_KEY_LEN 32 |
126 | |
127 | /* See the SNP spec version 0.9 for secrets page format */ |
128 | struct snp_secrets_page_layout { |
129 | u32 version; |
130 | u32 imien : 1, |
131 | rsvd1 : 31; |
132 | u32 fms; |
133 | u32 rsvd2; |
134 | u8 gosvw[16]; |
135 | u8 vmpck0[VMPCK_KEY_LEN]; |
136 | u8 vmpck1[VMPCK_KEY_LEN]; |
137 | u8 vmpck2[VMPCK_KEY_LEN]; |
138 | u8 vmpck3[VMPCK_KEY_LEN]; |
139 | struct secrets_os_area os_area; |
140 | u8 rsvd3[3840]; |
141 | } __packed; |
142 | |
143 | #ifdef CONFIG_AMD_MEM_ENCRYPT |
144 | extern void __sev_es_ist_enter(struct pt_regs *regs); |
145 | extern void __sev_es_ist_exit(void); |
146 | static __always_inline void sev_es_ist_enter(struct pt_regs *regs) |
147 | { |
148 | if (cc_vendor == CC_VENDOR_AMD && |
149 | cc_platform_has(attr: CC_ATTR_GUEST_STATE_ENCRYPT)) |
150 | __sev_es_ist_enter(regs); |
151 | } |
152 | static __always_inline void sev_es_ist_exit(void) |
153 | { |
154 | if (cc_vendor == CC_VENDOR_AMD && |
155 | cc_platform_has(attr: CC_ATTR_GUEST_STATE_ENCRYPT)) |
156 | __sev_es_ist_exit(); |
157 | } |
158 | extern int sev_es_setup_ap_jump_table(struct real_mode_header *rmh); |
159 | extern void __sev_es_nmi_complete(void); |
160 | static __always_inline void sev_es_nmi_complete(void) |
161 | { |
162 | if (cc_vendor == CC_VENDOR_AMD && |
163 | cc_platform_has(attr: CC_ATTR_GUEST_STATE_ENCRYPT)) |
164 | __sev_es_nmi_complete(); |
165 | } |
166 | extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd); |
167 | extern void sev_enable(struct boot_params *bp); |
168 | |
169 | static inline int rmpadjust(unsigned long vaddr, bool rmp_psize, unsigned long attrs) |
170 | { |
171 | int rc; |
172 | |
173 | /* "rmpadjust" mnemonic support in binutils 2.36 and newer */ |
174 | asm volatile(".byte 0xF3,0x0F,0x01,0xFE\n\t" |
175 | : "=a" (rc) |
176 | : "a" (vaddr), "c" (rmp_psize), "d" (attrs) |
177 | : "memory" , "cc" ); |
178 | |
179 | return rc; |
180 | } |
181 | static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) |
182 | { |
183 | bool no_rmpupdate; |
184 | int rc; |
185 | |
186 | /* "pvalidate" mnemonic support in binutils 2.36 and newer */ |
187 | asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFF\n\t" |
188 | CC_SET(c) |
189 | : CC_OUT(c) (no_rmpupdate), "=a" (rc) |
190 | : "a" (vaddr), "c" (rmp_psize), "d" (validate) |
191 | : "memory" , "cc" ); |
192 | |
193 | if (no_rmpupdate) |
194 | return PVALIDATE_FAIL_NOUPDATE; |
195 | |
196 | return rc; |
197 | } |
198 | |
199 | struct snp_guest_request_ioctl; |
200 | |
201 | void setup_ghcb(void); |
202 | void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, |
203 | unsigned long npages); |
204 | void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr, |
205 | unsigned long npages); |
206 | void __init snp_prep_memory(unsigned long paddr, unsigned int sz, enum psc_op op); |
207 | void snp_set_memory_shared(unsigned long vaddr, unsigned long npages); |
208 | void snp_set_memory_private(unsigned long vaddr, unsigned long npages); |
209 | void snp_set_wakeup_secondary_cpu(void); |
210 | bool snp_init(struct boot_params *bp); |
211 | void __init __noreturn snp_abort(void); |
212 | int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio); |
213 | void snp_accept_memory(phys_addr_t start, phys_addr_t end); |
214 | u64 snp_get_unsupported_features(u64 status); |
215 | u64 sev_get_status(void); |
216 | #else |
217 | static inline void sev_es_ist_enter(struct pt_regs *regs) { } |
218 | static inline void sev_es_ist_exit(void) { } |
219 | static inline int sev_es_setup_ap_jump_table(struct real_mode_header *rmh) { return 0; } |
220 | static inline void sev_es_nmi_complete(void) { } |
221 | static inline int sev_es_efi_map_ghcbs(pgd_t *pgd) { return 0; } |
222 | static inline void sev_enable(struct boot_params *bp) { } |
223 | static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) { return 0; } |
224 | static inline int rmpadjust(unsigned long vaddr, bool rmp_psize, unsigned long attrs) { return 0; } |
225 | static inline void setup_ghcb(void) { } |
226 | static inline void __init |
227 | early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, unsigned long npages) { } |
228 | static inline void __init |
229 | early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr, unsigned long npages) { } |
230 | static inline void __init snp_prep_memory(unsigned long paddr, unsigned int sz, enum psc_op op) { } |
231 | static inline void snp_set_memory_shared(unsigned long vaddr, unsigned long npages) { } |
232 | static inline void snp_set_memory_private(unsigned long vaddr, unsigned long npages) { } |
233 | static inline void snp_set_wakeup_secondary_cpu(void) { } |
234 | static inline bool snp_init(struct boot_params *bp) { return false; } |
235 | static inline void snp_abort(void) { } |
236 | static inline int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio) |
237 | { |
238 | return -ENOTTY; |
239 | } |
240 | |
241 | static inline void snp_accept_memory(phys_addr_t start, phys_addr_t end) { } |
242 | static inline u64 snp_get_unsupported_features(u64 status) { return 0; } |
243 | static inline u64 sev_get_status(void) { return 0; } |
244 | #endif |
245 | |
246 | #endif |
247 | |