diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index d53ee8a83..f0d909723 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -36,31 +36,20 @@ #include "386_common.h" -extern FILE *stdlog; +uint8_t opcode2; -/*Controls whether the accessed bit in a descriptor is set when CS is loaded.*/ -#define CS_ACCESSED - -/*Controls whether the accessed bit in a descriptor is set when a data or stack - selector is loaded.*/ -#define SEL_ACCESSED -int stimes = 0; -int dtimes = 0; -int btimes = 0; - -uint32_t abrt_error; int cgate16, cgate32; - -#define breaknullsegs 0 - int intgatesize; +uint32_t abrt_error; + void taskswitch286(uint16_t seg, uint16_t *segdat, int is32); -void taskswitch386(uint16_t seg, uint16_t *segdat); void pmodeint(int num, int soft); -/*NOT PRESENT is INT 0B - GPF is INT 0D*/ + +#define DPL ((segdat[2] >> 13) & 3) +#define DPL2 ((segdat2[2] >> 13) & 3) +#define DPL3 ((segdat3[2] >> 13) & 3) #ifdef ENABLE_X86SEG_LOG @@ -83,2641 +72,2292 @@ x86seg_log(const char *fmt, ...) #endif -void x86abort(const char *fmt, ...) +static void +seg_reset(x86seg *s) { - va_list ap; - - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - - nvr_save(); -#ifdef ENABLE_808X_LOG - dumpregs(1); -#endif - fflush(stdlog); - exit(-1); + s->access = 0x82; + s->ar_high = 0x10; + s->limit = 0xffff; + s->limit_low = 0; + s->limit_high = 0xffff; + if (s == &cpu_state.seg_cs) { + s->base = AT ? (cpu_16bitbus ? 0x00ff0000 : 0xffff0000) : 0x000ffff0; + s->seg = AT ? 0xf000 : 0xffff; + } else { + s->base = 0; + s->seg = 0; + } } -uint8_t opcode2; -static void seg_reset(x86seg *s) +void +x86seg_reset() { - s->access = (0 << 5) | 2 | 0x80; - s->ar_high = 0x10; - s->limit = 0xFFFF; - s->limit_low = 0; - s->limit_high = 0xffff; - if (s == &cpu_state.seg_cs) - { - s->base = AT ? (cpu_16bitbus ? 0xFF0000 : 0xFFFF0000) : 0xFFFF0; - s->seg = AT ? 0xF000 : 0xFFFF; - } - else - { - s->base = 0; - s->seg = 0; - } + seg_reset(&cpu_state.seg_cs); + seg_reset(&cpu_state.seg_ds); + seg_reset(&cpu_state.seg_es); + seg_reset(&cpu_state.seg_fs); + seg_reset(&cpu_state.seg_gs); + seg_reset(&cpu_state.seg_ss); } -void x86seg_reset() -{ - seg_reset(&cpu_state.seg_cs); - seg_reset(&cpu_state.seg_ds); - seg_reset(&cpu_state.seg_es); - seg_reset(&cpu_state.seg_fs); - seg_reset(&cpu_state.seg_gs); - seg_reset(&cpu_state.seg_ss); -} -void x86_doabrt(int x86_abrt) +void +x86_doabrt(int x86_abrt) { #ifndef USE_NEW_DYNAREC - CS = oldcs; + CS = oldcs; #endif - cpu_state.pc = cpu_state.oldpc; - cpu_state.seg_cs.access = (oldcpl << 5) | 0x80; - cpu_state.seg_cs.ar_high = 0x10; + cpu_state.pc = cpu_state.oldpc; + cpu_state.seg_cs.access = (oldcpl << 5) | 0x80; + cpu_state.seg_cs.ar_high = 0x10; - if (msw & 1) - pmodeint(x86_abrt, 0); - else - { - uint32_t addr = (x86_abrt << 2) + idt.base; - if (stack32) - { - writememw(ss,ESP-2,cpu_state.flags); - writememw(ss,ESP-4,CS); - writememw(ss,ESP-6,cpu_state.pc); - ESP-=6; - } - else - { - writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); - writememw(ss,((SP-4)&0xFFFF),CS); - writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); - SP-=6; - } + if (msw & 1) + pmodeint(x86_abrt, 0); + else { + uint32_t addr = (x86_abrt << 2) + idt.base; + if (stack32) { + writememw(ss, ESP - 2, cpu_state.flags); + writememw(ss, ESP - 4, CS); + writememw(ss, ESP - 6, cpu_state.pc); + ESP -= 6; + } else { + writememw(ss, ((SP - 2) & 0xffff), cpu_state.flags); + writememw(ss, ((SP - 4) & 0xffff), CS); + writememw(ss, ((SP - 6) & 0xffff), cpu_state.pc); + SP -= 6; + } - cpu_state.flags &= ~I_FLAG; - cpu_state.flags &= ~T_FLAG; + cpu_state.flags &= ~(I_FLAG | T_FLAG); #ifndef USE_NEW_DYNAREC - oxpc=cpu_state.pc; + oxpc = cpu_state.pc; #endif - cpu_state.pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - return; - } - - if (cpu_state.abrt || x86_was_reset) return; - - if (intgatesize == 16) - { - if (stack32) - { - writememw(ss, ESP-2, abrt_error); - ESP-=2; - } - else - { - writememw(ss, ((SP-2)&0xFFFF), abrt_error); - SP-=2; - } - } - else - { - if (stack32) - { - writememl(ss, ESP-4, abrt_error); - ESP-=4; - } - else - { - writememl(ss, ((SP-4)&0xFFFF), abrt_error); - SP-=4; - } - } + cpu_state.pc = readmemw(0, addr); + loadcs(readmemw(0, addr + 2)); + return; + } + + if (cpu_state.abrt || x86_was_reset) + return; + + if (intgatesize == 16) { + if (stack32) { + writememw(ss, ESP - 2, abrt_error); + ESP -= 2; + } else { + writememw(ss, ((SP - 2) & 0xffff), abrt_error); + SP -= 2; + } + } else { + if (stack32) { + writememl(ss, ESP - 4, abrt_error); + ESP -= 4; + } else { + writememl(ss, ((SP - 4) & 0xffff), abrt_error); + SP -= 4; + } + } } -void x86gpf(char *s, uint16_t error) + + +void +x86gpf(char *s, uint16_t error) { - cpu_state.abrt = ABRT_GPF; - abrt_error = error; + cpu_state.abrt = ABRT_GPF; + abrt_error = error; } -void x86ss(char *s, uint16_t error) + + +void +x86ss(char *s, uint16_t error) { - cpu_state.abrt = ABRT_SS; - abrt_error = error; + cpu_state.abrt = ABRT_SS; + abrt_error = error; } + + void x86ts(char *s, uint16_t error) { - cpu_state.abrt = ABRT_TS; - abrt_error = error; -} -void x86np(char *s, uint16_t error) -{ - cpu_state.abrt = ABRT_NP; - abrt_error = error; + cpu_state.abrt = ABRT_TS; + abrt_error = error; } -static void set_stack32(int s) +void +x86np(char *s, uint16_t error) { - stack32 = s; - if (stack32) - cpu_cur_status |= CPU_STATUS_STACK32; + cpu_state.abrt = ABRT_NP; + abrt_error = error; +} + + +static void +set_stack32(int s) +{ + stack32 = s; + + if (stack32) + cpu_cur_status |= CPU_STATUS_STACK32; + else + cpu_cur_status &= ~CPU_STATUS_STACK32; +} + + +static void +set_use32(int u) +{ + use32 = u ? 0x300 : 0; + + if (u) + cpu_cur_status |= CPU_STATUS_USE32; + else + cpu_cur_status &= ~CPU_STATUS_USE32; +} + + +void +do_seg_load(x86seg *s, uint16_t *segdat) +{ + s->limit = segdat[0] | ((segdat[3] & 0x000f) << 16); + if (segdat[3] & 0x0080) + s->limit = (s->limit << 12) | 0xfff; + s->base = segdat[1] | ((segdat[2] & 0x00ff) << 16); + if (is386) + s->base |= ((segdat[3] >> 8) << 24); + s->access = segdat[2] >> 8; + s->ar_high = segdat[3] & 0xff; + + if (((segdat[2] & 0x1800) != 0x1000) || !(segdat[2] & (1 << 10))) { + /* Expand-down */ + s->limit_high = s->limit; + s->limit_low = 0; + } else { + s->limit_high = (segdat[3] & 0x40) ? 0xffffffff : 0xffff; + s->limit_low = s->limit + 1; + } + + if (s == &cpu_state.seg_ds) { + if ((s->base == 0) && (s->limit_low == 0) && (s->limit_high == 0xffffffff)) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; else - cpu_cur_status &= ~CPU_STATUS_STACK32; + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &cpu_state.seg_ss) { + if ((s->base == 0) && (s->limit_low == 0) && (s->limit_high == 0xffffffff)) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } } -static void set_use32(int u) + +static void +do_seg_v86_init(x86seg *s) { - if (u) - { - use32 = 0x300; - cpu_cur_status |= CPU_STATUS_USE32; - } - else - { - use32 = 0; - cpu_cur_status &= ~CPU_STATUS_USE32; - } + s->access = 0xe2; + s->ar_high = 0x10; + s->limit = 0xffff; + s->limit_low = 0; + s->limit_high = 0xffff; } -void do_seg_load(x86seg *s, uint16_t *segdat) + +static void +check_seg_valid(x86seg *s) { - s->limit = segdat[0] | ((segdat[3] & 0xF) << 16); - if (segdat[3] & 0x80) - s->limit = (s->limit << 12) | 0xFFF; - s->base = segdat[1] | ((segdat[2] & 0xFF) << 16); - if (is386) - s->base |= ((segdat[3] >> 8) << 24); - s->access = segdat[2] >> 8; - s->ar_high = segdat[3] & 0xff; + int dpl = (s->access >> 5) & 3; + int valid = 1; + x86seg *dt = (s->seg & 0x0004) ? &ldt : &gdt; - if ((segdat[2] & 0x1800) != 0x1000 || !(segdat[2] & (1 << 10))) /*expand-down*/ - { - s->limit_high = s->limit; - s->limit_low = 0; - } - else - { - s->limit_high = (segdat[3] & 0x40) ? 0xffffffff : 0xffff; - s->limit_low = s->limit + 1; - } + if (((s->seg & 0xfff8) + 7) >= dt->limit) + valid = 0; - if (s == &cpu_state.seg_ds) - { - if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATDS; - } - if (s == &cpu_state.seg_ss) - { - if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATSS; - } + switch (s->access & 0x1f) { + case 0x10: case 0x11: case 0x12: case 0x13: /* Data segments */ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1a: case 0x1b: /* Readable non-conforming code */ + if (((s->seg & 3) > dpl) || ((CPL) > dpl)) { + valid = 0; + break; + } + break; + + case 0x1e: case 0x1f: /* Readable conforming code */ + break; + + default: + valid = 0; + break; + } + + if (!valid) + loadseg(0, s); } -static void do_seg_v86_init(x86seg *s) + +static void +read_descriptor(uint32_t addr, uint16_t *segdat, uint32_t *segdat32, int override) { - s->access = (3 << 5) | 2 | 0x80; - s->ar_high = 0x10; - s->limit = 0xffff; - s->limit_low = 0; - s->limit_high = 0xffff; + if (override) + cpl_override = 1; + if (cpu_16bitbus) { + segdat[0] = readmemw(0, addr); + segdat[1] = readmemw(0, addr + 2); + segdat[2] = readmemw(0, addr + 4); + segdat[3] = readmemw(0, addr + 6); + } else { + segdat32[0] = readmeml(0, addr); + segdat32[1] = readmeml(0, addr + 4); + } + if (override) + cpl_override = 0; } -static void check_seg_valid(x86seg *s) + +#ifdef USE_NEW_DYNAREC +int +#else +void +#endif +loadseg(uint16_t seg, x86seg *s) { - int dpl = (s->access >> 5) & 3; - int valid = 1; - - if (s->seg & 4) - { - if ((s->seg & ~7) >= ldt.limit) - { - valid = 0; - } - } - else - { - if ((s->seg & ~7) >= gdt.limit) - { - valid = 0; - } - } - - switch (s->access & 0x1f) - { - case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x1A: case 0x1B: /*Readable non-conforming code*/ - if ((s->seg & 3) > dpl || (CPL) > dpl) - { - valid = 0; - break; - } - break; - - case 0x1E: case 0x1F: /*Readable conforming code*/ - break; - - default: - valid = 0; - break; - } - - if (!valid) - loadseg(0, s); -} + uint16_t segdat[4]; + uint32_t addr, *segdat32 = (uint32_t *) segdat; + int dpl; + x86seg *dt; + if ((msw & 1) && !(cpu_state.eflags & VM_FLAG)) { + if (!(seg & 0xfffc)) { + if (s == &cpu_state.seg_ss) { + x86ss(NULL,0); #ifdef USE_NEW_DYNAREC -int loadseg(uint16_t seg, x86seg *s) + return 1; #else -void loadseg(uint16_t seg, x86seg *s) + return; #endif -{ - uint16_t segdat[4]; - uint32_t addr; - int dpl; - - if (msw&1 && !(cpu_state.eflags&VM_FLAG)) - { - if (!(seg&~3)) - { - if (s==&cpu_state.seg_ss) - { - x86ss(NULL,0); -#ifdef USE_NEW_DYNAREC - return 1; -#else - return; -#endif - } - s->seg = 0; - s->access = 0x80; - s->ar_high = 0x10; - s->base=-1; - if (s == &cpu_state.seg_ds) - cpu_cur_status |= CPU_STATUS_NOTFLATDS; -#ifdef USE_NEW_DYNAREC - return 0; -#else - return; -#endif - } - addr=seg&~7; - if (seg&4) - { - if ((addr+7)>ldt.limit) - { - x86gpf("loadseg(): Bigger than LDT limit",seg&~3); -#ifdef USE_NEW_DYNAREC - return 1; -#else - return; -#endif - } - addr+=ldt.base; - } - else - { - if ((addr+7)>gdt.limit) - { - x86gpf("loadseg(): Bigger than GDT limit",seg&~3); -#ifdef USE_NEW_DYNAREC - return 1; -#else - return; -#endif - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); -#ifdef USE_NEW_DYNAREC - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return 1; -#else - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; -#endif - dpl=(segdat[2]>>13)&3; - if (s==&cpu_state.seg_ss) - { - if (!(seg&~3)) - { - x86gpf("loadseg(): Zero stack segment",seg&~3); -#ifdef USE_NEW_DYNAREC - return 1; -#else - return; -#endif - } - if ((seg&3)!=CPL) - { - x86gpf("loadseg(): Stack segment RPL != CPL",seg&~3); -#ifdef USE_NEW_DYNAREC - return 1; -#else - return; -#endif - } - if (dpl!=CPL) - { - x86gpf("loadseg(): Stack segment DPL != CPL",seg&~3); -#ifdef USE_NEW_DYNAREC - return 1; -#else - return; -#endif - } - switch ((segdat[2]>>8)&0x1F) - { - case 0x12: case 0x13: case 0x16: case 0x17: /*r/w*/ - break; - default: - x86gpf("loadseg(): Unknown stack segment type",seg&~3); -#ifdef USE_NEW_DYNAREC - return 1; -#else - return; -#endif - } - if (!(segdat[2]&0x8000)) - { - x86ss(NULL,seg&~3); -#ifdef USE_NEW_DYNAREC - return 1; -#else - return; -#endif - } - set_stack32((segdat[3] & 0x40) ? 1 : 0); - } - else if (s!=&cpu_state.seg_cs) - { - x86seg_log("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); - x86seg_log("Seg type %03X\n",segdat[2]&0x1F00); - switch ((segdat[2]>>8)&0x1F) - { - case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x1A: case 0x1B: /*Readable non-conforming code*/ - if ((seg&3)>dpl) - { - x86gpf("loadseg(): Normal segment RPL > DPL",seg&~3); -#ifdef USE_NEW_DYNAREC - return 1; -#else - return; -#endif - } - if ((CPL)>dpl) - { - x86gpf("loadseg(): Normal segment DPL < CPL",seg&~3); -#ifdef USE_NEW_DYNAREC - return 1; -#else - return; -#endif - } - break; - case 0x1E: case 0x1F: /*Readable conforming code*/ - break; - default: - x86gpf("loadseg(): Unknown normal segment type",seg&~3); -#ifdef USE_NEW_DYNAREC - return 1; -#else - return; -#endif - } - } - - if (!(segdat[2] & 0x8000)) - { - x86np("Load data seg not present", seg & 0xfffc); -#ifdef USE_NEW_DYNAREC - return 1; -#else - return; -#endif - } - s->seg = seg; - do_seg_load(s, segdat); - -#ifndef CS_ACCESSED - if (s != &_cs) - { -#endif -#ifdef SEL_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif -#ifndef CS_ACCESSED - } -#endif - s->checked = 0; -#ifdef USE_DYNAREC - if (s == &cpu_state.seg_ds) - codegen_flat_ds = 0; - if (s == &cpu_state.seg_ss) - codegen_flat_ss = 0; -#endif - } - else - { - s->access = (3 << 5) | 2 | 0x80; + } + s->seg = 0; + s->access = 0x80; s->ar_high = 0x10; - s->base = seg << 4; - s->seg = seg; - s->checked = 1; + s->base = -1; + if (s == &cpu_state.seg_ds) + cpu_cur_status |= CPU_STATUS_NOTFLATDS; +#ifdef USE_NEW_DYNAREC + return 0; +#else + return; +#endif + } + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86gpf("loadseg(): Bigger than LDT limit", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + dpl = (segdat[2] >> 13) & 3; + if (s == &cpu_state.seg_ss) { + if (!(seg & 0xfffc)) { + x86gpf("loadseg(): Zero stack segment", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + if ((seg & 0x0003) != CPL) { + x86gpf("loadseg(): Stack segment RPL != CPL", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + if (dpl != CPL) { + x86gpf("loadseg(): Stack segment DPL != CPL", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + switch ((segdat[2] >> 8) & 0x1f) { + case 0x12: case 0x13: case 0x16: case 0x17: + /* R/W */ + break; + default: + x86gpf("loadseg(): Unknown stack segment type", seg & ~3); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + if (!(segdat[2] & 0x8000)) { + x86ss(NULL, seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + set_stack32((segdat[3] & 0x40) ? 1 : 0); + } else if (s != &cpu_state.seg_cs) { + x86seg_log("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); + x86seg_log("Seg type %03X\n",segdat[2] & 0x1f00); + switch ((segdat[2] >> 8) & 0x1f) { + case 0x10: case 0x11: case 0x12: case 0x13: /* Data segments */ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1a: case 0x1b: /* Readable non-conforming code */ + if ((seg & 0x0003) > dpl) { + x86gpf("loadseg(): Normal segment RPL > DPL", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + if ((CPL) > dpl) { + x86gpf("loadseg(): Normal segment DPL < CPL", seg& 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + break; + case 0x1e: case 0x1f: /* Readable conforming code */ + break; + default: + x86gpf("loadseg(): Unknown normal segment type", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + } + + if (!(segdat[2] & 0x8000)) { + x86np("Load data seg not present", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + s->seg = seg; + do_seg_load(s, segdat); + + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + s->checked = 0; #ifdef USE_DYNAREC - if (s == &cpu_state.seg_ds) - codegen_flat_ds = 0; - if (s == &cpu_state.seg_ss) - codegen_flat_ss = 0; + if (s == &cpu_state.seg_ds) + codegen_flat_ds = 0; + if (s == &cpu_state.seg_ss) + codegen_flat_ss = 0; #endif - if (s == &cpu_state.seg_ss && (cpu_state.eflags & VM_FLAG)) - set_stack32(0); - } - - if (s == &cpu_state.seg_ds) - { - if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATDS; - } - if (s == &cpu_state.seg_ss) - { - if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATSS; - } + } else { + s->access = 0xe2; + s->ar_high = 0x10; + s->base = seg << 4; + s->seg = seg; + s->checked = 1; +#ifdef USE_DYNAREC + if (s == &cpu_state.seg_ds) + codegen_flat_ds = 0; + if (s == &cpu_state.seg_ss) + codegen_flat_ss = 0; +#endif + if (s == &cpu_state.seg_ss && (cpu_state.eflags & VM_FLAG)) + set_stack32(0); + } + + if (s == &cpu_state.seg_ds) { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &cpu_state.seg_ss) { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } #ifdef USE_NEW_DYNAREC - return cpu_state.abrt; + return cpu_state.abrt; #endif } -#define DPL ((segdat[2]>>13)&3) -#define DPL2 ((segdat2[2]>>13)&3) -#define DPL3 ((segdat3[2]>>13)&3) -void loadcs(uint16_t seg) +void +loadcs(uint16_t seg) { - uint16_t segdat[4]; - uint32_t addr; - x86seg_log("Load CS %04X\n",seg); - if (msw&1 && !(cpu_state.eflags&VM_FLAG)) - { - if (!(seg&~3)) - { - x86gpf("loadcs(): Protected mode selector is zero",0); - return; - } - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf("loadcs(): Protected mode selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("loadcs(): Protected mode selector > GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - if (segdat[2]&0x1000) /*Normal code segment*/ - { - if (!(segdat[2]&0x400)) /*Not conforming*/ - { - if ((seg&3)>CPL) - { - x86gpf("loadcs(): Non-conforming RPL > CPL",seg&~3); - return; - } - if (CPL != DPL) - { - x86gpf("loadcs(): Non-conforming CPL != DPL",seg&~3); - return; - } - } - if (CPL < DPL) - { - x86gpf("loadcs(): CPL < DPL",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS not present", seg & 0xfffc); - return; - } - set_use32(segdat[3] & 0x40); - CS=(seg&~3)|CPL; - do_seg_load(&cpu_state.seg_cs, segdat); - use32=(segdat[3]&0x40)?0x300:0; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + uint16_t segdat[4]; + uint32_t addr, *segdat32 = (uint32_t *) segdat; + x86seg *dt; + + x86seg_log("Load CS %04X\n", seg); + + if ((msw & 1) && !(cpu_state.eflags & VM_FLAG)) { + if (!(seg & 0xfffc)) { + x86gpf("loadcs(): Protected mode selector is zero", 0); + return; + } + + addr = seg & 0xfff8; + dt = (seg & 0x0004)? &ldt : &gdt; + if ((addr + 7) >= dt->limit) { + x86gpf("loadcs(): Protected mode selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) + return; + if (segdat[2] & 0x1000) { + /* Normal code segment */ + if (!(segdat[2] & 0x0400)) { + /* Not conforming */ + if ((seg & 3) > CPL) { + x86gpf("loadcs(): Non-conforming RPL > CPL", seg & 0xfffc); + return; + } + if (CPL != DPL) { + x86gpf("loadcs(): Non-conforming CPL != DPL", seg & 0xfffc); + return; + } + } + if (CPL < DPL) { + x86gpf("loadcs(): CPL < DPL", seg & ~3); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Load CS not present", seg & 0xfffc); + return; + } + set_use32(segdat[3] & 0x40); + CS = (seg & 0xfffc) | CPL; + do_seg_load(&cpu_state.seg_cs, segdat); + use32 = (segdat[3] & 0x40) ? 0x300 : 0; + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - } - else /*System segment*/ - { - if (!(segdat[2]&0x8000)) - { - x86np("Load CS system seg not present\n", seg & 0xfffc); - return; - } - switch (segdat[2]&0xF00) - { - default: - x86gpf("Load CS system segment has bits 0-3 of access rights set",seg&~3); - return; - } - } - } - else - { - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - CS=seg & 0xFFFF; - if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; - else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; - cpu_state.seg_cs.ar_high = 0x10; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x0100); /* Set accessed bit */ + cpl_override = 0; + } else { + /* System segment */ + if (!(segdat[2] & 0x8000)) { + x86np("Load CS system seg not present", seg & 0xfffc); + return; + } + switch (segdat[2] & 0x0f00) { + default: + x86gpf("Load CS system segment has bits 0-3 of access rights set", seg & 0xfffc); + return; + } + } + } else { + cpu_state.seg_cs.base = (seg << 4); + cpu_state.seg_cs.limit = 0xffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + cpu_state.seg_cs.seg = seg & 0xffff; + cpu_state.seg_cs.access = (cpu_state.eflags & VM_FLAG) ? 0xe2 : 0x82; + cpu_state.seg_cs.ar_high = 0x10; + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif - } + } } -void loadcsjmp(uint16_t seg, uint32_t old_pc) + +void +loadcsjmp(uint16_t seg, uint32_t old_pc) { - uint16_t segdat[4]; - uint32_t addr; - uint16_t type,seg2; - uint32_t newpc; - if (msw&1 && !(cpu_state.eflags&VM_FLAG)) - { - if (!(seg&~3)) - { - x86gpf("loadcsjmp(): Selector is zero",0); - return; - } - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf("loacsjmp(): Selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("loacsjmp(): Selector > GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - x86seg_log("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); - if (segdat[2]&0x1000) /*Normal code segment*/ - { - if (!(segdat[2]&0x400)) /*Not conforming*/ - { - if ((seg&3)>CPL) - { - x86gpf("loadcsjmp(): segment PL > CPL",seg&~3); - return; - } - if (CPL != DPL) - { - x86gpf("loadcsjmp(): CPL != DPL",seg&~3); - return; - } - } - if (CPL < DPL) - { - x86gpf("loadcsjmp(): CPL < DPL",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS JMP not present\n", seg & 0xfffc); - return; - } - set_use32(segdat[3]&0x40); + uint16_t type, seg2; + uint16_t segdat[4]; + uint32_t addr, newpc; + uint32_t *segdat32 = (uint32_t *) segdat; + x86seg *dt; -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - CS = (seg & ~3) | CPL; - segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + if ((msw & 1) && !(cpu_state.eflags & VM_FLAG)) { + if (!(seg & 0xfffc)) { + x86gpf("loadcsjmp(): Selector is zero", 0); + return; + } + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? &ldt : &gdt; + if ((addr + 7) >= dt->limit) { + x86gpf("loacsjmp(): Selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) + return; + x86seg_log("%04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); + if (segdat[2] & 0x1000) { + /* Normal code segment */ + if (!(segdat[2] & 0x0400)) { + /* Not conforming */ + if ((seg & 0x0003) > CPL) { + x86gpf("loadcsjmp(): segment PL > CPL", seg & 0xfffc); + return; + } + if (CPL != DPL) { + x86gpf("loadcsjmp(): CPL != DPL", seg & 0xfffc); + return; + } + } + if (CPL < DPL) { + x86gpf("loadcsjmp(): CPL < DPL",seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Load CS JMP not present", seg & 0xfffc); + return; + } + set_use32(segdat[3] & 0x0040); - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x0100); /* Set accessed bit */ + cpl_override = 0; + + CS = (seg & 0xfffc) | CPL; + segdat[2] = (segdat[2] & ~(3 << 13)) | (CPL << 13); + + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif - cycles -= timing_jmp_pm; - } - else /*System segment*/ - { - if (!(segdat[2]&0x8000)) - { - x86np("Load CS JMP system selector not present\n", seg & 0xfffc); - return; - } - type=segdat[2]&0xF00; - newpc=segdat[0]; - if (type&0x800) newpc|=segdat[3]<<16; - switch (type) - { - case 0x400: /*Call gate*/ - case 0xC00: - cgate32=(type&0x800); - cgate16=!cgate32; + cycles -= timing_jmp_pm; + } else { /* System segment */ + if (!(segdat[2] & 0x8000)) { + x86np("Load CS JMP system selector not present", seg & 0xfffc); + return; + } + type = segdat[2] & 0x0f00; + newpc = segdat[0]; + if (type & 0x0800) + newpc |= (segdat[3] << 16); + switch (type) { + case 0x0400: /* Call gate */ + case 0x0c00: + cgate32 = (type & 0x0800); + cgate16 = !cgate32; #ifndef USE_NEW_DYNAREC - oldcs=CS; + oldcs=CS; #endif - cpu_state.oldpc = cpu_state.pc; - if (DPL < CPL) - { - x86gpf("loadcsjmp(): Call gate DPL < CPL",seg&~3); - return; - } - if (DPL < (seg&3)) - { - x86gpf("loadcsjmp(): Call gate DPL< RPL",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS JMP call gate not present\n", seg & 0xfffc); - return; - } - seg2=segdat[1]; + cpu_state.oldpc = cpu_state.pc; + if (DPL < CPL) { + x86gpf("loadcsjmp(): Call gate DPL < CPL",seg & 0xfffc); + return; + } + if (DPL < (seg & 0x0003)) { + x86gpf("loadcsjmp(): Call gate DPL< RPL",seg&~3); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Load CS JMP call gate not present", seg & 0xfffc); + return; + } + seg2 = segdat[1]; - if (!(seg2&~3)) - { - x86gpf(NULL,0); - return; - } - addr=seg2&~7; - if (seg2&4) - { - if (addr>=ldt.limit) - { - x86gpf("loadcsjmp(): Call gate selector > LDT limit",seg2&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("loadcsjmp(): Call gate selector > GDT limit",seg2&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + if (!(seg2 & 0xfffc)) { + x86gpf("Load CS JMP call gate selector is NULL", 0); + return; + } + addr = seg2 & 0xfff8; + dt = (seg2 & 0x0004) ? &ldt : &gdt; + if ((addr + 7) >= dt->limit) { + x86gpf("loadcsjmp(): Call gate selector > DT limit", seg2 & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) + return; - if (DPL > CPL) - { - x86gpf("loadcsjmp(): ex DPL > CPL",seg2&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS JMP from call gate not present\n", seg2 & 0xfffc); - return; - } + if (DPL > CPL) { + x86gpf("loadcsjmp(): ex DPL > CPL",seg2 & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Load CS JMP from call gate not present", seg2 & 0xfffc); + return; + } - - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ - if (DPL > CPL) - { - x86gpf("loadcsjmp(): Non-conforming DPL > CPL",seg2&~3); - return; - } - /*FALLTHROUGH*/ - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - CS=seg2; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + switch (segdat[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming code */ + if (DPL > CPL) { + x86gpf("loadcsjmp(): Non-conforming DPL > CPL", seg2 & 0xfffc); + return; + } + /*FALLTHROUGH*/ + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + CS = seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif - set_use32(segdat[3]&0x40); - cpu_state.pc=newpc; + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - break; + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + break; - default: - x86gpf("loadcsjmp(): Unknown type",seg2&~3); - return; - } - cycles -= timing_jmp_pm_gate; - break; + default: + x86gpf("loadcsjmp(): Unknown type", seg2 & 0xfffc); + return; + } + cycles -= timing_jmp_pm_gate; + break; - - case 0x100: /*286 Task gate*/ - case 0x900: /*386 Task gate*/ - cpu_state.pc = old_pc; - optype=JMP; - cpl_override=1; - taskswitch286(seg,segdat,segdat[2]&0x800); - cpu_state.flags &= ~NT_FLAG; - cpl_override=0; - return; + case 0x100: /* 286 Task gate */ + case 0x900: /* 386 Task gate */ + cpu_state.pc = old_pc; + optype = JMP; + cpl_override = 1; + taskswitch286(seg,segdat,segdat[2] & 0x800); + cpu_state.flags &= ~NT_FLAG; + cpl_override=0; + return; - default: - x86gpf(NULL,0); - return; - } - } - } - else - { - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - CS=seg; - if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; - else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; - cpu_state.seg_cs.ar_high = 0x10; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + default: + x86gpf("Load CS JMP call gate selector unknown type", 0); + return; + } + } + } else { + cpu_state.seg_cs.base = seg << 4; + cpu_state.seg_cs.limit = 0xffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + cpu_state.seg_cs.seg = seg; + cpu_state.seg_cs.access = (cpu_state.eflags & VM_FLAG) ? 0xe2 : 0x82; + cpu_state.seg_cs.ar_high = 0x10; + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif - cycles -= timing_jmp_rm; - } + cycles -= timing_jmp_rm; + } } -void PUSHW(uint16_t v) + +void +PUSHW(uint16_t v) { - if (stack32) - { - writememw(ss,ESP-2,v); - if (cpu_state.abrt) return; - ESP-=2; - } - else - { - writememw(ss,((SP-2)&0xFFFF),v); - if (cpu_state.abrt) return; - SP-=2; - } + if (stack32) { + writememw(ss, ESP - 2, v); + if (cpu_state.abrt) + return; + ESP -= 2; + } else { + writememw(ss, ((SP - 2) & 0xffff), v); + if (cpu_state.abrt) + return; + SP -= 2; + } } -void PUSHL(uint32_t v) + + +void +PUSHL(uint32_t v) { - if (stack32) - { - writememl(ss,ESP-4,v); - if (cpu_state.abrt) return; - ESP-=4; - } - else - { - writememl(ss,((SP-4)&0xFFFF),v); - if (cpu_state.abrt) return; - SP-=4; - } + if (cpu_16bitbus) { + PUSHW(v & 0xffff); + PUSHW(v >> 16); + } else { + if (stack32) { + writememl(ss, ESP - 4, v); + if (cpu_state.abrt) + return; + ESP -= 4; + } else { + writememl(ss, ((SP - 4) & 0xffff), v); + if (cpu_state.abrt) + return; + SP -= 4; + } + } } -uint16_t POPW() + + +uint16_t +POPW() { - uint16_t tempw; - if (stack32) - { - tempw=readmemw(ss,ESP); - if (cpu_state.abrt) return 0; - ESP+=2; - } - else - { - tempw=readmemw(ss,SP); - if (cpu_state.abrt) return 0; - SP+=2; - } - return tempw; + uint16_t tempw; + if (stack32) { + tempw = readmemw(ss, ESP); + if (cpu_state.abrt) + return 0; + ESP += 2; + } else { + tempw = readmemw(ss, SP); + if (cpu_state.abrt) + return 0; + SP += 2; + } + return tempw; } -uint32_t POPL() + + +uint32_t +POPL() { - uint32_t templ; - if (stack32) - { - templ=readmeml(ss,ESP); - if (cpu_state.abrt) return 0; - ESP+=4; - } - else - { - templ=readmeml(ss,SP); - if (cpu_state.abrt) return 0; - SP+=4; - } - return templ; + uint32_t templ; + + if (cpu_16bitbus) { + templ = POPW(); + templ |= (POPW() << 16); + } else { + if (stack32) { + templ = readmeml(ss, ESP); + if (cpu_state.abrt) + return 0; + ESP += 4; + } else { + templ = readmeml(ss, SP); + if (cpu_state.abrt) + return 0; + SP += 4; + } + } + + return templ; } + #ifdef USE_NEW_DYNAREC void loadcscall(uint16_t seg, uint32_t old_pc) #else void loadcscall(uint16_t seg) #endif { - uint16_t seg2; - uint16_t segdat[4],segdat2[4],newss; - uint32_t addr,oldssbase=ss, oaddr; - uint32_t newpc; - int count; - uint32_t oldss,oldsp,newsp, oldsp2; - int type; - uint16_t tempw; + uint16_t seg2, newss; + uint16_t segdat[4], segdat2[4]; + uint32_t addr, oldssbase = ss; + uint32_t oaddr, newpc; + uint32_t *segdat32 = (uint32_t *) segdat; + uint32_t *segdat232 = (uint32_t *) segdat2; + int count, type; + uint32_t oldss, oldsp, newsp, oldsp2; + uint16_t tempw; + x86seg *dt; - if (msw&1 && !(cpu_state.eflags&VM_FLAG)) - { - x86seg_log("Protected mode CS load! %04X\n", seg); - if (!(seg&~3)) - { - x86gpf("loadcscall(): Protected mode selector is zero",0); - return; - } - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf("loadcscall(): Selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("loadcscall(): Selector > GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - type=segdat[2]&0xF00; - newpc=segdat[0]; - if (type&0x800) newpc|=segdat[3]<<16; + if ((msw & 1) && !(cpu_state.eflags & VM_FLAG)) { + x86seg_log("Protected mode CS load! %04X\n", seg); + if (!(seg & 0xfffc)) { + x86gpf("loadcscall(): Protected mode selector is zero",0); + return; + } + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? &ldt : &gdt; + if ((addr + 7) >= dt->limit) { + x86gpf("loadcscall(): Selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) + return; + type = segdat[2] & 0x0f00; + newpc = segdat[0]; + if (type & 0x0800) + newpc |= segdat[3] << 16; - x86seg_log("Code seg call - %04X - %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2]); - if (segdat[2]&0x1000) - { - if (!(segdat[2]&0x400)) /*Not conforming*/ - { - if ((seg&3)>CPL) - { - x86gpf("loadcscall(): Non-conforming RPL > CPL",seg&~3); - return; - } - if (CPL != DPL) - { - x86gpf("loadcscall(): Non-conforming CPL != DPL",seg&~3); - return; - } - } - if (CPL < DPL) - { - x86gpf("loadcscall(): CPL < DPL",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS call not present", seg & 0xfffc); - return; - } - set_use32(segdat[3]&0x40); + x86seg_log("Code seg call - %04X - %04X %04X %04X\n", seg, segdat[0], segdat[1], segdat[2]); + if (segdat[2] & 0x1000) { + if (!(segdat[2] & 0x0400)) { /* Not conforming */ + if ((seg & 0x0003) > CPL) { + x86gpf("loadcscall(): Non-conforming RPL > CPL", seg & 0xfffc); + return; + } + if (CPL != DPL) { + x86gpf("loadcscall(): Non-conforming CPL != DPL", seg & 0xfffc); + return; + } + } + if (CPL < DPL) { + x86gpf("loadcscall(): CPL < DPL", seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Load CS call not present", seg & 0xfffc); + return; + } + set_use32(segdat[3] & 0x0040); -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - /*Conforming segments don't change CPL, so preserve existing CPL*/ - if (segdat[2]&0x400) - { - seg = (seg & ~3) | CPL; - segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); - } - else /*On non-conforming segments, set RPL = CPL*/ - seg = (seg & ~3) | CPL; - CS=seg; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + + /* Conforming segments don't change CPL, so preserve existing CPL */ + if (segdat[2] & 0x0400) { + seg = (seg & 0xfffc) | CPL; + segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + } else /* On non-conforming segments, set RPL = CPL */ + seg = (seg & 0xfffc) | CPL; + CS = seg; + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif #ifdef ENABLE_X86SEG_LOG - x86seg_log("Complete\n"); + x86seg_log("Complete\n"); #endif - cycles -= timing_call_pm; - } - else - { - type=segdat[2]&0xF00; - x86seg_log("Type %03X\n",type); - switch (type) - { - case 0x400: /*Call gate*/ - case 0xC00: /*386 Call gate*/ - x86seg_log("Callgate %08X\n", cpu_state.pc); - cgate32=(type&0x800); - cgate16=!cgate32; + cycles -= timing_call_pm; + } else { + type = segdat[2] & 0x0f00; + x86seg_log("Type %03X\n", type); + switch (type) { + case 0x0400: /* Call gate */ + case 0x0c00: /* 386 Call gate */ + x86seg_log("Callgate %08X\n", cpu_state.pc); + cgate32 = (type & 0x0800); + cgate16 = !cgate32; #ifndef USE_NEW_DYNAREC - oldcs=CS; + oldcs = CS; #endif - count=segdat[2]&31; - if (DPL < CPL) - { - x86gpf("loadcscall(): ex DPL < CPL",seg&~3); - return; - } - if ((DPL < (seg&3))) - { - x86gpf("loadcscall(): ex (DPL < (seg&3))",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Call gate not present\n", seg & 0xfffc); - return; - } - seg2=segdat[1]; - - x86seg_log("New address : %04X:%08X\n", seg2, newpc); - - if (!(seg2&~3)) - { - x86gpf(NULL,0); - return; - } - addr=seg2&~7; - if (seg2&4) - { - if (addr>=ldt.limit) - { - x86gpf("loadcscall(): ex Selector > LDT limit",seg2&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("loadcscall(): ex Selector > GDT limit",seg2&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - - x86seg_log("Code seg2 call - %04X - %04X %04X %04X\n",seg2,segdat[0],segdat[1],segdat[2]); - - if (DPL > CPL) - { - x86gpf("loadcscall(): ex DPL > CPL",seg2&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86seg_log("Call gate CS not present %04X\n",seg2); - x86np("Call gate CS not present", seg2 & 0xfffc); - return; - } + count = segdat[2] & 0x001f; + if (DPL < CPL) { + x86gpf("loadcscall(): ex DPL < CPL",seg & 0xfffc); + return; + } + if (DPL < (seg & 0x0003)) { + x86gpf("loadcscall(): ex DPL < RPL", seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Call gate not present", seg & 0xfffc); + return; + } + seg2 = segdat[1]; - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ - if (DPL < CPL) - { -#ifdef USE_NEW_DYNAREC - uint16_t oldcs = CS; -#endif - oaddr = addr; - /*Load new stack*/ - oldss=SS; - oldsp=oldsp2=ESP; - cpl_override=1; - if (tr.access&8) - { - addr = 4 + tr.base + (DPL * 8); - newss=readmemw(0,addr+4); - newsp=readmeml(0,addr); - } - else - { - addr = 2 + tr.base + (DPL * 4); - newss=readmemw(0,addr+2); - newsp=readmemw(0,addr); - } - cpl_override=0; - if (cpu_state.abrt) return; - x86seg_log("New stack %04X:%08X\n",newss,newsp); - if (!(newss&~3)) - { - x86ts(NULL,newss&~3); - return; - } - addr=newss&~7; - if (newss&4) - { - if ((addr+7)>ldt.limit) - { - x86abort("Bigger than LDT limit %04X %08X %04X CSC SS\n",newss,addr,ldt.limit); - x86ts(NULL,newss&~3); - return; - } - addr+=ldt.base; - } - else - { - if ((addr+7)>gdt.limit) - { - x86abort("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); - x86ts(NULL,newss&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - x86seg_log("Read stack seg\n"); - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - x86seg_log("Read stack seg done!\n"); - if (((newss & 3) != DPL) || (DPL2 != DPL)) - { - x86ts(NULL,newss&~3); - return; - } - if ((segdat2[2]&0x1A00)!=0x1200) - { - x86ts(NULL,newss&~3); - return; - } - if (!(segdat2[2]&0x8000)) - { - x86ss("Call gate loading SS not present\n", newss & 0xfffc); - return; - } - if (!stack32) oldsp &= 0xFFFF; - SS=newss; - set_stack32((segdat2[3] & 0x40) ? 1 : 0); - if (stack32) ESP=newsp; - else SP=newsp; - - do_seg_load(&cpu_state.seg_ss, segdat2); + x86seg_log("New address : %04X:%08X\n", seg2, newpc); - x86seg_log("Set access 1\n"); + if (!(seg2 & 0xfffc)) { + x86gpf("loadcscall(): ex selector is NULL", 0); + return; + } + addr = seg2 & 0xfff8; + dt = (seg2 & 0x0004) ? &ldt : &gdt; + if ((addr + 7) >= dt->limit) { + x86gpf("loadcscall(): ex Selector > DT limit", seg2 & 0xfff8); + return; + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) + return; -#ifdef SEL_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - CS=seg2; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); -#ifdef USE_NEW_DYNAREC - oldcpl = CPL; -#endif - set_use32(segdat[3]&0x40); - cpu_state.pc=newpc; + x86seg_log("Code seg2 call - %04X - %04X %04X %04X\n", seg2, segdat[0], segdat[1], segdat[2]); - x86seg_log("Set access 2\n"); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif + if (DPL > CPL) { + x86gpf("loadcscall(): ex DPL > CPL", seg2 & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + x86seg_log("Call gate CS not present %04X\n", seg2); + x86np("Call gate CS not present", seg2 & 0xfffc); + return; + } - x86seg_log("Type %04X\n",type); - if (type==0xC00) - { - PUSHL(oldss); - PUSHL(oldsp2); - if (cpu_state.abrt) - { - SS = oldss; - ESP = oldsp2; + switch (segdat[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming code */ + if (DPL < CPL) { #ifdef USE_NEW_DYNAREC - CS = oldcs; + uint16_t oldcs = CS; #endif - return; - } - if (count) - { - while (count) - { - count--; - PUSHL(readmeml(oldssbase,oldsp+(count*4))); - if (cpu_state.abrt) - { - SS = oldss; - ESP = oldsp2; -#ifdef USE_NEW_DYNAREC - CS = oldcs; -#endif - return; - } - } - } - } - else - { - x86seg_log("Stack %04X\n",SP); - PUSHW(oldss); - x86seg_log("Write SS to %04X:%04X\n",SS,SP); - PUSHW(oldsp2); - if (cpu_state.abrt) - { - SS = oldss; - ESP = oldsp2; -#ifdef USE_NEW_DYNAREC - CS = oldcs; -#endif - return; - } - x86seg_log("Write SP to %04X:%04X\n",SS,SP); - if (count) - { - while (count) - { - count--; - tempw=readmemw(oldssbase,(oldsp&0xFFFF)+(count*2)); - x86seg_log("PUSH %04X\n",tempw); - PUSHW(tempw); - if (cpu_state.abrt) - { - SS = oldss; - ESP = oldsp2; -#ifdef USE_NEW_DYNAREC - CS = oldcs; -#endif - return; - } - } - } - } - cycles -= timing_call_pm_gate_inner; - break; - } - else if (DPL > CPL) - { - x86gpf("loadcscall(): Call PM Gate Inner DPL > CPL",seg2&~3); - return; - } - /*FALLTHROUGH*/ - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - CS=seg2; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); -#ifdef USE_NEW_DYNAREC - oldcpl = CPL; -#endif - set_use32(segdat[3]&0x40); - cpu_state.pc=newpc; + oaddr = addr; + /* Load new stack */ + oldss = SS; + oldsp = oldsp2 = ESP; + cpl_override = 1; + if (tr.access & 8) { + addr = 4 + tr.base + (DPL << 3); + newss = readmemw(0, addr + 4); + if (cpu_16bitbus) { + newsp = readmemw(0, addr); + newsp |= (readmemw(0, addr + 2) << 16); + } else + newsp = readmeml(0, addr); + } else { + addr = 2 + tr.base + (DPL * 4); + newss = readmemw(0, addr + 2); + newsp = readmemw(0, addr); + } + cpl_override = 0; + if (cpu_state.abrt) + return; + x86seg_log("New stack %04X:%08X\n", newss, newsp); + if (!(newss & 0xfffc)) { + x86ts(NULL, newss & 0xfffc); + return; + } + addr = newss & 0xfff8; + dt = (newss & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + fatal("Bigger than DT limit %04X %08X %04X CSC SS\n", newss, addr, dt->limit); + x86ts(NULL, newss & ~3); + return; + } + addr += dt->base; + x86seg_log("Read stack seg\n"); + read_descriptor(addr, segdat2, segdat232, 1); + if (cpu_state.abrt) + return; + x86seg_log("Read stack seg done!\n"); + if (((newss & 0x0003) != DPL) || (DPL2 != DPL)) { + x86ts(NULL, newss & 0xfffc); + return; + } + if ((segdat2[2] & 0x1a00) != 0x1200) { + x86ts("Call gate loading SS unknown type", newss & 0xfffc); + return; + } + if (!(segdat2[2] & 0x8000)) { + x86ss("Call gate loading SS not present", newss & 0xfffc); + return; + } + if (!stack32) + oldsp &= 0xffff; + SS = newss; + set_stack32((segdat2[3] & 0x0040) ? 1 : 0); + if (stack32) + ESP = newsp; + else + SP = newsp; -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - cycles -= timing_call_pm_gate; - break; - - default: - x86gpf("loadcscall(): Unknown subtype",seg2&~3); - return; - } - break; + do_seg_load(&cpu_state.seg_ss, segdat2); - case 0x100: /*286 Task gate*/ - case 0x900: /*386 Task gate*/ + x86seg_log("Set access 1\n"); + cpl_override = 1; + writememw(0, addr + 4, segdat2[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + + CS = seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - cpu_state.pc = old_pc; + oldcpl = CPL; +#endif + set_use32(segdat[3] & 0x0040); + cpu_state.pc = newpc; + + x86seg_log("Set access 2\n"); + + cpl_override = 1; + writememw(0, oaddr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + + x86seg_log("Type %04X\n", type); + if (type == 0x0c00) { + PUSHL(oldss); + PUSHL(oldsp2); + if (cpu_state.abrt) { + SS = oldss; + ESP = oldsp2; +#ifdef USE_NEW_DYNAREC + CS = oldcs; +#endif + return; + } + if (count) { + while (count--) { + PUSHL(readmeml(oldssbase, oldsp + (count << 2))); + if (cpu_state.abrt) { + SS = oldss; + ESP = oldsp2; +#ifdef USE_NEW_DYNAREC + CS = oldcs; +#endif + return; + } + } + } + } else { + x86seg_log("Stack %04X\n", SP); + PUSHW(oldss); + x86seg_log("Write SS to %04X:%04X\n", SS, SP); + PUSHW(oldsp2); + if (cpu_state.abrt) { + SS = oldss; + ESP = oldsp2; +#ifdef USE_NEW_DYNAREC + CS = oldcs; +#endif + return; + } + x86seg_log("Write SP to %04X:%04X\n", SS, SP); + if (count) { + while (count--) { + tempw = readmemw(oldssbase, (oldsp & 0xffff) + (count << 1)); + x86seg_log("PUSH %04X\n", tempw); + PUSHW(tempw); + if (cpu_state.abrt) { + SS = oldss; + ESP = oldsp2; +#ifdef USE_NEW_DYNAREC + CS = oldcs; +#endif + return; + } + } + } + } + cycles -= timing_call_pm_gate_inner; + break; + } else if (DPL > CPL) { + x86gpf("loadcscall(): Call PM Gate Inner DPL > CPL",seg2 & 0xfffc); + return; + } + /*FALLTHROUGH*/ + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + CS = seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + set_use32(segdat[3] & 0x0040); + cpu_state.pc = newpc; + + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + cycles -= timing_call_pm_gate; + break; + + default: + x86gpf("loadcscall(): Unknown subtype", seg2 & 0xfffc); + return; + } + break; + + case 0x0100: /* 286 Task gate */ + case 0x0900: /* 386 Task gate */ +#ifdef USE_NEW_DYNAREC + cpu_state.pc = old_pc; #else - cpu_state.pc = oxpc; + cpu_state.pc = oxpc; #endif - cpl_override=1; - taskswitch286(seg,segdat,segdat[2]&0x800); - cpl_override=0; - break; + cpl_override = 1; + taskswitch286(seg, segdat, segdat[2] & 0x0800); + cpl_override = 0; + break; - default: - x86gpf("loadcscall(): Unknown type",seg&~3); - return; - } - } - } - else - { - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - CS=seg; - if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; - else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; - cpu_state.seg_cs.ar_high = 0x10; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + default: + x86gpf("loadcscall(): Unknown type", seg & 0xfffc); + return; + } + } + } else { + cpu_state.seg_cs.base = seg << 4; + cpu_state.seg_cs.limit = 0xffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + cpu_state.seg_cs.seg = seg; + cpu_state.seg_cs.access = (cpu_state.eflags & VM_FLAG) ? 0xe2 : 0x82; + cpu_state.seg_cs.ar_high = 0x10; + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif - } + } } -void pmoderetf(int is32, uint16_t off) + +void +pmoderetf(int is32, uint16_t off) { - uint32_t newpc; - uint32_t newsp; - uint32_t addr, oaddr; - uint16_t segdat[4],segdat2[4],seg,newss; - uint32_t oldsp=ESP; - x86seg_log("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,cpu_state.eflags); - if (is32) - { - newpc=POPL(); - seg=POPL(); if (cpu_state.abrt) return; - } - else - { - x86seg_log("PC read from %04X:%04X\n",SS,SP); - newpc=POPW(); - x86seg_log("CS read from %04X:%04X\n",SS,SP); - seg=POPW(); if (cpu_state.abrt) return; - } - x86seg_log("Return to %04X:%08X\n",seg,newpc); - if ((seg&3)=ldt.limit) - { - x86gpf("pmoderetf(): Selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("pmoderetf(): Selector > GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } - oaddr = addr; + uint16_t segdat[4], segdat2[4], seg,newss; + uint32_t newpc, newsp, addr, oaddr; + uint32_t oldsp = ESP; + uint32_t *segdat32 = (uint32_t *) segdat; + uint32_t *segdat232 = (uint32_t *) segdat2; + x86seg *dt; + + x86seg_log("RETF %i %04X:%04X %08X %04X\n", is32, CS, cpu_state.pc, cr0, cpu_state.eflags); + if (is32) { + newpc = POPL(); + seg = POPL(); + } else { + x86seg_log("PC read from %04X:%04X\n", SS, SP); + newpc = POPW(); + x86seg_log("CS read from %04X:%04X\n", SS, SP); + seg = POPW(); + } + if (cpu_state.abrt) + return; + + x86seg_log("Return to %04X:%08X\n", seg, newpc); + if ((seg & 0x0003) < CPL) { + ESP = oldsp; + x86gpf("pmoderetf(): seg < CPL", seg & 0xfffc); + return; + } + if (!(seg & 0xfffc)) { + x86gpf("pmoderetf(): seg is NULL", 0); + return; + } + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? &ldt : &gdt; + if ((addr + 7) >= dt->limit) { + x86gpf("pmoderetf(): Selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + oaddr = addr; + + x86seg_log("CPL %i RPL %i %i\n", CPL, seg & 0x0003, is32); + + if (stack32) + ESP += off; + else + SP += off; + + if (CPL == (seg & 0x0003)) { + x86seg_log("RETF CPL = RPL %04X\n", segdat[2]); + switch (segdat[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming */ + if (CPL != DPL) { + ESP = oldsp; + x86gpf("pmoderetf(): Non-conforming CPL != DPL", seg & 0xfffc); + return; + } + break; + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + if (CPL < DPL) { + ESP = oldsp; + x86gpf("pmoderetf(): Conforming CPL < DPL", seg & 0xfffc); + return; + } + break; + default: + x86gpf("pmoderetf(): Unknown type", seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + ESP = oldsp; + x86np("RETF CS not present", seg & 0xfffc); + return; + } + + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + + cpu_state.pc = newpc; + if (segdat[2] & 0x0400) + segdat[2] = (segdat[2] & ~(3 << 13)) | ((seg & 3) << 13); + CS = seg; + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + set_use32(segdat[3] & 0x0040); + + cycles -= timing_retf_pm; + } else { + switch (segdat[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming */ + if ((seg & 0x0003) != DPL) { + ESP = oldsp; + x86gpf("pmoderetf(): Non-conforming RPL != DPL", seg & 0xfffc); + return; + } + x86seg_log("RETF non-conforming, %i %i\n", seg & 0x0003, DPL); + break; + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + if ((seg & 0x0003) < DPL) { + ESP = oldsp; + x86gpf("pmoderetf(): Conforming RPL < DPL", seg & 0xfffc); + return; + } + x86seg_log("RETF conforming, %i %i\n", seg & 0x0003, DPL); + break; + default: + ESP = oldsp; + x86gpf("pmoderetf(): Unknown type", seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + ESP = oldsp; + x86np("RETF CS not present", seg & 0xfffc); + return; + } + if (is32) { + newsp = POPL(); + newss = POPL(); + if (cpu_state.abrt) + return; + } else { + x86seg_log("SP read from %04X:%04X\n", SS, SP); + newsp = POPW(); + x86seg_log("SS read from %04X:%04X\n", SS, SP); + newss = POPW(); + if (cpu_state.abrt) + return; + } + x86seg_log("Read new stack : %04X:%04X (%08X)\n", newss, newsp, ldt.base); + if (!(newss & 0xfffc)) { + ESP = oldsp; + x86gpf("pmoderetf(): New SS selector is zero",newss&~3); + return; + } + addr = newss & 0xfff8; + dt = (newss & 0x0004) ? &ldt : &gdt; + if ((addr + 7) >= dt->limit) { + ESP = oldsp; + x86gpf("pmoderetf(): New SS selector > DT limit", newss & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat2, segdat232, 1); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + x86seg_log("Segment data %04X %04X %04X %04X\n", segdat2[0], segdat2[1], segdat2[2], segdat2[3]); + if ((newss & 0x0003) != (seg & 0x0003)) { + ESP = oldsp; + x86gpf("pmoderetf(): New SS RPL > CS RPL", newss & 0xfffc); + return; + } + if ((segdat2[2] & 0x1a00) != 0x1200) { + ESP = oldsp; + x86gpf("pmoderetf(): New SS unknown type", newss & 0xfffc); + return; + } + if (!(segdat2[2] & 0x8000)) { + ESP = oldsp; + x86np("RETF loading SS not present", newss & 0xfffc); + return; + } + if (DPL2 != (seg & 3)) { + ESP = oldsp; + x86gpf("pmoderetf(): New SS DPL != CS RPL",newss & 0xfffc); + return; + } + SS = newss; + set_stack32((segdat2[3] & 0x0040) ? 1 : 0); + if (stack32) + ESP = newsp; + else + SP = newsp; + do_seg_load(&cpu_state.seg_ss, segdat2); + + cpl_override = 1; + writememw(0, addr + 4, segdat2[2] | 0x100); /* Set accessed bit */ + writememw(0, oaddr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + /* Conforming segments don't change CPL, so CPL = RPL */ + if (segdat[2] & 0x0400) + segdat[2] = (segdat[2] & ~(3 << 13)) | ((seg & 3) << 13); + cpu_state.pc = newpc; + CS = seg; + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + set_use32(segdat[3] & 0x0040); + + if (stack32) + ESP += off; + else + SP += off; + + check_seg_valid(&cpu_state.seg_ds); + check_seg_valid(&cpu_state.seg_es); + check_seg_valid(&cpu_state.seg_fs); + check_seg_valid(&cpu_state.seg_gs); + cycles -= timing_retf_pm_outer; + } +} + + +void +pmodeint(int num, int soft) +{ + uint16_t segdat[4], segdat2[4]; + uint16_t segdat3[4]; + uint16_t newss, seg = 0; + int type, new_cpl; + uint32_t addr, oaddr; + uint32_t oldss, oldsp; + uint32_t newsp; + uint32_t *segdat32 = (uint32_t *) segdat; + uint32_t *segdat232 = (uint32_t *) segdat2; + uint32_t *segdat332 = (uint32_t *) segdat3; + x86seg *dt; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL != 3) && soft) { + x86seg_log("V86 banned int\n"); + x86gpf("pmodeint(): V86 banned int", 0); + return; + } + addr = (num << 3); + if ((addr + 7) >= idt.limit) { + if (num == 0x08) { + /* Triple fault - reset! */ + softresetx86(); + cpu_set_edx(); + } else if (num == 0x0d) + pmodeint(8, 0); + else + x86gpf("pmodeint(): Vector > IDT limit", (num << 3) + 2 + !soft); + x86seg_log("addr >= IDT.limit\n"); + return; + } + addr += idt.base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) { + x86seg_log("Abrt reading from %08X\n", addr); + return; + } + oaddr = addr; + + x86seg_log("Addr %08X seg %04X %04X %04X %04X\n", addr, segdat[0], segdat[1], segdat[2], segdat[3]); + if (!(segdat[2] & 0x1f00)) { + x86gpf("pmodeint(): Vector descriptor with bad type", (num << 3) + 2); + return; + } + if ((DPL < CPL) && soft) { + x86gpf("pmodeint(): Vector DPL < CPL", (num << 3) + 2); + return; + } + type = segdat[2] & 0x1f00; + if (((type == 0x0e00) || (type == 0x0f00)) && !is386) { + x86gpf("pmodeint(): Gate type illegal on 286", seg & 0xfffc); + return; + } + switch (type) { + case 0x0600: case 0x0700: case 0x0e00: case 0x0f00: /* Interrupt and trap gates */ + intgatesize = (type >= 0x0800) ? 32 : 16; + if (!(segdat[2] & 0x8000)) { + x86np("Int gate not present", (num << 3) | 2); + return; + } + seg = segdat[1]; + new_cpl = seg & 0x0003; + + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? &ldt : &gdt; + if ((addr + 7) >= dt->limit) { + x86gpf("pmodeint(): Interrupt or trap gate selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat2, segdat232, 1); + if (cpu_state.abrt) + return; + oaddr = addr; - x86seg_log("CPL %i RPL %i %i\n",CPL,seg&3,is32); + if (DPL2 > CPL) { + x86gpf("pmodeint(): Interrupt or trap gate DPL > CPL", seg & 0xfffc); + return; + } + switch (segdat2[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming */ + if (DPL2 < CPL) { + if (!(segdat2[2] & 0x8000)) { + x86np("Int gate CS not present", segdat[1] & 0xfffc); + return; + } + if ((cpu_state.eflags & VM_FLAG) && DPL2) { + x86gpf("pmodeint(): Interrupt or trap gate non-zero DPL in V86 mode", segdat[1] & 0xfffc); + return; + } + /* Load new stack */ + oldss = SS; + oldsp = ESP; + cpl_override = 1; + if (tr.access & 8) { + addr = 4 + tr.base + (DPL2 << 3); + newss = readmemw(0, addr + 4); + newsp = readmeml(0, addr); + } else { + addr = 2 + tr.base + (DPL2 << 2); + newss = readmemw(0, addr + 2); + newsp = readmemw(0, addr); + } + cpl_override = 0; + if (!(newss & 0xfffc)) { + x86ss("pmodeint(): Interrupt or trap gate stack segment is NULL", newss & 0xfffc); + return; + } + addr = newss & 0xfff8; + dt = (newss & 0x0004) ? &ldt : &gdt; + if (addr >= dt->limit) { + x86ss("pmodeint(): Interrupt or trap gate stack segment > DT", newss & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat3, segdat332, 1); + if (cpu_state.abrt) + return; + if ((newss & 3) != DPL2) { + x86ss("pmodeint(): Interrupt or trap gate tack segment RPL > DPL",newss & 0xfffc); + return; + } + if (DPL3 != DPL2) { + x86ss("pmodeint(): Interrupt or trap gate tack segment DPL > DPL",newss & 0xfffc); + return; + } + if ((segdat3[2] & 0x1a00) != 0x1200) { + x86ss("pmodeint(): Interrupt or trap gate stack segment bad type", newss & 0xfffc); + return; + } + if (!(segdat3[2] & 0x8000)) { + x86np("Int gate loading SS not present", newss & 0xfffc); + return; + } + SS = newss; + set_stack32((segdat3[3] & 0x0040) ? 1 : 0); + if (stack32) + ESP = newsp; + else + SP = newsp; + do_seg_load(&cpu_state.seg_ss, segdat3); - if (stack32) ESP+=off; - else SP+=off; + cpl_override = 1; + writememw(0, addr + 4, segdat3[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; - if (CPL==(seg&3)) - { - x86seg_log("RETF CPL = RPL %04X\n", segdat[2]); - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if (CPL != DPL) - { - ESP=oldsp; - x86gpf("pmoderetf(): Non-conforming CPL != DPL",seg&~3); - return; - } - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if (CPL < DPL) - { - ESP=oldsp; - x86gpf("pmoderetf(): Conforming CPL < DPL",seg&~3); - return; - } - break; - default: - x86gpf("pmoderetf(): Unknown type",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - ESP=oldsp; - x86np("RETF CS not present\n", seg & 0xfffc); - return; - } - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - cpu_state.pc=newpc; - if (segdat[2] & 0x400) - segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); - CS = seg; - do_seg_load(&cpu_state.seg_cs, segdat); - cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); -#ifdef USE_NEW_DYNAREC - oldcpl = CPL; -#endif - set_use32(segdat[3] & 0x40); - - cycles -= timing_retf_pm; - } - else - { - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if ((seg&3) != DPL) - { - ESP=oldsp; - x86gpf("pmoderetf(): Non-conforming RPL != DPL",seg&~3); - return; - } - x86seg_log("RETF non-conforming, %i %i\n",seg&3, DPL); - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if ((seg&3) < DPL) - { - ESP=oldsp; - x86gpf("pmoderetf(): Conforming RPL < DPL",seg&~3); - return; - } - x86seg_log("RETF conforming, %i %i\n",seg&3, DPL); - break; - default: - ESP=oldsp; - x86gpf("pmoderetf(): Unknown type",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - ESP=oldsp; - x86np("RETF CS not present\n", seg & 0xfffc); - return; - } - if (is32) - { - newsp=POPL(); - newss=POPL(); if (cpu_state.abrt) return; - } - else - { - x86seg_log("SP read from %04X:%04X\n",SS,SP); - newsp=POPW(); - x86seg_log("SS read from %04X:%04X\n",SS,SP); - newss=POPW(); if (cpu_state.abrt) return; - } - x86seg_log("Read new stack : %04X:%04X (%08X)\n", newss, newsp, ldt.base); - if (!(newss&~3)) - { - ESP=oldsp; - x86gpf("pmoderetf(): New SS selector is zero",newss&~3); - return; - } - addr=newss&~7; - if (newss&4) - { - if (addr>=ldt.limit) - { - ESP=oldsp; - x86gpf("pmoderetf(): New SS selector > LDT limit",newss&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - ESP=oldsp; - x86gpf("pmoderetf(): New SS selector > GDT limit",newss&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } - x86seg_log("Segment data %04X %04X %04X %04X\n", segdat2[0], segdat2[1], segdat2[2], segdat2[3]); - if ((newss & 3) != (seg & 3)) - { - ESP=oldsp; - x86gpf("pmoderetf(): New SS RPL > CS RPL",newss&~3); - return; - } - if ((segdat2[2]&0x1A00)!=0x1200) - { - ESP=oldsp; - x86gpf("pmoderetf(): New SS unknown type",newss&~3); - return; - } - if (!(segdat2[2]&0x8000)) - { - ESP=oldsp; - x86np("RETF loading SS not present\n", newss & 0xfffc); - return; - } - if (DPL2 != (seg & 3)) - { - ESP=oldsp; - x86gpf("pmoderetf(): New SS DPL != CS RPL",newss&~3); - return; - } - SS=newss; - set_stack32((segdat2[3] & 0x40) ? 1 : 0); - if (stack32) ESP=newsp; - else SP=newsp; - do_seg_load(&cpu_state.seg_ss, segdat2); - -#ifdef SEL_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ - -#ifdef CS_ACCESSED - writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ -#endif - cpl_override = 0; -#endif - /*Conforming segments don't change CPL, so CPL = RPL*/ - if (segdat[2]&0x400) - segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); - - cpu_state.pc=newpc; - CS=seg; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); -#ifdef USE_NEW_DYNAREC - oldcpl = CPL; -#endif - set_use32(segdat[3] & 0x40); - - if (stack32) ESP+=off; - else SP+=off; - - check_seg_valid(&cpu_state.seg_ds); - check_seg_valid(&cpu_state.seg_es); - check_seg_valid(&cpu_state.seg_fs); - check_seg_valid(&cpu_state.seg_gs); - cycles -= timing_retf_pm_outer; - } -} - -void pmodeint(int num, int soft) -{ - uint16_t segdat[4],segdat2[4],segdat3[4]; - uint32_t addr, oaddr; - uint16_t newss; - uint32_t oldss,oldsp; - int type; - uint32_t newsp; - uint16_t seg = 0; - int new_cpl; - - if (cpu_state.eflags&VM_FLAG && IOPL!=3 && soft) - { - x86seg_log("V86 banned int\n"); - x86gpf("pmodeint(): V86 banned int",0); - return; - } - addr=(num<<3); - if (addr>=idt.limit) - { - if (num==8) - { - /*Triple fault - reset!*/ - softresetx86(); - cpu_set_edx(); - } - else if (num==0xD) - { - pmodeint(8,0); - } - else - { - x86gpf("pmodeint(): Vector > IDT limit",(num*8)+2+((soft)?0:1)); - } - x86seg_log("addr >= IDT.limit\n"); - return; - } - addr+=idt.base; - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(2,addr); - segdat[2]=readmemw(4,addr); - segdat[3]=readmemw(6,addr); cpl_override=0; - if (cpu_state.abrt) { - x86seg_log("Abrt reading from %08X\n",addr); - return; - } - oaddr = addr; - - x86seg_log("Addr %08X seg %04X %04X %04X %04X\n",addr,segdat[0],segdat[1],segdat[2],segdat[3]); - if (!(segdat[2]&0x1F00)) - { - x86gpf("pmodeint(): Vector descriptor with bad type",(num*8)+2); - return; - } - if (DPL=0x800)?32:16; - if (!(segdat[2]&0x8000)) - { - x86np("Int gate not present\n", (num << 3) | 2); - return; - } - seg=segdat[1]; - new_cpl = seg & 3; - - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf("pmodeint(): Interrupt or trap gate selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("pmodeint(): Interrupt or trap gate selector > GDT limit", seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - oaddr = addr; - - if (DPL2 > CPL) - { - x86gpf("pmodeint(): Interrupt or trap gate DPL > CPL",seg&~3); - return; - } - switch (segdat2[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if (DPL2=ldt.limit) - { - x86ss(NULL,newss&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86ss(NULL,newss&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat3[0]=readmemw(0,addr); - segdat3[1]=readmemw(0,addr+2); - segdat3[2]=readmemw(0,addr+4); - segdat3[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - if (((newss & 3) != DPL2) || (DPL3 != DPL2)) - { - x86ss(NULL,newss&~3); - return; - } - if ((segdat3[2]&0x1A00)!=0x1200) - { - x86ss(NULL,newss&~3); - return; - } - if (!(segdat3[2]&0x8000)) - { - x86np("Int gate loading SS not present\n", newss & 0xfffc); - return; - } - SS=newss; - set_stack32((segdat3[3] & 0x40) ? 1 : 0); - if (stack32) ESP=newsp; - else SP=newsp; - do_seg_load(&cpu_state.seg_ss, segdat3); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat3[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - x86seg_log("New stack %04X:%08X\n",SS,ESP); - cpl_override=1; - if (type>=0x800) - { - if (cpu_state.eflags & VM_FLAG) - { - PUSHL(GS); - PUSHL(FS); - PUSHL(DS); - PUSHL(ES); if (cpu_state.abrt) return; - loadseg(0,&cpu_state.seg_ds); - loadseg(0,&cpu_state.seg_es); - loadseg(0,&cpu_state.seg_fs); - loadseg(0,&cpu_state.seg_gs); - } - PUSHL(oldss); - PUSHL(oldsp); - PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); - PUSHL(CS); - PUSHL(cpu_state.pc); if (cpu_state.abrt) return; - } - else - { - PUSHW(oldss); - PUSHW(oldsp); - PUSHW(cpu_state.flags); - PUSHW(CS); - PUSHW(cpu_state.pc); if (cpu_state.abrt) return; - } - cpl_override=0; - cpu_state.seg_cs.access=0 | 0x80; - cycles -= timing_int_pm_outer - timing_int_pm; - break; - } - else if (DPL2!=CPL) - { - x86gpf("pmodeint(): DPL != CPL",seg&~3); - return; - } + x86seg_log("New stack %04X:%08X\n", SS, ESP); + cpl_override = 1; + if (type >= 0x0800) { + if (cpu_state.eflags & VM_FLAG) { + PUSHL(GS); + PUSHL(FS); + PUSHL(DS); + PUSHL(ES); + if (cpu_state.abrt) + return; + loadseg(0, &cpu_state.seg_ds); + loadseg(0, &cpu_state.seg_es); + loadseg(0, &cpu_state.seg_fs); + loadseg(0, &cpu_state.seg_gs); + } + PUSHL(oldss); + PUSHL(oldsp); + PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); + PUSHL(CS); + PUSHL(cpu_state.pc); + if (cpu_state.abrt) + return; + } else { + PUSHW(oldss); + PUSHW(oldsp); + PUSHW(cpu_state.flags); + PUSHW(CS); + PUSHW(cpu_state.pc); + if (cpu_state.abrt) + return; + } + cpl_override = 0; + cpu_state.seg_cs.access = 0x80; + cycles -= timing_int_pm_outer - timing_int_pm; + break; + } else if (DPL2 != CPL) { + x86gpf("pmodeint(): DPL != CPL", seg & 0xfffc); + return; + } /*FALLTHROUGH*/ - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if (!(segdat2[2]&0x8000)) - { - x86np("Int gate CS not present\n", segdat[1] & 0xfffc); - return; - } - if ((cpu_state.eflags & VM_FLAG) && DPL20x800) - { - PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); - PUSHL(CS); - PUSHL(cpu_state.pc); if (cpu_state.abrt) return; - } - else - { - PUSHW(cpu_state.flags); - PUSHW(CS); - PUSHW(cpu_state.pc); if (cpu_state.abrt) return; - } - new_cpl = CS & 3; - break; - default: - x86gpf("pmodeint(): Unknown type",seg&~3); - return; - } - do_seg_load(&cpu_state.seg_cs, segdat2); - CS = (seg & ~3) | new_cpl; - cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | (new_cpl << 5); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + if (!(segdat2[2] & 0x8000)) { + x86np("Int gate CS not present", segdat[1] & 0xfffc); + return; + } + if ((cpu_state.eflags & VM_FLAG) && (DPL2 < CPL)) { + x86gpf("pmodeint(): DPL < CPL in V86 mode", seg &~ 0xfffc); + return; + } + if (type > 0x0800) { + PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); + PUSHL(CS); + PUSHL(cpu_state.pc); + if (cpu_state.abrt) + return; + } else { + PUSHW(cpu_state.flags); + PUSHW(CS); + PUSHW(cpu_state.pc); + if (cpu_state.abrt) + return; + } + new_cpl = CS & 3; + break; + default: + x86gpf("pmodeint(): Unknown type", seg & 0xfffc); + return; + } + do_seg_load(&cpu_state.seg_cs, segdat2); + CS = (seg & 0xfffc) | new_cpl; + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~0x60) | (new_cpl << 5); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif - if (type>0x800) cpu_state.pc=segdat[0]|(segdat[3]<<16); - else cpu_state.pc=segdat[0]; - set_use32(segdat2[3]&0x40); + if (type > 0x0800) + cpu_state.pc = segdat[0] | (segdat[3] << 16); + else + cpu_state.pc = segdat[0]; + set_use32(segdat2[3] & 0x40); -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, oaddr+4, segdat2[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - cpu_state.eflags &= ~VM_FLAG; - cpu_cur_status &= ~CPU_STATUS_V86; - if (!(type&0x100)) - cpu_state.flags &= ~I_FLAG; - cpu_state.flags &= ~(T_FLAG|NT_FLAG); - cycles -= timing_int_pm; - break; - - case 0x500: /*Task gate*/ - seg=segdat[1]; - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf("pmodeint(): Task gate selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("pmodeint(): Task gate selector > GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); - cpl_override=0; if (cpu_state.abrt) return; - if (!(segdat2[2]&0x8000)) - { - x86np("Int task gate not present\n", segdat[1] & 0xfffc); - return; - } - optype=OPTYPE_INT; - cpl_override=1; - taskswitch286(seg,segdat2,segdat2[2]&0x800); - cpl_override=0; - break; - - default: - x86gpf(NULL,seg&~3); - return; - } + cpl_override = 1; + writememw(0, oaddr + 4, segdat2[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + + cpu_state.eflags &= ~VM_FLAG; + cpu_cur_status &= ~CPU_STATUS_V86; + if (!(type & 0x100)) + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~(T_FLAG | NT_FLAG); + cycles -= timing_int_pm; + break; + + case 0x500: /* Task gate */ + seg = segdat[1]; + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? &ldt : &gdt; + if ((addr + 7) >= dt->limit) { + x86gpf("pmodeint(): Task gate selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat2, segdat232, 1); + if (cpu_state.abrt) + return; + if (!(segdat2[2] & 0x8000)) { + x86np("Int task gate not present", segdat[1] & 0xfffc); + return; + } + optype = OPTYPE_INT; + cpl_override = 1; + taskswitch286(seg, segdat2, segdat2[2] & 0x0800); + cpl_override = 0; + break; + + default: + x86gpf("Protected mode interrupt unknown type", seg & 0xfffc); + return; + } } -void pmodeiret(int is32) + +void +pmodeiret(int is32) { - uint32_t newsp; - uint16_t newss; - uint32_t tempflags,flagmask; - uint32_t newpc; - uint16_t segdat[4],segdat2[4]; - uint16_t segs[4]; - uint16_t seg = 0; - uint32_t addr, oaddr; - uint32_t oldsp=ESP; - if (is386 && (cpu_state.eflags & VM_FLAG)) - { - if (IOPL!=3) - { - x86gpf(NULL,0); - return; - } + uint16_t newss, seg = 0; + uint16_t segdat[4],segdat2[4]; + uint16_t segs[4]; + uint32_t tempflags, flagmask; + uint32_t newpc, newsp; + uint32_t addr, oaddr; + uint32_t oldsp = ESP; + uint32_t *segdat32 = (uint32_t *) segdat; + uint32_t *segdat232 = (uint32_t *) segdat2; + x86seg *dt; + + if (is386 && (cpu_state.eflags & VM_FLAG)) { + if (IOPL != 3) { + x86gpf("Protected mode IRET: IOPL != 3", 0); + return; + } #ifndef USE_NEW_DYNAREC - oxpc=cpu_state.pc; + oxpc = cpu_state.pc; #endif - if (is32) - { - newpc=POPL(); - seg=POPL(); - tempflags=POPL(); if (cpu_state.abrt) return; - } - else - { - newpc=POPW(); - seg=POPW(); - tempflags=POPW(); if (cpu_state.abrt) return; - } - cpu_state.pc = newpc; - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - cpu_state.seg_cs.access |= 0x80; - cpu_state.seg_cs.ar_high = 0x10; - CS=seg; - cpu_state.flags = (cpu_state.flags & 0x3000) | (tempflags & 0xCFD5) | 2; - cycles -= timing_iret_rm; - return; - } + if (is32) { + newpc = POPL(); + seg = POPL(); + tempflags = POPL(); + } else { + newpc = POPW(); + seg = POPW(); + tempflags = POPW(); + } + if (cpu_state.abrt) + return; + + cpu_state.pc = newpc; + cpu_state.seg_cs.base= seg << 4; + cpu_state.seg_cs.limit = 0xffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + cpu_state.seg_cs.access |= 0x80; + cpu_state.seg_cs.ar_high = 0x10; + CS = seg; + cpu_state.flags = (cpu_state.flags & 0x3000) | (tempflags & 0xcfd5) | 2; + cycles -= timing_iret_rm; + return; + } + + if (cpu_state.flags & NT_FLAG) { + seg = readmemw(tr.base, 0); + addr = seg & 0xfff8; + if (seg & 0x0004) { + x86seg_log("TS LDT %04X %04X IRET\n", seg, gdt.limit); + x86ts("pmodeiret(): Selector points to LDT", seg & 0xfffc); + return; + } else { + if (addr >= gdt.limit) { + x86ts(NULL,seg&~3); + return; + } + addr += gdt.base; + } + cpl_override = 1; + read_descriptor(addr, segdat, segdat32, 1); + taskswitch286(seg, segdat,segdat[2] & 0x0800); + cpl_override = 0; + return; + } - if (cpu_state.flags & NT_FLAG) - { - seg=readmemw(tr.base,0); - addr=seg&~7; - if (seg&4) - { - x86seg_log("TS LDT %04X %04X IRET\n",seg,gdt.limit); - x86ts("pmodeiret(): Selector points to LDT",seg&~3); - return; - } - else - { - if (addr>=gdt.limit) - { - x86ts(NULL,seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); - taskswitch286(seg,segdat,segdat[2] & 0x800); - cpl_override=0; - return; - } #ifndef USE_NEW_DYNAREC - oxpc=cpu_state.pc; + oxpc=cpu_state.pc; #endif - flagmask=0xFFFF; - if (CPL) flagmask&=~0x3000; - if (IOPL>16)&VM_FLAG)) - { - newsp=POPL(); - newss=POPL(); - segs[0]=POPL(); - segs[1]=POPL(); - segs[2]=POPL(); - segs[3]=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } - cpu_state.eflags = tempflags>>16; - cpu_cur_status |= CPU_STATUS_V86; - loadseg(segs[0],&cpu_state.seg_es); - do_seg_v86_init(&cpu_state.seg_es); - loadseg(segs[1],&cpu_state.seg_ds); - do_seg_v86_init(&cpu_state.seg_ds); - cpu_cur_status |= CPU_STATUS_NOTFLATDS; - loadseg(segs[2],&cpu_state.seg_fs); - do_seg_v86_init(&cpu_state.seg_fs); - loadseg(segs[3],&cpu_state.seg_gs); - do_seg_v86_init(&cpu_state.seg_gs); + flagmask = 0xffff; + if (CPL != 0) + flagmask &= ~0x3000; + if (IOPL < CPL) + flagmask &= ~0x200; + if (is32) { + newpc = POPL(); + seg = POPL(); + tempflags = POPL(); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + if (is386 && ((tempflags >> 16) & VM_FLAG)) { + newsp = POPL(); + newss = POPL(); + segs[0] = POPL(); + segs[1] = POPL(); + segs[2] = POPL(); + segs[3] = POPL(); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + cpu_state.eflags = tempflags >> 16; + cpu_cur_status |= CPU_STATUS_V86; + loadseg(segs[0], &cpu_state.seg_es); + do_seg_v86_init(&cpu_state.seg_es); + loadseg(segs[1], &cpu_state.seg_ds); + do_seg_v86_init(&cpu_state.seg_ds); + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + loadseg(segs[2], &cpu_state.seg_fs); + do_seg_v86_init(&cpu_state.seg_fs); + loadseg(segs[3], &cpu_state.seg_gs); + do_seg_v86_init(&cpu_state.seg_gs); - cpu_state.pc = newpc & 0xffff; - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - CS=seg; - cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; - cpu_state.seg_cs.ar_high = 0x10; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + cpu_state.pc = newpc & 0xffff; + cpu_state.seg_cs.base = seg << 4; + cpu_state.seg_cs.limit = 0xffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + CS = seg; + cpu_state.seg_cs.access = 0xe2; + cpu_state.seg_cs.ar_high = 0x10; + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif - ESP=newsp; - loadseg(newss,&cpu_state.seg_ss); - do_seg_v86_init(&cpu_state.seg_ss); - cpu_cur_status |= CPU_STATUS_NOTFLATSS; - use32=0; - cpu_cur_status &= ~CPU_STATUS_USE32; - cpu_state.flags = (tempflags&0xFFD5)|2; - cycles -= timing_iret_v86; - return; - } - } - else - { - newpc=POPW(); - seg=POPW(); - tempflags=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } - } - if (!(seg&~3)) - { - ESP = oldsp; - x86gpf(NULL,0); - return; - } + ESP = newsp; + loadseg(newss, &cpu_state.seg_ss); + do_seg_v86_init(&cpu_state.seg_ss); + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + use32 = 0; + cpu_cur_status &= ~CPU_STATUS_USE32; + cpu_state.flags = (tempflags & 0xffd5) | 2; + cycles -= timing_iret_v86; + return; + } + } else { + newpc = POPW(); + seg = POPW(); + tempflags = POPW(); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + } + if (!(seg & 0xfffc)) { + ESP = oldsp; + x86gpf("pmodeiret(): Selector is NULL", 0); + return; + } - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - ESP = oldsp; - x86gpf("pmodeiret(): Selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - ESP = oldsp; - x86gpf("pmodeiret(): Selector > GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - if ((seg&3) < CPL) - { - ESP = oldsp; - x86gpf("pmodeiret(): RPL < CPL",seg&~3); - return; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? & ldt : &gdt; + if ((addr + 7) >= dt->limit) { + ESP = oldsp; + x86gpf("pmodeiret(): Selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + if ((seg & 0x0003) < CPL) { + ESP = oldsp; + x86gpf("pmodeiret(): RPL < CPL", seg & 0xfffc); + return; + } + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ - if ((seg&3) != DPL) - { - ESP = oldsp; - x86gpf("pmodeiret(): Non-conforming RPL != DPL",seg&~3); - return; - } - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming code*/ - if ((seg&3) < DPL) - { - ESP = oldsp; - x86gpf("pmodeiret(): Conforming RPL < DPL",seg&~3); - return; - } - break; - default: - ESP = oldsp; - x86gpf(NULL,seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - ESP = oldsp; - x86np("IRET CS not present\n", seg & 0xfffc); - return; - } - if ((seg&3) == CPL) - { - CS=seg; - do_seg_load(&cpu_state.seg_cs, segdat); - cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + switch (segdat[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming code */ + if ((seg & 0x0003) != DPL) { + ESP = oldsp; + x86gpf("pmodeiret(): Non-conforming RPL != DPL", seg & 0xfffc); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /* Conforming code */ + if ((seg & 0x0003) < DPL) { + ESP = oldsp; + x86gpf("pmodeiret(): Conforming RPL < DPL",seg&~3); + return; + } + break; + default: + ESP = oldsp; + x86gpf("pmodeiret(): Unknown type", seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + ESP = oldsp; + x86np("IRET CS not present", seg & 0xfffc); + return; + } + if ((seg & 0x0003) == CPL) { + CS = seg; + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~0x60) | ((CS & 0x0003) << 5); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif - set_use32(segdat[3]&0x40); + set_use32(segdat[3] & 0x0040); -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - cycles -= timing_iret_pm; - } - else /*Return to outer level*/ - { - oaddr = addr; - x86seg_log("Outer level\n"); - if (is32) - { - newsp=POPL(); - newss=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } - } - else - { - newsp=POPW(); - newss=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } - } - - x86seg_log("IRET load stack %04X:%04X\n",newss,newsp); - - if (!(newss&~3)) - { - ESP = oldsp; - x86gpf("pmodeiret(): New SS selector is zero",newss&~3); - return; - } - addr=newss&~7; - if (newss&4) - { - if (addr>=ldt.limit) - { - ESP = oldsp; - x86gpf("pmodeiret(): New SS selector > LDT limit",newss&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - ESP = oldsp; - x86gpf("pmodeiret(): New SS selector > GDT limit",newss&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } - if ((newss & 3) != (seg & 3)) - { - ESP = oldsp; - x86gpf("pmodeiret(): New SS RPL > CS RPL",newss&~3); - return; - } - if ((segdat2[2]&0x1A00)!=0x1200) - { - ESP = oldsp; - x86gpf("pmodeiret(): New SS bad type",newss&~3); - return; - } - if (DPL2 != (seg & 3)) - { - ESP = oldsp; - x86gpf("pmodeiret(): New SS DPL != CS RPL",newss&~3); - return; - } - if (!(segdat2[2]&0x8000)) - { - ESP = oldsp; - x86np("IRET loading SS not present\n", newss & 0xfffc); - return; - } - SS=newss; - set_stack32((segdat2[3] & 0x40) ? 1 : 0); - if (stack32) ESP=newsp; - else SP=newsp; - do_seg_load(&cpu_state.seg_ss, segdat2); + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + cycles -= timing_iret_pm; + } else { /* Return to outer level */ + oaddr = addr; + x86seg_log("Outer level\n"); + if (is32) { + newsp = POPL(); + newss = POPL(); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + } else { + newsp = POPW(); + newss = POPW(); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + } -#ifdef SEL_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + x86seg_log("IRET load stack %04X:%04X\n", newss, newsp); -#ifdef CS_ACCESSED - writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ -#endif - cpl_override = 0; -#endif - /*Conforming segments don't change CPL, so CPL = RPL*/ - if (segdat[2]&0x400) - segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + if (!(newss & 0xfffc)) { + ESP = oldsp; + x86gpf("pmodeiret(): New SS selector is zero", newss & 0xfffc); + return; + } + addr = newss & 0xfff8; + dt = (newss & 0x0004) ? &ldt : &gdt; + if ((addr + 7) >= dt->limit) { + ESP = oldsp; + x86gpf("pmodeiret(): New SS selector > DT limit", newss & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat2, segdat232, 1); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + if ((newss & 3) != (seg & 3)) { + SP = oldsp; + x86gpf("pmodeiret(): New SS RPL > CS RPL",newss & 0xfffc); + return; + } + if ((segdat2[2] & 0x1a00) != 0x1200) { + ESP = oldsp; + x86gpf("pmodeiret(): New SS bad type", newss & 0xfffc); + return; + } + if (DPL2 != (seg & 0x0003)) { + ESP = oldsp; + x86gpf("pmodeiret(): New SS DPL != CS RPL",newss & 0xfffc); + return; + } + if (!(segdat2[2] & 0x8000)) { + ESP = oldsp; + x86np("IRET loading SS not present", newss & 0xfffc); + return; + } + SS = newss; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); + if (stack32) + ESP = newsp; + else + SP = newsp; + do_seg_load(&cpu_state.seg_ss, segdat2); - CS=seg; - do_seg_load(&cpu_state.seg_cs, segdat); - cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + cpl_override = 1; + writememw(0, addr + 4, segdat2[2] | 0x100); /* Set accessed bit */ + writememw(0, oaddr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + /* Conforming segments don't change CPL, so CPL = RPL */ + if (segdat[2] & 0x0400) + segdat[2] = (segdat[2] & ~(3 << 13)) | ((seg & 3) << 13); + + CS = seg; + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~0x60) | ((CS & 3) << 5); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif - set_use32(segdat[3] & 0x40); + set_use32(segdat[3] & 0x40); - check_seg_valid(&cpu_state.seg_ds); - check_seg_valid(&cpu_state.seg_es); - check_seg_valid(&cpu_state.seg_fs); - check_seg_valid(&cpu_state.seg_gs); - cycles -= timing_iret_pm_outer; - } - cpu_state.pc=newpc; - cpu_state.flags = (cpu_state.flags&~flagmask) | (tempflags&flagmask&0xFFD5)|2; - if (is32) cpu_state.eflags = tempflags>>16; + check_seg_valid(&cpu_state.seg_ds); + check_seg_valid(&cpu_state.seg_es); + check_seg_valid(&cpu_state.seg_fs); + check_seg_valid(&cpu_state.seg_gs); + cycles -= timing_iret_pm_outer; + } + cpu_state.pc = newpc; + cpu_state.flags = (cpu_state.flags &~ flagmask) | (tempflags & flagmask & 0xffd5) | 2; + if (is32) + cpu_state.eflags = tempflags >> 16; } -void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) + +void +taskswitch286(uint16_t seg, uint16_t *segdat, int is32) { - uint32_t base; - uint32_t limit; - uint32_t templ; - uint16_t tempw; + uint16_t tempw, new_ldt; + uint16_t new_es, new_cs, new_ss, new_ds, new_fs, new_gs; + uint16_t segdat2[4]; + uint32_t base, limit; + uint32_t templ, new_cr3 = 0; + uint32_t new_eax, new_ebx, new_ecx, new_edx, new_esp, new_ebp; + uint32_t new_esi, new_edi, new_pc, new_flags, addr; + uint32_t *segdat232 = (uint32_t *) segdat2; + x86seg *dt; - uint32_t new_cr3=0; - uint16_t new_es,new_cs,new_ss,new_ds,new_fs,new_gs; - uint16_t new_ldt; + base = segdat[1] | ((segdat[2] & 0x00ff) << 16); + limit = segdat[0]; + if (is386) { + base |= (segdat[3] >> 8) << 24; + limit |= (segdat[3] & 0x000f) << 16; + } - uint32_t new_eax,new_ebx,new_ecx,new_edx,new_esp,new_ebp,new_esi,new_edi,new_pc,new_flags; + if (is32) { + if (limit < 103) { + x86ts("taskswitch286(): limit < 103", seg); + return; + } - uint32_t addr; - - uint16_t segdat2[4]; + if ((optype == JMP) || (optype == CALL) || (optype == OPTYPE_INT)) { + if (tr.seg & 0x0004) + tempw = readmemw(ldt.base, (seg & 0xfff8) + 4); + else + tempw = readmemw(gdt.base, (seg & 0xfff8) + 4); + if (cpu_state.abrt) + return; + tempw |= 0x0200; + if (tr.seg & 0x0004) + writememw(ldt.base, (seg & 0xfff8) + 4, tempw); + else + writememw(gdt.base, (seg & 0xfff8) + 4, tempw); + } + if (cpu_state.abrt) + return; - base=segdat[1]|((segdat[2]&0xFF)<<16); - limit=segdat[0]; - if(is386) - { - base |= (segdat[3]>>8)<<24; - limit |= (segdat[3]&0xF)<<16; - } + if (optype == IRET) + cpu_state.flags &= ~NT_FLAG; - if (is32) - { - if (limit < 103) - { - x86ts(NULL, seg); - return; - } + cpu_386_flags_rebuild(); + writememl(tr.base, 0x1C, cr3); + writememl(tr.base, 0x20, cpu_state.pc); + writememl(tr.base, 0x24, cpu_state.flags | (cpu_state.eflags << 16)); - if (optype==JMP || optype==CALL || optype==OPTYPE_INT) - { - if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); - else tempw=readmemw(gdt.base,(seg&~7)+4); - if (cpu_state.abrt) return; - tempw|=0x200; - if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); - else writememw(gdt.base,(seg&~7)+4,tempw); - } - if (cpu_state.abrt) return; + writememl(tr.base, 0x28, EAX); + writememl(tr.base, 0x2C, ECX); + writememl(tr.base, 0x30, EDX); + writememl(tr.base, 0x34, EBX); + writememl(tr.base, 0x38, ESP); + writememl(tr.base, 0x3C, EBP); + writememl(tr.base, 0x40, ESI); + writememl(tr.base, 0x44, EDI); - if (optype==IRET) cpu_state.flags&=~NT_FLAG; + writememl(tr.base, 0x48, ES); + writememl(tr.base, 0x4C, CS); + writememl(tr.base, 0x50, SS); + writememl(tr.base, 0x54, DS); + writememl(tr.base, 0x58, FS); + writememl(tr.base, 0x5C, GS); - cpu_386_flags_rebuild(); - writememl(tr.base,0x1C,cr3); - writememl(tr.base,0x20,cpu_state.pc); - writememl(tr.base,0x24,cpu_state.flags | (cpu_state.eflags<<16)); - - writememl(tr.base,0x28,EAX); - writememl(tr.base,0x2C,ECX); - writememl(tr.base,0x30,EDX); - writememl(tr.base,0x34,EBX); - writememl(tr.base,0x38,ESP); - writememl(tr.base,0x3C,EBP); - writememl(tr.base,0x40,ESI); - writememl(tr.base,0x44,EDI); - - writememl(tr.base,0x48,ES); - writememl(tr.base,0x4C,CS); - writememl(tr.base,0x50,SS); - writememl(tr.base,0x54,DS); - writememl(tr.base,0x58,FS); - writememl(tr.base,0x5C,GS); - - if (optype==JMP || optype==IRET) - { - if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); - else tempw=readmemw(gdt.base,(tr.seg&~7)+4); - if (cpu_state.abrt) return; - tempw&=~0x200; - if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); - else writememw(gdt.base,(tr.seg&~7)+4,tempw); - } - if (cpu_state.abrt) return; - - if (optype==OPTYPE_INT || optype==CALL) - { - writememl(base,0,tr.seg); - if (cpu_state.abrt) - return; - } - + if ((optype == JMP) || (optype == IRET)) { + if (tr.seg & 0x0004) + tempw = readmemw(ldt.base, (tr.seg & 0xfff8) + 4); + else + tempw = readmemw(gdt.base, (tr.seg & 0xfff8) + 4); + if (cpu_state.abrt) + return; + tempw &= ~0x0200; + if (tr.seg & 0x0004) + writememw(ldt.base, (tr.seg & 0xfff8) + 4, tempw); + else + writememw(gdt.base, (tr.seg & 0xfff8) + 4, tempw); + } + if (cpu_state.abrt) + return; - new_cr3=readmeml(base,0x1C); - new_pc=readmeml(base,0x20); - new_flags=readmeml(base,0x24); - if (optype == OPTYPE_INT || optype == CALL) - new_flags |= NT_FLAG; - - new_eax=readmeml(base,0x28); - new_ecx=readmeml(base,0x2C); - new_edx=readmeml(base,0x30); - new_ebx=readmeml(base,0x34); - new_esp=readmeml(base,0x38); - new_ebp=readmeml(base,0x3C); - new_esi=readmeml(base,0x40); - new_edi=readmeml(base,0x44); + if ((optype == OPTYPE_INT) || (optype == CALL)) { + writememl(base, 0, tr.seg); + if (cpu_state.abrt) + return; + } - new_es=readmemw(base,0x48); - new_cs=readmemw(base,0x4C); - new_ss=readmemw(base,0x50); - new_ds=readmemw(base,0x54); - new_fs=readmemw(base,0x58); - new_gs=readmemw(base,0x5C); - new_ldt=readmemw(base,0x60); + new_cr3 = readmeml(base, 0x1C); + new_pc = readmeml(base, 0x20); + new_flags = readmeml(base, 0x24); + if ((optype == OPTYPE_INT) || (optype == CALL)) + new_flags |= NT_FLAG; - cr0 |= 8; + new_eax = readmeml(base, 0x28); + new_ecx = readmeml(base, 0x2C); + new_edx = readmeml(base, 0x30); + new_ebx = readmeml(base, 0x34); + new_esp = readmeml(base, 0x38); + new_ebp = readmeml(base, 0x3C); + new_esi = readmeml(base, 0x40); + new_edi = readmeml(base, 0x44); - cr3=new_cr3; - flushmmucache(); + new_es = readmemw(base, 0x48); + new_cs = readmemw(base, 0x4C); + new_ss = readmemw(base, 0x50); + new_ds = readmemw(base, 0x54); + new_fs = readmemw(base, 0x58); + new_gs = readmemw(base, 0x5C); + new_ldt = readmemw(base, 0x60); - cpu_state.pc=new_pc; - cpu_state.flags = new_flags; - cpu_state.eflags = new_flags>>16; - cpu_386_flags_extract(); + cr0 |= 8; - ldt.seg=new_ldt; - templ=(ldt.seg&~7)+gdt.base; - ldt.limit=readmemw(0,templ); - if (readmemb(0,templ+6)&0x80) - { - ldt.limit<<=12; - ldt.limit|=0xFFF; - } - ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); + cr3 = new_cr3; + flushmmucache(); - if (cpu_state.eflags & VM_FLAG) - { - loadcs(new_cs); - set_use32(0); - cpu_cur_status |= CPU_STATUS_V86; - } - else - { - if (!(new_cs&~3)) - { - x86ts(NULL,0); - return; - } - addr=new_cs&~7; - if (new_cs&4) - { - if (addr>=ldt.limit) - { - x86ts(NULL,new_cs&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86ts(NULL,new_cs&~3); - return; - } - addr+=gdt.base; - } - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); - if (!(segdat2[2]&0x8000)) - { - x86np("TS loading CS not present\n", new_cs & 0xfffc); - return; - } - switch (segdat2[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if ((new_cs&3) != DPL2) - { - x86ts(NULL,new_cs&~3); - return; - } - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if ((new_cs&3) < DPL2) - { - x86ts(NULL,new_cs&~3); - return; - } - break; - default: - x86ts(NULL,new_cs&~3); - return; - } + cpu_state.pc = new_pc; + cpu_state.flags = new_flags; + cpu_state.eflags = new_flags >> 16; + cpu_386_flags_extract(); - CS=new_cs; - do_seg_load(&cpu_state.seg_cs, segdat2); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + ldt.seg = new_ldt; + templ = (ldt.seg & ~7) + gdt.base; + ldt.limit = readmemw(0, templ); + if (readmemb(0, templ + 6) & 0x80) { + ldt.limit <<= 12; + ldt.limit |= 0xfff; + } + ldt.base = (readmemw(0, templ + 2)) | (readmemb(0, templ + 4) << 16) | (readmemb(0, templ + 7) << 24); + + if (cpu_state.eflags & VM_FLAG) { + loadcs(new_cs); + set_use32(0); + cpu_cur_status |= CPU_STATUS_V86; + } else { + if (!(new_cs & 0xfffc)) { + x86ts("taskswitch286(): New CS selector is null", 0); + return; + } + addr = new_cs & 0xfff8; + dt = (new_cs & 0x0004) ? &ldt : &gdt; + if ((addr + 7) >= dt->limit) { + x86ts("taskswitch286(): New CS selector > DT limit", new_cs & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat2, segdat232, 0); + if (!(segdat2[2] & 0x8000)) { + x86np("TS loading CS not present", new_cs & 0xfffc); + return; + } + switch (segdat2[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming */ + if ((new_cs & 0x0003) != DPL2) { + x86ts("TS loading CS RPL != DPL2", new_cs & 0xfffc); + return; + } + break; + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + if ((new_cs & 0x0003) < DPL2) { + x86ts("TS loading CS RPL < DPL2", new_cs & 0xfffc); + return; + } + break; + default: + x86ts("TS loading CS unknown type", new_cs & 0xfffc); + return; + } + + CS = new_cs; + do_seg_load(&cpu_state.seg_cs, segdat2); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif - set_use32(segdat2[3] & 0x40); - cpu_cur_status &= ~CPU_STATUS_V86; - } + set_use32(segdat2[3] & 0x0040); + cpu_cur_status &= ~CPU_STATUS_V86; + } - EAX=new_eax; - ECX=new_ecx; - EDX=new_edx; - EBX=new_ebx; - ESP=new_esp; - EBP=new_ebp; - ESI=new_esi; - EDI=new_edi; + EAX = new_eax; + ECX = new_ecx; + EDX = new_edx; + EBX = new_ebx; + ESP = new_esp; + EBP = new_ebp; + ESI = new_esi; + EDI = new_edi; - loadseg(new_es,&cpu_state.seg_es); - loadseg(new_ss,&cpu_state.seg_ss); - loadseg(new_ds,&cpu_state.seg_ds); - loadseg(new_fs,&cpu_state.seg_fs); - loadseg(new_gs,&cpu_state.seg_gs); - } - else - { - if (limit < 43) - { - x86ts(NULL, seg); - return; - } + loadseg(new_es, &cpu_state.seg_es); + loadseg(new_ss, &cpu_state.seg_ss); + loadseg(new_ds, &cpu_state.seg_ds); + loadseg(new_fs, &cpu_state.seg_fs); + loadseg(new_gs, &cpu_state.seg_gs); + } else { + if (limit < 43) { + x86ts(NULL, seg); + return; + } - if (optype==JMP || optype==CALL || optype==OPTYPE_INT) - { - if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); - else tempw=readmemw(gdt.base,(seg&~7)+4); - if (cpu_state.abrt) return; - tempw|=0x200; - if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); - else writememw(gdt.base,(seg&~7)+4,tempw); - } - if (cpu_state.abrt) return; + if ((optype == JMP) || (optype == CALL) || (optype == OPTYPE_INT)) { + if (tr.seg & 0x0004) + tempw = readmemw(ldt.base, (seg & 0xfff8) + 4); + else + tempw = readmemw(gdt.base, (seg & 0xfff8) + 4); + if (cpu_state.abrt) + return; + tempw |= 0x200; + if (tr.seg & 0x0004) + writememw(ldt.base, (seg & 0xfff8) + 4, tempw); + else + writememw(gdt.base, (seg & 0xfff8) + 4, tempw); + } + if (cpu_state.abrt) + return; - if (optype == IRET) - cpu_state.flags &= ~NT_FLAG; + if (optype == IRET) + cpu_state.flags &= ~NT_FLAG; - cpu_386_flags_rebuild(); - writememw(tr.base,0x0E,cpu_state.pc); - writememw(tr.base,0x10,cpu_state.flags); - - writememw(tr.base,0x12,AX); - writememw(tr.base,0x14,CX); - writememw(tr.base,0x16,DX); - writememw(tr.base,0x18,BX); - writememw(tr.base,0x1A,SP); - writememw(tr.base,0x1C,BP); - writememw(tr.base,0x1E,SI); - writememw(tr.base,0x20,DI); - - writememw(tr.base,0x22,ES); - writememw(tr.base,0x24,CS); - writememw(tr.base,0x26,SS); - writememw(tr.base,0x28,DS); - - if (optype==JMP || optype==IRET) - { - if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); - else tempw=readmemw(gdt.base,(tr.seg&~7)+4); - if (cpu_state.abrt) return; - tempw&=~0x200; - if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); - else writememw(gdt.base,(tr.seg&~7)+4,tempw); - } - if (cpu_state.abrt) return; - - if (optype==OPTYPE_INT || optype==CALL) - { - writememw(base,0,tr.seg); - if (cpu_state.abrt) - return; - } - - new_pc=readmemw(base,0x0E); - new_flags=readmemw(base,0x10); - if (optype == OPTYPE_INT || optype == CALL) - new_flags |= NT_FLAG; - - new_eax=readmemw(base,0x12); - new_ecx=readmemw(base,0x14); - new_edx=readmemw(base,0x16); - new_ebx=readmemw(base,0x18); - new_esp=readmemw(base,0x1A); - new_ebp=readmemw(base,0x1C); - new_esi=readmemw(base,0x1E); - new_edi=readmemw(base,0x20); + cpu_386_flags_rebuild(); + writememw(tr.base, 0x0e, cpu_state.pc); + writememw(tr.base, 0x10, cpu_state.flags); - new_es=readmemw(base,0x22); - new_cs=readmemw(base,0x24); - new_ss=readmemw(base,0x26); - new_ds=readmemw(base,0x28); - new_ldt=readmemw(base,0x2A); + writememw(tr.base, 0x12, AX); + writememw(tr.base, 0x14, CX); + writememw(tr.base, 0x16, DX); + writememw(tr.base, 0x18, BX); + writememw(tr.base, 0x1a, SP); + writememw(tr.base, 0x1c, BP); + writememw(tr.base, 0x1e, SI); + writememw(tr.base, 0x20, DI); - msw |= 8; - - cpu_state.pc=new_pc; - cpu_state.flags = new_flags; - cpu_386_flags_extract(); + writememw(tr.base, 0x22, ES); + writememw(tr.base, 0x24, CS); + writememw(tr.base, 0x26, SS); + writememw(tr.base, 0x28, DS); - ldt.seg=new_ldt; - templ=(ldt.seg&~7)+gdt.base; - ldt.limit=readmemw(0,templ); - ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16); - if (is386) - { - if (readmemb(0,templ+6)&0x80) - { - ldt.limit<<=12; - ldt.limit|=0xFFF; - } - ldt.base|=(readmemb(0,templ+7)<<24); - } + if ((optype == JMP) || (optype == IRET)) { + if (tr.seg & 0x0004) + tempw = readmemw(ldt.base, (tr.seg & 0xfff8) + 4); + else + tempw = readmemw(gdt.base, (tr.seg & 0xfff8) + 4); + if (cpu_state.abrt) + return; + tempw &= ~0x200; + if (tr.seg & 0x0004) + writememw(ldt.base, (tr.seg & 0xfff8) + 4, tempw); + else + writememw(gdt.base, (tr.seg & 0xfff8) + 4, tempw); + } + if (cpu_state.abrt) + return; - if (!(new_cs&~3)) - { - x86ts(NULL,0); - return; - } - addr=new_cs&~7; - if (new_cs&4) - { - if (addr>=ldt.limit) - { - x86ts(NULL,new_cs&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86ts(NULL,new_cs&~3); - return; - } - addr+=gdt.base; - } - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); - if (!(segdat2[2]&0x8000)) - { - x86np("TS loading CS not present\n", new_cs & 0xfffc); - return; - } - switch (segdat2[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if ((new_cs&3) != DPL2) - { - x86ts(NULL,new_cs&~3); - return; - } - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if ((new_cs&3) < DPL2) - { - x86ts(NULL,new_cs&~3); - return; - } - break; - default: - x86ts(NULL,new_cs&~3); - return; - } + if ((optype == OPTYPE_INT) || (optype == CALL)) { + writememw(base, 0, tr.seg); + if (cpu_state.abrt) + return; + } - CS=new_cs; - do_seg_load(&cpu_state.seg_cs, segdat2); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + new_pc = readmemw(base, 0x0e); + new_flags = readmemw(base, 0x10); + if ((optype == OPTYPE_INT) || (optype == CALL)) + new_flags |= NT_FLAG; + + new_eax = readmemw(base, 0x12); + new_ecx = readmemw(base, 0x14); + new_edx = readmemw(base, 0x16); + new_ebx = readmemw(base, 0x18); + new_esp = readmemw(base, 0x1a); + new_ebp = readmemw(base, 0x1c); + new_esi = readmemw(base, 0x1e); + new_edi = readmemw(base, 0x20); + + new_es = readmemw(base, 0x22); + new_cs = readmemw(base, 0x24); + new_ss = readmemw(base, 0x26); + new_ds = readmemw(base, 0x28); + new_ldt = readmemw(base, 0x2a); + + msw |= 8; + + cpu_state.pc = new_pc; + cpu_state.flags = new_flags; + cpu_386_flags_extract(); + + ldt.seg = new_ldt; + templ = (ldt.seg & 0xfff8) + gdt.base; + ldt.limit = readmemw(0, templ); + ldt.base = (readmemw(0, templ + 2)) | (readmemb(0, templ + 4) << 16); + if (is386) { + if (readmemb(0, templ + 6) & 0x80) { + ldt.limit <<= 12; + ldt.limit |= 0xfff; + } + ldt.base |= (readmemb(0, templ + 7) << 24); + } + + if (!(new_cs & 0xfff8)) { + x86ts(NULL, 0); + return; + } + addr = new_cs & 0xfff8; + dt = (new_cs & 0x0004) ? &ldt : &gdt; + if ((addr + 7) >= dt->limit) { + x86ts(NULL, new_cs & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat2, segdat232, 0); + if (!(segdat2[2] & 0x8000)) { + x86np("TS loading CS not present", new_cs & 0xfffc); + return; + } + switch (segdat2[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming */ + if ((new_cs & 0x0003) != DPL2) { + x86ts(NULL,new_cs & 0xfffc); + return; + } + break; + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + if ((new_cs & 0x0003) < DPL2) { + x86ts(NULL,new_cs & 0xfffc); + return; + } + break; + default: + x86ts(NULL, new_cs & 0xfffc); + return; + } + + CS = new_cs; + do_seg_load(&cpu_state.seg_cs, segdat2); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); #ifdef USE_NEW_DYNAREC - oldcpl = CPL; + oldcpl = CPL; #endif - set_use32(0); + set_use32(0); - EAX=new_eax | 0xFFFF0000; - ECX=new_ecx | 0xFFFF0000; - EDX=new_edx | 0xFFFF0000; - EBX=new_ebx | 0xFFFF0000; - ESP=new_esp | 0xFFFF0000; - EBP=new_ebp | 0xFFFF0000; - ESI=new_esi | 0xFFFF0000; - EDI=new_edi | 0xFFFF0000; + EAX = new_eax | 0xffff0000; + ECX = new_ecx | 0xffff0000; + EDX = new_edx | 0xffff0000; + EBX = new_ebx | 0xffff0000; + ESP = new_esp | 0xffff0000; + EBP = new_ebp | 0xffff0000; + ESI = new_esi | 0xffff0000; + EDI = new_edi | 0xffff0000; - loadseg(new_es,&cpu_state.seg_es); - loadseg(new_ss,&cpu_state.seg_ss); - loadseg(new_ds,&cpu_state.seg_ds); - if (is386) - { - loadseg(0,&cpu_state.seg_fs); - loadseg(0,&cpu_state.seg_gs); - } - } + loadseg(new_es, &cpu_state.seg_es); + loadseg(new_ss, &cpu_state.seg_ss); + loadseg(new_ds, &cpu_state.seg_ds); + if (is386) { + loadseg(0, &cpu_state.seg_fs); + loadseg(0, &cpu_state.seg_gs); + } + } - tr.seg=seg; - tr.base=base; - tr.limit=limit; - tr.access=segdat[2]>>8; - tr.ar_high = segdat[3] & 0xff; + tr.seg = seg; + tr.base = base; + tr.limit = limit; + tr.access = segdat[2] >> 8; + tr.ar_high = segdat[3] & 0xff; }