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