2 * x86 segmentation related helpers: (sysemu-only code)
3 * TSS, interrupts, system calls, jumps and call/task gates, descriptors
5 * Copyright (c) 2003 Fabrice Bellard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
23 #include "exec/helper-proto.h"
24 #include "exec/cpu_ldst.h"
25 #include "tcg/helper-tcg.h"
26 #include "../seg_helper.h"
29 void helper_syscall(CPUX86State
*env
, int next_eip_addend
)
33 if (!(env
->efer
& MSR_EFER_SCE
)) {
34 raise_exception_err_ra(env
, EXCP06_ILLOP
, 0, GETPC());
36 selector
= (env
->star
>> 32) & 0xffff;
37 if (env
->hflags
& HF_LMA_MASK
) {
40 env
->regs
[R_ECX
] = env
->eip
+ next_eip_addend
;
41 env
->regs
[11] = cpu_compute_eflags(env
) & ~RF_MASK
;
43 code64
= env
->hflags
& HF_CS64_MASK
;
45 env
->eflags
&= ~(env
->fmask
| RF_MASK
);
46 cpu_load_eflags(env
, env
->eflags
, 0);
47 cpu_x86_load_seg_cache(env
, R_CS
, selector
& 0xfffc,
49 DESC_G_MASK
| DESC_P_MASK
|
51 DESC_CS_MASK
| DESC_R_MASK
| DESC_A_MASK
|
53 cpu_x86_load_seg_cache(env
, R_SS
, (selector
+ 8) & 0xfffc,
55 DESC_G_MASK
| DESC_B_MASK
| DESC_P_MASK
|
57 DESC_W_MASK
| DESC_A_MASK
);
59 env
->eip
= env
->lstar
;
61 env
->eip
= env
->cstar
;
64 env
->regs
[R_ECX
] = (uint32_t)(env
->eip
+ next_eip_addend
);
66 env
->eflags
&= ~(IF_MASK
| RF_MASK
| VM_MASK
);
67 cpu_x86_load_seg_cache(env
, R_CS
, selector
& 0xfffc,
69 DESC_G_MASK
| DESC_B_MASK
| DESC_P_MASK
|
71 DESC_CS_MASK
| DESC_R_MASK
| DESC_A_MASK
);
72 cpu_x86_load_seg_cache(env
, R_SS
, (selector
+ 8) & 0xfffc,
74 DESC_G_MASK
| DESC_B_MASK
| DESC_P_MASK
|
76 DESC_W_MASK
| DESC_A_MASK
);
77 env
->eip
= (uint32_t)env
->star
;
80 #endif /* TARGET_X86_64 */
82 void handle_even_inj(CPUX86State
*env
, int intno
, int is_int
,
83 int error_code
, int is_hw
, int rm
)
85 CPUState
*cs
= env_cpu(env
);
86 uint32_t event_inj
= x86_ldl_phys(cs
, env
->vm_vmcb
+ offsetof(struct vmcb
,
89 if (!(event_inj
& SVM_EVTINJ_VALID
)) {
93 type
= SVM_EVTINJ_TYPE_SOFT
;
95 type
= SVM_EVTINJ_TYPE_EXEPT
;
97 event_inj
= intno
| type
| SVM_EVTINJ_VALID
;
98 if (!rm
&& exception_has_error_code(intno
)) {
99 event_inj
|= SVM_EVTINJ_VALID_ERR
;
100 x86_stl_phys(cs
, env
->vm_vmcb
+ offsetof(struct vmcb
,
101 control
.event_inj_err
),
105 env
->vm_vmcb
+ offsetof(struct vmcb
, control
.event_inj
),
110 void x86_cpu_do_interrupt(CPUState
*cs
)
112 X86CPU
*cpu
= X86_CPU(cs
);
113 CPUX86State
*env
= &cpu
->env
;
115 if (cs
->exception_index
== EXCP_VMEXIT
) {
116 assert(env
->old_exception
== -1);
119 do_interrupt_all(cpu
, cs
->exception_index
,
120 env
->exception_is_int
,
122 env
->exception_next_eip
, 0);
123 /* successfully delivered */
124 env
->old_exception
= -1;
128 bool x86_cpu_exec_interrupt(CPUState
*cs
, int interrupt_request
)
130 X86CPU
*cpu
= X86_CPU(cs
);
131 CPUX86State
*env
= &cpu
->env
;
134 interrupt_request
= x86_cpu_pending_interrupt(cs
, interrupt_request
);
135 if (!interrupt_request
) {
139 /* Don't process multiple interrupt requests in a single call.
140 * This is required to make icount-driven execution deterministic.
142 switch (interrupt_request
) {
143 case CPU_INTERRUPT_POLL
:
144 cs
->interrupt_request
&= ~CPU_INTERRUPT_POLL
;
145 apic_poll_irq(cpu
->apic_state
);
147 case CPU_INTERRUPT_SIPI
:
150 case CPU_INTERRUPT_SMI
:
151 cpu_svm_check_intercept_param(env
, SVM_EXIT_SMI
, 0, 0);
152 cs
->interrupt_request
&= ~CPU_INTERRUPT_SMI
;
155 case CPU_INTERRUPT_NMI
:
156 cpu_svm_check_intercept_param(env
, SVM_EXIT_NMI
, 0, 0);
157 cs
->interrupt_request
&= ~CPU_INTERRUPT_NMI
;
158 env
->hflags2
|= HF2_NMI_MASK
;
159 do_interrupt_x86_hardirq(env
, EXCP02_NMI
, 1);
161 case CPU_INTERRUPT_MCE
:
162 cs
->interrupt_request
&= ~CPU_INTERRUPT_MCE
;
163 do_interrupt_x86_hardirq(env
, EXCP12_MCHK
, 0);
165 case CPU_INTERRUPT_HARD
:
166 cpu_svm_check_intercept_param(env
, SVM_EXIT_INTR
, 0, 0);
167 cs
->interrupt_request
&= ~(CPU_INTERRUPT_HARD
|
169 intno
= cpu_get_pic_interrupt(env
);
170 qemu_log_mask(CPU_LOG_TB_IN_ASM
,
171 "Servicing hardware INT=0x%02x\n", intno
);
172 do_interrupt_x86_hardirq(env
, intno
, 1);
174 case CPU_INTERRUPT_VIRQ
:
175 cpu_svm_check_intercept_param(env
, SVM_EXIT_VINTR
, 0, 0);
176 intno
= x86_ldl_phys(cs
, env
->vm_vmcb
177 + offsetof(struct vmcb
, control
.int_vector
));
178 qemu_log_mask(CPU_LOG_TB_IN_ASM
,
179 "Servicing virtual hardware INT=0x%02x\n", intno
);
180 do_interrupt_x86_hardirq(env
, intno
, 1);
181 cs
->interrupt_request
&= ~CPU_INTERRUPT_VIRQ
;
182 env
->int_ctl
&= ~V_IRQ_MASK
;
186 /* Ensure that no TB jump will be modified as the program flow was changed. */
190 /* check if Port I/O is allowed in TSS */
191 void helper_check_io(CPUX86State
*env
, uint32_t addr
, uint32_t size
)
193 uintptr_t retaddr
= GETPC();
194 uint32_t io_offset
, val
, mask
;
196 /* TSS must be a valid 32 bit one */
197 if (!(env
->tr
.flags
& DESC_P_MASK
) ||
198 ((env
->tr
.flags
>> DESC_TYPE_SHIFT
) & 0xf) != 9 ||
199 env
->tr
.limit
< 103) {
202 io_offset
= cpu_lduw_kernel_ra(env
, env
->tr
.base
+ 0x66, retaddr
);
203 io_offset
+= (addr
>> 3);
204 /* Note: the check needs two bytes */
205 if ((io_offset
+ 1) > env
->tr
.limit
) {
208 val
= cpu_lduw_kernel_ra(env
, env
->tr
.base
+ io_offset
, retaddr
);
210 mask
= (1 << size
) - 1;
211 /* all bits must be zero to allow the I/O */
212 if ((val
& mask
) != 0) {
214 raise_exception_err_ra(env
, EXCP0D_GPF
, 0, retaddr
);