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