|
7 | 7 | * Author: Joerg Roedel <[email protected]>
|
8 | 8 | */
|
9 | 9 |
|
| 10 | +#include <linux/sched/debug.h> /* For show_regs() */ |
10 | 11 | #include <linux/kernel.h>
|
| 12 | +#include <linux/printk.h> |
11 | 13 | #include <linux/mm.h>
|
12 | 14 |
|
13 | 15 | #include <asm/sev-es.h>
|
|
18 | 20 | #include <asm/trapnr.h>
|
19 | 21 | #include <asm/svm.h>
|
20 | 22 |
|
| 23 | +/* For early boot hypervisor communication in SEV-ES enabled guests */ |
| 24 | +static struct ghcb boot_ghcb_page __bss_decrypted __aligned(PAGE_SIZE); |
| 25 | + |
| 26 | +/* |
| 27 | + * Needs to be in the .data section because we need it NULL before bss is |
| 28 | + * cleared |
| 29 | + */ |
| 30 | +static struct ghcb __initdata *boot_ghcb; |
| 31 | + |
| 32 | +/* Needed in vc_early_forward_exception */ |
| 33 | +void do_early_exception(struct pt_regs *regs, int trapnr); |
| 34 | + |
21 | 35 | static inline u64 sev_es_rd_ghcb_msr(void)
|
22 | 36 | {
|
23 | 37 | return __rdmsr(MSR_AMD64_SEV_ES_GHCB);
|
@@ -161,3 +175,105 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
|
161 | 175 |
|
162 | 176 | /* Include code shared with pre-decompression boot stage */
|
163 | 177 | #include "sev-es-shared.c"
|
| 178 | + |
| 179 | +/* |
| 180 | + * This function runs on the first #VC exception after the kernel |
| 181 | + * switched to virtual addresses. |
| 182 | + */ |
| 183 | +static bool __init sev_es_setup_ghcb(void) |
| 184 | +{ |
| 185 | + /* First make sure the hypervisor talks a supported protocol. */ |
| 186 | + if (!sev_es_negotiate_protocol()) |
| 187 | + return false; |
| 188 | + |
| 189 | + /* |
| 190 | + * Clear the boot_ghcb. The first exception comes in before the bss |
| 191 | + * section is cleared. |
| 192 | + */ |
| 193 | + memset(&boot_ghcb_page, 0, PAGE_SIZE); |
| 194 | + |
| 195 | + /* Alright - Make the boot-ghcb public */ |
| 196 | + boot_ghcb = &boot_ghcb_page; |
| 197 | + |
| 198 | + return true; |
| 199 | +} |
| 200 | + |
| 201 | +static void __init vc_early_forward_exception(struct es_em_ctxt *ctxt) |
| 202 | +{ |
| 203 | + int trapnr = ctxt->fi.vector; |
| 204 | + |
| 205 | + if (trapnr == X86_TRAP_PF) |
| 206 | + native_write_cr2(ctxt->fi.cr2); |
| 207 | + |
| 208 | + ctxt->regs->orig_ax = ctxt->fi.error_code; |
| 209 | + do_early_exception(ctxt->regs, trapnr); |
| 210 | +} |
| 211 | + |
| 212 | +static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt, |
| 213 | + struct ghcb *ghcb, |
| 214 | + unsigned long exit_code) |
| 215 | +{ |
| 216 | + enum es_result result; |
| 217 | + |
| 218 | + switch (exit_code) { |
| 219 | + default: |
| 220 | + /* |
| 221 | + * Unexpected #VC exception |
| 222 | + */ |
| 223 | + result = ES_UNSUPPORTED; |
| 224 | + } |
| 225 | + |
| 226 | + return result; |
| 227 | +} |
| 228 | + |
| 229 | +bool __init handle_vc_boot_ghcb(struct pt_regs *regs) |
| 230 | +{ |
| 231 | + unsigned long exit_code = regs->orig_ax; |
| 232 | + struct es_em_ctxt ctxt; |
| 233 | + enum es_result result; |
| 234 | + |
| 235 | + /* Do initial setup or terminate the guest */ |
| 236 | + if (unlikely(boot_ghcb == NULL && !sev_es_setup_ghcb())) |
| 237 | + sev_es_terminate(GHCB_SEV_ES_REASON_GENERAL_REQUEST); |
| 238 | + |
| 239 | + vc_ghcb_invalidate(boot_ghcb); |
| 240 | + |
| 241 | + result = vc_init_em_ctxt(&ctxt, regs, exit_code); |
| 242 | + if (result == ES_OK) |
| 243 | + result = vc_handle_exitcode(&ctxt, boot_ghcb, exit_code); |
| 244 | + |
| 245 | + /* Done - now check the result */ |
| 246 | + switch (result) { |
| 247 | + case ES_OK: |
| 248 | + vc_finish_insn(&ctxt); |
| 249 | + break; |
| 250 | + case ES_UNSUPPORTED: |
| 251 | + early_printk("PANIC: Unsupported exit-code 0x%02lx in early #VC exception (IP: 0x%lx)\n", |
| 252 | + exit_code, regs->ip); |
| 253 | + goto fail; |
| 254 | + case ES_VMM_ERROR: |
| 255 | + early_printk("PANIC: Failure in communication with VMM (exit-code 0x%02lx IP: 0x%lx)\n", |
| 256 | + exit_code, regs->ip); |
| 257 | + goto fail; |
| 258 | + case ES_DECODE_FAILED: |
| 259 | + early_printk("PANIC: Failed to decode instruction (exit-code 0x%02lx IP: 0x%lx)\n", |
| 260 | + exit_code, regs->ip); |
| 261 | + goto fail; |
| 262 | + case ES_EXCEPTION: |
| 263 | + vc_early_forward_exception(&ctxt); |
| 264 | + break; |
| 265 | + case ES_RETRY: |
| 266 | + /* Nothing to do */ |
| 267 | + break; |
| 268 | + default: |
| 269 | + BUG(); |
| 270 | + } |
| 271 | + |
| 272 | + return true; |
| 273 | + |
| 274 | +fail: |
| 275 | + show_regs(regs); |
| 276 | + |
| 277 | + while (true) |
| 278 | + halt(); |
| 279 | +} |
0 commit comments