Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2
3#include "misc.h"
4#include "error.h"
5#include "sev.h"
6
7#include <linux/kernel.h>
8#include <linux/string.h>
9#include <asm/insn.h>
10#include <asm/pgtable_types.h>
11#include <asm/ptrace.h>
12#include <asm/sev.h>
13#include <asm/trapnr.h>
14#include <asm/trap_pf.h>
15#include <asm/fpu/xcr.h>
16
17#define __BOOT_COMPRESSED
18#undef __init
19#define __init
20
21/* Basic instruction decoding support needed */
22#include "../../lib/inat.c"
23#include "../../lib/insn.c"
24
25/*
26 * Copy a version of this function here - insn-eval.c can't be used in
27 * pre-decompression code.
28 */
29bool insn_has_rep_prefix(struct insn *insn)
30{
31 insn_byte_t p;
32
33 insn_get_prefixes(insn);
34
35 for_each_insn_prefix(insn, p) {
36 if (p == 0xf2 || p == 0xf3)
37 return true;
38 }
39
40 return false;
41}
42
43enum es_result vc_decode_insn(struct es_em_ctxt *ctxt)
44{
45 char buffer[MAX_INSN_SIZE];
46 int ret;
47
48 memcpy(buffer, (unsigned char *)ctxt->regs->ip, MAX_INSN_SIZE);
49
50 ret = insn_decode(&ctxt->insn, buffer, MAX_INSN_SIZE, INSN_MODE_64);
51 if (ret < 0)
52 return ES_DECODE_FAILED;
53
54 return ES_OK;
55}
56
57extern void sev_insn_decode_init(void) __alias(inat_init_tables);
58
59/*
60 * Only a dummy for insn_get_seg_base() - Early boot-code is 64bit only and
61 * doesn't use segments.
62 */
63static unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx)
64{
65 return 0UL;
66}
67
68static enum es_result vc_write_mem(struct es_em_ctxt *ctxt,
69 void *dst, char *buf, size_t size)
70{
71 memcpy(dst, buf, size);
72
73 return ES_OK;
74}
75
76static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
77 void *src, char *buf, size_t size)
78{
79 memcpy(buf, src, size);
80
81 return ES_OK;
82}
83
84static enum es_result vc_ioio_check(struct es_em_ctxt *ctxt, u16 port, size_t size)
85{
86 return ES_OK;
87}
88
89static bool fault_in_kernel_space(unsigned long address)
90{
91 return false;
92}
93
94#define sev_printk(fmt, ...)
95
96#include "../../coco/sev/vc-shared.c"
97
98void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)
99{
100 struct es_em_ctxt ctxt;
101 enum es_result result;
102
103 if (!boot_ghcb && !early_setup_ghcb())
104 sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
105
106 vc_ghcb_invalidate(boot_ghcb);
107 result = vc_init_em_ctxt(&ctxt, regs, exit_code);
108 if (result != ES_OK)
109 goto finish;
110
111 result = vc_check_opcode_bytes(&ctxt, exit_code);
112 if (result != ES_OK)
113 goto finish;
114
115 switch (exit_code) {
116 case SVM_EXIT_RDTSC:
117 case SVM_EXIT_RDTSCP:
118 result = vc_handle_rdtsc(boot_ghcb, &ctxt, exit_code);
119 break;
120 case SVM_EXIT_IOIO:
121 result = vc_handle_ioio(boot_ghcb, &ctxt);
122 break;
123 case SVM_EXIT_CPUID:
124 result = vc_handle_cpuid(boot_ghcb, &ctxt);
125 break;
126 default:
127 result = ES_UNSUPPORTED;
128 break;
129 }
130
131finish:
132 if (result == ES_OK)
133 vc_finish_insn(&ctxt);
134 else if (result != ES_RETRY)
135 sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
136}