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