]>
Commit | Line | Data |
---|---|---|
f6df304f TL |
1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
2 | From: Maxim Levitsky <mlevitsk@redhat.com> | |
83250735 | 3 | Date: Wed, 3 Aug 2022 18:50:05 +0300 |
f6df304f TL |
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 | --- | |
83250735 TL |
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(+) | |
f6df304f | 18 | |
83250735 | 19 | diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c |
16f4d03e | 20 | index c19e782ecc54..48173cb63f7a 100644 |
83250735 TL |
21 | --- a/arch/x86/kvm/emulate.c |
22 | +++ b/arch/x86/kvm/emulate.c | |
16f4d03e | 23 | @@ -5856,3 +5856,9 @@ bool emulator_can_use_gpa(struct x86_emulate_ctxt *ctxt) |
83250735 TL |
24 | |
25 | return true; | |
26 | } | |
27 | + | |
28 | +void __init kvm_emulator_init(void) | |
29 | +{ | |
30 | + __check_smram32_offsets(); | |
31 | + __check_smram64_offsets(); | |
32 | +} | |
f6df304f | 33 | diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h |
3ae8384f | 34 | index 8dff25d267b7..0eb13204bbc2 100644 |
f6df304f TL |
35 | --- a/arch/x86/kvm/kvm_emulate.h |
36 | +++ b/arch/x86/kvm/kvm_emulate.h | |
83250735 TL |
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; | |
3ae8384f | 45 | @@ -481,6 +482,223 @@ enum x86_intercept { |
f6df304f TL |
46 | nr_x86_intercepts |
47 | }; | |
48 | ||
49 | + | |
83250735 | 50 | +/* 32 bit KVM's emulated SMM layout. Loosely based on Intel's layout */ |
f6df304f TL |
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 { | |
83250735 TL |
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]; | |
f6df304f TL |
65 | + |
66 | + /* | |
83250735 TL |
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. | |
f6df304f | 69 | + */ |
83250735 TL |
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; | |
f6df304f TL |
98 | +} __packed; |
99 | + | |
83250735 TL |
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 */ | |
f6df304f TL |
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 { | |
f6df304f | 151 | + |
83250735 TL |
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; | |
f6df304f TL |
162 | + |
163 | + /* I/O restart and auto halt restart are not implemented by KVM */ | |
83250735 TL |
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; | |
f6df304f TL |
175 | + |
176 | + /* | |
83250735 TL |
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. | |
f6df304f | 179 | + */ |
83250735 TL |
180 | + u64 svm_guest_flag; |
181 | + u64 svm_guest_vmcb_gpa; | |
182 | + u64 svm_guest_virtual_int; /* unknown purpose, not implemented */ | |
f6df304f | 183 | + |
83250735 TL |
184 | + u32 reserved3[3]; |
185 | + u32 smm_revison; | |
186 | + u32 smbase; | |
187 | + u32 reserved4[5]; | |
f6df304f | 188 | + |
83250735 TL |
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; | |
f6df304f | 196 | + |
83250735 TL |
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 | +}; | |
f6df304f | 206 | + |
f6df304f | 207 | + |
83250735 TL |
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) | |
f6df304f | 212 | + |
83250735 TL |
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 | +} | |
f6df304f | 256 | + |
83250735 TL |
257 | +union kvm_smram { |
258 | + struct kvm_smram_state_64 smram64; | |
259 | + struct kvm_smram_state_32 smram32; | |
260 | + u8 bytes[512]; | |
f6df304f TL |
261 | +}; |
262 | + | |
83250735 TL |
263 | +void __init kvm_emulator_init(void); |
264 | + | |
f6df304f TL |
265 | + |
266 | /* Host execution mode. */ | |
267 | #if defined(CONFIG_X86_32) | |
268 | #define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32 | |
83250735 | 269 | diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c |
16f4d03e | 270 | index b3e72a86184e..8e6e85720242 100644 |
83250735 TL |
271 | --- a/arch/x86/kvm/x86.c |
272 | +++ b/arch/x86/kvm/x86.c | |
16f4d03e | 273 | @@ -13273,6 +13273,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_vmgexit_msr_protocol_exit); |
83250735 TL |
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); |