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