130493a03SClaudio Fontana /*
230493a03SClaudio Fontana * x86 segmentation related helpers: (sysemu-only code)
330493a03SClaudio Fontana * TSS, interrupts, system calls, jumps and call/task gates, descriptors
430493a03SClaudio Fontana *
530493a03SClaudio Fontana * Copyright (c) 2003 Fabrice Bellard
630493a03SClaudio Fontana *
730493a03SClaudio Fontana * This library is free software; you can redistribute it and/or
830493a03SClaudio Fontana * modify it under the terms of the GNU Lesser General Public
930493a03SClaudio Fontana * License as published by the Free Software Foundation; either
1030493a03SClaudio Fontana * version 2.1 of the License, or (at your option) any later version.
1130493a03SClaudio Fontana *
1230493a03SClaudio Fontana * This library is distributed in the hope that it will be useful,
1330493a03SClaudio Fontana * but WITHOUT ANY WARRANTY; without even the implied warranty of
1430493a03SClaudio Fontana * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1530493a03SClaudio Fontana * Lesser General Public License for more details.
1630493a03SClaudio Fontana *
1730493a03SClaudio Fontana * You should have received a copy of the GNU Lesser General Public
1830493a03SClaudio Fontana * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1930493a03SClaudio Fontana */
2030493a03SClaudio Fontana
2130493a03SClaudio Fontana #include "qemu/osdep.h"
22cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h"
23ec1d32afSPhilippe Mathieu-Daudé #include "qemu/main-loop.h"
2430493a03SClaudio Fontana #include "cpu.h"
2530493a03SClaudio Fontana #include "exec/helper-proto.h"
2630493a03SClaudio Fontana #include "exec/cpu_ldst.h"
2730493a03SClaudio Fontana #include "tcg/helper-tcg.h"
28d76b9c6fSRichard Henderson #include "../seg_helper.h"
2930493a03SClaudio Fontana
helper_syscall(CPUX86State * env,int next_eip_addend)3030493a03SClaudio Fontana void helper_syscall(CPUX86State *env, int next_eip_addend)
3130493a03SClaudio Fontana {
3230493a03SClaudio Fontana int selector;
3330493a03SClaudio Fontana
3430493a03SClaudio Fontana if (!(env->efer & MSR_EFER_SCE)) {
3530493a03SClaudio Fontana raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
3630493a03SClaudio Fontana }
3730493a03SClaudio Fontana selector = (env->star >> 32) & 0xffff;
3863fd8ef0SPaolo Bonzini #ifdef TARGET_X86_64
3930493a03SClaudio Fontana if (env->hflags & HF_LMA_MASK) {
4030493a03SClaudio Fontana int code64;
4130493a03SClaudio Fontana
4230493a03SClaudio Fontana env->regs[R_ECX] = env->eip + next_eip_addend;
4330493a03SClaudio Fontana env->regs[11] = cpu_compute_eflags(env) & ~RF_MASK;
4430493a03SClaudio Fontana
4530493a03SClaudio Fontana code64 = env->hflags & HF_CS64_MASK;
4630493a03SClaudio Fontana
4730493a03SClaudio Fontana env->eflags &= ~(env->fmask | RF_MASK);
4830493a03SClaudio Fontana cpu_load_eflags(env, env->eflags, 0);
4930493a03SClaudio Fontana cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
5030493a03SClaudio Fontana 0, 0xffffffff,
5130493a03SClaudio Fontana DESC_G_MASK | DESC_P_MASK |
5230493a03SClaudio Fontana DESC_S_MASK |
5330493a03SClaudio Fontana DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
5430493a03SClaudio Fontana DESC_L_MASK);
5530493a03SClaudio Fontana cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
5630493a03SClaudio Fontana 0, 0xffffffff,
5730493a03SClaudio Fontana DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
5830493a03SClaudio Fontana DESC_S_MASK |
5930493a03SClaudio Fontana DESC_W_MASK | DESC_A_MASK);
6030493a03SClaudio Fontana if (code64) {
6130493a03SClaudio Fontana env->eip = env->lstar;
6230493a03SClaudio Fontana } else {
6330493a03SClaudio Fontana env->eip = env->cstar;
6430493a03SClaudio Fontana }
6563fd8ef0SPaolo Bonzini } else
6663fd8ef0SPaolo Bonzini #endif
6763fd8ef0SPaolo Bonzini {
6830493a03SClaudio Fontana env->regs[R_ECX] = (uint32_t)(env->eip + next_eip_addend);
6930493a03SClaudio Fontana
7030493a03SClaudio Fontana env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
7130493a03SClaudio Fontana cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
7230493a03SClaudio Fontana 0, 0xffffffff,
7330493a03SClaudio Fontana DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
7430493a03SClaudio Fontana DESC_S_MASK |
7530493a03SClaudio Fontana DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
7630493a03SClaudio Fontana cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
7730493a03SClaudio Fontana 0, 0xffffffff,
7830493a03SClaudio Fontana DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
7930493a03SClaudio Fontana DESC_S_MASK |
8030493a03SClaudio Fontana DESC_W_MASK | DESC_A_MASK);
8130493a03SClaudio Fontana env->eip = (uint32_t)env->star;
8230493a03SClaudio Fontana }
8330493a03SClaudio Fontana }
8430493a03SClaudio Fontana
handle_even_inj(CPUX86State * env,int intno,int is_int,int error_code,int is_hw,int rm)8530493a03SClaudio Fontana void handle_even_inj(CPUX86State *env, int intno, int is_int,
8630493a03SClaudio Fontana int error_code, int is_hw, int rm)
8730493a03SClaudio Fontana {
8830493a03SClaudio Fontana CPUState *cs = env_cpu(env);
8930493a03SClaudio Fontana uint32_t event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
9030493a03SClaudio Fontana control.event_inj));
9130493a03SClaudio Fontana
9230493a03SClaudio Fontana if (!(event_inj & SVM_EVTINJ_VALID)) {
9330493a03SClaudio Fontana int type;
9430493a03SClaudio Fontana
9530493a03SClaudio Fontana if (is_int) {
9630493a03SClaudio Fontana type = SVM_EVTINJ_TYPE_SOFT;
9730493a03SClaudio Fontana } else {
9830493a03SClaudio Fontana type = SVM_EVTINJ_TYPE_EXEPT;
9930493a03SClaudio Fontana }
10030493a03SClaudio Fontana event_inj = intno | type | SVM_EVTINJ_VALID;
10130493a03SClaudio Fontana if (!rm && exception_has_error_code(intno)) {
10230493a03SClaudio Fontana event_inj |= SVM_EVTINJ_VALID_ERR;
10330493a03SClaudio Fontana x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
10430493a03SClaudio Fontana control.event_inj_err),
10530493a03SClaudio Fontana error_code);
10630493a03SClaudio Fontana }
10730493a03SClaudio Fontana x86_stl_phys(cs,
10830493a03SClaudio Fontana env->vm_vmcb + offsetof(struct vmcb, control.event_inj),
10930493a03SClaudio Fontana event_inj);
11030493a03SClaudio Fontana }
11130493a03SClaudio Fontana }
11230493a03SClaudio Fontana
x86_cpu_do_interrupt(CPUState * cs)11330493a03SClaudio Fontana void x86_cpu_do_interrupt(CPUState *cs)
11430493a03SClaudio Fontana {
11530493a03SClaudio Fontana X86CPU *cpu = X86_CPU(cs);
11630493a03SClaudio Fontana CPUX86State *env = &cpu->env;
11730493a03SClaudio Fontana
11830493a03SClaudio Fontana if (cs->exception_index == EXCP_VMEXIT) {
11930493a03SClaudio Fontana assert(env->old_exception == -1);
12030493a03SClaudio Fontana do_vmexit(env);
12130493a03SClaudio Fontana } else {
12230493a03SClaudio Fontana do_interrupt_all(cpu, cs->exception_index,
12330493a03SClaudio Fontana env->exception_is_int,
12430493a03SClaudio Fontana env->error_code,
12530493a03SClaudio Fontana env->exception_next_eip, 0);
12630493a03SClaudio Fontana /* successfully delivered */
12730493a03SClaudio Fontana env->old_exception = -1;
12830493a03SClaudio Fontana }
12930493a03SClaudio Fontana }
130d76b9c6fSRichard Henderson
x86_cpu_exec_halt(CPUState * cpu)131408b2b3dSPeter Maydell bool x86_cpu_exec_halt(CPUState *cpu)
132ec1d32afSPhilippe Mathieu-Daudé {
133ec1d32afSPhilippe Mathieu-Daudé X86CPU *x86_cpu = X86_CPU(cpu);
134*6dd7d8c6SPaolo Bonzini CPUX86State *env = &x86_cpu->env;
135ec1d32afSPhilippe Mathieu-Daudé
136*6dd7d8c6SPaolo Bonzini if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
137ec1d32afSPhilippe Mathieu-Daudé bql_lock();
138ec1d32afSPhilippe Mathieu-Daudé apic_poll_irq(x86_cpu->apic_state);
139ec1d32afSPhilippe Mathieu-Daudé cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
140ec1d32afSPhilippe Mathieu-Daudé bql_unlock();
141ec1d32afSPhilippe Mathieu-Daudé }
142*6dd7d8c6SPaolo Bonzini
143*6dd7d8c6SPaolo Bonzini if (!cpu_has_work(cpu)) {
144*6dd7d8c6SPaolo Bonzini return false;
145*6dd7d8c6SPaolo Bonzini }
146*6dd7d8c6SPaolo Bonzini
147*6dd7d8c6SPaolo Bonzini /* Complete HLT instruction. */
148*6dd7d8c6SPaolo Bonzini if (env->eflags & TF_MASK) {
149*6dd7d8c6SPaolo Bonzini env->dr[6] |= DR6_BS;
150*6dd7d8c6SPaolo Bonzini do_interrupt_all(x86_cpu, EXCP01_DB, 0, 0, env->eip, 0);
151*6dd7d8c6SPaolo Bonzini }
152*6dd7d8c6SPaolo Bonzini return true;
153ec1d32afSPhilippe Mathieu-Daudé }
154ec1d32afSPhilippe Mathieu-Daudé
x86_need_replay_interrupt(int interrupt_request)1556ae75481SPhilippe Mathieu-Daudé bool x86_need_replay_interrupt(int interrupt_request)
1566ae75481SPhilippe Mathieu-Daudé {
1576ae75481SPhilippe Mathieu-Daudé /*
1586ae75481SPhilippe Mathieu-Daudé * CPU_INTERRUPT_POLL is a virtual event which gets converted into a
1596ae75481SPhilippe Mathieu-Daudé * "real" interrupt event later. It does not need to be recorded for
1606ae75481SPhilippe Mathieu-Daudé * replay purposes.
1616ae75481SPhilippe Mathieu-Daudé */
1626ae75481SPhilippe Mathieu-Daudé return !(interrupt_request & CPU_INTERRUPT_POLL);
1636ae75481SPhilippe Mathieu-Daudé }
1646ae75481SPhilippe Mathieu-Daudé
x86_cpu_exec_interrupt(CPUState * cs,int interrupt_request)1650792e6c8SPhilippe Mathieu-Daudé bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
1660792e6c8SPhilippe Mathieu-Daudé {
1670792e6c8SPhilippe Mathieu-Daudé X86CPU *cpu = X86_CPU(cs);
1680792e6c8SPhilippe Mathieu-Daudé CPUX86State *env = &cpu->env;
1690792e6c8SPhilippe Mathieu-Daudé int intno;
1700792e6c8SPhilippe Mathieu-Daudé
1710792e6c8SPhilippe Mathieu-Daudé interrupt_request = x86_cpu_pending_interrupt(cs, interrupt_request);
1720792e6c8SPhilippe Mathieu-Daudé if (!interrupt_request) {
1730792e6c8SPhilippe Mathieu-Daudé return false;
1740792e6c8SPhilippe Mathieu-Daudé }
1750792e6c8SPhilippe Mathieu-Daudé
1760792e6c8SPhilippe Mathieu-Daudé /* Don't process multiple interrupt requests in a single call.
1770792e6c8SPhilippe Mathieu-Daudé * This is required to make icount-driven execution deterministic.
1780792e6c8SPhilippe Mathieu-Daudé */
1790792e6c8SPhilippe Mathieu-Daudé switch (interrupt_request) {
1800792e6c8SPhilippe Mathieu-Daudé case CPU_INTERRUPT_POLL:
1810792e6c8SPhilippe Mathieu-Daudé cs->interrupt_request &= ~CPU_INTERRUPT_POLL;
1820792e6c8SPhilippe Mathieu-Daudé apic_poll_irq(cpu->apic_state);
1830792e6c8SPhilippe Mathieu-Daudé break;
1840792e6c8SPhilippe Mathieu-Daudé case CPU_INTERRUPT_SIPI:
1850792e6c8SPhilippe Mathieu-Daudé do_cpu_sipi(cpu);
1860792e6c8SPhilippe Mathieu-Daudé break;
1870792e6c8SPhilippe Mathieu-Daudé case CPU_INTERRUPT_SMI:
1880792e6c8SPhilippe Mathieu-Daudé cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0, 0);
1890792e6c8SPhilippe Mathieu-Daudé cs->interrupt_request &= ~CPU_INTERRUPT_SMI;
1900792e6c8SPhilippe Mathieu-Daudé do_smm_enter(cpu);
1910792e6c8SPhilippe Mathieu-Daudé break;
1920792e6c8SPhilippe Mathieu-Daudé case CPU_INTERRUPT_NMI:
1930792e6c8SPhilippe Mathieu-Daudé cpu_svm_check_intercept_param(env, SVM_EXIT_NMI, 0, 0);
1940792e6c8SPhilippe Mathieu-Daudé cs->interrupt_request &= ~CPU_INTERRUPT_NMI;
1950792e6c8SPhilippe Mathieu-Daudé env->hflags2 |= HF2_NMI_MASK;
1960792e6c8SPhilippe Mathieu-Daudé do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
1970792e6c8SPhilippe Mathieu-Daudé break;
1980792e6c8SPhilippe Mathieu-Daudé case CPU_INTERRUPT_MCE:
1990792e6c8SPhilippe Mathieu-Daudé cs->interrupt_request &= ~CPU_INTERRUPT_MCE;
2000792e6c8SPhilippe Mathieu-Daudé do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
2010792e6c8SPhilippe Mathieu-Daudé break;
2020792e6c8SPhilippe Mathieu-Daudé case CPU_INTERRUPT_HARD:
2030792e6c8SPhilippe Mathieu-Daudé cpu_svm_check_intercept_param(env, SVM_EXIT_INTR, 0, 0);
2040792e6c8SPhilippe Mathieu-Daudé cs->interrupt_request &= ~(CPU_INTERRUPT_HARD |
2050792e6c8SPhilippe Mathieu-Daudé CPU_INTERRUPT_VIRQ);
2060792e6c8SPhilippe Mathieu-Daudé intno = cpu_get_pic_interrupt(env);
207346cd004SAlex Bennée qemu_log_mask(CPU_LOG_INT,
2080792e6c8SPhilippe Mathieu-Daudé "Servicing hardware INT=0x%02x\n", intno);
2090792e6c8SPhilippe Mathieu-Daudé do_interrupt_x86_hardirq(env, intno, 1);
2100792e6c8SPhilippe Mathieu-Daudé break;
2110792e6c8SPhilippe Mathieu-Daudé case CPU_INTERRUPT_VIRQ:
2120792e6c8SPhilippe Mathieu-Daudé cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR, 0, 0);
2130792e6c8SPhilippe Mathieu-Daudé intno = x86_ldl_phys(cs, env->vm_vmcb
2140792e6c8SPhilippe Mathieu-Daudé + offsetof(struct vmcb, control.int_vector));
215346cd004SAlex Bennée qemu_log_mask(CPU_LOG_INT,
2160792e6c8SPhilippe Mathieu-Daudé "Servicing virtual hardware INT=0x%02x\n", intno);
2170792e6c8SPhilippe Mathieu-Daudé do_interrupt_x86_hardirq(env, intno, 1);
2180792e6c8SPhilippe Mathieu-Daudé cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
2190792e6c8SPhilippe Mathieu-Daudé env->int_ctl &= ~V_IRQ_MASK;
2200792e6c8SPhilippe Mathieu-Daudé break;
2210792e6c8SPhilippe Mathieu-Daudé }
2220792e6c8SPhilippe Mathieu-Daudé
2230792e6c8SPhilippe Mathieu-Daudé /* Ensure that no TB jump will be modified as the program flow was changed. */
2240792e6c8SPhilippe Mathieu-Daudé return true;
2250792e6c8SPhilippe Mathieu-Daudé }
2260792e6c8SPhilippe Mathieu-Daudé
227d76b9c6fSRichard Henderson /* check if Port I/O is allowed in TSS */
helper_check_io(CPUX86State * env,uint32_t addr,uint32_t size)228d76b9c6fSRichard Henderson void helper_check_io(CPUX86State *env, uint32_t addr, uint32_t size)
229d76b9c6fSRichard Henderson {
230d76b9c6fSRichard Henderson uintptr_t retaddr = GETPC();
231d76b9c6fSRichard Henderson uint32_t io_offset, val, mask;
232d76b9c6fSRichard Henderson
233d76b9c6fSRichard Henderson /* TSS must be a valid 32 bit one */
234d76b9c6fSRichard Henderson if (!(env->tr.flags & DESC_P_MASK) ||
235d76b9c6fSRichard Henderson ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
236d76b9c6fSRichard Henderson env->tr.limit < 103) {
237d76b9c6fSRichard Henderson goto fail;
238d76b9c6fSRichard Henderson }
239d76b9c6fSRichard Henderson io_offset = cpu_lduw_kernel_ra(env, env->tr.base + 0x66, retaddr);
240d76b9c6fSRichard Henderson io_offset += (addr >> 3);
241d76b9c6fSRichard Henderson /* Note: the check needs two bytes */
242d76b9c6fSRichard Henderson if ((io_offset + 1) > env->tr.limit) {
243d76b9c6fSRichard Henderson goto fail;
244d76b9c6fSRichard Henderson }
245d76b9c6fSRichard Henderson val = cpu_lduw_kernel_ra(env, env->tr.base + io_offset, retaddr);
246d76b9c6fSRichard Henderson val >>= (addr & 7);
247d76b9c6fSRichard Henderson mask = (1 << size) - 1;
248d76b9c6fSRichard Henderson /* all bits must be zero to allow the I/O */
249d76b9c6fSRichard Henderson if ((val & mask) != 0) {
250d76b9c6fSRichard Henderson fail:
251d76b9c6fSRichard Henderson raise_exception_err_ra(env, EXCP0D_GPF, 0, retaddr);
252d76b9c6fSRichard Henderson }
253d76b9c6fSRichard Henderson }
254