]> git.proxmox.com Git - pve-kernel.git/blob - patches/kernel/0012-KVM-x86-emulator-smm-add-structs-for-KVM-s-smram-lay.patch
5f1b39137e6f9f21c41f35f47cdc6553ef6603a0
[pve-kernel.git] / patches / kernel / 0012-KVM-x86-emulator-smm-add-structs-for-KVM-s-smram-lay.patch
1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Maxim Levitsky <mlevitsk@redhat.com>
3 Date: Wed, 3 Aug 2022 18:50:05 +0300
4 Subject: [PATCH] KVM: x86: emulator/smm: add structs for KVM's smram layout
5
6 Those structs will be used to read/write the smram state image.
7
8 Also document the differences between KVM's SMRAM layout and SMRAM
9 layout that is used by real Intel/AMD cpus.
10
11 Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
12 Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
13 ---
14 arch/x86/kvm/emulate.c | 6 +
15 arch/x86/kvm/kvm_emulate.h | 218 +++++++++++++++++++++++++++++++++++++
16 arch/x86/kvm/x86.c | 1 +
17 3 files changed, 225 insertions(+)
18
19 diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
20 index 874d124438d1..bf1238152318 100644
21 --- a/arch/x86/kvm/emulate.c
22 +++ b/arch/x86/kvm/emulate.c
23 @@ -5850,3 +5850,9 @@ bool emulator_can_use_gpa(struct x86_emulate_ctxt *ctxt)
24
25 return true;
26 }
27 +
28 +void __init kvm_emulator_init(void)
29 +{
30 + __check_smram32_offsets();
31 + __check_smram64_offsets();
32 +}
33 diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h
34 index 8dff25d267b7..0eb13204bbc2 100644
35 --- a/arch/x86/kvm/kvm_emulate.h
36 +++ b/arch/x86/kvm/kvm_emulate.h
37 @@ -13,6 +13,7 @@
38 #define _ASM_X86_KVM_X86_EMULATE_H
39
40 #include <asm/desc_defs.h>
41 +#include <linux/build_bug.h>
42 #include "fpu.h"
43
44 struct x86_emulate_ctxt;
45 @@ -481,6 +482,223 @@ enum x86_intercept {
46 nr_x86_intercepts
47 };
48
49 +
50 +/* 32 bit KVM's emulated SMM layout. Loosely based on Intel's layout */
51 +
52 +struct kvm_smm_seg_state_32 {
53 + u32 flags;
54 + u32 limit;
55 + u32 base;
56 +} __packed;
57 +
58 +struct kvm_smram_state_32 {
59 + u32 reserved1[62];
60 + u32 smbase;
61 + u32 smm_revision;
62 + u32 reserved2[5];
63 + u32 cr4; /* CR4 is not present in Intel/AMD SMRAM image */
64 + u32 reserved3[5];
65 +
66 + /*
67 + * Segment state is not present/documented in the Intel/AMD SMRAM image
68 + * Instead this area on Intel/AMD contains IO/HLT restart flags.
69 + */
70 + struct kvm_smm_seg_state_32 ds;
71 + struct kvm_smm_seg_state_32 fs;
72 + struct kvm_smm_seg_state_32 gs;
73 + struct kvm_smm_seg_state_32 idtr; /* IDTR has only base and limit */
74 + struct kvm_smm_seg_state_32 tr;
75 + u32 reserved;
76 + struct kvm_smm_seg_state_32 gdtr; /* GDTR has only base and limit */
77 + struct kvm_smm_seg_state_32 ldtr;
78 + struct kvm_smm_seg_state_32 es;
79 + struct kvm_smm_seg_state_32 cs;
80 + struct kvm_smm_seg_state_32 ss;
81 +
82 + u32 es_sel;
83 + u32 cs_sel;
84 + u32 ss_sel;
85 + u32 ds_sel;
86 + u32 fs_sel;
87 + u32 gs_sel;
88 + u32 ldtr_sel;
89 + u32 tr_sel;
90 +
91 + u32 dr7;
92 + u32 dr6;
93 + u32 gprs[8]; /* GPRS in the "natural" X86 order (EAX/ECX/EDX.../EDI) */
94 + u32 eip;
95 + u32 eflags;
96 + u32 cr3;
97 + u32 cr0;
98 +} __packed;
99 +
100 +
101 +static inline void __check_smram32_offsets(void)
102 +{
103 +#define __CHECK_SMRAM32_OFFSET(field, offset) \
104 + ASSERT_STRUCT_OFFSET(struct kvm_smram_state_32, field, offset - 0xFE00)
105 +
106 + __CHECK_SMRAM32_OFFSET(reserved1, 0xFE00);
107 + __CHECK_SMRAM32_OFFSET(smbase, 0xFEF8);
108 + __CHECK_SMRAM32_OFFSET(smm_revision, 0xFEFC);
109 + __CHECK_SMRAM32_OFFSET(reserved2, 0xFF00);
110 + __CHECK_SMRAM32_OFFSET(cr4, 0xFF14);
111 + __CHECK_SMRAM32_OFFSET(reserved3, 0xFF18);
112 + __CHECK_SMRAM32_OFFSET(ds, 0xFF2C);
113 + __CHECK_SMRAM32_OFFSET(fs, 0xFF38);
114 + __CHECK_SMRAM32_OFFSET(gs, 0xFF44);
115 + __CHECK_SMRAM32_OFFSET(idtr, 0xFF50);
116 + __CHECK_SMRAM32_OFFSET(tr, 0xFF5C);
117 + __CHECK_SMRAM32_OFFSET(gdtr, 0xFF6C);
118 + __CHECK_SMRAM32_OFFSET(ldtr, 0xFF78);
119 + __CHECK_SMRAM32_OFFSET(es, 0xFF84);
120 + __CHECK_SMRAM32_OFFSET(cs, 0xFF90);
121 + __CHECK_SMRAM32_OFFSET(ss, 0xFF9C);
122 + __CHECK_SMRAM32_OFFSET(es_sel, 0xFFA8);
123 + __CHECK_SMRAM32_OFFSET(cs_sel, 0xFFAC);
124 + __CHECK_SMRAM32_OFFSET(ss_sel, 0xFFB0);
125 + __CHECK_SMRAM32_OFFSET(ds_sel, 0xFFB4);
126 + __CHECK_SMRAM32_OFFSET(fs_sel, 0xFFB8);
127 + __CHECK_SMRAM32_OFFSET(gs_sel, 0xFFBC);
128 + __CHECK_SMRAM32_OFFSET(ldtr_sel, 0xFFC0);
129 + __CHECK_SMRAM32_OFFSET(tr_sel, 0xFFC4);
130 + __CHECK_SMRAM32_OFFSET(dr7, 0xFFC8);
131 + __CHECK_SMRAM32_OFFSET(dr6, 0xFFCC);
132 + __CHECK_SMRAM32_OFFSET(gprs, 0xFFD0);
133 + __CHECK_SMRAM32_OFFSET(eip, 0xFFF0);
134 + __CHECK_SMRAM32_OFFSET(eflags, 0xFFF4);
135 + __CHECK_SMRAM32_OFFSET(cr3, 0xFFF8);
136 + __CHECK_SMRAM32_OFFSET(cr0, 0xFFFC);
137 +#undef __CHECK_SMRAM32_OFFSET
138 +}
139 +
140 +
141 +/* 64 bit KVM's emulated SMM layout. Based on AMD64 layout */
142 +
143 +struct kvm_smm_seg_state_64 {
144 + u16 selector;
145 + u16 attributes;
146 + u32 limit;
147 + u64 base;
148 +};
149 +
150 +struct kvm_smram_state_64 {
151 +
152 + struct kvm_smm_seg_state_64 es;
153 + struct kvm_smm_seg_state_64 cs;
154 + struct kvm_smm_seg_state_64 ss;
155 + struct kvm_smm_seg_state_64 ds;
156 + struct kvm_smm_seg_state_64 fs;
157 + struct kvm_smm_seg_state_64 gs;
158 + struct kvm_smm_seg_state_64 gdtr; /* GDTR has only base and limit*/
159 + struct kvm_smm_seg_state_64 ldtr;
160 + struct kvm_smm_seg_state_64 idtr; /* IDTR has only base and limit*/
161 + struct kvm_smm_seg_state_64 tr;
162 +
163 + /* I/O restart and auto halt restart are not implemented by KVM */
164 + u64 io_restart_rip;
165 + u64 io_restart_rcx;
166 + u64 io_restart_rsi;
167 + u64 io_restart_rdi;
168 + u32 io_restart_dword;
169 + u32 reserved1;
170 + u8 io_inst_restart;
171 + u8 auto_hlt_restart;
172 + u8 reserved2[6];
173 +
174 + u64 efer;
175 +
176 + /*
177 + * Two fields below are implemented on AMD only, to store
178 + * SVM guest vmcb address if the #SMI was received while in the guest mode.
179 + */
180 + u64 svm_guest_flag;
181 + u64 svm_guest_vmcb_gpa;
182 + u64 svm_guest_virtual_int; /* unknown purpose, not implemented */
183 +
184 + u32 reserved3[3];
185 + u32 smm_revison;
186 + u32 smbase;
187 + u32 reserved4[5];
188 +
189 + /* ssp and svm_* fields below are not implemented by KVM */
190 + u64 ssp;
191 + u64 svm_guest_pat;
192 + u64 svm_host_efer;
193 + u64 svm_host_cr4;
194 + u64 svm_host_cr3;
195 + u64 svm_host_cr0;
196 +
197 + u64 cr4;
198 + u64 cr3;
199 + u64 cr0;
200 + u64 dr7;
201 + u64 dr6;
202 + u64 rflags;
203 + u64 rip;
204 + u64 gprs[16]; /* GPRS in a reversed "natural" X86 order (R15/R14/../RCX/RAX.) */
205 +};
206 +
207 +
208 +static inline void __check_smram64_offsets(void)
209 +{
210 +#define __CHECK_SMRAM64_OFFSET(field, offset) \
211 + ASSERT_STRUCT_OFFSET(struct kvm_smram_state_64, field, offset - 0xFE00)
212 +
213 + __CHECK_SMRAM64_OFFSET(es, 0xFE00);
214 + __CHECK_SMRAM64_OFFSET(cs, 0xFE10);
215 + __CHECK_SMRAM64_OFFSET(ss, 0xFE20);
216 + __CHECK_SMRAM64_OFFSET(ds, 0xFE30);
217 + __CHECK_SMRAM64_OFFSET(fs, 0xFE40);
218 + __CHECK_SMRAM64_OFFSET(gs, 0xFE50);
219 + __CHECK_SMRAM64_OFFSET(gdtr, 0xFE60);
220 + __CHECK_SMRAM64_OFFSET(ldtr, 0xFE70);
221 + __CHECK_SMRAM64_OFFSET(idtr, 0xFE80);
222 + __CHECK_SMRAM64_OFFSET(tr, 0xFE90);
223 + __CHECK_SMRAM64_OFFSET(io_restart_rip, 0xFEA0);
224 + __CHECK_SMRAM64_OFFSET(io_restart_rcx, 0xFEA8);
225 + __CHECK_SMRAM64_OFFSET(io_restart_rsi, 0xFEB0);
226 + __CHECK_SMRAM64_OFFSET(io_restart_rdi, 0xFEB8);
227 + __CHECK_SMRAM64_OFFSET(io_restart_dword, 0xFEC0);
228 + __CHECK_SMRAM64_OFFSET(reserved1, 0xFEC4);
229 + __CHECK_SMRAM64_OFFSET(io_inst_restart, 0xFEC8);
230 + __CHECK_SMRAM64_OFFSET(auto_hlt_restart, 0xFEC9);
231 + __CHECK_SMRAM64_OFFSET(reserved2, 0xFECA);
232 + __CHECK_SMRAM64_OFFSET(efer, 0xFED0);
233 + __CHECK_SMRAM64_OFFSET(svm_guest_flag, 0xFED8);
234 + __CHECK_SMRAM64_OFFSET(svm_guest_vmcb_gpa, 0xFEE0);
235 + __CHECK_SMRAM64_OFFSET(svm_guest_virtual_int, 0xFEE8);
236 + __CHECK_SMRAM64_OFFSET(reserved3, 0xFEF0);
237 + __CHECK_SMRAM64_OFFSET(smm_revison, 0xFEFC);
238 + __CHECK_SMRAM64_OFFSET(smbase, 0xFF00);
239 + __CHECK_SMRAM64_OFFSET(reserved4, 0xFF04);
240 + __CHECK_SMRAM64_OFFSET(ssp, 0xFF18);
241 + __CHECK_SMRAM64_OFFSET(svm_guest_pat, 0xFF20);
242 + __CHECK_SMRAM64_OFFSET(svm_host_efer, 0xFF28);
243 + __CHECK_SMRAM64_OFFSET(svm_host_cr4, 0xFF30);
244 + __CHECK_SMRAM64_OFFSET(svm_host_cr3, 0xFF38);
245 + __CHECK_SMRAM64_OFFSET(svm_host_cr0, 0xFF40);
246 + __CHECK_SMRAM64_OFFSET(cr4, 0xFF48);
247 + __CHECK_SMRAM64_OFFSET(cr3, 0xFF50);
248 + __CHECK_SMRAM64_OFFSET(cr0, 0xFF58);
249 + __CHECK_SMRAM64_OFFSET(dr7, 0xFF60);
250 + __CHECK_SMRAM64_OFFSET(dr6, 0xFF68);
251 + __CHECK_SMRAM64_OFFSET(rflags, 0xFF70);
252 + __CHECK_SMRAM64_OFFSET(rip, 0xFF78);
253 + __CHECK_SMRAM64_OFFSET(gprs, 0xFF80);
254 +#undef __CHECK_SMRAM64_OFFSET
255 +}
256 +
257 +union kvm_smram {
258 + struct kvm_smram_state_64 smram64;
259 + struct kvm_smram_state_32 smram32;
260 + u8 bytes[512];
261 +};
262 +
263 +void __init kvm_emulator_init(void);
264 +
265 +
266 /* Host execution mode. */
267 #if defined(CONFIG_X86_32)
268 #define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32
269 diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
270 index dbaff0c7c8c2..aec63cebe0b7 100644
271 --- a/arch/x86/kvm/x86.c
272 +++ b/arch/x86/kvm/x86.c
273 @@ -13009,6 +13009,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_vmgexit_msr_protocol_exit);
274 static int __init kvm_x86_init(void)
275 {
276 kvm_mmu_x86_module_init();
277 + kvm_emulator_init();
278 return 0;
279 }
280 module_init(kvm_x86_init);