1 /*
2 * x86 SVM helpers (sysemu only)
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "qemu/osdep.h"
21 #include "cpu.h"
22 #include "exec/helper-proto.h"
23 #include "exec/exec-all.h"
24 #include "exec/cpu_ldst.h"
25 #include "tcg/helper-tcg.h"
26
27 /* Secure Virtual Machine helpers */
28
svm_save_seg(CPUX86State * env,hwaddr addr,const SegmentCache * sc)29 static inline void svm_save_seg(CPUX86State *env, hwaddr addr,
30 const SegmentCache *sc)
31 {
32 CPUState *cs = env_cpu(env);
33
34 x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, selector),
35 sc->selector);
36 x86_stq_phys(cs, addr + offsetof(struct vmcb_seg, base),
37 sc->base);
38 x86_stl_phys(cs, addr + offsetof(struct vmcb_seg, limit),
39 sc->limit);
40 x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, attrib),
41 ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
42 }
43
44 /*
45 * VMRUN and VMLOAD canonicalizes (i.e., sign-extend to bit 63) all base
46 * addresses in the segment registers that have been loaded.
47 */
svm_canonicalization(CPUX86State * env,target_ulong * seg_base)48 static inline void svm_canonicalization(CPUX86State *env, target_ulong *seg_base)
49 {
50 uint16_t shift_amt = 64 - cpu_x86_virtual_addr_width(env);
51 *seg_base = ((((long) *seg_base) << shift_amt) >> shift_amt);
52 }
53
svm_load_seg(CPUX86State * env,hwaddr addr,SegmentCache * sc)54 static inline void svm_load_seg(CPUX86State *env, hwaddr addr,
55 SegmentCache *sc)
56 {
57 CPUState *cs = env_cpu(env);
58 unsigned int flags;
59
60 sc->selector = x86_lduw_phys(cs,
61 addr + offsetof(struct vmcb_seg, selector));
62 sc->base = x86_ldq_phys(cs, addr + offsetof(struct vmcb_seg, base));
63 sc->limit = x86_ldl_phys(cs, addr + offsetof(struct vmcb_seg, limit));
64 flags = x86_lduw_phys(cs, addr + offsetof(struct vmcb_seg, attrib));
65 sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
66 svm_canonicalization(env, &sc->base);
67 }
68
svm_load_seg_cache(CPUX86State * env,hwaddr addr,int seg_reg)69 static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr,
70 int seg_reg)
71 {
72 SegmentCache sc1, *sc = &sc1;
73
74 svm_load_seg(env, addr, sc);
75 cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
76 sc->base, sc->limit, sc->flags);
77 }
78
is_efer_invalid_state(CPUX86State * env)79 static inline bool is_efer_invalid_state (CPUX86State *env)
80 {
81 if (!(env->efer & MSR_EFER_SVME)) {
82 return true;
83 }
84
85 if (env->efer & MSR_EFER_RESERVED) {
86 return true;
87 }
88
89 if ((env->efer & (MSR_EFER_LMA | MSR_EFER_LME)) &&
90 !(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
91 return true;
92 }
93
94 if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
95 && !(env->cr[4] & CR4_PAE_MASK)) {
96 return true;
97 }
98
99 if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
100 && !(env->cr[0] & CR0_PE_MASK)) {
101 return true;
102 }
103
104 if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
105 && (env->cr[4] & CR4_PAE_MASK)
106 && (env->segs[R_CS].flags & DESC_L_MASK)
107 && (env->segs[R_CS].flags & DESC_B_MASK)) {
108 return true;
109 }
110
111 return false;
112 }
113
virtual_gif_enabled(CPUX86State * env)114 static inline bool virtual_gif_enabled(CPUX86State *env)
115 {
116 if (likely(env->hflags & HF_GUEST_MASK)) {
117 return (env->features[FEAT_SVM] & CPUID_SVM_VGIF)
118 && (env->int_ctl & V_GIF_ENABLED_MASK);
119 }
120 return false;
121 }
122
virtual_vm_load_save_enabled(CPUX86State * env,uint32_t exit_code,uintptr_t retaddr)123 static inline bool virtual_vm_load_save_enabled(CPUX86State *env, uint32_t exit_code, uintptr_t retaddr)
124 {
125 uint64_t lbr_ctl;
126
127 if (likely(env->hflags & HF_GUEST_MASK)) {
128 if (likely(!(env->hflags2 & HF2_NPT_MASK)) || !(env->efer & MSR_EFER_LMA)) {
129 cpu_vmexit(env, exit_code, 0, retaddr);
130 }
131
132 lbr_ctl = x86_ldl_phys(env_cpu(env), env->vm_vmcb + offsetof(struct vmcb,
133 control.lbr_ctl));
134 return (env->features[FEAT_SVM] & CPUID_SVM_V_VMSAVE_VMLOAD)
135 && (lbr_ctl & V_VMLOAD_VMSAVE_ENABLED_MASK);
136
137 }
138
139 return false;
140 }
141
virtual_gif_set(CPUX86State * env)142 static inline bool virtual_gif_set(CPUX86State *env)
143 {
144 return !virtual_gif_enabled(env) || (env->int_ctl & V_GIF_MASK);
145 }
146
helper_vmrun(CPUX86State * env,int aflag,int next_eip_addend)147 void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
148 {
149 CPUState *cs = env_cpu(env);
150 X86CPU *cpu = env_archcpu(env);
151 target_ulong addr;
152 uint64_t nested_ctl;
153 uint32_t event_inj;
154 uint32_t asid;
155 uint64_t new_cr0;
156 uint64_t new_cr3;
157 uint64_t new_cr4;
158
159 cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC());
160
161 if (aflag == 2) {
162 addr = env->regs[R_EAX];
163 } else {
164 addr = (uint32_t)env->regs[R_EAX];
165 }
166
167 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
168
169 env->vm_vmcb = addr;
170
171 /* save the current CPU state in the hsave page */
172 x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.base),
173 env->gdt.base);
174 x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit),
175 env->gdt.limit);
176
177 x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.base),
178 env->idt.base);
179 x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.limit),
180 env->idt.limit);
181
182 x86_stq_phys(cs,
183 env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
184 x86_stq_phys(cs,
185 env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
186 x86_stq_phys(cs,
187 env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
188 x86_stq_phys(cs,
189 env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
190 x86_stq_phys(cs,
191 env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
192 x86_stq_phys(cs,
193 env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
194
195 x86_stq_phys(cs,
196 env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
197 x86_stq_phys(cs,
198 env->vm_hsave + offsetof(struct vmcb, save.rflags),
199 cpu_compute_eflags(env));
200
201 svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.es),
202 &env->segs[R_ES]);
203 svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
204 &env->segs[R_CS]);
205 svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
206 &env->segs[R_SS]);
207 svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
208 &env->segs[R_DS]);
209
210 x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.rip),
211 env->eip + next_eip_addend);
212 x86_stq_phys(cs,
213 env->vm_hsave + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
214 x86_stq_phys(cs,
215 env->vm_hsave + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
216
217 /* load the interception bitmaps so we do not need to access the
218 vmcb in svm mode */
219 env->intercept = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
220 control.intercept));
221 env->intercept_cr_read = x86_lduw_phys(cs, env->vm_vmcb +
222 offsetof(struct vmcb,
223 control.intercept_cr_read));
224 env->intercept_cr_write = x86_lduw_phys(cs, env->vm_vmcb +
225 offsetof(struct vmcb,
226 control.intercept_cr_write));
227 env->intercept_dr_read = x86_lduw_phys(cs, env->vm_vmcb +
228 offsetof(struct vmcb,
229 control.intercept_dr_read));
230 env->intercept_dr_write = x86_lduw_phys(cs, env->vm_vmcb +
231 offsetof(struct vmcb,
232 control.intercept_dr_write));
233 env->intercept_exceptions = x86_ldl_phys(cs, env->vm_vmcb +
234 offsetof(struct vmcb,
235 control.intercept_exceptions
236 ));
237
238 nested_ctl = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
239 control.nested_ctl));
240 asid = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
241 control.asid));
242
243 uint64_t msrpm_base_pa = x86_ldq_phys(cs, env->vm_vmcb +
244 offsetof(struct vmcb,
245 control.msrpm_base_pa));
246 uint64_t iopm_base_pa = x86_ldq_phys(cs, env->vm_vmcb +
247 offsetof(struct vmcb, control.iopm_base_pa));
248
249 if ((msrpm_base_pa & ~0xfff) >= (1ull << cpu->phys_bits) - SVM_MSRPM_SIZE) {
250 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
251 }
252
253 if ((iopm_base_pa & ~0xfff) >= (1ull << cpu->phys_bits) - SVM_IOPM_SIZE) {
254 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
255 }
256
257 env->nested_pg_mode = 0;
258
259 if (!cpu_svm_has_intercept(env, SVM_EXIT_VMRUN)) {
260 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
261 }
262 if (asid == 0) {
263 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
264 }
265
266 if (nested_ctl & SVM_NPT_ENABLED) {
267 env->nested_cr3 = x86_ldq_phys(cs,
268 env->vm_vmcb + offsetof(struct vmcb,
269 control.nested_cr3));
270 env->hflags2 |= HF2_NPT_MASK;
271
272 env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK;
273 }
274
275 /* enable intercepts */
276 env->hflags |= HF_GUEST_MASK;
277
278 env->tsc_offset = x86_ldq_phys(cs, env->vm_vmcb +
279 offsetof(struct vmcb, control.tsc_offset));
280
281 new_cr0 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr0));
282 if (new_cr0 & SVM_CR0_RESERVED_MASK) {
283 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
284 }
285 if ((new_cr0 & CR0_NW_MASK) && !(new_cr0 & CR0_CD_MASK)) {
286 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
287 }
288 new_cr3 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr3));
289 if ((env->efer & MSR_EFER_LMA) &&
290 (new_cr3 & ((~0ULL) << cpu->phys_bits))) {
291 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
292 }
293 new_cr4 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr4));
294 if (new_cr4 & cr4_reserved_bits(env)) {
295 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
296 }
297 /* clear exit_info_2 so we behave like the real hardware */
298 x86_stq_phys(cs,
299 env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
300
301 cpu_x86_update_cr0(env, new_cr0);
302 cpu_x86_update_cr4(env, new_cr4);
303 cpu_x86_update_cr3(env, new_cr3);
304 env->cr[2] = x86_ldq_phys(cs,
305 env->vm_vmcb + offsetof(struct vmcb, save.cr2));
306 env->int_ctl = x86_ldl_phys(cs,
307 env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
308 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
309 if (env->int_ctl & V_INTR_MASKING_MASK) {
310 env->hflags2 |= HF2_VINTR_MASK;
311 if (env->eflags & IF_MASK) {
312 env->hflags2 |= HF2_HIF_MASK;
313 }
314 }
315
316 cpu_load_efer(env,
317 x86_ldq_phys(cs,
318 env->vm_vmcb + offsetof(struct vmcb, save.efer)));
319 env->eflags = 0;
320 cpu_load_eflags(env, x86_ldq_phys(cs,
321 env->vm_vmcb + offsetof(struct vmcb,
322 save.rflags)),
323 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
324
325 svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
326 R_ES);
327 svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
328 R_CS);
329 svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
330 R_SS);
331 svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
332 R_DS);
333 svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.idtr),
334 &env->idt);
335 svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.gdtr),
336 &env->gdt);
337
338 env->eip = x86_ldq_phys(cs,
339 env->vm_vmcb + offsetof(struct vmcb, save.rip));
340
341 env->regs[R_ESP] = x86_ldq_phys(cs,
342 env->vm_vmcb + offsetof(struct vmcb, save.rsp));
343 env->regs[R_EAX] = x86_ldq_phys(cs,
344 env->vm_vmcb + offsetof(struct vmcb, save.rax));
345 env->dr[7] = x86_ldq_phys(cs,
346 env->vm_vmcb + offsetof(struct vmcb, save.dr7));
347 env->dr[6] = x86_ldq_phys(cs,
348 env->vm_vmcb + offsetof(struct vmcb, save.dr6));
349
350 #ifdef TARGET_X86_64
351 if (env->dr[6] & DR_RESERVED_MASK) {
352 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
353 }
354 if (env->dr[7] & DR_RESERVED_MASK) {
355 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
356 }
357 #endif
358
359 if (is_efer_invalid_state(env)) {
360 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
361 }
362
363 switch (x86_ldub_phys(cs,
364 env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
365 case TLB_CONTROL_DO_NOTHING:
366 break;
367 case TLB_CONTROL_FLUSH_ALL_ASID:
368 /* FIXME: this is not 100% correct but should work for now */
369 tlb_flush(cs);
370 break;
371 }
372
373 env->hflags2 |= HF2_GIF_MASK;
374
375 if (ctl_has_irq(env)) {
376 CPUState *cs = env_cpu(env);
377
378 cs->interrupt_request |= CPU_INTERRUPT_VIRQ;
379 }
380
381 if (virtual_gif_set(env)) {
382 env->hflags2 |= HF2_VGIF_MASK;
383 }
384
385 /* maybe we need to inject an event */
386 event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
387 control.event_inj));
388 if (event_inj & SVM_EVTINJ_VALID) {
389 uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
390 uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
391 uint32_t event_inj_err = x86_ldl_phys(cs, env->vm_vmcb +
392 offsetof(struct vmcb,
393 control.event_inj_err));
394
395 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
396 /* FIXME: need to implement valid_err */
397 switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
398 case SVM_EVTINJ_TYPE_INTR:
399 cs->exception_index = vector;
400 env->error_code = event_inj_err;
401 env->exception_is_int = 0;
402 env->exception_next_eip = -1;
403 qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
404 /* XXX: is it always correct? */
405 do_interrupt_x86_hardirq(env, vector, 1);
406 break;
407 case SVM_EVTINJ_TYPE_NMI:
408 cs->exception_index = EXCP02_NMI;
409 env->error_code = event_inj_err;
410 env->exception_is_int = 0;
411 env->exception_next_eip = env->eip;
412 qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
413 cpu_loop_exit(cs);
414 break;
415 case SVM_EVTINJ_TYPE_EXEPT:
416 if (vector == EXCP02_NMI || vector >= 31) {
417 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
418 }
419 cs->exception_index = vector;
420 env->error_code = event_inj_err;
421 env->exception_is_int = 0;
422 env->exception_next_eip = -1;
423 qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
424 cpu_loop_exit(cs);
425 break;
426 case SVM_EVTINJ_TYPE_SOFT:
427 cs->exception_index = vector;
428 env->error_code = event_inj_err;
429 env->exception_is_int = 1;
430 env->exception_next_eip = env->eip;
431 qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
432 cpu_loop_exit(cs);
433 break;
434 default:
435 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
436 break;
437 }
438 qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", cs->exception_index,
439 env->error_code);
440 }
441 }
442
helper_vmmcall(CPUX86State * env)443 void helper_vmmcall(CPUX86State *env)
444 {
445 cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0, GETPC());
446 raise_exception(env, EXCP06_ILLOP);
447 }
448
helper_vmload(CPUX86State * env,int aflag)449 void helper_vmload(CPUX86State *env, int aflag)
450 {
451 CPUState *cs = env_cpu(env);
452 target_ulong addr;
453 int prot;
454
455 cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC());
456
457 if (aflag == 2) {
458 addr = env->regs[R_EAX];
459 } else {
460 addr = (uint32_t)env->regs[R_EAX];
461 }
462
463 if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) {
464 addr = get_hphys(cs, addr, MMU_DATA_LOAD, &prot);
465 }
466
467 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx
468 "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
469 addr, x86_ldq_phys(cs, addr + offsetof(struct vmcb,
470 save.fs.base)),
471 env->segs[R_FS].base);
472
473 svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.fs), R_FS);
474 svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.gs), R_GS);
475 svm_load_seg(env, addr + offsetof(struct vmcb, save.tr), &env->tr);
476 svm_load_seg(env, addr + offsetof(struct vmcb, save.ldtr), &env->ldt);
477
478 #ifdef TARGET_X86_64
479 env->kernelgsbase = x86_ldq_phys(cs, addr + offsetof(struct vmcb,
480 save.kernel_gs_base));
481 env->lstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.lstar));
482 env->cstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.cstar));
483 env->fmask = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.sfmask));
484 svm_canonicalization(env, &env->kernelgsbase);
485 #endif
486 env->star = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.star));
487 env->sysenter_cs = x86_ldq_phys(cs,
488 addr + offsetof(struct vmcb, save.sysenter_cs));
489 env->sysenter_esp = x86_ldq_phys(cs, addr + offsetof(struct vmcb,
490 save.sysenter_esp));
491 env->sysenter_eip = x86_ldq_phys(cs, addr + offsetof(struct vmcb,
492 save.sysenter_eip));
493
494 }
495
helper_vmsave(CPUX86State * env,int aflag)496 void helper_vmsave(CPUX86State *env, int aflag)
497 {
498 CPUState *cs = env_cpu(env);
499 target_ulong addr;
500 int prot;
501
502 cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC());
503
504 if (aflag == 2) {
505 addr = env->regs[R_EAX];
506 } else {
507 addr = (uint32_t)env->regs[R_EAX];
508 }
509
510 if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) {
511 addr = get_hphys(cs, addr, MMU_DATA_STORE, &prot);
512 }
513
514 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx
515 "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
516 addr, x86_ldq_phys(cs,
517 addr + offsetof(struct vmcb, save.fs.base)),
518 env->segs[R_FS].base);
519
520 svm_save_seg(env, addr + offsetof(struct vmcb, save.fs),
521 &env->segs[R_FS]);
522 svm_save_seg(env, addr + offsetof(struct vmcb, save.gs),
523 &env->segs[R_GS]);
524 svm_save_seg(env, addr + offsetof(struct vmcb, save.tr),
525 &env->tr);
526 svm_save_seg(env, addr + offsetof(struct vmcb, save.ldtr),
527 &env->ldt);
528
529 #ifdef TARGET_X86_64
530 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.kernel_gs_base),
531 env->kernelgsbase);
532 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.lstar), env->lstar);
533 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.cstar), env->cstar);
534 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sfmask), env->fmask);
535 #endif
536 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.star), env->star);
537 x86_stq_phys(cs,
538 addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
539 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_esp),
540 env->sysenter_esp);
541 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_eip),
542 env->sysenter_eip);
543 }
544
helper_stgi(CPUX86State * env)545 void helper_stgi(CPUX86State *env)
546 {
547 cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0, GETPC());
548
549 if (virtual_gif_enabled(env)) {
550 env->int_ctl |= V_GIF_MASK;
551 env->hflags2 |= HF2_VGIF_MASK;
552 } else {
553 env->hflags2 |= HF2_GIF_MASK;
554 }
555 }
556
helper_clgi(CPUX86State * env)557 void helper_clgi(CPUX86State *env)
558 {
559 cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0, GETPC());
560
561 if (virtual_gif_enabled(env)) {
562 env->int_ctl &= ~V_GIF_MASK;
563 env->hflags2 &= ~HF2_VGIF_MASK;
564 } else {
565 env->hflags2 &= ~HF2_GIF_MASK;
566 }
567 }
568
cpu_svm_has_intercept(CPUX86State * env,uint32_t type)569 bool cpu_svm_has_intercept(CPUX86State *env, uint32_t type)
570 {
571 switch (type) {
572 case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
573 if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
574 return true;
575 }
576 break;
577 case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
578 if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
579 return true;
580 }
581 break;
582 case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
583 if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
584 return true;
585 }
586 break;
587 case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
588 if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
589 return true;
590 }
591 break;
592 case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
593 if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
594 return true;
595 }
596 break;
597 default:
598 if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
599 return true;
600 }
601 break;
602 }
603 return false;
604 }
605
cpu_svm_check_intercept_param(CPUX86State * env,uint32_t type,uint64_t param,uintptr_t retaddr)606 void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
607 uint64_t param, uintptr_t retaddr)
608 {
609 CPUState *cs = env_cpu(env);
610
611 if (likely(!(env->hflags & HF_GUEST_MASK))) {
612 return;
613 }
614
615 if (!cpu_svm_has_intercept(env, type)) {
616 return;
617 }
618
619 if (type == SVM_EXIT_MSR) {
620 /* FIXME: this should be read in at vmrun (faster this way?) */
621 uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb +
622 offsetof(struct vmcb,
623 control.msrpm_base_pa));
624 uint32_t t0, t1;
625
626 switch ((uint32_t)env->regs[R_ECX]) {
627 case 0 ... 0x1fff:
628 t0 = (env->regs[R_ECX] * 2) % 8;
629 t1 = (env->regs[R_ECX] * 2) / 8;
630 break;
631 case 0xc0000000 ... 0xc0001fff:
632 t0 = (8192 + env->regs[R_ECX] - 0xc0000000) * 2;
633 t1 = (t0 / 8);
634 t0 %= 8;
635 break;
636 case 0xc0010000 ... 0xc0011fff:
637 t0 = (16384 + env->regs[R_ECX] - 0xc0010000) * 2;
638 t1 = (t0 / 8);
639 t0 %= 8;
640 break;
641 default:
642 cpu_vmexit(env, type, param, retaddr);
643 t0 = 0;
644 t1 = 0;
645 break;
646 }
647 if (x86_ldub_phys(cs, addr + t1) & ((1 << param) << t0)) {
648 cpu_vmexit(env, type, param, retaddr);
649 }
650 return;
651 }
652
653 cpu_vmexit(env, type, param, retaddr);
654 }
655
helper_svm_check_intercept(CPUX86State * env,uint32_t type)656 void helper_svm_check_intercept(CPUX86State *env, uint32_t type)
657 {
658 cpu_svm_check_intercept_param(env, type, 0, GETPC());
659 }
660
helper_svm_check_io(CPUX86State * env,uint32_t port,uint32_t param,uint32_t next_eip_addend)661 void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
662 uint32_t next_eip_addend)
663 {
664 CPUState *cs = env_cpu(env);
665
666 if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
667 /* FIXME: this should be read in at vmrun (faster this way?) */
668 uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb +
669 offsetof(struct vmcb, control.iopm_base_pa));
670 uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
671
672 if (x86_lduw_phys(cs, addr + port / 8) & (mask << (port & 7))) {
673 /* next env->eip */
674 x86_stq_phys(cs,
675 env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
676 env->eip + next_eip_addend);
677 cpu_vmexit(env, SVM_EXIT_IOIO, param | (port << 16), GETPC());
678 }
679 }
680 }
681
cpu_vmexit(CPUX86State * env,uint32_t exit_code,uint64_t exit_info_1,uintptr_t retaddr)682 void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1,
683 uintptr_t retaddr)
684 {
685 CPUState *cs = env_cpu(env);
686
687 cpu_restore_state(cs, retaddr, true);
688
689 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016"
690 PRIx64 ", " TARGET_FMT_lx ")!\n",
691 exit_code, exit_info_1,
692 x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
693 control.exit_info_2)),
694 env->eip);
695
696 cs->exception_index = EXCP_VMEXIT;
697 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_code),
698 exit_code);
699
700 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
701 control.exit_info_1), exit_info_1),
702
703 /* remove any pending exception */
704 env->old_exception = -1;
705 cpu_loop_exit(cs);
706 }
707
do_vmexit(CPUX86State * env)708 void do_vmexit(CPUX86State *env)
709 {
710 CPUState *cs = env_cpu(env);
711
712 if (env->hflags & HF_INHIBIT_IRQ_MASK) {
713 x86_stl_phys(cs,
714 env->vm_vmcb + offsetof(struct vmcb, control.int_state),
715 SVM_INTERRUPT_SHADOW_MASK);
716 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
717 } else {
718 x86_stl_phys(cs,
719 env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
720 }
721 env->hflags2 &= ~HF2_NPT_MASK;
722
723 /* Save the VM state in the vmcb */
724 svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
725 &env->segs[R_ES]);
726 svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
727 &env->segs[R_CS]);
728 svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
729 &env->segs[R_SS]);
730 svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
731 &env->segs[R_DS]);
732
733 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base),
734 env->gdt.base);
735 x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit),
736 env->gdt.limit);
737
738 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.base),
739 env->idt.base);
740 x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit),
741 env->idt.limit);
742
743 x86_stq_phys(cs,
744 env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
745 x86_stq_phys(cs,
746 env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
747 x86_stq_phys(cs,
748 env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
749 x86_stq_phys(cs,
750 env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
751 x86_stq_phys(cs,
752 env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
753 x86_stl_phys(cs,
754 env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), env->int_ctl);
755
756 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rflags),
757 cpu_compute_eflags(env));
758 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rip),
759 env->eip);
760 x86_stq_phys(cs,
761 env->vm_vmcb + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
762 x86_stq_phys(cs,
763 env->vm_vmcb + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
764 x86_stq_phys(cs,
765 env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
766 x86_stq_phys(cs,
767 env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
768 x86_stb_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cpl),
769 env->hflags & HF_CPL_MASK);
770
771 /* Reload the host state from vm_hsave */
772 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
773 env->hflags &= ~HF_GUEST_MASK;
774 env->intercept = 0;
775 env->intercept_exceptions = 0;
776 cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
777 env->int_ctl = 0;
778 env->tsc_offset = 0;
779
780 env->gdt.base = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
781 save.gdtr.base));
782 env->gdt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb,
783 save.gdtr.limit));
784
785 env->idt.base = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
786 save.idtr.base));
787 env->idt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb,
788 save.idtr.limit));
789
790 cpu_x86_update_cr0(env, x86_ldq_phys(cs,
791 env->vm_hsave + offsetof(struct vmcb,
792 save.cr0)) |
793 CR0_PE_MASK);
794 cpu_x86_update_cr4(env, x86_ldq_phys(cs,
795 env->vm_hsave + offsetof(struct vmcb,
796 save.cr4)));
797 cpu_x86_update_cr3(env, x86_ldq_phys(cs,
798 env->vm_hsave + offsetof(struct vmcb,
799 save.cr3)));
800 /* we need to set the efer after the crs so the hidden flags get
801 set properly */
802 cpu_load_efer(env, x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
803 save.efer)));
804 env->eflags = 0;
805 cpu_load_eflags(env, x86_ldq_phys(cs,
806 env->vm_hsave + offsetof(struct vmcb,
807 save.rflags)),
808 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK |
809 VM_MASK));
810
811 svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.es),
812 R_ES);
813 svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
814 R_CS);
815 svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
816 R_SS);
817 svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
818 R_DS);
819
820 env->eip = x86_ldq_phys(cs,
821 env->vm_hsave + offsetof(struct vmcb, save.rip));
822 env->regs[R_ESP] = x86_ldq_phys(cs, env->vm_hsave +
823 offsetof(struct vmcb, save.rsp));
824 env->regs[R_EAX] = x86_ldq_phys(cs, env->vm_hsave +
825 offsetof(struct vmcb, save.rax));
826
827 env->dr[6] = x86_ldq_phys(cs,
828 env->vm_hsave + offsetof(struct vmcb, save.dr6));
829 env->dr[7] = x86_ldq_phys(cs,
830 env->vm_hsave + offsetof(struct vmcb, save.dr7));
831
832 /* other setups */
833 x86_stl_phys(cs,
834 env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
835 x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
836 control.event_inj)));
837 x86_stl_phys(cs,
838 env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
839 x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
840 control.event_inj_err)));
841 x86_stl_phys(cs,
842 env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
843
844 env->hflags2 &= ~HF2_GIF_MASK;
845 env->hflags2 &= ~HF2_VGIF_MASK;
846 /* FIXME: Resets the current ASID register to zero (host ASID). */
847
848 /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
849
850 /* Clears the TSC_OFFSET inside the processor. */
851
852 /* If the host is in PAE mode, the processor reloads the host's PDPEs
853 from the page table indicated the host's CR3. If the PDPEs contain
854 illegal state, the processor causes a shutdown. */
855
856 /* Disables all breakpoints in the host DR7 register. */
857
858 /* Checks the reloaded host state for consistency. */
859
860 /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
861 host's code segment or non-canonical (in the case of long mode), a
862 #GP fault is delivered inside the host. */
863 }
864