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