uint8_t *ptr;
type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+#ifdef DEBUG_PCALL
+ if (loglevel)
+ fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
+#endif
/* if task gate, we read the TSS segment and we load it */
if (type == 5) {
/* load all registers without an exception, then reload them with
possible exception */
env->eip = new_eip;
- eflags_mask = FL_UPDATE_CPL0_MASK;
+ eflags_mask = TF_MASK | AC_MASK | ID_MASK |
+ IF_MASK | IOPL_MASK | VM_MASK | RF_MASK;
if (!(type & 8))
eflags_mask &= 0xffff;
load_eflags(new_eflags, eflags_mask);
uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
uint32_t old_eip;
-#ifdef DEBUG_PCALL
- if (loglevel) {
- static int count;
- fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d CS:IP=%04x:%08x CPL=%d\n",
- count, intno, error_code, is_int, env->segs[R_CS].selector, env->eip, env->hflags & 3);
-#if 0
- {
- int i;
- uint8_t *ptr;
- printf(" code=");
- ptr = env->segs[R_CS].base + env->eip;
- for(i = 0; i < 16; i++) {
- printf(" %02x", ldub(ptr + i));
- }
- printf("\n");
- }
-#endif
- count++;
- }
-#endif
-
has_error_code = 0;
if (!is_int && !is_hw) {
switch(intno) {
ssp = get_seg_base(ss_e1, ss_e2);
} else if ((e2 & DESC_C_MASK) || dpl == cpl) {
/* to same priviledge */
+ if (env->eflags & VM_MASK)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
new_stack = 0;
sp_mask = get_sp_mask(env->segs[R_SS].flags);
ssp = env->segs[R_SS].base;
esp = ESP;
+ dpl = cpl;
} else {
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
new_stack = 0; /* avoid warning */
else
old_eip = env->eip;
if (shift == 1) {
- if (env->eflags & VM_MASK) {
- 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);
- PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
- }
if (new_stack) {
+ if (env->eflags & VM_MASK) {
+ 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);
+ PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
+ }
PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
PUSHL(ssp, esp, sp_mask, ESP);
}
}
} else {
if (new_stack) {
+ if (env->eflags & VM_MASK) {
+ 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);
+ PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
+ }
PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
PUSHW(ssp, esp, sp_mask, ESP);
}
}
if (new_stack) {
+ if (env->eflags & VM_MASK) {
+ /* XXX: explain me why W2K hangs if the whole segment cache is
+ reset ? */
+ env->segs[R_ES].selector = 0;
+ env->segs[R_ES].flags = 0;
+ env->segs[R_DS].selector = 0;
+ env->segs[R_DS].flags = 0;
+ env->segs[R_FS].selector = 0;
+ env->segs[R_FS].flags = 0;
+ env->segs[R_GS].selector = 0;
+ env->segs[R_GS].flags = 0;
+ }
ss = (ss & ~3) | dpl;
cpu_x86_load_seg_cache(env, R_SS, ss,
ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
/* real mode interrupt */
static void do_interrupt_real(int intno, int is_int, int error_code,
- unsigned int next_eip)
+ unsigned int next_eip)
{
SegmentCache *dt;
uint8_t *ptr, *ssp;
void do_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip, int is_hw)
{
+#if 0
+ {
+ extern FILE *stdout;
+ static int count;
+ if ((env->cr[0] && CR0_PE_MASK)) {
+ fprintf(stdout, "%d: interrupt: vector=%02x error_code=%04x int=%d CPL=%d CS:EIP=%04x:%08x SS:ESP=%04x:%08x EAX=%08x\n",
+ count, intno, error_code, is_int,
+ env->hflags & HF_CPL_MASK,
+ env->segs[R_CS].selector, EIP,
+ env->segs[R_SS].selector, ESP,
+ EAX);
+ if (0) {
+ cpu_x86_dump_state(env, stdout, X86_DUMP_CCOP);
+#if 0
+ {
+ int i;
+ uint8_t *ptr;
+ fprintf(stdout, " code=");
+ ptr = env->segs[R_CS].base + env->eip;
+ for(i = 0; i < 16; i++) {
+ fprintf(stdout, " %02x", ldub(ptr + i));
+ }
+ fprintf(stdout, "\n");
+ }
+#endif
+ }
+ count++;
+ }
+ }
+#endif
+
+#ifdef DEBUG_PCALL
+ if (loglevel) {
+ static int count;
+ fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d\n",
+ count, intno, error_code, is_int);
+ cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
+#if 0
+ {
+ int i;
+ uint8_t *ptr;
+ fprintf(logfile, " code=");
+ ptr = env->segs[R_CS].base + env->eip;
+ for(i = 0; i < 16; i++) {
+ fprintf(logfile, " %02x", ldub(ptr + i));
+ }
+ fprintf(logfile, "\n");
+ }
+#endif
+ count++;
+ }
+#endif
if (env->cr[0] & CR0_PE_MASK) {
do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
} else {
CC_SRC = eflags;
}
-/* We simulate a pre-MMX pentium as in valgrind */
#define CPUID_FP87 (1 << 0)
#define CPUID_VME (1 << 1)
#define CPUID_DE (1 << 2)
void helper_cpuid(void)
{
- if (EAX == 0) {
- EAX = 1; /* max EAX index supported */
+ switch(EAX) {
+ case 0:
+ EAX = 2; /* max EAX index supported */
EBX = 0x756e6547;
ECX = 0x6c65746e;
EDX = 0x49656e69;
- } else if (EAX == 1) {
- int family, model, stepping;
- /* EAX = 1 info */
+ break;
+ case 1:
+ {
+ int family, model, stepping;
+ /* EAX = 1 info */
#if 0
- /* pentium 75-200 */
- family = 5;
- model = 2;
- stepping = 11;
+ /* pentium 75-200 */
+ family = 5;
+ model = 2;
+ stepping = 11;
#else
- /* pentium pro */
- family = 6;
- model = 1;
- stepping = 3;
+ /* pentium pro */
+ family = 6;
+ model = 1;
+ stepping = 3;
#endif
- EAX = (family << 8) | (model << 4) | stepping;
+ EAX = (family << 8) | (model << 4) | stepping;
+ EBX = 0;
+ ECX = 0;
+ EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
+ CPUID_TSC | CPUID_MSR | CPUID_MCE |
+ CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
+ }
+ break;
+ default:
+ /* cache info: needed for Pentium Pro compatibility */
+ EAX = 0x410601;
EBX = 0;
ECX = 0;
- EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
- CPUID_TSC | CPUID_MSR | CPUID_MCE |
- CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
+ EDX = 0;
+ break;
}
}
if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
load_seg_cache_raw_dt(&env->tr, e1, e2);
- e2 |= 0x00000200; /* set the busy bit */
+ e2 |= DESC_TSS_BUSY_MASK;
stl_kernel(ptr + 4, e2);
}
env->tr.selector = selector;
}
/* only works if protected mode and not VM86. seg_reg must be != R_CS */
-void load_seg(int seg_reg, int selector, unsigned int cur_eip)
+void load_seg(int seg_reg, int selector)
{
uint32_t e1, e2;
int cpl, dpl, rpl;
int index;
uint8_t *ptr;
+ selector &= 0xffff;
if ((selector & 0xfffc) == 0) {
/* null selector case */
- if (seg_reg == R_SS) {
- EIP = cur_eip;
+ if (seg_reg == R_SS)
raise_exception_err(EXCP0D_GPF, 0);
- } else {
- cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
- }
+ cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
} else {
if (selector & 0x4)
else
dt = &env->gdt;
index = selector & ~7;
- if ((index + 7) > dt->limit) {
- EIP = cur_eip;
+ if ((index + 7) > dt->limit)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- }
ptr = dt->base + index;
e1 = ldl_kernel(ptr);
e2 = ldl_kernel(ptr + 4);
- if (!(e2 & DESC_S_MASK)) {
- EIP = cur_eip;
+ if (!(e2 & DESC_S_MASK))
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- }
rpl = selector & 3;
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
cpl = env->hflags & HF_CPL_MASK;
if (seg_reg == R_SS) {
/* must be writable segment */
- if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) {
- EIP = cur_eip;
+ if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- }
- if (rpl != cpl || dpl != cpl) {
- EIP = cur_eip;
+ if (rpl != cpl || dpl != cpl)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- }
} else {
/* must be readable segment */
- if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
- EIP = cur_eip;
+ if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- }
if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
/* if not conforming code, test rights */
- if (dpl < cpl || dpl < rpl) {
- EIP = cur_eip;
+ if (dpl < cpl || dpl < rpl)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- }
}
}
if (!(e2 & DESC_P_MASK)) {
- EIP = cur_eip;
if (seg_reg == R_SS)
raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
else
if (loglevel) {
fprintf(logfile, "lcall %04x:%08x\n",
new_cs, new_eip);
+ cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
}
#endif
if ((new_cs & 0xfffc) == 0)
POPW(ssp, sp, sp_mask, new_cs);
POPW(ssp, sp, sp_mask, new_eflags);
}
- ESP = (ESP & ~sp_mask) | (sp & 0xffff);
+ ESP = (ESP & ~sp_mask) | (sp & sp_mask);
load_seg_vm(R_CS, new_cs);
env->eip = new_eip;
if (env->eflags & VM_MASK)
- eflags_mask = FL_UPDATE_MASK32 | IF_MASK | RF_MASK;
+ eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK;
else
- eflags_mask = FL_UPDATE_CPL0_MASK;
+ eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK;
if (shift == 0)
eflags_mask &= 0xffff;
load_eflags(new_eflags, eflags_mask);
}
+static inline void validate_seg(int seg_reg, int cpl)
+{
+ int dpl;
+ uint32_t e2;
+
+ e2 = env->segs[seg_reg].flags;
+ dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+ if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
+ /* data or non conforming code segment */
+ if (dpl < cpl) {
+ cpu_x86_load_seg_cache(env, seg_reg, 0, NULL, 0, 0);
+ }
+ }
+}
+
/* protected mode iret */
static inline void helper_ret_protected(int shift, int is_iret, int addend)
{
uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss, sp_mask;
uint32_t new_es, new_ds, new_fs, new_gs;
uint32_t e1, e2, ss_e1, ss_e2;
- int cpl, dpl, rpl, eflags_mask;
+ int cpl, dpl, rpl, eflags_mask, iopl;
uint8_t *ssp;
sp_mask = get_sp_mask(env->segs[R_SS].flags);
}
#ifdef DEBUG_PCALL
if (loglevel) {
- fprintf(logfile, "lret new %04x:%08x\n",
- new_cs, new_eip);
+ fprintf(logfile, "lret new %04x:%08x addend=0x%x\n",
+ new_cs, new_eip, addend);
+ cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
}
#endif
if ((new_cs & 0xfffc) == 0)
cpu_x86_set_cpl(env, rpl);
sp = new_esp;
/* XXX: change sp_mask according to old segment ? */
+
+ /* validate data segments */
+ validate_seg(R_ES, cpl);
+ validate_seg(R_DS, cpl);
+ validate_seg(R_FS, cpl);
+ validate_seg(R_GS, cpl);
}
ESP = (ESP & ~sp_mask) | (sp & sp_mask);
env->eip = new_eip;
if (is_iret) {
- /* NOTE: 'cpl' can be different from the current CPL */
+ /* NOTE: 'cpl' is the _old_ CPL */
+ eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK;
if (cpl == 0)
- eflags_mask = FL_UPDATE_CPL0_MASK;
- else
- eflags_mask = FL_UPDATE_MASK32;
+ eflags_mask |= IOPL_MASK;
+ iopl = (env->eflags >> IOPL_SHIFT) & 3;
+ if (cpl <= iopl)
+ eflags_mask |= IF_MASK;
if (shift == 0)
eflags_mask &= 0xffff;
load_eflags(new_eflags, eflags_mask);
POPL(ssp, sp, sp_mask, new_gs);
/* modify processor state */
- load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK);
+ load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
+ IF_MASK | IOPL_MASK | VM_MASK | VIF_MASK | VIP_MASK);
load_seg_vm(R_CS, new_cs & 0xffff);
cpu_x86_set_cpl(env, 3);
load_seg_vm(R_SS, new_ss & 0xffff);
generated code */
saved_env = env;
env = cpu_single_env;
- if (is_write && page_unprotect(addr)) {
- /* nothing more to do: the page was write protected because
- there was code in it. page_unprotect() flushed the code. */
- }
ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
if (ret) {