[VM][I386][WIP] Porting features around virtual-8086 mode from NP2.
//#endif
static CPU_TRANSLATE(i386);
+void terminate()
+{
+ printf("WARN: unexpected exception\n");
+}
#include "mame/lib/softfloat/softfloat.c"
#include "mame/lib/softfloat/fsincos.c"
static void zero_state(i386_state *cpustate);
static void pentium_smi(i386_state* cpustate);
-#define FAULT(fault,error) {cpustate->ext = 1; i386_trap_with_error(cpustate,fault,0,0,error); return;}
-#define FAULT_EXP(fault,error) {cpustate->ext = 1; i386_trap_with_error(cpustate,fault,0,trap_level+1,error); return;}
+#define FAULT(fault,error) {logerror("FAULT(%s , %s) PC=%08x V8086=%s PROTECTED=%s\n", #fault, #error, cpustate->pc, (cpustate->VM) ? "YES" : "NO", (PROTECTED_MODE) ? "YES" : "NO"); cpustate->ext = 1; i386_trap_with_error(cpustate,fault,0,0,error); return;}
+#define FAULT_EXP(fault,error) {logerror("FAULT_EXP(%s , %s) PC=%08x V8086=%s PROTECTED=%s\n", #fault, #error, cpustate->pc, (cpustate->VM) ? "YES" : "NO", (PROTECTED_MODE) ? "YES" : "NO"); cpustate->ext = 1; i386_trap_with_error(cpustate,fault,0,trap_level+1,error); return;}
static void cpu_reset_generic(i386_state* cpustate)
{
if( !(PROTECTED_MODE) )
{
/* 16-bit */
- PUSH16(cpustate, oldflags & 0xffff );
- PUSH16(cpustate, cpustate->sreg[CS].selector );
- if(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1)
- PUSH16(cpustate, cpustate->eip );
- else
- PUSH16(cpustate, cpustate->prev_eip );
-
- cpustate->sreg[CS].selector = READ16(cpustate, cpustate->idtr.base + entry + 2 );
- cpustate->eip = READ16(cpustate, cpustate->idtr.base + entry );
-
- cpustate->TF = 0;
- cpustate->IF = 0;
+ try {
+ PUSH16(cpustate, oldflags & 0xffff );
+ PUSH16(cpustate, cpustate->sreg[CS].selector );
+ if(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1)
+ PUSH16(cpustate, cpustate->eip );
+ else
+ PUSH16(cpustate, cpustate->prev_eip );
+
+ cpustate->sreg[CS].selector = READ16(cpustate, cpustate->idtr.base + entry + 2 );
+ cpustate->eip = READ16(cpustate, cpustate->idtr.base + entry );
+
+ cpustate->TF = 0;
+ cpustate->IF = 0;
+ } catch(UINT64 e) {
+ logerror("Irregular exception happened %08x for 16bit.\n", e);
+ return;
+ } catch(UINT32 e) {
+ logerror("Irregular exception happened %08x for 16bit.\n", e);
+ return;
+ }
}
else
{
UINT8 CPL = cpustate->CPL, DPL = 0; //, RPL = 0;
/* 32-bit */
- v1 = READ32PL0(cpustate, cpustate->idtr.base + entry );
- v2 = READ32PL0(cpustate, cpustate->idtr.base + entry + 4 );
+ //try {
+ v1 = READ32PL0(cpustate, cpustate->idtr.base + entry );
+ v2 = READ32PL0(cpustate, cpustate->idtr.base + entry + 4 );
+ //} catch(UINT64 e) {
+ // logerror("Irregular exception happened %08x for protected mode.\n", e);
+ //} catch(UINT32 e) {
+ // logerror("Irregular exception happened %08x for protected mode.\n", e);
+ //}
offset = (v2 & 0xffff0000) | (v1 & 0xffff);
segment = (v1 >> 16) & 0xffff;
type = (v2>>8) & 0x1F;
catch(UINT64 e)
{
REG32(ESP) = tempSP;
+ logerror("THROWN at i386_trap() IRQ=%02x EIP=%08x V8086_MODE=%s line %d\n", irq, cpustate->eip, (V8086_MODE) ? "Yes" : "No", __LINE__);
throw e;
}
if(SetRPL != 0)
// no error code is pushed for software interrupts, either.
if(PROTECTED_MODE)
{
- UINT32 entry = irq * 8;
- UINT32 v2,type;
- v2 = READ32PL0(cpustate, cpustate->idtr.base + entry + 4 );
- type = (v2>>8) & 0x1F;
- if(type == 5)
- {
- v2 = READ32PL0(cpustate, cpustate->idtr.base + entry);
- v2 = READ32PL0(cpustate, cpustate->gdtr.base + ((v2 >> 16) & 0xfff8) + 4);
+ try {
+ UINT32 entry = irq * 8;
+ UINT32 v2,type;
+ v2 = READ32PL0(cpustate, cpustate->idtr.base + entry + 4 );
type = (v2>>8) & 0x1F;
+ if(type == 5)
+ {
+ v2 = READ32PL0(cpustate, cpustate->idtr.base + entry);
+ v2 = READ32PL0(cpustate, cpustate->gdtr.base + ((v2 >> 16) & 0xfff8) + 4);
+ type = (v2>>8) & 0x1F;
+ }
+ if(type >= 9)
+ PUSH32(cpustate,error);
+ else
+ PUSH16(cpustate,error);
+ } catch(UINT64 e) {
+ logerror("Irregular exception happened %08x for protected mode in trap_with_error()_.\n", e);
+ } catch(UINT32 e) {
+ logerror("Irregular exception happened %08x for protected mode in trap_with_error()_.\n", e);
}
- if(type >= 9)
- PUSH32(cpustate,error);
- else
+ }
+ else {
+ try {
PUSH16(cpustate,error);
+ } catch(UINT64 e) {
+ logerror("Irregular exception happened %08x for 16bit mode in trap_with_error()_.\n", e);
+ } catch(UINT32 e) {
+ logerror("Irregular exception happened %08x for 16bit mode in trap_with_error()_.\n", e);
+ }
}
- else
- PUSH16(cpustate,error);
}
}
catch(UINT64 e)
{
REG32(ESP) = tempSP;
+ logerror("THROWN at I386_OP(i386_protected_mode_call)() line %d\n", __LINE__);
throw e;
}
catch(UINT64 e)
{
cpustate->ext = 1;
+ logerror("Illegal instruction EIP=%08x VM8086=%s exception %08x irq=0 irq_gate=0 ERROR=%08x\n", cpustate->eip, (cpustate->VM) ? "YES" : "NO", e & 0xffffffff, e >> 32);
i386_trap_with_error(cpustate,e&0xffffffff,0,0,e>>32);
}
//#ifdef SINGLE_MODE_DMA
catch(UINT64 e)
{
cpustate->ext = 1;
+ logerror("Illegal instruction EIP=%08x VM8086=%s exception %08x irq=0 irq_gate=0 ERROR=%08x\n", cpustate->eip, (cpustate->VM) ? "YES" : "NO", e & 0xffffffff, e >> 32);
i386_trap_with_error(cpustate,e&0xffffffff,0,0,e>>32);
}
//#ifdef SINGLE_MODE_DMA
CYCLES(cpustate,CYCLES_CALL_INTERSEG); /* TODO: Timing = 17 + m */
//#ifdef I386_PSEUDO_BIOS
- BIOS_CALL_FAR(((ptr << 4) + offset) & cpustate->a20_mask)
+ //if(!(V8086_MODE)) {
+ BIOS_CALL_FAR(((ptr << 4) + offset) & cpustate->a20_mask);
+ //}
//#endif
if( PROTECTED_MODE && !V8086_MODE)
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset,2) == 0)
REG16(AX) = POP16(cpustate);
- else
+ else {
+ logerror("pop_ax() EXCEPTION(stack address fault)\n");
FAULT(FAULT_SS,0)
+ }
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset,2) == 0)
REG16(CX) = POP16(cpustate);
- else
+ else {
+ logerror("pop_cx() EXCEPTION(stack address fault)\n");
FAULT(FAULT_SS,0)
+ }
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset,2) == 0)
REG16(DX) = POP16(cpustate);
- else
+ else {
+ logerror("pop_dx() EXCEPTION(stack address fault)\n");
FAULT(FAULT_SS,0)
+ }
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset,2) == 0)
REG16(BX) = POP16(cpustate);
- else
+ else {
+ logerror("pop_bx() EXCEPTION(stack address fault)\n");
FAULT(FAULT_SS,0)
+ }
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset,2) == 0)
REG16(SP) = POP16(cpustate);
- else
+ else {
+ logerror("pop_sp() EXCEPTION(stack address fault)\n");
FAULT(FAULT_SS,0)
+ }
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset,2) == 0)
REG16(BP) = POP16(cpustate);
- else
+ else {
+ logerror("pop_bp() EXCEPTION(stack address fault)\n");
FAULT(FAULT_SS,0)
+ }
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset,2) == 0)
REG16(SI) = POP16(cpustate);
- else
+ else {
+ logerror("pop_si() EXCEPTION(stack address fault)\n");
FAULT(FAULT_SS,0)
+ }
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
if(i386_limit_check(cpustate,SS,offset,2) == 0)
REG16(DI) = POP16(cpustate);
- else
+ else {
+ logerror("pop_di() EXCEPTION(stack address fault)\n");
FAULT(FAULT_SS,0)
+ }
CYCLES(cpustate,CYCLES_POP_REG_SHORT);
}
else
{
cpustate->ext = 1;
+ logerror("Illegal address(pop_seg16) EIP=%08x VM8086=%s exception FAULT_SS irq=0 irq_gate=0 trap_level=0 ERROR=0\n", cpustate->eip, (cpustate->VM) ? "YES" : "NO");
i386_trap_with_error(cpustate,FAULT_SS,0,0,0);
return false;
}
catch(UINT64 e)
{
REG32(ESP) = temp_sp;
+ logerror("THROWN at I386_OP(pop_rm16)() line %d\n", __LINE__);
throw e;
}
}
selector = READ16(cpustate,ea + 2);
CYCLES(cpustate,CYCLES_CALL_MEM_INTERSEG); /* TODO: Timing = 10 + m */
//#ifdef I386_PSEUDO_BIOS
- BIOS_CALL_FAR(((selector << 4) + address) & cpustate->a20_mask)
+ //if(!(V8086_MODE)) {
+ BIOS_CALL_FAR(((selector << 4) + address) & cpustate->a20_mask);
+ //}
//#endif
if(PROTECTED_MODE && !V8086_MODE)
{
}
}
+extern void i386_change_protect_mode(i386_state *cpustate, int val);
+extern void i386_change_paging_mode(i386_state *cpustate, int val);
+
static void I386OP(group0F00_16)(i386_state *cpustate) // Opcode 0x0f 00
{
UINT32 address, ea;
case 2: /* LLDT */
if ( PROTECTED_MODE && !V8086_MODE )
{
- if(cpustate->CPL)
+ if(cpustate->CPL) {
+ logerror("group0F00_16: LLDT() EXCEPTION(PROTECTED_MODE && !V8086_MODE) / CPL set.\n");
FAULT(FAULT_GP,0)
+ }
if( modrm >= 0xc0 ) {
address = LOAD_RM16(modrm);
cpustate->ldtr.segment = address;
case 3: /* LTR */
if ( PROTECTED_MODE && !V8086_MODE )
{
- if(cpustate->CPL)
+ if(cpustate->CPL) {
+ logerror("group0F00_16: LTR() EXCEPTION(PROTECTED_MODE && !V8086_MODE) / CPL set.\n");
FAULT(FAULT_GP,0)
+ }
if( modrm >= 0xc0 ) {
address = LOAD_RM16(modrm);
cpustate->task.segment = address;
}
case 2: /* LGDT */
{
- if(PROTECTED_MODE && cpustate->CPL)
+ if(PROTECTED_MODE && cpustate->CPL) {
+ logerror("group0F01_16: LGDT() EXCEPTION(PROTECTED_MODE) / CPL set.\n");
FAULT(FAULT_GP,0)
+ }
if( modrm >= 0xc0 ) {
address = LOAD_RM16(modrm);
ea = i386_translate(cpustate, CS, address, 0, 6 );
}
case 3: /* LIDT */
{
- if(PROTECTED_MODE && cpustate->CPL)
+ if(PROTECTED_MODE && cpustate->CPL) {
+ logerror("group0F01_16: LLDT() EXCEPTION(PROTECTED_MODE) / CPL set.\n");
FAULT(FAULT_GP,0)
+ }
if( modrm >= 0xc0 ) {
address = LOAD_RM16(modrm);
ea = i386_translate(cpustate, CS, address, 0, 6 );
}
case 6: /* LMSW */
{
- if(PROTECTED_MODE && cpustate->CPL)
+ if(PROTECTED_MODE && cpustate->CPL) {
+ logerror("group0F01_16: LMSW() EXCEPTION(PROTECTED_MODE) / CPL set.\n");
FAULT(FAULT_GP,0)
+ }
UINT16 b;
if( modrm >= 0xc0 ) {
b = LOAD_RM16(modrm);
} else {
ea = GetEA(cpustate,modrm,0,2);
CYCLES(cpustate,CYCLES_LMSW_MEM);
- b = READ16(cpustate,ea);
+ b = READ16(cpustate,ea);
}
if(PROTECTED_MODE)
b |= 0x0001; // cannot return to real mode using this instruction.
- cpustate->cr[0] &= ~0x0000000f;
+ cpustate->cr[0] &= ~0x0000000e;
cpustate->cr[0] |= b & 0x0000000f;
+ if(!(cpustate->cr[0] & CPU_CRx_PE) && (b & CPU_CRx_PE)) {
+ i386_change_protect_mode(cpustate, 1);
+ }
break;
}
default:
} else {
UINT32 ea = GetEA(cpustate,modrm,1,4);
src = LOAD_REG32(modrm);
- WRITE32(cpustate,ea, src);
+ WRITE32(cpustate,ea, src);
CYCLES(cpustate,CYCLES_MOV_REG_MEM);
}
}
else
{
cpustate->ext = 1;
+ logerror("Illegal address(pop_seg32) EIP=%08x VM8086=%s exception FAULT_SS irq=0 irq_gate=0 trap_level=0 ERROR=0\n", cpustate->eip, (cpustate->VM) ? "YES" : "NO");
i386_trap_with_error(cpustate,FAULT_SS,0,0,0);
return false;
}
catch(UINT64 e)
{
REG32(ESP) = temp_sp;
+ logerror("THROWN at I386_OP(pop_rm32)() line %d\n", __LINE__);
throw e;
}
}
if(PROTECTED_MODE)
{
UINT8 IOPL = cpustate->IOP1 | (cpustate->IOP2 << 1);
- if(cpustate->CPL > IOPL)
+ if(cpustate->CPL > IOPL) {
+ logerror("Privilege error: I386OP(cli) CPL=%d IOPL=%d\n", cpustate->CPL, IOPL);
FAULT(FAULT_GP,0);
+ }
}
cpustate->IF = 0;
CYCLES(cpustate,CYCLES_CLI);
}
}
+// From np2,, ia32/system_inst.c
+// Descriptions of CRx:
+/*
+ * 0 = PE (protect enable)
+ * 1 = MP (monitor coprocesser)
+ * 2 = EM (emulation)
+ * 3 = TS (task switch)
+ * 4 = ET (extend type, FPU present = 1)
+ * 5 = NE (numeric error)
+ * 16 = WP (write protect)
+ * 18 = AM (alignment mask)
+ * 29 = NW (not write-through)
+ * 30 = CD (cache diable)
+ * 31 = PG (pageing)
+ */
+#define CPU_CRx_PE (1 << 0)
+#define CPU_CRx_MP (1 << 1)
+#define CPU_CRx_EM (1 << 2)
+#define CPU_CRx_TS (1 << 3)
+#define CPU_CRx_ET (1 << 4)
+#define CPU_CRx_NE (1 << 5)
+#define CPU_CRx_WP (1 << 16)
+#define CPU_CRx_AM (1 << 18)
+#define CPU_CRx_NW (1 << 29)
+#define CPU_CRx_CD (1 << 30)
+#define CPU_CRx_PG (1 << 31)
+#define CPU_CRx_ALL (CPU_CRx_PE|CPU_CRx_MP|CPU_CRx_EM|CPU_CRx_TS|CPU_CRx_ET|CPU_CRx_NE|CPU_CRx_WP|CPU_CRx_AM|CPU_CRx_NW|CPU_CRx_CD|CPU_CRx_PG)
+
+#define CPU_CR3_PD_MASK 0xfffff000
+#define CPU_CR3_PWT (1 << 3)
+#define CPU_CR3_PCD (1 << 4)
+#define CPU_CR3_MASK (CPU_CR3_PD_MASK|CPU_CR3_PWT|CPU_CR3_PCD)
+
static void I386OP(mov_r32_cr)(i386_state *cpustate) // Opcode 0x0f 20
{
- if(PROTECTED_MODE && cpustate->CPL)
- FAULT(FAULT_GP, 0);
UINT8 modrm = FETCH(cpustate);
+ if(modrm < 0xc0) {
+ FAULT(FAULT_UD, 0);
+ return;
+ }
+ if((PROTECTED_MODE && ((V8086_MODE) || (cpustate->CPL != 0)))) {
+ logerror("Call from non-supervisor privilege: I386OP(mov_r32_cr)");
+ FAULT(FAULT_GP, 0);
+ }
UINT8 cr = (modrm >> 3) & 0x7;
+ if(cr < 5) {
+ STORE_RM32(modrm, cpustate->cr[cr]);
+ CYCLES(cpustate,CYCLES_MOV_CR_REG);
+ } else {
+ logerror("Index error");
+ }
+}
+
+#define CPU_DR6_B(r) (1 << (r))
+#define CPU_DR6_BD (1 << 13)
+#define CPU_DR6_BS (1 << 14)
+#define CPU_DR6_BT (1 << 15)
+
+#define CPU_DR7_L(r) (1 << ((r) * 2))
+#define CPU_DR7_G(r) (1 << ((r) * 2 + 1))
+#define CPU_DR7_LE (1 << 8)
+#define CPU_DR7_GE (1 << 9)
+#define CPU_DR7_GD (1 << 13)
+#define CPU_DR7_RW(r) (3 << ((r) * 4 + 16))
+#define CPU_DR7_LEN(r) (3 << ((r) * 4 + 16 + 2))
- STORE_RM32(modrm, cpustate->cr[cr]);
- CYCLES(cpustate,CYCLES_MOV_CR_REG);
+void i386_change_protect_mode(i386_state *cpustate, int val)
+{
+ //
+ cpustate->sreg[SS].d = 0;
+ cpustate->CPL = 0;
+ if(val == 0) {
+ cpustate->cr[0] = cpustate->cr[0] & ~0x1;
+ } else {
+ cpustate->cr[0] = cpustate->cr[0] | ~0x1;
+ }
+}
+
+void i386_change_paging_mode(i386_state *cpustate, int val)
+{
+ // ToDo: Implement paging bit.
}
static void I386OP(mov_r32_dr)(i386_state *cpustate) // Opcode 0x0f 21
{
- if(PROTECTED_MODE && cpustate->CPL)
- FAULT(FAULT_GP, 0);
UINT8 modrm = FETCH(cpustate);
+ if(modrm < 0xc0) {
+ FAULT(FAULT_UD, 0);
+ return;
+ }
+ if((PROTECTED_MODE && ((V8086_MODE) || (cpustate->CPL != 0)))) {
+ logerror("Call from non-supervisor privilege: I386OP(mov_r32_dr)");
+ FAULT(FAULT_GP, 0);
+ }
+ if((cpustate->dr[7] & CPU_DR7_GD) != 0) {
+ cpustate->dr[6] |= CPU_DR6_BD;
+ cpustate->dr[7] &= ~CPU_DR7_GD;
+ FAULT(FAULT_DB, 0);
+ }
UINT8 dr = (modrm >> 3) & 0x7;
- STORE_RM32(modrm, cpustate->dr[dr]);
switch(dr)
{
case 0:
case 1:
case 2:
case 3:
+ STORE_RM32(modrm, cpustate->dr[dr]);
CYCLES(cpustate,CYCLES_MOV_REG_DR0_3);
break;
+ case 4:
case 6:
+ STORE_RM32(modrm, ((cpustate->dr[6] & 0x0000f00f) | 0xfff0ff0));
+ CYCLES(cpustate,CYCLES_MOV_REG_DR6_7);
+ break;
case 7:
+ STORE_RM32(modrm, cpustate->dr[dr]);
CYCLES(cpustate,CYCLES_MOV_REG_DR6_7);
break;
+ default:
+ logerror("i386: mov_r32_dr illegal index \n", dr);
+ return;
+ break;
}
}
static void I386OP(mov_cr_r32)(i386_state *cpustate) // Opcode 0x0f 22
{
- if(PROTECTED_MODE && cpustate->CPL)
- FAULT(FAULT_GP, 0);
UINT8 modrm = FETCH(cpustate);
UINT8 cr = (modrm >> 3) & 0x7;
+ if(modrm < 0xc0) {
+ FAULT(FAULT_UD, 0);
+ return;
+ }
+ if((PROTECTED_MODE && ((V8086_MODE) || (cpustate->CPL != 0)))) {
+ logerror("Call from non-supervisor privilege: I386OP(mov_cr_r32)");
+ FAULT(FAULT_GP, 0);
+ }
UINT32 data = LOAD_RM32(modrm);
+ UINT32 data_bak;
switch(cr)
{
case 0:
- data &= 0xfffeffff; // wp not supported on 386
CYCLES(cpustate,CYCLES_MOV_REG_CR0);
// if (PROTECTED_MODE != BIT(data, 0))
// debugger_privilege_hook();
+ if((data & (CPU_CRx_PE | CPU_CRx_PG)) == CPU_CRx_PG) {
+ FAULT(FAULT_GP, 0);
+ }
+ if((data & (CPU_CRx_NW | CPU_CRx_CD)) == CPU_CRx_NW) {
+ FAULT(FAULT_GP, 0);
+ }
+ data_bak = cpustate->cr[cr];
+ // ToDo: FPU
+ data &= CPU_CRx_ALL; // wp not supported on 386
+ data &= ~CPU_CRx_WP;
+ if(((data_bak ^ data) & (CPU_CRx_PE | CPU_CRx_PG)) != 0) {
+ // ToDo: TLB flush (paging)
+ vtlb_flush_dynamic(cpustate->vtlb);
+ }
+ if(((data_bak ^ data) & (CPU_CRx_PE)) != 0) {
+ if((data & CPU_CRx_PE) != 0) {
+ i386_change_protect_mode(cpustate, 1);
+ }
+ }
+ if(((data_bak ^ data) & (CPU_CRx_PG)) != 0) {
+ if((data & CPU_CRx_PG) != 0) {
+ // ToDo: change pg(1)
+ } else {
+ // ToDo: change pg(0)
+ }
+ }
+ if(((data_bak ^ data) & (CPU_CRx_PE)) != 0) {
+ if((data & CPU_CRx_PE) == 0) {
+ i386_change_protect_mode(cpustate, 0);
+ }
+ }
+ cpustate->cr[cr] |= (data & ~CPU_CRx_PE);
+ // ToDo: WP = (cr[0] & CPU_CRx_WP) ? 0x10 : 0;
+ return;
break;
case 2: CYCLES(cpustate,CYCLES_MOV_REG_CR2); break;
case 3:
CYCLES(cpustate,CYCLES_MOV_REG_CR3);
vtlb_flush_dynamic(cpustate->vtlb);
break;
- case 4: CYCLES(cpustate,1); break; // TODO
+ case 4:
+ /*
+ * 10 = OSXMMEXCPT (support non masking exception by OS)
+ * 9 = OSFXSR (support FXSAVE, FXRSTOR by OS)
+ * 8 = PCE (performance monitoring counter enable)
+ * 7 = PGE (page global enable)
+ * 6 = MCE (machine check enable)
+ * 5 = PAE (physical address extention)
+ * 4 = PSE (page size extention)
+ * 3 = DE (debug extention)
+ * 2 = TSD (time stamp diable)
+ * 1 = PVI (protected mode virtual interrupt)
+ * 0 = VME (VM8086 mode extention)
+ */
+ data_bak = 0x00000000; // ToDo: PGE
+ if((data & ~data_bak) != 0) {
+ if((data & 0xfffffc00) != 0) {
+ FAULT(FAULT_GP, 0);
+ }
+ logerror("mov cr4 r32 : set 0x%08x\n", data);
+ }
+ data_bak = cpustate->cr[4];
+ cpustate->cr[cr] = data;
+ if(((data ^ data_bak) & ((1 << 4) | (1 << 7) | (1 << 4))) != 0) { // PSE | PGE | PAE
+ vtlb_flush_dynamic(cpustate->vtlb);
+ }
+ CYCLES(cpustate,1);
+ return;
+ break; // TODO
default:
logerror("i386: mov_cr_r32 CR%d!\n", cr);
return;
static void I386OP(mov_dr_r32)(i386_state *cpustate) // Opcode 0x0f 23
{
- if(PROTECTED_MODE && cpustate->CPL)
- FAULT(FAULT_GP, 0);
UINT8 modrm = FETCH(cpustate);
+ if(modrm < 0xc0) {
+ FAULT(FAULT_UD, 0);
+ return;
+ }
+ if((PROTECTED_MODE && ((V8086_MODE) || (cpustate->CPL != 0)))) {
+ logerror("Call from non-supervisor privilege: I386OP(mov_dr_r32)");
+ FAULT(FAULT_GP, 0);
+ }
+ if ((cpustate->dr[7] & CPU_DR7_GD) != 0){
+ cpustate->dr[6] |= CPU_DR6_BD;
+ cpustate->dr[7] &= ~CPU_DR7_GD;
+ FAULT(FAULT_DB, 0);
+ }
UINT8 dr = (modrm >> 3) & 0x7;
- cpustate->dr[dr] = LOAD_RM32(modrm);
switch(dr)
{
case 0:
case 1:
case 2:
case 3:
+ cpustate->dr[dr] = LOAD_RM32(modrm);
CYCLES(cpustate,CYCLES_MOV_DR0_3_REG);
break;
case 6:
+ cpustate->dr[dr] = LOAD_RM32(modrm);
+ CYCLES(cpustate,CYCLES_MOV_DR6_7_REG);
+ break;
case 7:
+ cpustate->dr[dr] = LOAD_RM32(modrm);
+ cpustate->reg.d[EBP] = 0;
CYCLES(cpustate,CYCLES_MOV_DR6_7_REG);
break;
default:
catch (UINT64 e)
{
cpustate->eip = cpustate->prev_eip;
+ logerror("THROWN at I386_OP(repeat)() line %d\n", __LINE__);
throw e;
}
if(PROTECTED_MODE)
{
UINT8 IOPL = cpustate->IOP1 | (cpustate->IOP2 << 1);
- if(cpustate->CPL > IOPL)
+ if(cpustate->CPL > IOPL) {
+ logerror("Privilege error: I386OP(sti) CPL=%d IOPL=%d\n", cpustate->CPL, IOPL);
FAULT(FAULT_GP,0);
+ }
}
cpustate->delayed_interrupt_enable = 1; // IF is set after the next instruction.
CYCLES(cpustate,CYCLES_STI);
{
int interrupt = FETCH(cpustate);
CYCLES(cpustate,CYCLES_INT);
- BIOS_INT(interrupt)
+ if(V8086_MODE) {
+ //logerror("INT %02xh @V8086(16) mode\n", interrupt);
+ if((!cpustate->IOP1 || !cpustate->IOP2))
+ {
+ logerror("IRQ (%08x): Is in Virtual 8086 mode and IOPL != 3.\n",cpustate->pc);
+ //FAULT(FAULT_GP,0);
+ } else {
+ BIOS_INT(interrupt);
+ }
+ } else {
+ //logerror("INT %02xh @16bit mode\n", interrupt);
+ BIOS_INT(interrupt);
+ }
cpustate->ext = 0; // not an external interrupt
i386_trap(cpustate,interrupt, 1, 0);
cpustate->ext = 1;
{
int interrupt = FETCH(cpustate);
CYCLES(cpustate,CYCLES_INT);
- // Not calling 16bit BIOS
+#if 0
+ if(V8086_MODE) {
+ logerror("INT %02xh @V8086(32) mode\n", interrupt);
+ if((!cpustate->IOP1 || !cpustate->IOP2))
+ {
+ //logerror("IRQ (%08x): Is in Virtual 8086 mode and IOPL != 3.\n",cpustate->pc);
+ //FAULT(FAULT_GP,0);
+ } else {
+
+ BIOS_INT(interrupt);
+ }
+ } else {
+ logerror("INT %02xh @32bit mode\n", interrupt);
+ BIOS_INT(interrupt);
+ }
+#endif
cpustate->ext = 0; // not an external interrupt
i386_trap(cpustate,interrupt, 1, 0);
cpustate->ext = 1;
static void I386OP(hlt)(i386_state *cpustate) // Opcode 0xf4
{
- if(PROTECTED_MODE && cpustate->CPL != 0)
+ if(PROTECTED_MODE && cpustate->CPL != 0) {
+ logerror("Call from no-supervisor privilege: I386OP(hlt)");
FAULT(FAULT_GP,0);
+ }
cpustate->halted = 1;
CYCLES(cpustate,CYCLES_HLT);
if (cpustate->cycles > 0)
static void I386OP(clts)(i386_state *cpustate) // Opcode 0x0f 0x06
{
// Privileged instruction, CPL must be zero. Can be used in real or v86 mode.
- if(PROTECTED_MODE && cpustate->CPL != 0)
+ if(PROTECTED_MODE && cpustate->CPL != 0) {
+ logerror("Call from non-supervisor privilege: I386OP(clts)");
FAULT(FAULT_GP,0)
+ }
cpustate->cr[0] &= ~0x08; /* clear TS bit */
CYCLES(cpustate,CYCLES_CLTS);
}
static void I386OP(loadall)(i386_state *cpustate) // Opcode 0x0f 0x07 (0x0f 0x05 on 80286), undocumented
{
- if(PROTECTED_MODE && (cpustate->CPL != 0))
+ if(PROTECTED_MODE && (cpustate->CPL != 0)) {
+ logerror("Call from non-supervisor privilege: I386OP(loadall)");
FAULT(FAULT_GP,0)
+ }
UINT32 ea = i386_translate(cpustate, ES, REG32(EDI), 0, 204);
cpustate->cr[0] = READ32(cpustate, ea) & 0xfffeffff; // wp not supported on 386
set_flags(cpustate, READ32(cpustate, ea + 0x04));
};
/* Protected mode exceptions */
-#define FAULT_UD 6 // Invalid Opcode
-#define FAULT_NM 7 // Coprocessor not available
-#define FAULT_DF 8 // Double Fault
-#define FAULT_TS 10 // Invalid TSS
-#define FAULT_NP 11 // Segment or Gate not present
-#define FAULT_SS 12 // Stack fault
-#define FAULT_GP 13 // General Protection Fault
-#define FAULT_PF 14 // Page Fault
-#define FAULT_MF 16 // Match (Coprocessor) Fault
+#define FAULT_DE 0 // F
+#define FAULT_DB 1 // DEBUG
+#define FAULT_NMI 2 // NMI
+#define FAULT_BP 3 //
+#define FAULT_OF 4 //
+#define FAULT_BR 5 //
+#define FAULT_UD 6 // Invalid Opcode
+#define FAULT_NM 7 // Coprocessor not available
+#define FAULT_DF 8 // Double Fault
+#define FAULT_TS 10 // Invalid TSS
+#define FAULT_NP 11 // Segment or Gate not present
+#define FAULT_SS 12 // Stack fault
+#define FAULT_GP 13 // General Protection Fault
+#define FAULT_PF 14 // Page Fault
+#define FAULT_RSV 15 // *Reserved*
+#define FAULT_MF 16 // Match (Coprocessor) Fault
+#define FAULT_AC 17 //
+#define FAULT_MC 18 //
+#define FAULT_XF 19 //
/* MXCSR Control and Status Register */
#define MXCSR_IE (1<<0) // Invalid Operation Flag
extern int i386_parity_table[256];
static int i386_limit_check(i386_state *cpustate, int seg, UINT32 offset, UINT32 size);
-#define FAULT_THROW(fault,error) { throw (UINT64)(fault | (UINT64)error << 32); }
-#define PF_THROW(error) { cpustate->cr[2] = address; FAULT_THROW(FAULT_PF,error); }
+#define FAULT_THROW(fault,error) { \
+ /*logerror("FAULT_THROW(%s , %s)\n", #fault , #error );*/ \
+ throw (UINT64)(fault | (UINT64)error << 32); \
+ }
+
+#if 0
+#include <execinfo.h>
+static void pf_throw_sub(i386_state* cpustate, uint32_t address, uint64_t error)
+{
+ void *np[32];
+ int nptrs =backtrace(np, 32);
+ char **ss = backtrace_symbols(np, nptrs);
+ logerror("Backtrace: \n"); \
+ for(int __i = 0; __i < nptrs; __i++) {
+ logerror("%s\n", ss[__i]);
+ }
+}
+#define PF_THROW(error) { \
+ logerror("PF_THROW(%s) at %08x from function %s\n", #error, address, __func__); \
+ pf_throw_sub(cpustate, address, error); \
+ cpustate->cr[2] = address; \
+ FAULT_THROW(FAULT_PF,error); \
+ }
+
+#else
+#define PF_THROW(error) { \
+ /*logerror("PF_THROW(%s) at %08x from function %s\n", #error, address, __func__);*/ \
+ cpustate->cr[2] = address; \
+ FAULT_THROW(FAULT_PF,error); \
+ }
+#endif
#define PROTECTED_MODE (cpustate->cr[0] & 0x1)
#define STACK_32BIT (cpustate->sreg[SS].d)
#define V8086_MODE (cpustate->VM)