4 * Copyright (c) 2003 Fabrice Bellard
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.
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.
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/>.
21 #include "exec/cpu-all.h"
24 #if !defined(CONFIG_USER_ONLY)
25 #include "exec/softmmu_exec.h"
26 #endif /* !defined(CONFIG_USER_ONLY) */
28 /* Secure Virtual Machine helpers */
30 #if defined(CONFIG_USER_ONLY)
32 void helper_vmrun(CPUX86State
*env
, int aflag
, int next_eip_addend
)
36 void helper_vmmcall(CPUX86State
*env
)
40 void helper_vmload(CPUX86State
*env
, int aflag
)
44 void helper_vmsave(CPUX86State
*env
, int aflag
)
48 void helper_stgi(CPUX86State
*env
)
52 void helper_clgi(CPUX86State
*env
)
56 void helper_skinit(CPUX86State
*env
)
60 void helper_invlpga(CPUX86State
*env
, int aflag
)
64 void helper_vmexit(CPUX86State
*env
, uint32_t exit_code
, uint64_t exit_info_1
)
68 void cpu_vmexit(CPUX86State
*nenv
, uint32_t exit_code
, uint64_t exit_info_1
)
72 void helper_svm_check_intercept_param(CPUX86State
*env
, uint32_t type
,
77 void cpu_svm_check_intercept_param(CPUX86State
*env
, uint32_t type
,
82 void helper_svm_check_io(CPUX86State
*env
, uint32_t port
, uint32_t param
,
83 uint32_t next_eip_addend
)
88 static inline void svm_save_seg(CPUX86State
*env
, hwaddr addr
,
89 const SegmentCache
*sc
)
91 stw_phys(addr
+ offsetof(struct vmcb_seg
, selector
),
93 stq_phys(addr
+ offsetof(struct vmcb_seg
, base
),
95 stl_phys(addr
+ offsetof(struct vmcb_seg
, limit
),
97 stw_phys(addr
+ offsetof(struct vmcb_seg
, attrib
),
98 ((sc
->flags
>> 8) & 0xff) | ((sc
->flags
>> 12) & 0x0f00));
101 static inline void svm_load_seg(CPUX86State
*env
, hwaddr addr
,
106 sc
->selector
= lduw_phys(addr
+ offsetof(struct vmcb_seg
, selector
));
107 sc
->base
= ldq_phys(addr
+ offsetof(struct vmcb_seg
, base
));
108 sc
->limit
= ldl_phys(addr
+ offsetof(struct vmcb_seg
, limit
));
109 flags
= lduw_phys(addr
+ offsetof(struct vmcb_seg
, attrib
));
110 sc
->flags
= ((flags
& 0xff) << 8) | ((flags
& 0x0f00) << 12);
113 static inline void svm_load_seg_cache(CPUX86State
*env
, hwaddr addr
,
116 SegmentCache sc1
, *sc
= &sc1
;
118 svm_load_seg(env
, addr
, sc
);
119 cpu_x86_load_seg_cache(env
, seg_reg
, sc
->selector
,
120 sc
->base
, sc
->limit
, sc
->flags
);
123 void helper_vmrun(CPUX86State
*env
, int aflag
, int next_eip_addend
)
129 cpu_svm_check_intercept_param(env
, SVM_EXIT_VMRUN
, 0);
134 addr
= (uint32_t)EAX
;
137 qemu_log_mask(CPU_LOG_TB_IN_ASM
, "vmrun! " TARGET_FMT_lx
"\n", addr
);
141 /* save the current CPU state in the hsave page */
142 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.gdtr
.base
),
144 stl_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.gdtr
.limit
),
147 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.idtr
.base
),
149 stl_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.idtr
.limit
),
152 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.cr0
), env
->cr
[0]);
153 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.cr2
), env
->cr
[2]);
154 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.cr3
), env
->cr
[3]);
155 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.cr4
), env
->cr
[4]);
156 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.dr6
), env
->dr
[6]);
157 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.dr7
), env
->dr
[7]);
159 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.efer
), env
->efer
);
160 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.rflags
),
161 cpu_compute_eflags(env
));
163 svm_save_seg(env
, env
->vm_hsave
+ offsetof(struct vmcb
, save
.es
),
165 svm_save_seg(env
, env
->vm_hsave
+ offsetof(struct vmcb
, save
.cs
),
167 svm_save_seg(env
, env
->vm_hsave
+ offsetof(struct vmcb
, save
.ss
),
169 svm_save_seg(env
, env
->vm_hsave
+ offsetof(struct vmcb
, save
.ds
),
172 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.rip
),
173 EIP
+ next_eip_addend
);
174 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.rsp
), ESP
);
175 stq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.rax
), EAX
);
177 /* load the interception bitmaps so we do not need to access the
179 env
->intercept
= ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
181 env
->intercept_cr_read
= lduw_phys(env
->vm_vmcb
+
182 offsetof(struct vmcb
,
183 control
.intercept_cr_read
));
184 env
->intercept_cr_write
= lduw_phys(env
->vm_vmcb
+
185 offsetof(struct vmcb
,
186 control
.intercept_cr_write
));
187 env
->intercept_dr_read
= lduw_phys(env
->vm_vmcb
+
188 offsetof(struct vmcb
,
189 control
.intercept_dr_read
));
190 env
->intercept_dr_write
= lduw_phys(env
->vm_vmcb
+
191 offsetof(struct vmcb
,
192 control
.intercept_dr_write
));
193 env
->intercept_exceptions
= ldl_phys(env
->vm_vmcb
+
194 offsetof(struct vmcb
,
195 control
.intercept_exceptions
198 /* enable intercepts */
199 env
->hflags
|= HF_SVMI_MASK
;
201 env
->tsc_offset
= ldq_phys(env
->vm_vmcb
+
202 offsetof(struct vmcb
, control
.tsc_offset
));
204 env
->gdt
.base
= ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
206 env
->gdt
.limit
= ldl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
209 env
->idt
.base
= ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
211 env
->idt
.limit
= ldl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
214 /* clear exit_info_2 so we behave like the real hardware */
215 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.exit_info_2
), 0);
217 cpu_x86_update_cr0(env
, ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
219 cpu_x86_update_cr4(env
, ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
221 cpu_x86_update_cr3(env
, ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
223 env
->cr
[2] = ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.cr2
));
224 int_ctl
= ldl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.int_ctl
));
225 env
->hflags2
&= ~(HF2_HIF_MASK
| HF2_VINTR_MASK
);
226 if (int_ctl
& V_INTR_MASKING_MASK
) {
227 env
->v_tpr
= int_ctl
& V_TPR_MASK
;
228 env
->hflags2
|= HF2_VINTR_MASK
;
229 if (env
->eflags
& IF_MASK
) {
230 env
->hflags2
|= HF2_HIF_MASK
;
235 ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.efer
)));
237 cpu_load_eflags(env
, ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
239 ~(CC_O
| CC_S
| CC_Z
| CC_A
| CC_P
| CC_C
| DF_MASK
));
240 CC_OP
= CC_OP_EFLAGS
;
242 svm_load_seg_cache(env
, env
->vm_vmcb
+ offsetof(struct vmcb
, save
.es
),
244 svm_load_seg_cache(env
, env
->vm_vmcb
+ offsetof(struct vmcb
, save
.cs
),
246 svm_load_seg_cache(env
, env
->vm_vmcb
+ offsetof(struct vmcb
, save
.ss
),
248 svm_load_seg_cache(env
, env
->vm_vmcb
+ offsetof(struct vmcb
, save
.ds
),
251 EIP
= ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.rip
));
253 ESP
= ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.rsp
));
254 EAX
= ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.rax
));
255 env
->dr
[7] = ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.dr7
));
256 env
->dr
[6] = ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.dr6
));
257 cpu_x86_set_cpl(env
, ldub_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
260 /* FIXME: guest state consistency checks */
262 switch (ldub_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.tlb_ctl
))) {
263 case TLB_CONTROL_DO_NOTHING
:
265 case TLB_CONTROL_FLUSH_ALL_ASID
:
266 /* FIXME: this is not 100% correct but should work for now */
271 env
->hflags2
|= HF2_GIF_MASK
;
273 if (int_ctl
& V_IRQ_MASK
) {
274 env
->interrupt_request
|= CPU_INTERRUPT_VIRQ
;
277 /* maybe we need to inject an event */
278 event_inj
= ldl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
280 if (event_inj
& SVM_EVTINJ_VALID
) {
281 uint8_t vector
= event_inj
& SVM_EVTINJ_VEC_MASK
;
282 uint16_t valid_err
= event_inj
& SVM_EVTINJ_VALID_ERR
;
283 uint32_t event_inj_err
= ldl_phys(env
->vm_vmcb
+
284 offsetof(struct vmcb
,
285 control
.event_inj_err
));
287 qemu_log_mask(CPU_LOG_TB_IN_ASM
, "Injecting(%#hx): ", valid_err
);
288 /* FIXME: need to implement valid_err */
289 switch (event_inj
& SVM_EVTINJ_TYPE_MASK
) {
290 case SVM_EVTINJ_TYPE_INTR
:
291 env
->exception_index
= vector
;
292 env
->error_code
= event_inj_err
;
293 env
->exception_is_int
= 0;
294 env
->exception_next_eip
= -1;
295 qemu_log_mask(CPU_LOG_TB_IN_ASM
, "INTR");
296 /* XXX: is it always correct? */
297 do_interrupt_x86_hardirq(env
, vector
, 1);
299 case SVM_EVTINJ_TYPE_NMI
:
300 env
->exception_index
= EXCP02_NMI
;
301 env
->error_code
= event_inj_err
;
302 env
->exception_is_int
= 0;
303 env
->exception_next_eip
= EIP
;
304 qemu_log_mask(CPU_LOG_TB_IN_ASM
, "NMI");
307 case SVM_EVTINJ_TYPE_EXEPT
:
308 env
->exception_index
= vector
;
309 env
->error_code
= event_inj_err
;
310 env
->exception_is_int
= 0;
311 env
->exception_next_eip
= -1;
312 qemu_log_mask(CPU_LOG_TB_IN_ASM
, "EXEPT");
315 case SVM_EVTINJ_TYPE_SOFT
:
316 env
->exception_index
= vector
;
317 env
->error_code
= event_inj_err
;
318 env
->exception_is_int
= 1;
319 env
->exception_next_eip
= EIP
;
320 qemu_log_mask(CPU_LOG_TB_IN_ASM
, "SOFT");
324 qemu_log_mask(CPU_LOG_TB_IN_ASM
, " %#x %#x\n", env
->exception_index
,
329 void helper_vmmcall(CPUX86State
*env
)
331 cpu_svm_check_intercept_param(env
, SVM_EXIT_VMMCALL
, 0);
332 raise_exception(env
, EXCP06_ILLOP
);
335 void helper_vmload(CPUX86State
*env
, int aflag
)
339 cpu_svm_check_intercept_param(env
, SVM_EXIT_VMLOAD
, 0);
344 addr
= (uint32_t)EAX
;
347 qemu_log_mask(CPU_LOG_TB_IN_ASM
, "vmload! " TARGET_FMT_lx
348 "\nFS: %016" PRIx64
" | " TARGET_FMT_lx
"\n",
349 addr
, ldq_phys(addr
+ offsetof(struct vmcb
,
351 env
->segs
[R_FS
].base
);
353 svm_load_seg_cache(env
, addr
+ offsetof(struct vmcb
, save
.fs
), R_FS
);
354 svm_load_seg_cache(env
, addr
+ offsetof(struct vmcb
, save
.gs
), R_GS
);
355 svm_load_seg(env
, addr
+ offsetof(struct vmcb
, save
.tr
), &env
->tr
);
356 svm_load_seg(env
, addr
+ offsetof(struct vmcb
, save
.ldtr
), &env
->ldt
);
359 env
->kernelgsbase
= ldq_phys(addr
+ offsetof(struct vmcb
,
360 save
.kernel_gs_base
));
361 env
->lstar
= ldq_phys(addr
+ offsetof(struct vmcb
, save
.lstar
));
362 env
->cstar
= ldq_phys(addr
+ offsetof(struct vmcb
, save
.cstar
));
363 env
->fmask
= ldq_phys(addr
+ offsetof(struct vmcb
, save
.sfmask
));
365 env
->star
= ldq_phys(addr
+ offsetof(struct vmcb
, save
.star
));
366 env
->sysenter_cs
= ldq_phys(addr
+ offsetof(struct vmcb
, save
.sysenter_cs
));
367 env
->sysenter_esp
= ldq_phys(addr
+ offsetof(struct vmcb
,
369 env
->sysenter_eip
= ldq_phys(addr
+ offsetof(struct vmcb
,
373 void helper_vmsave(CPUX86State
*env
, int aflag
)
377 cpu_svm_check_intercept_param(env
, SVM_EXIT_VMSAVE
, 0);
382 addr
= (uint32_t)EAX
;
385 qemu_log_mask(CPU_LOG_TB_IN_ASM
, "vmsave! " TARGET_FMT_lx
386 "\nFS: %016" PRIx64
" | " TARGET_FMT_lx
"\n",
387 addr
, ldq_phys(addr
+ offsetof(struct vmcb
, save
.fs
.base
)),
388 env
->segs
[R_FS
].base
);
390 svm_save_seg(env
, addr
+ offsetof(struct vmcb
, save
.fs
),
392 svm_save_seg(env
, addr
+ offsetof(struct vmcb
, save
.gs
),
394 svm_save_seg(env
, addr
+ offsetof(struct vmcb
, save
.tr
),
396 svm_save_seg(env
, addr
+ offsetof(struct vmcb
, save
.ldtr
),
400 stq_phys(addr
+ offsetof(struct vmcb
, save
.kernel_gs_base
),
402 stq_phys(addr
+ offsetof(struct vmcb
, save
.lstar
), env
->lstar
);
403 stq_phys(addr
+ offsetof(struct vmcb
, save
.cstar
), env
->cstar
);
404 stq_phys(addr
+ offsetof(struct vmcb
, save
.sfmask
), env
->fmask
);
406 stq_phys(addr
+ offsetof(struct vmcb
, save
.star
), env
->star
);
407 stq_phys(addr
+ offsetof(struct vmcb
, save
.sysenter_cs
), env
->sysenter_cs
);
408 stq_phys(addr
+ offsetof(struct vmcb
, save
.sysenter_esp
),
410 stq_phys(addr
+ offsetof(struct vmcb
, save
.sysenter_eip
),
414 void helper_stgi(CPUX86State
*env
)
416 cpu_svm_check_intercept_param(env
, SVM_EXIT_STGI
, 0);
417 env
->hflags2
|= HF2_GIF_MASK
;
420 void helper_clgi(CPUX86State
*env
)
422 cpu_svm_check_intercept_param(env
, SVM_EXIT_CLGI
, 0);
423 env
->hflags2
&= ~HF2_GIF_MASK
;
426 void helper_skinit(CPUX86State
*env
)
428 cpu_svm_check_intercept_param(env
, SVM_EXIT_SKINIT
, 0);
429 /* XXX: not implemented */
430 raise_exception(env
, EXCP06_ILLOP
);
433 void helper_invlpga(CPUX86State
*env
, int aflag
)
437 cpu_svm_check_intercept_param(env
, SVM_EXIT_INVLPGA
, 0);
442 addr
= (uint32_t)EAX
;
445 /* XXX: could use the ASID to see if it is needed to do the
447 tlb_flush_page(env
, addr
);
450 void helper_svm_check_intercept_param(CPUX86State
*env
, uint32_t type
,
453 if (likely(!(env
->hflags
& HF_SVMI_MASK
))) {
457 case SVM_EXIT_READ_CR0
... SVM_EXIT_READ_CR0
+ 8:
458 if (env
->intercept_cr_read
& (1 << (type
- SVM_EXIT_READ_CR0
))) {
459 helper_vmexit(env
, type
, param
);
462 case SVM_EXIT_WRITE_CR0
... SVM_EXIT_WRITE_CR0
+ 8:
463 if (env
->intercept_cr_write
& (1 << (type
- SVM_EXIT_WRITE_CR0
))) {
464 helper_vmexit(env
, type
, param
);
467 case SVM_EXIT_READ_DR0
... SVM_EXIT_READ_DR0
+ 7:
468 if (env
->intercept_dr_read
& (1 << (type
- SVM_EXIT_READ_DR0
))) {
469 helper_vmexit(env
, type
, param
);
472 case SVM_EXIT_WRITE_DR0
... SVM_EXIT_WRITE_DR0
+ 7:
473 if (env
->intercept_dr_write
& (1 << (type
- SVM_EXIT_WRITE_DR0
))) {
474 helper_vmexit(env
, type
, param
);
477 case SVM_EXIT_EXCP_BASE
... SVM_EXIT_EXCP_BASE
+ 31:
478 if (env
->intercept_exceptions
& (1 << (type
- SVM_EXIT_EXCP_BASE
))) {
479 helper_vmexit(env
, type
, param
);
483 if (env
->intercept
& (1ULL << (SVM_EXIT_MSR
- SVM_EXIT_INTR
))) {
484 /* FIXME: this should be read in at vmrun (faster this way?) */
485 uint64_t addr
= ldq_phys(env
->vm_vmcb
+
486 offsetof(struct vmcb
,
487 control
.msrpm_base_pa
));
490 switch ((uint32_t)ECX
) {
495 case 0xc0000000 ... 0xc0001fff:
496 t0
= (8192 + ECX
- 0xc0000000) * 2;
500 case 0xc0010000 ... 0xc0011fff:
501 t0
= (16384 + ECX
- 0xc0010000) * 2;
506 helper_vmexit(env
, type
, param
);
511 if (ldub_phys(addr
+ t1
) & ((1 << param
) << t0
)) {
512 helper_vmexit(env
, type
, param
);
517 if (env
->intercept
& (1ULL << (type
- SVM_EXIT_INTR
))) {
518 helper_vmexit(env
, type
, param
);
524 void cpu_svm_check_intercept_param(CPUX86State
*env
, uint32_t type
,
527 helper_svm_check_intercept_param(env
, type
, param
);
530 void helper_svm_check_io(CPUX86State
*env
, uint32_t port
, uint32_t param
,
531 uint32_t next_eip_addend
)
533 if (env
->intercept
& (1ULL << (SVM_EXIT_IOIO
- SVM_EXIT_INTR
))) {
534 /* FIXME: this should be read in at vmrun (faster this way?) */
535 uint64_t addr
= ldq_phys(env
->vm_vmcb
+
536 offsetof(struct vmcb
, control
.iopm_base_pa
));
537 uint16_t mask
= (1 << ((param
>> 4) & 7)) - 1;
539 if (lduw_phys(addr
+ port
/ 8) & (mask
<< (port
& 7))) {
541 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.exit_info_2
),
542 env
->eip
+ next_eip_addend
);
543 helper_vmexit(env
, SVM_EXIT_IOIO
, param
| (port
<< 16));
548 /* Note: currently only 32 bits of exit_code are used */
549 void helper_vmexit(CPUX86State
*env
, uint32_t exit_code
, uint64_t exit_info_1
)
553 qemu_log_mask(CPU_LOG_TB_IN_ASM
, "vmexit(%08x, %016" PRIx64
", %016"
554 PRIx64
", " TARGET_FMT_lx
")!\n",
555 exit_code
, exit_info_1
,
556 ldq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
557 control
.exit_info_2
)),
560 if (env
->hflags
& HF_INHIBIT_IRQ_MASK
) {
561 stl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.int_state
),
562 SVM_INTERRUPT_SHADOW_MASK
);
563 env
->hflags
&= ~HF_INHIBIT_IRQ_MASK
;
565 stl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.int_state
), 0);
568 /* Save the VM state in the vmcb */
569 svm_save_seg(env
, env
->vm_vmcb
+ offsetof(struct vmcb
, save
.es
),
571 svm_save_seg(env
, env
->vm_vmcb
+ offsetof(struct vmcb
, save
.cs
),
573 svm_save_seg(env
, env
->vm_vmcb
+ offsetof(struct vmcb
, save
.ss
),
575 svm_save_seg(env
, env
->vm_vmcb
+ offsetof(struct vmcb
, save
.ds
),
578 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.gdtr
.base
),
580 stl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.gdtr
.limit
),
583 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.idtr
.base
),
585 stl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.idtr
.limit
),
588 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.efer
), env
->efer
);
589 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.cr0
), env
->cr
[0]);
590 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.cr2
), env
->cr
[2]);
591 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.cr3
), env
->cr
[3]);
592 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.cr4
), env
->cr
[4]);
594 int_ctl
= ldl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.int_ctl
));
595 int_ctl
&= ~(V_TPR_MASK
| V_IRQ_MASK
);
596 int_ctl
|= env
->v_tpr
& V_TPR_MASK
;
597 if (env
->interrupt_request
& CPU_INTERRUPT_VIRQ
) {
598 int_ctl
|= V_IRQ_MASK
;
600 stl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.int_ctl
), int_ctl
);
602 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.rflags
),
603 cpu_compute_eflags(env
));
604 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.rip
),
606 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.rsp
), ESP
);
607 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.rax
), EAX
);
608 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.dr7
), env
->dr
[7]);
609 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.dr6
), env
->dr
[6]);
610 stb_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, save
.cpl
),
611 env
->hflags
& HF_CPL_MASK
);
613 /* Reload the host state from vm_hsave */
614 env
->hflags2
&= ~(HF2_HIF_MASK
| HF2_VINTR_MASK
);
615 env
->hflags
&= ~HF_SVMI_MASK
;
617 env
->intercept_exceptions
= 0;
618 env
->interrupt_request
&= ~CPU_INTERRUPT_VIRQ
;
621 env
->gdt
.base
= ldq_phys(env
->vm_hsave
+ offsetof(struct vmcb
,
623 env
->gdt
.limit
= ldl_phys(env
->vm_hsave
+ offsetof(struct vmcb
,
626 env
->idt
.base
= ldq_phys(env
->vm_hsave
+ offsetof(struct vmcb
,
628 env
->idt
.limit
= ldl_phys(env
->vm_hsave
+ offsetof(struct vmcb
,
631 cpu_x86_update_cr0(env
, ldq_phys(env
->vm_hsave
+ offsetof(struct vmcb
,
634 cpu_x86_update_cr4(env
, ldq_phys(env
->vm_hsave
+ offsetof(struct vmcb
,
636 cpu_x86_update_cr3(env
, ldq_phys(env
->vm_hsave
+ offsetof(struct vmcb
,
638 /* we need to set the efer after the crs so the hidden flags get
640 cpu_load_efer(env
, ldq_phys(env
->vm_hsave
+ offsetof(struct vmcb
,
643 cpu_load_eflags(env
, ldq_phys(env
->vm_hsave
+ offsetof(struct vmcb
,
645 ~(CC_O
| CC_S
| CC_Z
| CC_A
| CC_P
| CC_C
| DF_MASK
));
646 CC_OP
= CC_OP_EFLAGS
;
648 svm_load_seg_cache(env
, env
->vm_hsave
+ offsetof(struct vmcb
, save
.es
),
650 svm_load_seg_cache(env
, env
->vm_hsave
+ offsetof(struct vmcb
, save
.cs
),
652 svm_load_seg_cache(env
, env
->vm_hsave
+ offsetof(struct vmcb
, save
.ss
),
654 svm_load_seg_cache(env
, env
->vm_hsave
+ offsetof(struct vmcb
, save
.ds
),
657 EIP
= ldq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.rip
));
658 ESP
= ldq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.rsp
));
659 EAX
= ldq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.rax
));
661 env
->dr
[6] = ldq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.dr6
));
662 env
->dr
[7] = ldq_phys(env
->vm_hsave
+ offsetof(struct vmcb
, save
.dr7
));
665 cpu_x86_set_cpl(env
, 0);
666 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.exit_code
),
668 stq_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.exit_info_1
),
671 stl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.exit_int_info
),
672 ldl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
673 control
.event_inj
)));
674 stl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.exit_int_info_err
),
675 ldl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
,
676 control
.event_inj_err
)));
677 stl_phys(env
->vm_vmcb
+ offsetof(struct vmcb
, control
.event_inj
), 0);
679 env
->hflags2
&= ~HF2_GIF_MASK
;
680 /* FIXME: Resets the current ASID register to zero (host ASID). */
682 /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
684 /* Clears the TSC_OFFSET inside the processor. */
686 /* If the host is in PAE mode, the processor reloads the host's PDPEs
687 from the page table indicated the host's CR3. If the PDPEs contain
688 illegal state, the processor causes a shutdown. */
690 /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
691 env
->cr
[0] |= CR0_PE_MASK
;
692 env
->eflags
&= ~VM_MASK
;
694 /* Disables all breakpoints in the host DR7 register. */
696 /* Checks the reloaded host state for consistency. */
698 /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
699 host's code segment or non-canonical (in the case of long mode), a
700 #GP fault is delivered inside the host. */
702 /* remove any pending exception */
703 env
->exception_index
= -1;
705 env
->old_exception
= -1;
710 void cpu_vmexit(CPUX86State
*env
, uint32_t exit_code
, uint64_t exit_info_1
)
712 helper_vmexit(env
, exit_code
, exit_info_1
);