blob: ab472f6eea354fb6ab74fe118c1aa48adf13e075 [file] [log] [blame]
Blue Swirl6bada5e2012-04-29 14:42:35 +00001/*
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
Peter Maydellb6a0aa02016-01-26 18:17:03 +000020#include "qemu/osdep.h"
Blue Swirl6bada5e2012-04-29 14:42:35 +000021#include "cpu.h"
Paolo Bonzini022c62c2012-12-17 18:19:49 +010022#include "exec/cpu-all.h"
Richard Henderson2ef61752014-04-07 22:31:41 -070023#include "exec/helper-proto.h"
Paolo Bonzinif08b6172014-03-28 19:42:10 +010024#include "exec/cpu_ldst.h"
Blue Swirl92fc4b52012-04-29 20:35:48 +000025
Blue Swirl6bada5e2012-04-29 14:42:35 +000026/* Secure Virtual Machine helpers */
27
28#if defined(CONFIG_USER_ONLY)
29
Blue Swirl052e80d2012-04-29 15:51:49 +000030void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
Blue Swirl6bada5e2012-04-29 14:42:35 +000031{
32}
33
Blue Swirl052e80d2012-04-29 15:51:49 +000034void helper_vmmcall(CPUX86State *env)
Blue Swirl6bada5e2012-04-29 14:42:35 +000035{
36}
37
Blue Swirl052e80d2012-04-29 15:51:49 +000038void helper_vmload(CPUX86State *env, int aflag)
Blue Swirl6bada5e2012-04-29 14:42:35 +000039{
40}
41
Blue Swirl052e80d2012-04-29 15:51:49 +000042void helper_vmsave(CPUX86State *env, int aflag)
Blue Swirl6bada5e2012-04-29 14:42:35 +000043{
44}
45
Blue Swirl052e80d2012-04-29 15:51:49 +000046void helper_stgi(CPUX86State *env)
Blue Swirl6bada5e2012-04-29 14:42:35 +000047{
48}
49
Blue Swirl052e80d2012-04-29 15:51:49 +000050void helper_clgi(CPUX86State *env)
Blue Swirl6bada5e2012-04-29 14:42:35 +000051{
52}
53
Blue Swirl052e80d2012-04-29 15:51:49 +000054void helper_skinit(CPUX86State *env)
Blue Swirl6bada5e2012-04-29 14:42:35 +000055{
56}
57
Blue Swirl052e80d2012-04-29 15:51:49 +000058void helper_invlpga(CPUX86State *env, int aflag)
Blue Swirl6bada5e2012-04-29 14:42:35 +000059{
60}
61
Blue Swirl052e80d2012-04-29 15:51:49 +000062void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
Blue Swirl6bada5e2012-04-29 14:42:35 +000063{
64}
65
66void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1)
67{
68}
69
Blue Swirl052e80d2012-04-29 15:51:49 +000070void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
71 uint64_t param)
Blue Swirl6bada5e2012-04-29 14:42:35 +000072{
73}
74
75void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
76 uint64_t param)
77{
78}
79
Blue Swirl052e80d2012-04-29 15:51:49 +000080void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
Blue Swirl6bada5e2012-04-29 14:42:35 +000081 uint32_t next_eip_addend)
82{
83}
84#else
85
Avi Kivitya8170e52012-10-23 12:30:10 +020086static inline void svm_save_seg(CPUX86State *env, hwaddr addr,
Blue Swirl6bada5e2012-04-29 14:42:35 +000087 const SegmentCache *sc)
88{
Andreas Färber19d6ca12014-03-09 19:15:27 +010089 CPUState *cs = CPU(x86_env_get_cpu(env));
90
Paolo Bonzinib216aa62015-04-08 13:39:37 +020091 x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, selector),
Blue Swirl6bada5e2012-04-29 14:42:35 +000092 sc->selector);
Paolo Bonzinib216aa62015-04-08 13:39:37 +020093 x86_stq_phys(cs, addr + offsetof(struct vmcb_seg, base),
Blue Swirl6bada5e2012-04-29 14:42:35 +000094 sc->base);
Paolo Bonzinib216aa62015-04-08 13:39:37 +020095 x86_stl_phys(cs, addr + offsetof(struct vmcb_seg, limit),
Blue Swirl6bada5e2012-04-29 14:42:35 +000096 sc->limit);
Paolo Bonzinib216aa62015-04-08 13:39:37 +020097 x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, attrib),
Blue Swirl6bada5e2012-04-29 14:42:35 +000098 ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
99}
100
Avi Kivitya8170e52012-10-23 12:30:10 +0200101static inline void svm_load_seg(CPUX86State *env, hwaddr addr,
Blue Swirl052e80d2012-04-29 15:51:49 +0000102 SegmentCache *sc)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000103{
Andreas Färber19d6ca12014-03-09 19:15:27 +0100104 CPUState *cs = CPU(x86_env_get_cpu(env));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000105 unsigned int flags;
106
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200107 sc->selector = x86_lduw_phys(cs,
Edgar E. Iglesias41701aa2013-12-17 14:33:56 +1000108 addr + offsetof(struct vmcb_seg, selector));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200109 sc->base = x86_ldq_phys(cs, addr + offsetof(struct vmcb_seg, base));
110 sc->limit = x86_ldl_phys(cs, addr + offsetof(struct vmcb_seg, limit));
111 flags = x86_lduw_phys(cs, addr + offsetof(struct vmcb_seg, attrib));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000112 sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
113}
114
Avi Kivitya8170e52012-10-23 12:30:10 +0200115static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr,
Blue Swirl052e80d2012-04-29 15:51:49 +0000116 int seg_reg)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000117{
118 SegmentCache sc1, *sc = &sc1;
119
Blue Swirl052e80d2012-04-29 15:51:49 +0000120 svm_load_seg(env, addr, sc);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000121 cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
122 sc->base, sc->limit, sc->flags);
123}
124
Blue Swirl052e80d2012-04-29 15:51:49 +0000125void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000126{
Andreas Färber19d6ca12014-03-09 19:15:27 +0100127 CPUState *cs = CPU(x86_env_get_cpu(env));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000128 target_ulong addr;
129 uint32_t event_inj;
130 uint32_t int_ctl;
131
Blue Swirl052e80d2012-04-29 15:51:49 +0000132 cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000133
134 if (aflag == 2) {
liguang4b34e3a2013-05-28 16:20:59 +0800135 addr = env->regs[R_EAX];
Blue Swirl6bada5e2012-04-29 14:42:35 +0000136 } else {
liguang4b34e3a2013-05-28 16:20:59 +0800137 addr = (uint32_t)env->regs[R_EAX];
Blue Swirl6bada5e2012-04-29 14:42:35 +0000138 }
139
140 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
141
142 env->vm_vmcb = addr;
143
144 /* save the current CPU state in the hsave page */
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200145 x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.base),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000146 env->gdt.base);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200147 x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000148 env->gdt.limit);
149
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200150 x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.base),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000151 env->idt.base);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200152 x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.limit),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000153 env->idt.limit);
154
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200155 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100156 env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200157 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100158 env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200159 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100160 env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200161 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100162 env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200163 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100164 env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200165 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100166 env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000167
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200168 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100169 env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200170 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100171 env->vm_hsave + offsetof(struct vmcb, save.rflags),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000172 cpu_compute_eflags(env));
173
Blue Swirl052e80d2012-04-29 15:51:49 +0000174 svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.es),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000175 &env->segs[R_ES]);
Blue Swirl052e80d2012-04-29 15:51:49 +0000176 svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000177 &env->segs[R_CS]);
Blue Swirl052e80d2012-04-29 15:51:49 +0000178 svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000179 &env->segs[R_SS]);
Blue Swirl052e80d2012-04-29 15:51:49 +0000180 svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000181 &env->segs[R_DS]);
182
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200183 x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.rip),
liguanga78d0ea2013-05-28 16:21:07 +0800184 env->eip + next_eip_addend);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200185 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100186 env->vm_hsave + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200187 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100188 env->vm_hsave + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000189
190 /* load the interception bitmaps so we do not need to access the
191 vmcb in svm mode */
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200192 env->intercept = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000193 control.intercept));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200194 env->intercept_cr_read = x86_lduw_phys(cs, env->vm_vmcb +
Blue Swirl6bada5e2012-04-29 14:42:35 +0000195 offsetof(struct vmcb,
196 control.intercept_cr_read));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200197 env->intercept_cr_write = x86_lduw_phys(cs, env->vm_vmcb +
Blue Swirl6bada5e2012-04-29 14:42:35 +0000198 offsetof(struct vmcb,
199 control.intercept_cr_write));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200200 env->intercept_dr_read = x86_lduw_phys(cs, env->vm_vmcb +
Blue Swirl6bada5e2012-04-29 14:42:35 +0000201 offsetof(struct vmcb,
202 control.intercept_dr_read));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200203 env->intercept_dr_write = x86_lduw_phys(cs, env->vm_vmcb +
Blue Swirl6bada5e2012-04-29 14:42:35 +0000204 offsetof(struct vmcb,
205 control.intercept_dr_write));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200206 env->intercept_exceptions = x86_ldl_phys(cs, env->vm_vmcb +
Blue Swirl6bada5e2012-04-29 14:42:35 +0000207 offsetof(struct vmcb,
208 control.intercept_exceptions
209 ));
210
211 /* enable intercepts */
212 env->hflags |= HF_SVMI_MASK;
213
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200214 env->tsc_offset = x86_ldq_phys(cs, env->vm_vmcb +
Blue Swirl6bada5e2012-04-29 14:42:35 +0000215 offsetof(struct vmcb, control.tsc_offset));
216
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200217 env->gdt.base = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000218 save.gdtr.base));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200219 env->gdt.limit = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000220 save.gdtr.limit));
221
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200222 env->idt.base = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000223 save.idtr.base));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200224 env->idt.limit = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000225 save.idtr.limit));
226
227 /* clear exit_info_2 so we behave like the real hardware */
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200228 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100229 env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000230
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200231 cpu_x86_update_cr0(env, x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000232 env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000233 save.cr0)));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200234 cpu_x86_update_cr4(env, x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000235 env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000236 save.cr4)));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200237 cpu_x86_update_cr3(env, x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000238 env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000239 save.cr3)));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200240 env->cr[2] = x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000241 env->vm_vmcb + offsetof(struct vmcb, save.cr2));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200242 int_ctl = x86_ldl_phys(cs,
Edgar E. Iglesiasfdfba1a2013-11-15 14:46:38 +0100243 env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000244 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
245 if (int_ctl & V_INTR_MASKING_MASK) {
246 env->v_tpr = int_ctl & V_TPR_MASK;
247 env->hflags2 |= HF2_VINTR_MASK;
248 if (env->eflags & IF_MASK) {
249 env->hflags2 |= HF2_HIF_MASK;
250 }
251 }
252
253 cpu_load_efer(env,
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200254 x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000255 env->vm_vmcb + offsetof(struct vmcb, save.efer)));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000256 env->eflags = 0;
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200257 cpu_load_eflags(env, x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000258 env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000259 save.rflags)),
260 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000261
Blue Swirl052e80d2012-04-29 15:51:49 +0000262 svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
263 R_ES);
264 svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
265 R_CS);
266 svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
267 R_SS);
268 svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
269 R_DS);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000270
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200271 env->eip = x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000272 env->vm_vmcb + offsetof(struct vmcb, save.rip));
liguang0bc60a82013-05-28 16:21:09 +0800273
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200274 env->regs[R_ESP] = x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000275 env->vm_vmcb + offsetof(struct vmcb, save.rsp));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200276 env->regs[R_EAX] = x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000277 env->vm_vmcb + offsetof(struct vmcb, save.rax));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200278 env->dr[7] = x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000279 env->vm_vmcb + offsetof(struct vmcb, save.dr7));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200280 env->dr[6] = x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000281 env->vm_vmcb + offsetof(struct vmcb, save.dr6));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000282
283 /* FIXME: guest state consistency checks */
284
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200285 switch (x86_ldub_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000286 env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
Blue Swirl6bada5e2012-04-29 14:42:35 +0000287 case TLB_CONTROL_DO_NOTHING:
288 break;
289 case TLB_CONTROL_FLUSH_ALL_ASID:
290 /* FIXME: this is not 100% correct but should work for now */
Andreas Färber00c8cb02013-09-04 02:19:44 +0200291 tlb_flush(cs, 1);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000292 break;
293 }
294
295 env->hflags2 |= HF2_GIF_MASK;
296
297 if (int_ctl & V_IRQ_MASK) {
Andreas Färber259186a2013-01-17 18:51:17 +0100298 CPUState *cs = CPU(x86_env_get_cpu(env));
299
300 cs->interrupt_request |= CPU_INTERRUPT_VIRQ;
Blue Swirl6bada5e2012-04-29 14:42:35 +0000301 }
302
303 /* maybe we need to inject an event */
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200304 event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000305 control.event_inj));
306 if (event_inj & SVM_EVTINJ_VALID) {
307 uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
308 uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200309 uint32_t event_inj_err = x86_ldl_phys(cs, env->vm_vmcb +
Blue Swirl6bada5e2012-04-29 14:42:35 +0000310 offsetof(struct vmcb,
311 control.event_inj_err));
312
313 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
314 /* FIXME: need to implement valid_err */
315 switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
316 case SVM_EVTINJ_TYPE_INTR:
Andreas Färber27103422013-08-26 08:31:06 +0200317 cs->exception_index = vector;
Blue Swirl6bada5e2012-04-29 14:42:35 +0000318 env->error_code = event_inj_err;
319 env->exception_is_int = 0;
320 env->exception_next_eip = -1;
321 qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
322 /* XXX: is it always correct? */
323 do_interrupt_x86_hardirq(env, vector, 1);
324 break;
325 case SVM_EVTINJ_TYPE_NMI:
Andreas Färber27103422013-08-26 08:31:06 +0200326 cs->exception_index = EXCP02_NMI;
Blue Swirl6bada5e2012-04-29 14:42:35 +0000327 env->error_code = event_inj_err;
328 env->exception_is_int = 0;
liguanga78d0ea2013-05-28 16:21:07 +0800329 env->exception_next_eip = env->eip;
Blue Swirl6bada5e2012-04-29 14:42:35 +0000330 qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
Andreas Färber5638d182013-08-27 17:52:12 +0200331 cpu_loop_exit(cs);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000332 break;
333 case SVM_EVTINJ_TYPE_EXEPT:
Andreas Färber27103422013-08-26 08:31:06 +0200334 cs->exception_index = vector;
Blue Swirl6bada5e2012-04-29 14:42:35 +0000335 env->error_code = event_inj_err;
336 env->exception_is_int = 0;
337 env->exception_next_eip = -1;
338 qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
Andreas Färber5638d182013-08-27 17:52:12 +0200339 cpu_loop_exit(cs);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000340 break;
341 case SVM_EVTINJ_TYPE_SOFT:
Andreas Färber27103422013-08-26 08:31:06 +0200342 cs->exception_index = vector;
Blue Swirl6bada5e2012-04-29 14:42:35 +0000343 env->error_code = event_inj_err;
344 env->exception_is_int = 1;
liguanga78d0ea2013-05-28 16:21:07 +0800345 env->exception_next_eip = env->eip;
Blue Swirl6bada5e2012-04-29 14:42:35 +0000346 qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
Andreas Färber5638d182013-08-27 17:52:12 +0200347 cpu_loop_exit(cs);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000348 break;
349 }
Andreas Färber27103422013-08-26 08:31:06 +0200350 qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", cs->exception_index,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000351 env->error_code);
352 }
353}
354
Blue Swirl052e80d2012-04-29 15:51:49 +0000355void helper_vmmcall(CPUX86State *env)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000356{
Blue Swirl052e80d2012-04-29 15:51:49 +0000357 cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000358 raise_exception(env, EXCP06_ILLOP);
359}
360
Blue Swirl052e80d2012-04-29 15:51:49 +0000361void helper_vmload(CPUX86State *env, int aflag)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000362{
Andreas Färber19d6ca12014-03-09 19:15:27 +0100363 CPUState *cs = CPU(x86_env_get_cpu(env));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000364 target_ulong addr;
365
Blue Swirl052e80d2012-04-29 15:51:49 +0000366 cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000367
368 if (aflag == 2) {
liguang4b34e3a2013-05-28 16:20:59 +0800369 addr = env->regs[R_EAX];
Blue Swirl6bada5e2012-04-29 14:42:35 +0000370 } else {
liguang4b34e3a2013-05-28 16:20:59 +0800371 addr = (uint32_t)env->regs[R_EAX];
Blue Swirl6bada5e2012-04-29 14:42:35 +0000372 }
373
374 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx
375 "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200376 addr, x86_ldq_phys(cs, addr + offsetof(struct vmcb,
Blue Swirl052e80d2012-04-29 15:51:49 +0000377 save.fs.base)),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000378 env->segs[R_FS].base);
379
Blue Swirl052e80d2012-04-29 15:51:49 +0000380 svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.fs), R_FS);
381 svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.gs), R_GS);
382 svm_load_seg(env, addr + offsetof(struct vmcb, save.tr), &env->tr);
383 svm_load_seg(env, addr + offsetof(struct vmcb, save.ldtr), &env->ldt);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000384
385#ifdef TARGET_X86_64
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200386 env->kernelgsbase = x86_ldq_phys(cs, addr + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000387 save.kernel_gs_base));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200388 env->lstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.lstar));
389 env->cstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.cstar));
390 env->fmask = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.sfmask));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000391#endif
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200392 env->star = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.star));
393 env->sysenter_cs = x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000394 addr + offsetof(struct vmcb, save.sysenter_cs));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200395 env->sysenter_esp = x86_ldq_phys(cs, addr + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000396 save.sysenter_esp));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200397 env->sysenter_eip = x86_ldq_phys(cs, addr + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000398 save.sysenter_eip));
399}
400
Blue Swirl052e80d2012-04-29 15:51:49 +0000401void helper_vmsave(CPUX86State *env, int aflag)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000402{
Andreas Färber19d6ca12014-03-09 19:15:27 +0100403 CPUState *cs = CPU(x86_env_get_cpu(env));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000404 target_ulong addr;
405
Blue Swirl052e80d2012-04-29 15:51:49 +0000406 cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000407
408 if (aflag == 2) {
liguang4b34e3a2013-05-28 16:20:59 +0800409 addr = env->regs[R_EAX];
Blue Swirl6bada5e2012-04-29 14:42:35 +0000410 } else {
liguang4b34e3a2013-05-28 16:20:59 +0800411 addr = (uint32_t)env->regs[R_EAX];
Blue Swirl6bada5e2012-04-29 14:42:35 +0000412 }
413
414 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx
415 "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200416 addr, x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000417 addr + offsetof(struct vmcb, save.fs.base)),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000418 env->segs[R_FS].base);
419
Blue Swirl052e80d2012-04-29 15:51:49 +0000420 svm_save_seg(env, addr + offsetof(struct vmcb, save.fs),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000421 &env->segs[R_FS]);
Blue Swirl052e80d2012-04-29 15:51:49 +0000422 svm_save_seg(env, addr + offsetof(struct vmcb, save.gs),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000423 &env->segs[R_GS]);
Blue Swirl052e80d2012-04-29 15:51:49 +0000424 svm_save_seg(env, addr + offsetof(struct vmcb, save.tr),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000425 &env->tr);
Blue Swirl052e80d2012-04-29 15:51:49 +0000426 svm_save_seg(env, addr + offsetof(struct vmcb, save.ldtr),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000427 &env->ldt);
428
429#ifdef TARGET_X86_64
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200430 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.kernel_gs_base),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000431 env->kernelgsbase);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200432 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.lstar), env->lstar);
433 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.cstar), env->cstar);
434 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sfmask), env->fmask);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000435#endif
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200436 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.star), env->star);
437 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100438 addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200439 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_esp),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000440 env->sysenter_esp);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200441 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_eip),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000442 env->sysenter_eip);
443}
444
Blue Swirl052e80d2012-04-29 15:51:49 +0000445void helper_stgi(CPUX86State *env)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000446{
Blue Swirl052e80d2012-04-29 15:51:49 +0000447 cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000448 env->hflags2 |= HF2_GIF_MASK;
449}
450
Blue Swirl052e80d2012-04-29 15:51:49 +0000451void helper_clgi(CPUX86State *env)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000452{
Blue Swirl052e80d2012-04-29 15:51:49 +0000453 cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000454 env->hflags2 &= ~HF2_GIF_MASK;
455}
456
Blue Swirl052e80d2012-04-29 15:51:49 +0000457void helper_skinit(CPUX86State *env)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000458{
Blue Swirl052e80d2012-04-29 15:51:49 +0000459 cpu_svm_check_intercept_param(env, SVM_EXIT_SKINIT, 0);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000460 /* XXX: not implemented */
461 raise_exception(env, EXCP06_ILLOP);
462}
463
Blue Swirl052e80d2012-04-29 15:51:49 +0000464void helper_invlpga(CPUX86State *env, int aflag)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000465{
Andreas Färber31b030d2013-09-04 01:29:02 +0200466 X86CPU *cpu = x86_env_get_cpu(env);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000467 target_ulong addr;
468
Blue Swirl052e80d2012-04-29 15:51:49 +0000469 cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000470
471 if (aflag == 2) {
liguang4b34e3a2013-05-28 16:20:59 +0800472 addr = env->regs[R_EAX];
Blue Swirl6bada5e2012-04-29 14:42:35 +0000473 } else {
liguang4b34e3a2013-05-28 16:20:59 +0800474 addr = (uint32_t)env->regs[R_EAX];
Blue Swirl6bada5e2012-04-29 14:42:35 +0000475 }
476
477 /* XXX: could use the ASID to see if it is needed to do the
478 flush */
Andreas Färber31b030d2013-09-04 01:29:02 +0200479 tlb_flush_page(CPU(cpu), addr);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000480}
481
Blue Swirl052e80d2012-04-29 15:51:49 +0000482void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
483 uint64_t param)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000484{
Andreas Färber19d6ca12014-03-09 19:15:27 +0100485 CPUState *cs = CPU(x86_env_get_cpu(env));
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000486
Blue Swirl6bada5e2012-04-29 14:42:35 +0000487 if (likely(!(env->hflags & HF_SVMI_MASK))) {
488 return;
489 }
490 switch (type) {
491 case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
492 if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
Blue Swirl052e80d2012-04-29 15:51:49 +0000493 helper_vmexit(env, type, param);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000494 }
495 break;
496 case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
497 if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
Blue Swirl052e80d2012-04-29 15:51:49 +0000498 helper_vmexit(env, type, param);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000499 }
500 break;
501 case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
502 if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
Blue Swirl052e80d2012-04-29 15:51:49 +0000503 helper_vmexit(env, type, param);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000504 }
505 break;
506 case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
507 if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
Blue Swirl052e80d2012-04-29 15:51:49 +0000508 helper_vmexit(env, type, param);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000509 }
510 break;
511 case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
512 if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
Blue Swirl052e80d2012-04-29 15:51:49 +0000513 helper_vmexit(env, type, param);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000514 }
515 break;
516 case SVM_EXIT_MSR:
517 if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) {
518 /* FIXME: this should be read in at vmrun (faster this way?) */
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200519 uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb +
Blue Swirl6bada5e2012-04-29 14:42:35 +0000520 offsetof(struct vmcb,
521 control.msrpm_base_pa));
522 uint32_t t0, t1;
523
liguanga4165612013-05-28 16:21:01 +0800524 switch ((uint32_t)env->regs[R_ECX]) {
Blue Swirl6bada5e2012-04-29 14:42:35 +0000525 case 0 ... 0x1fff:
liguanga4165612013-05-28 16:21:01 +0800526 t0 = (env->regs[R_ECX] * 2) % 8;
527 t1 = (env->regs[R_ECX] * 2) / 8;
Blue Swirl6bada5e2012-04-29 14:42:35 +0000528 break;
529 case 0xc0000000 ... 0xc0001fff:
liguanga4165612013-05-28 16:21:01 +0800530 t0 = (8192 + env->regs[R_ECX] - 0xc0000000) * 2;
Blue Swirl6bada5e2012-04-29 14:42:35 +0000531 t1 = (t0 / 8);
532 t0 %= 8;
533 break;
534 case 0xc0010000 ... 0xc0011fff:
liguanga4165612013-05-28 16:21:01 +0800535 t0 = (16384 + env->regs[R_ECX] - 0xc0010000) * 2;
Blue Swirl6bada5e2012-04-29 14:42:35 +0000536 t1 = (t0 / 8);
537 t0 %= 8;
538 break;
539 default:
Blue Swirl052e80d2012-04-29 15:51:49 +0000540 helper_vmexit(env, type, param);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000541 t0 = 0;
542 t1 = 0;
543 break;
544 }
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200545 if (x86_ldub_phys(cs, addr + t1) & ((1 << param) << t0)) {
Blue Swirl052e80d2012-04-29 15:51:49 +0000546 helper_vmexit(env, type, param);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000547 }
548 }
549 break;
550 default:
551 if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
Blue Swirl052e80d2012-04-29 15:51:49 +0000552 helper_vmexit(env, type, param);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000553 }
554 break;
555 }
556}
557
Blue Swirl052e80d2012-04-29 15:51:49 +0000558void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000559 uint64_t param)
560{
Blue Swirl052e80d2012-04-29 15:51:49 +0000561 helper_svm_check_intercept_param(env, type, param);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000562}
563
Blue Swirl052e80d2012-04-29 15:51:49 +0000564void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000565 uint32_t next_eip_addend)
566{
Andreas Färber19d6ca12014-03-09 19:15:27 +0100567 CPUState *cs = CPU(x86_env_get_cpu(env));
568
Blue Swirl6bada5e2012-04-29 14:42:35 +0000569 if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
570 /* FIXME: this should be read in at vmrun (faster this way?) */
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200571 uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb +
Blue Swirl6bada5e2012-04-29 14:42:35 +0000572 offsetof(struct vmcb, control.iopm_base_pa));
573 uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
574
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200575 if (x86_lduw_phys(cs, addr + port / 8) & (mask << (port & 7))) {
liguanga78d0ea2013-05-28 16:21:07 +0800576 /* next env->eip */
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200577 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100578 env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000579 env->eip + next_eip_addend);
Blue Swirl052e80d2012-04-29 15:51:49 +0000580 helper_vmexit(env, SVM_EXIT_IOIO, param | (port << 16));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000581 }
582 }
583}
584
585/* Note: currently only 32 bits of exit_code are used */
Blue Swirl052e80d2012-04-29 15:51:49 +0000586void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000587{
Andreas Färber259186a2013-01-17 18:51:17 +0100588 CPUState *cs = CPU(x86_env_get_cpu(env));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000589 uint32_t int_ctl;
590
591 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016"
592 PRIx64 ", " TARGET_FMT_lx ")!\n",
593 exit_code, exit_info_1,
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200594 x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000595 control.exit_info_2)),
liguanga78d0ea2013-05-28 16:21:07 +0800596 env->eip);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000597
598 if (env->hflags & HF_INHIBIT_IRQ_MASK) {
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200599 x86_stl_phys(cs,
Edgar E. Iglesiasab1da852013-12-17 15:07:29 +1000600 env->vm_vmcb + offsetof(struct vmcb, control.int_state),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000601 SVM_INTERRUPT_SHADOW_MASK);
602 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
603 } else {
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200604 x86_stl_phys(cs,
Edgar E. Iglesiasab1da852013-12-17 15:07:29 +1000605 env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000606 }
607
608 /* Save the VM state in the vmcb */
Blue Swirl052e80d2012-04-29 15:51:49 +0000609 svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000610 &env->segs[R_ES]);
Blue Swirl052e80d2012-04-29 15:51:49 +0000611 svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000612 &env->segs[R_CS]);
Blue Swirl052e80d2012-04-29 15:51:49 +0000613 svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000614 &env->segs[R_SS]);
Blue Swirl052e80d2012-04-29 15:51:49 +0000615 svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000616 &env->segs[R_DS]);
617
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200618 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000619 env->gdt.base);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200620 x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000621 env->gdt.limit);
622
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200623 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.base),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000624 env->idt.base);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200625 x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000626 env->idt.limit);
627
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200628 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100629 env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200630 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100631 env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200632 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100633 env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200634 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100635 env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200636 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100637 env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000638
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200639 int_ctl = x86_ldl_phys(cs,
Edgar E. Iglesiasfdfba1a2013-11-15 14:46:38 +0100640 env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000641 int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
642 int_ctl |= env->v_tpr & V_TPR_MASK;
Andreas Färber259186a2013-01-17 18:51:17 +0100643 if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) {
Blue Swirl6bada5e2012-04-29 14:42:35 +0000644 int_ctl |= V_IRQ_MASK;
645 }
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200646 x86_stl_phys(cs,
Edgar E. Iglesiasab1da852013-12-17 15:07:29 +1000647 env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000648
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200649 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rflags),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000650 cpu_compute_eflags(env));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200651 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rip),
Blue Swirl052e80d2012-04-29 15:51:49 +0000652 env->eip);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200653 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100654 env->vm_vmcb + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200655 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100656 env->vm_vmcb + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200657 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100658 env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200659 x86_stq_phys(cs,
Edgar E. Iglesiasf6066042013-11-28 00:11:44 +0100660 env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200661 x86_stb_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cpl),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000662 env->hflags & HF_CPL_MASK);
663
664 /* Reload the host state from vm_hsave */
665 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
666 env->hflags &= ~HF_SVMI_MASK;
667 env->intercept = 0;
668 env->intercept_exceptions = 0;
Andreas Färber259186a2013-01-17 18:51:17 +0100669 cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
Blue Swirl6bada5e2012-04-29 14:42:35 +0000670 env->tsc_offset = 0;
671
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200672 env->gdt.base = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000673 save.gdtr.base));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200674 env->gdt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000675 save.gdtr.limit));
676
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200677 env->idt.base = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000678 save.idtr.base));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200679 env->idt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000680 save.idtr.limit));
681
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200682 cpu_x86_update_cr0(env, x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000683 env->vm_hsave + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000684 save.cr0)) |
685 CR0_PE_MASK);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200686 cpu_x86_update_cr4(env, x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000687 env->vm_hsave + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000688 save.cr4)));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200689 cpu_x86_update_cr3(env, x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000690 env->vm_hsave + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000691 save.cr3)));
692 /* we need to set the efer after the crs so the hidden flags get
693 set properly */
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200694 cpu_load_efer(env, x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000695 save.efer)));
696 env->eflags = 0;
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200697 cpu_load_eflags(env, x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000698 env->vm_hsave + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000699 save.rflags)),
Kevin O'Connor30452022014-04-29 16:37:50 -0400700 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK |
701 VM_MASK));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000702
Blue Swirl052e80d2012-04-29 15:51:49 +0000703 svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.es),
704 R_ES);
705 svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
706 R_CS);
707 svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
708 R_SS);
709 svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
710 R_DS);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000711
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200712 env->eip = x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000713 env->vm_hsave + offsetof(struct vmcb, save.rip));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200714 env->regs[R_ESP] = x86_ldq_phys(cs, env->vm_hsave +
liguang90a25412013-05-28 16:21:10 +0800715 offsetof(struct vmcb, save.rsp));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200716 env->regs[R_EAX] = x86_ldq_phys(cs, env->vm_hsave +
liguang90a25412013-05-28 16:21:10 +0800717 offsetof(struct vmcb, save.rax));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000718
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200719 env->dr[6] = x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000720 env->vm_hsave + offsetof(struct vmcb, save.dr6));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200721 env->dr[7] = x86_ldq_phys(cs,
Edgar E. Iglesias2c174492013-12-17 14:05:40 +1000722 env->vm_hsave + offsetof(struct vmcb, save.dr7));
Blue Swirl6bada5e2012-04-29 14:42:35 +0000723
724 /* other setups */
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200725 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_code),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000726 exit_code);
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200727 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1),
Blue Swirl6bada5e2012-04-29 14:42:35 +0000728 exit_info_1);
729
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200730 x86_stl_phys(cs,
Edgar E. Iglesiasab1da852013-12-17 15:07:29 +1000731 env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200732 x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000733 control.event_inj)));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200734 x86_stl_phys(cs,
Edgar E. Iglesiasab1da852013-12-17 15:07:29 +1000735 env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200736 x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
Blue Swirl6bada5e2012-04-29 14:42:35 +0000737 control.event_inj_err)));
Paolo Bonzinib216aa62015-04-08 13:39:37 +0200738 x86_stl_phys(cs,
Edgar E. Iglesiasab1da852013-12-17 15:07:29 +1000739 env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000740
741 env->hflags2 &= ~HF2_GIF_MASK;
742 /* FIXME: Resets the current ASID register to zero (host ASID). */
743
744 /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
745
746 /* Clears the TSC_OFFSET inside the processor. */
747
748 /* If the host is in PAE mode, the processor reloads the host's PDPEs
749 from the page table indicated the host's CR3. If the PDPEs contain
750 illegal state, the processor causes a shutdown. */
751
Blue Swirl6bada5e2012-04-29 14:42:35 +0000752 /* Disables all breakpoints in the host DR7 register. */
753
754 /* Checks the reloaded host state for consistency. */
755
756 /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
757 host's code segment or non-canonical (in the case of long mode), a
758 #GP fault is delivered inside the host. */
759
760 /* remove any pending exception */
Andreas Färber27103422013-08-26 08:31:06 +0200761 cs->exception_index = -1;
Blue Swirl6bada5e2012-04-29 14:42:35 +0000762 env->error_code = 0;
763 env->old_exception = -1;
764
Andreas Färber5638d182013-08-27 17:52:12 +0200765 cpu_loop_exit(cs);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000766}
767
Blue Swirl052e80d2012-04-29 15:51:49 +0000768void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
Blue Swirl6bada5e2012-04-29 14:42:35 +0000769{
Blue Swirl052e80d2012-04-29 15:51:49 +0000770 helper_vmexit(env, exit_code, exit_info_1);
Blue Swirl6bada5e2012-04-29 14:42:35 +0000771}
772
773#endif