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