#include "cpu.h"
#include "qemu/log.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/cpu_ldst.h"
//#define DEBUG_PCALL
-#if !defined(CONFIG_USER_ONLY)
-#include "exec/softmmu_exec.h"
-#endif /* !defined(CONFIG_USER_ONLY) */
-
#ifdef DEBUG_PCALL
# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
-# define LOG_PCALL_STATE(env) \
- log_cpu_state_mask(CPU_LOG_PCALL, (env), CPU_DUMP_CCOP)
+# define LOG_PCALL_STATE(cpu) \
+ log_cpu_state_mask(CPU_LOG_PCALL, (cpu), CPU_DUMP_CCOP)
#else
# define LOG_PCALL(...) do { } while (0)
-# define LOG_PCALL_STATE(env) do { } while (0)
+# define LOG_PCALL_STATE(cpu) do { } while (0)
+#endif
+
+#ifndef CONFIG_USER_ONLY
+#define CPU_MMU_INDEX (cpu_mmu_index_kernel(env))
+#define MEMSUFFIX _kernel
+#define DATA_SIZE 1
+#include "exec/cpu_ldst_template.h"
+
+#define DATA_SIZE 2
+#include "exec/cpu_ldst_template.h"
+
+#define DATA_SIZE 4
+#include "exec/cpu_ldst_template.h"
+
+#define DATA_SIZE 8
+#include "exec/cpu_ldst_template.h"
+#undef CPU_MMU_INDEX
+#undef MEMSUFFIX
#endif
/* return non zero if error */
static inline void load_seg_vm(CPUX86State *env, int seg, int selector)
{
selector &= 0xffff;
- cpu_x86_load_seg_cache(env, seg, selector,
- (selector << 4), 0xffff, 0);
+
+ cpu_x86_load_seg_cache(env, seg, selector, (selector << 4), 0xffff,
+ DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+ DESC_A_MASK | (3 << DESC_DPL_SHIFT));
}
static inline void get_ss_esp_from_tss(CPUX86State *env, uint32_t *ss_ptr,
uint32_t *esp_ptr, int dpl)
{
+ X86CPU *cpu = x86_env_get_cpu(env);
int type, index, shift;
#if 0
#endif
if (!(env->tr.flags & DESC_P_MASK)) {
- cpu_abort(env, "invalid tss");
+ cpu_abort(CPU(cpu), "invalid tss");
}
type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
if ((type & 7) != 1) {
- cpu_abort(env, "invalid tss type");
+ cpu_abort(CPU(cpu), "invalid tss type");
}
shift = type >> 3;
index = (dpl * 4 + 2) << shift;
}
}
-/* XXX: merge with load_seg() */
-static void tss_load_seg(CPUX86State *env, int seg_reg, int selector)
+static void tss_load_seg(CPUX86State *env, int seg_reg, int selector, int cpl)
{
uint32_t e1, e2;
- int rpl, dpl, cpl;
+ int rpl, dpl;
if ((selector & 0xfffc) != 0) {
if (load_segment(env, &e1, &e2, selector) != 0) {
}
rpl = selector & 3;
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- cpl = env->hflags & HF_CPL_MASK;
if (seg_reg == R_CS) {
if (!(e2 & DESC_CS_MASK)) {
raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc);
}
- /* XXX: is it correct? */
if (dpl != rpl) {
raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc);
}
- if ((e2 & DESC_C_MASK) && dpl > rpl) {
- raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc);
- }
} else if (seg_reg == R_SS) {
/* SS must be writable data */
if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) {
for (i = 0; i < 6; i++) {
load_seg_vm(env, i, new_segs[i]);
}
- /* in vm86, CPL is always 3 */
- cpu_x86_set_cpl(env, 3);
} else {
- /* CPL is set the RPL of CS */
- cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
/* first just selectors as the rest may trigger exceptions */
for (i = 0; i < 6; i++) {
cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
/* load the segments */
if (!(new_eflags & VM_MASK)) {
- tss_load_seg(env, R_CS, new_segs[R_CS]);
- tss_load_seg(env, R_SS, new_segs[R_SS]);
- tss_load_seg(env, R_ES, new_segs[R_ES]);
- tss_load_seg(env, R_DS, new_segs[R_DS]);
- tss_load_seg(env, R_FS, new_segs[R_FS]);
- tss_load_seg(env, R_GS, new_segs[R_GS]);
+ int cpl = new_segs[R_CS] & 3;
+ tss_load_seg(env, R_CS, new_segs[R_CS], cpl);
+ tss_load_seg(env, R_SS, new_segs[R_SS], cpl);
+ tss_load_seg(env, R_ES, new_segs[R_ES], cpl);
+ tss_load_seg(env, R_DS, new_segs[R_DS], cpl);
+ tss_load_seg(env, R_FS, new_segs[R_FS], cpl);
+ tss_load_seg(env, R_GS, new_segs[R_GS], cpl);
}
/* check that env->eip is in the CS segment limits */
int has_error_code, new_stack, shift;
uint32_t e1, e2, offset, ss = 0, esp, ss_e1 = 0, ss_e2 = 0;
uint32_t old_eip, sp_mask;
+ int vm86 = env->eflags & VM_MASK;
has_error_code = 0;
if (!is_int && !is_hw) {
ssp = get_seg_base(ss_e1, ss_e2);
} else if ((e2 & DESC_C_MASK) || dpl == cpl) {
/* to same privilege */
- if (env->eflags & VM_MASK) {
+ if (vm86) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc);
}
new_stack = 0;
#if 0
/* XXX: check that enough room is available */
push_size = 6 + (new_stack << 2) + (has_error_code << 1);
- if (env->eflags & VM_MASK) {
+ if (vm86) {
push_size += 8;
}
push_size <<= shift;
#endif
if (shift == 1) {
if (new_stack) {
- if (env->eflags & VM_MASK) {
+ if (vm86) {
PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
}
} else {
if (new_stack) {
- if (env->eflags & VM_MASK) {
+ if (vm86) {
PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
}
}
+ /* interrupt gate clear IF mask */
+ if ((type & 1) == 0) {
+ env->eflags &= ~IF_MASK;
+ }
+ env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
+
if (new_stack) {
- if (env->eflags & VM_MASK) {
+ if (vm86) {
cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
get_seg_base(e1, e2),
get_seg_limit(e1, e2),
e2);
- cpu_x86_set_cpl(env, dpl);
env->eip = offset;
-
- /* interrupt gate clear IF mask */
- if ((type & 1) == 0) {
- env->eflags &= ~IF_MASK;
- }
- env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
}
#ifdef TARGET_X86_64
static inline target_ulong get_rsp_from_tss(CPUX86State *env, int level)
{
+ X86CPU *cpu = x86_env_get_cpu(env);
int index;
#if 0
#endif
if (!(env->tr.flags & DESC_P_MASK)) {
- cpu_abort(env, "invalid tss");
+ cpu_abort(CPU(cpu), "invalid tss");
}
index = 8 * level + 4;
if ((index + 7) > env->tr.limit) {
PUSHQ(esp, error_code);
}
+ /* interrupt gate clear IF mask */
+ if ((type & 1) == 0) {
+ env->eflags &= ~IF_MASK;
+ }
+ env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
+
if (new_stack) {
ss = 0 | dpl;
cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
get_seg_base(e1, e2),
get_seg_limit(e1, e2),
e2);
- cpu_x86_set_cpl(env, dpl);
env->eip = offset;
-
- /* interrupt gate clear IF mask */
- if ((type & 1) == 0) {
- env->eflags &= ~IF_MASK;
- }
- env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
}
#endif
#if defined(CONFIG_USER_ONLY)
void helper_syscall(CPUX86State *env, int next_eip_addend)
{
- env->exception_index = EXCP_SYSCALL;
+ CPUState *cs = CPU(x86_env_get_cpu(env));
+
+ cs->exception_index = EXCP_SYSCALL;
env->exception_next_eip = env->eip + next_eip_addend;
- cpu_loop_exit(env);
+ cpu_loop_exit(cs);
}
#else
void helper_syscall(CPUX86State *env, int next_eip_addend)
code64 = env->hflags & HF_CS64_MASK;
- cpu_x86_set_cpl(env, 0);
+ env->eflags &= ~env->fmask;
+ cpu_load_eflags(env, env->eflags, 0);
cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
0, 0xffffffff,
DESC_G_MASK | DESC_P_MASK |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK |
DESC_W_MASK | DESC_A_MASK);
- env->eflags &= ~env->fmask;
- cpu_load_eflags(env, env->eflags, 0);
if (code64) {
env->eip = env->lstar;
} else {
} else {
env->regs[R_ECX] = (uint32_t)(env->eip + next_eip_addend);
- cpu_x86_set_cpl(env, 0);
+ env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
0, 0xffffffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK |
DESC_W_MASK | DESC_A_MASK);
- env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
env->eip = (uint32_t)env->star;
}
}
}
selector = (env->star >> 48) & 0xffff;
if (env->hflags & HF_LMA_MASK) {
+ cpu_load_eflags(env, (uint32_t)(env->regs[11]), TF_MASK | AC_MASK
+ | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK |
+ NT_MASK);
if (dflag == 2) {
cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
0, 0xffffffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
DESC_W_MASK | DESC_A_MASK);
- cpu_load_eflags(env, (uint32_t)(env->regs[11]), TF_MASK | AC_MASK
- | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK |
- NT_MASK);
- cpu_x86_set_cpl(env, 3);
} else {
+ env->eflags |= IF_MASK;
cpu_x86_load_seg_cache(env, R_CS, selector | 3,
0, 0xffffffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
DESC_W_MASK | DESC_A_MASK);
- env->eflags |= IF_MASK;
- cpu_x86_set_cpl(env, 3);
}
}
#endif
static void handle_even_inj(CPUX86State *env, int intno, int is_int,
int error_code, int is_hw, int rm)
{
- uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb,
+ CPUState *cs = CPU(x86_env_get_cpu(env));
+ uint32_t event_inj = ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
control.event_inj));
if (!(event_inj & SVM_EVTINJ_VALID)) {
event_inj = intno | type | SVM_EVTINJ_VALID;
if (!rm && exception_has_error_code(intno)) {
event_inj |= SVM_EVTINJ_VALID_ERR;
- stl_phys(env->vm_vmcb + offsetof(struct vmcb,
+ stl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
control.event_inj_err),
error_code);
}
- stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj),
+ stl_phys(cs->as,
+ env->vm_vmcb + offsetof(struct vmcb, control.event_inj),
event_inj);
}
}
* the int instruction. next_eip is the env->eip value AFTER the interrupt
* instruction. It is only relevant if is_int is TRUE.
*/
-static void do_interrupt_all(CPUX86State *env, int intno, int is_int,
+static void do_interrupt_all(X86CPU *cpu, int intno, int is_int,
int error_code, target_ulong next_eip, int is_hw)
{
+ CPUX86State *env = &cpu->env;
+
if (qemu_loglevel_mask(CPU_LOG_INT)) {
if ((env->cr[0] & CR0_PE_MASK)) {
static int count;
qemu_log(" env->regs[R_EAX]=" TARGET_FMT_lx, env->regs[R_EAX]);
}
qemu_log("\n");
- log_cpu_state(env, CPU_DUMP_CCOP);
+ log_cpu_state(CPU(cpu), CPU_DUMP_CCOP);
#if 0
{
int i;
#if !defined(CONFIG_USER_ONLY)
if (env->hflags & HF_SVMI_MASK) {
- uint32_t event_inj = ldl_phys(env->vm_vmcb +
+ CPUState *cs = CPU(cpu);
+ uint32_t event_inj = ldl_phys(cs->as, env->vm_vmcb +
offsetof(struct vmcb,
control.event_inj));
- stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj),
+ stl_phys(cs->as,
+ env->vm_vmcb + offsetof(struct vmcb, control.event_inj),
event_inj & ~SVM_EVTINJ_VALID);
}
#endif
/* if user mode only, we simulate a fake exception
which will be handled outside the cpu execution
loop */
- do_interrupt_user(env, env->exception_index,
+ do_interrupt_user(env, cs->exception_index,
env->exception_is_int,
env->error_code,
env->exception_next_eip);
/* simulate a real cpu exception. On i386, it can
trigger new exceptions, but we do not handle
double or triple faults yet. */
- do_interrupt_all(env, env->exception_index,
+ do_interrupt_all(cpu, cs->exception_index,
env->exception_is_int,
env->error_code,
env->exception_next_eip, 0);
void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw)
{
- do_interrupt_all(env, intno, 0, 0, 0, is_hw);
+ do_interrupt_all(x86_env_get_cpu(env), intno, 0, 0, 0, is_hw);
}
void helper_enter_level(CPUX86State *env, int level, int data32,
}
next_eip = env->eip + next_eip_addend;
switch_tss(env, new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
- CC_OP = CC_OP_EFLAGS;
break;
case 4: /* 286 call gate */
case 12: /* 386 call gate */
next_eip = env->eip + next_eip_addend;
LOG_PCALL("lcall %04x:%08x s=%d\n", new_cs, (uint32_t)new_eip, shift);
- LOG_PCALL_STATE(env);
+ LOG_PCALL_STATE(CPU(x86_env_get_cpu(env)));
if ((new_cs & 0xfffc) == 0) {
raise_exception_err(env, EXCP0D_GPF, 0);
}
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc);
}
switch_tss(env, new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
- CC_OP = CC_OP_EFLAGS;
return;
case 4: /* 286 call gate */
case 12: /* 386 call gate */
get_seg_base(e1, e2),
get_seg_limit(e1, e2),
e2);
- cpu_x86_set_cpl(env, dpl);
SET_ESP(sp, sp_mask);
env->eip = offset;
}
}
LOG_PCALL("lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
new_cs, new_eip, shift, addend);
- LOG_PCALL_STATE(env);
+ LOG_PCALL_STATE(CPU(x86_env_get_cpu(env)));
if ((new_cs & 0xfffc) == 0) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc);
}
get_seg_base(e1, e2),
get_seg_limit(e1, e2),
e2);
- cpu_x86_set_cpl(env, rpl);
sp = new_esp;
#ifdef TARGET_X86_64
if (env->hflags & HF_CS64_MASK) {
IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK |
VIP_MASK);
load_seg_vm(env, R_CS, new_cs & 0xffff);
- cpu_x86_set_cpl(env, 3);
load_seg_vm(env, R_SS, new_ss & 0xffff);
load_seg_vm(env, R_ES, new_es & 0xffff);
load_seg_vm(env, R_DS, new_ds & 0xffff);
raise_exception_err(env, EXCP0D_GPF, 0);
}
env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
- cpu_x86_set_cpl(env, 0);
#ifdef TARGET_X86_64
if (env->hflags & HF_LMA_MASK) {
if (env->sysenter_cs == 0 || cpl != 0) {
raise_exception_err(env, EXCP0D_GPF, 0);
}
- cpu_x86_set_cpl(env, 3);
#ifdef TARGET_X86_64
if (dflag == 2) {
cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) |
void cpu_x86_load_seg(CPUX86State *env, int seg_reg, int selector)
{
if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
+ int dpl = (env->eflags & VM_MASK) ? 3 : 0;
selector &= 0xffff;
cpu_x86_load_seg_cache(env, seg_reg, selector,
- (selector << 4), 0xffff, 0);
+ (selector << 4), 0xffff,
+ DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+ DESC_A_MASK | (dpl << DESC_DPL_SHIFT));
} else {
helper_load_seg(env, seg_reg, selector);
}
}
#endif
+
+/* check if Port I/O is allowed in TSS */
+static inline void check_io(CPUX86State *env, int addr, int size)
+{
+ int io_offset, val, mask;
+
+ /* TSS must be a valid 32 bit one */
+ if (!(env->tr.flags & DESC_P_MASK) ||
+ ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
+ env->tr.limit < 103) {
+ goto fail;
+ }
+ io_offset = cpu_lduw_kernel(env, env->tr.base + 0x66);
+ io_offset += (addr >> 3);
+ /* Note: the check needs two bytes */
+ if ((io_offset + 1) > env->tr.limit) {
+ goto fail;
+ }
+ val = cpu_lduw_kernel(env, env->tr.base + io_offset);
+ val >>= (addr & 7);
+ mask = (1 << size) - 1;
+ /* all bits must be zero to allow the I/O */
+ if ((val & mask) != 0) {
+ fail:
+ raise_exception_err(env, EXCP0D_GPF, 0);
+ }
+}
+
+void helper_check_iob(CPUX86State *env, uint32_t t0)
+{
+ check_io(env, t0, 1);
+}
+
+void helper_check_iow(CPUX86State *env, uint32_t t0)
+{
+ check_io(env, t0, 2);
+}
+
+void helper_check_iol(CPUX86State *env, uint32_t t0)
+{
+ check_io(env, t0, 4);
+}