[VM][I386][WIP] Around V8086 mode.
#define U64(v) UINT64(v)
#define fatalerror(...) exit(1)
+
+#define logdebug(...) \
+ { \
+ if(cpustate != NULL) { \
+ if(cpustate->parent_device != NULL) { \
+ cpustate->parent_device->out_debug_log(__VA_ARGS__); \
+ } \
+ } \
+ }
+
+#define loginfo(...) \
+ { \
+ if(cpustate != NULL) { \
+ if(cpustate->parent_device != NULL) { \
+ cpustate->parent_device->out_debug_log(__VA_ARGS__); \
+ } \
+ } \
+ }
+
#if 0
#define logerror(...)
#else
int i386_parity_table[256];
MODRM_TABLE i386_MODRM_table[256];
-static void i386_trap_with_error(i386_state* cpustate, int irq, int irq_gate, int trap_level, UINT32 err);
+static void i386_trap_with_error(i386_state* cpustate, int irq, int irq_gate, int trap_level, UINT32 err, int is_top);
static void i286_task_switch(i386_state* cpustate, UINT16 selector, UINT8 nested);
static void i386_task_switch(i386_state* cpustate, UINT16 selector, UINT8 nested);
static void build_opcode_table(i386_state *cpustate, UINT32 features);
static void zero_state(i386_state *cpustate);
static void pentium_smi(i386_state* cpustate);
-#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;}
+#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, 0); 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, 0); return;}
static void cpu_reset_generic(i386_state* cpustate)
{
}
#if 0
if(old_vm != cpustate->VM) {
- if((cpustate->VM) && (PROTECTED_MODE)){
+ if((V8086_MODE) && (PROTECTED_MODE)){
// LOAD ES CS SS DS FS GS
i386_load_segment_descriptor(cpustate, ES);
i386_load_segment_descriptor(cpustate, CS);
stack.selector = selector;
i386_load_protected_mode_segment(cpustate,&stack,NULL);
DPL = (stack.flags >> 5) & 0x03;
-
+ logdebug("SReg load: SELECTOR=%04X FLAGS=%04X BASE=%08X LIMIT=%08X VALID=%s %s\n", stack.selector, stack.flags, stack.base, stack.limit, (stack.valid) ? "YES" : "NO", (stack.d == 0) ? "16bit SP" : "32bit ESP");
if((selector & ~0x0003) == 0)
{
logerror("SReg Load (%08x): Selector is null.\n",cpustate->pc);
{
if((selector & ~0x0007) > cpustate->ldtr.limit)
{
- logerror("SReg Load (%08x): Selector is out of LDT bounds.\n",cpustate->pc);
+ logerror("SReg Load (%08x): Selector is out of LDT bounds.LDTR.limit=%4X : selector=%04X\n",cpustate->pc, cpustate->ldtr.limit, selector);
FAULT(FAULT_GP,selector & ~0x03)
}
}
{
if((selector & ~0x0007) > cpustate->gdtr.limit)
{
- logerror("SReg Load (%08x): Selector is out of GDT bounds.\n",cpustate->pc);
+ logerror("SReg Load (%08x): Selector is out of bounds. GDT GDTR.limit=%04X : %04X\n",cpustate->pc, cpustate->gdtr.limit, selector);
FAULT(FAULT_GP,selector & ~0x03)
}
}
{
if((selector & ~0x0007) > cpustate->ldtr.limit)
{
- logerror("SReg Load (%08x): Selector is out of LDT bounds.\n",cpustate->pc);
+ logerror("SReg Load (%08x): Selector is out of LDT bounds.LDTR.limit=%04X : %04X\n",cpustate->pc, cpustate->ldtr.limit, selector);
FAULT(FAULT_GP,selector & ~0x03)
}
}
if(trap_level == 2)
{
- logerror("IRQ: Double fault.\n");
+ logdebug("IRQ: Double fault. IRQ%02Xh GATE=%d PC=%08X\n", irq, irq_gate, cpustate->pc);
FAULT_EXP(FAULT_DF,0);
}
if(trap_level >= 3)
{
- logerror("IRQ: Triple fault. CPU reset.\n");
+ logdebug("IRQ: Triple fault. CPU reset. IRQ%02Xh GATE=%d PC=%08X\n", irq, irq_gate, cpustate->pc);
//CPU_RESET_CALL(CPU_MODEL);
cpu_reset_generic(cpustate);
cpustate->shutdown = 1;
FAULT_EXP(FAULT_GP,0)
}
/* change CPL before accessing the stack */
+ UINT32 _oldCPL = cpustate->CPL;
+ if(_oldCPL != DPL) logerror("TRAP/INT GATE: Privilege changed from %d to %d at %08X, INT# %d, GATE %d TYPE %d\n", _oldCPL, DPL, cpustate->pc, irq, irq_gate, type);
cpustate->CPL = DPL;
/* check for page fault at new stack TODO: check if stack frame crosses page boundary */
WRITE_TEST(cpustate, stack.base+newESP-1);
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__);
+ logerror("THROWN EXCEPTION %08X at i386_trap() IRQ=%02x EIP=%08x V8086_MODE=%s line %d\n", e, irq, cpustate->eip, (V8086_MODE) ? "Yes" : "No", __LINE__);
throw e;
+ } catch(UINT32 e)
+ {
+ REG32(ESP) = tempSP;
+ logerror("THROWN EXCEPTION %08X at i386_trap() IRQ=%02x EIP=%08x V8086_MODE=%s line %d\n", e, irq, cpustate->eip, (V8086_MODE) ? "Yes" : "No", __LINE__);
+ throw (UINT64)e;
+ } catch(...) {
+ REG32(ESP) = tempSP;
+ logerror("THROWN EXCEPTION (UNKNOWN) at i386_trap() IRQ=%02x EIP=%08x V8086_MODE=%s line %d\n", irq, cpustate->eip, (V8086_MODE) ? "Yes" : "No", __LINE__);
+ throw 0; // Unknown
}
UINT16 o_selector = cpustate->sreg[CS].selector;
if(SetRPL != 0)
}
-static void i386_trap_with_error(i386_state *cpustate,int irq, int irq_gate, int trap_level, UINT32 error)
+static void i386_trap_with_error(i386_state *cpustate,int irq, int irq_gate, int trap_level, UINT32 error, int is_top)
{
-// try {
+ // buffering direct call from trap.
+ if(is_top != 0) {
+ try {
+ i386_trap(cpustate,irq,irq_gate,trap_level);
+ } 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 {
i386_trap(cpustate,irq,irq_gate,trap_level);
-// } 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;
-// }
+ }
if(irq == FAULT_DF || irq == FAULT_TS || irq == FAULT_NP || irq == FAULT_SS || irq == FAULT_GP || irq == FAULT_GP || irq == FAULT_AC)
{
cpustate->task.flags = seg.flags;
/* Set TS bit in CR0 */
- cpustate->cr[0] |= 0x08;
+ cpustate->cr[0] |= I386_CR0_TS;
/* Load incoming task state from the new task's TSS */
tss = cpustate->task.base;
WRITE16(cpustate,tss+0,old_task);
cpustate->NT = 1;
}
- CHANGE_PC(cpustate,cpustate->eip);
+ UINT32 _oldCPL = cpustate->CPL;
+ UINT32 _oldPC = cpustate->pc;
+ CHANGE_PC(cpustate,cpustate->eip);
cpustate->CPL = (cpustate->sreg[SS].flags >> 5) & 3;
+ UINT32 _newCPL = cpustate->CPL;
+ if(_oldCPL != _newCPL) logerror("I286 TASK SWITCH: Privilege changed from %d to %d at ADDR %08X to %08X\n", _oldCPL, _newCPL, _oldPC, cpustate->pc);
+
logerror("80286 Task Switch from selector %04x to %04x\n",old_task,selector);
}
cpustate->task.flags = seg.flags;
/* Set TS bit in CR0 */
- cpustate->cr[0] |= 0x08;
+ cpustate->cr[0] |= I386_CR0_TS;
/* Load incoming task state from the new task's TSS */
tss = cpustate->task.base;
WRITE8(cpustate,cpustate->gdtr.base + (selector & ~0x0007) + 5,ar_byte | 0x02);
}
+ UINT32 _oldCPL = cpustate->CPL;
+ UINT32 _oldPC = cpustate->pc;
+
CHANGE_PC(cpustate,cpustate->eip);
cpustate->CPL = (cpustate->sreg[SS].flags >> 5) & 3;
+ UINT32 _newCPL = cpustate->CPL;
+ if(_oldCPL != _newCPL) logerror("I80386 TASK SWITCH: Privilege changed from %d to %d at ADDR %08X to %08X\n", _oldCPL, _newCPL, _oldPC, cpustate->pc);
printf("i386 Task Switch from selector %04x to %04x\n",old_task,selector);
}
if ( (cpustate->irq_state) && cpustate->IF )
{
cpustate->cycles -= 2;
- i386_trap(cpustate, cpustate->pic->get_intr_ack(), 1, 0);
+ int irqnum = cpustate->pic->get_intr_ack();
+ try {
+ i386_trap(cpustate, irqnum, 1, 0);
+ } catch(UINT64 e) {
+ logdebug("EXCEPTION %08X VIA INTERRUPT/TRAP HANDLING IRQ=%02Xh(%d) ADDR=%08X\n", e, irqnum, irqnum, cpustate->pc);
+ } catch(UINT32 e) {
+ logdebug("EXCEPTION %08X VIA INTERRUPT/TRAP HANDLING IRQ=%02Xh(%d) ADDR=%08X\n", e, irqnum, irqnum, cpustate->pc);
+ } catch (...) {
+ logdebug("EXCEPTION (UNKNOWN) VIA INTERRUPT/TRAP HANDLING IRQ=%02Xh(%d) ADDR=%08X\n", irqnum, irqnum, cpustate->pc);
+ }
cpustate->irq_state = 0;
}
}
selector = gate.selector;
offset = gate.offset;
+ UINT32 _oldCPL = cpustate->CPL;
cpustate->CPL = (stack.flags >> 5) & 0x03;
+ UINT32 _newCPL = cpustate->CPL;
+ if(_oldCPL != _newCPL) logerror("Privilege changed by protected mode call from %d to %d ADDR %08X\n", _oldCPL, _newCPL, cpustate->pc);
/* check for page fault at new stack */
WRITE_TEST(cpustate, stack.base+newESP-1);
/* switch to new stack */
catch(UINT64 e)
{
REG32(ESP) = tempSP;
- logerror("THROWN at I386_OP(i386_protected_mode_call)() line %d\n", __LINE__);
+ logerror("THROWN %08X at I386_OP(i386_protected_mode_call)() at %08X\n", e, cpustate->pc);
throw e;
- }
+ } catch(UINT32 e)
+ {
+ REG32(ESP) = tempSP;
+ logerror("THROWN %08X at I386_OP(i386_protected_mode_call)() at %08X\n", e, cpustate->pc);
+ throw (UINT64)e;
+ } catch(...) {
+ REG32(ESP) = tempSP;
+ logerror("THROWN (UNKNOWN) at I386_OP(i386_protected_mode_call)() at %08X\n", cpustate->pc);
+ throw (UINT64)0;
+ }
CHANGE_PC(cpustate,cpustate->eip);
}
i386_load_segment_descriptor(cpustate,FS);
i386_load_segment_descriptor(cpustate,GS);
i386_load_segment_descriptor(cpustate,SS);
- logerror("Return to V8086 MODE: old CPL=%d new CPL=3 PC=%08X\n", cpustate->CPL, cpustate->pc);
+ logerror("IRET: Return to V8086 MODE: old CPL=%d new CPL=3 PC=%08X\n", cpustate->CPL, cpustate->pc);
cpustate->CPL = 3; // Virtual 8086 tasks are always run at CPL 3
}
else
// Init CR0
// From ia32_initreg() of np2, i386c/ia32/interface.c
- cpustate->cr[0] = CPU_CRx_CD | CPU_CRx_NW;
+ cpustate->cr[0] = I386_CR0_CD | I386_CR0_NW;
// ToDo: FPU
- //cpustate->cr[0] &= ~CPU_CRx_EM;
- //cpustate->cr[0] |= CPU_CRx_ET;
- cpustate->cr[0] |= (CPU_CRx_EM | CPU_CRx_NE);
- cpustate->cr[0] &= (CPU_CRx_MP | CPU_CRx_ET);
+ //cpustate->cr[0] &= ~I386_CR0_EM;
+ //cpustate->cr[0] |= I386_CR0_ET;
+ cpustate->cr[0] |= (I386_CR0_EM | I386_CR0_NE);
+ cpustate->cr[0] &= ~(I386_CR0_MP | I386_CR0_ET);
// Init GDTR/IDTR
cpustate->gdtr.base = 0x0000;
cpustate->gdtr.limit = 0xffff;
cpustate->a20_mask = ~0;
// Move to zero_state().
- //cpustate->cr[0] = 0x7fffffe0; // reserved bits set to 1
+ cpustate->cr[0] = 0x7fffffe0; // reserved bits set to 1
//cpustate->eflags = 2; // From NP2 : ia32_initreg(), interface.c
cpustate->eflags_mask = 0x00037fd7;
cpustate->eip = 0xfff0;
REG32(EDX) = (3 << 8) | (0 << 4) | (8);
cpustate->CPL = 0;
+ logerror("RESET CPL to 0 by resetting\n", cpustate->CPL);
CHANGE_PC(cpustate,cpustate->eip);
}
if(cpustate->smm)
return;
- cpustate->cr[0] &= ~(0x8000000d);
+ cpustate->cr[0] &= ~(0x8000000d);// !(PG | TS | EM | PE)
set_flags(cpustate, 2);
// if(!cpustate->smiact.isnull())
// cpustate->smiact(true);
cpustate->nmi_latched = true;
return;
}
- if ( state )
- i386_trap(cpustate,2, 1, 0);
+ if ( state ) {
+ try {
+ i386_trap(cpustate,2, 1, 0);
+ } catch(UINT64 e) {
+ logdebug("EXCEPTION %08X VIA making INT02h at i386_set_irq_line() ADDR=%08X\n", e, cpustate->pc);
+ } catch(UINT32 e) {
+ logdebug("EXCEPTION %08X VIA making INT02h at i386_set_irq_line() ADDR=%08X\n", e, cpustate->pc);
+ } catch(...) {
+ logdebug("EXCEPTION (UNKNOWN) VIA making INT02h at i386_set_irq_line() ADDR=%08X\n", cpustate->pc);
+ }
+ }
}
+
else
{
cpustate->irq_state = state;
{
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);
+ i386_trap_with_error(cpustate,e&0xffffffff,0,0,e>>32, 1);
+ } catch(UINT32 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,0, 1);
+ } catch(...) {
+ cpustate->ext = 1;
+ logerror("Illegal instruction EIP=%08x VM8086=%s exception %08x irq=0 irq_gate=0 ERROR=UNKNOWN\n", cpustate->eip, (cpustate->VM) ? "YES" : "NO");
+ i386_trap_with_error(cpustate,0,0,0,0, 1);
}
+
//#ifdef SINGLE_MODE_DMA
if(cpustate->dma != NULL) {
cpustate->dma->do_dma();
{
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);
+ i386_trap_with_error(cpustate,e&0xffffffff,0,0,e>>32, 1);
+ }
+ catch(UINT32 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, 0);
+ i386_trap_with_error(cpustate,e,0,0,0, 1);
+ }
+ catch(...)
+ {
+ 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", 0, 0);
+ i386_trap_with_error(cpustate,0,0,0,0, 1);
}
//#ifdef SINGLE_MODE_DMA
if(cpustate->dma != NULL) {
cpustate->a20_mask = ~0;
- cpustate->cr[0] = 0x00000010;
+ cpustate->cr[0] = 0x00000010; // ET
//cpustate->eflags = 0;
cpustate->eflags_mask = 0x00077fd7;
cpustate->eip = 0xfff0;
--- /dev/null
+#pragma once
+
+
+// From np2,, ia32/system_inst.c
+// Descriptions of CRx:
+/*
+ * CR0: From https://en.wikipedia.org/wiki/Control_register
+ * 0 PE Protected Mode Enable If 1, system is in protected mode, else system is in real mode
+ * 1 MP Monitor co-processor Controls interaction of WAIT/FWAIT instructions with TS flag in CR0
+ * 2 EM Emulation If set, no x87 floating-point unit present, if clear, x87 FPU present
+ * 3 TS Task switched Allows saving x87 task context upon a task switch only after x87 instruction used
+ * 4 ET Extension type On the 386, it allowed to specify whether the external math coprocessor was an 80287 or 80387
+ * 5 NE Numeric error Enable internal x87 floating point error reporting when set, else enables PC style x87 error detection
+ * 16 WP Write protect When set, the CPU can't write to read-only pages when privilege level is 0
+ * 18 AM Alignment mask Alignment check enabled if AM set, AC flag (in EFLAGS register) set, and privilege level is 3
+ * 29 NW Not-write through Globally enables/disable write-through caching
+ * 30 CD Cache disable Globally enables/disable the memory cache
+ * 31 PG Paging If 1, enable paging and use the § CR3 register, else disable paging.
+ */
+#define I386_CR0_PE (1 << 0)
+#define I386_CR0_MP (1 << 1)
+#define I386_CR0_EM (1 << 2)
+#define I386_CR0_TS (1 << 3)
+#define I386_CR0_ET (1 << 4)
+#define I386_CR0_NE (1 << 5)
+#define I386_CR0_WP (1 << 16)
+#define I386_CR0_AM (1 << 18)
+#define I386_CR0_NW (1 << 29)
+#define I386_CR0_CD (1 << 30)
+#define I386_CR0_PG (1 << 31)
+#define I386_CR0_ALL (I386_CR0_PE|I386_CR0_MP|I386_CR0_EM|I386_CR0_TS|I386_CR0_ET|I386_CR0_NE|I386_CR0_WP|I386_CR0_AM|I386_CR0_NW|I386_CR0_CD|I386_CR0_PG)
+
+#define I386_CR3_PD_MASK 0xfffff000
+#define I386_CR3_PCID 0x00000fff
+#define I386_CR3_PWT (1 << 3)
+#define I386_CR3_PCD (1 << 4)
+#define I386_CR3_MASK (I386_CR3_PD_MASK|I386_CR3_PWT|I386_CR3_PCD)
+
+/*
+ * CR4: From https://en.wikipedia.org/wiki/Control_register#CR4
+ * 0 VME Virtual 8086 Mode Extensions If set, enables support for the virtual interrupt flag (VIF) in virtual-8086 mode.
+ * 1 PVI Protected-mode Virtual Interrupts If set, enables support for the virtual interrupt flag (VIF) in protected mode.
+ * 2 TSD Time Stamp Disable If set, RDTSC instruction can only be executed when in ring 0, otherwise RDTSC can be used at any privilege level.
+ * 3 DE Debugging Extensions If set, enables debug register based breaks on I/O space access.
+ * 4 PSE Page Size Extension If unset, page size is 4 KiB, else page size is increased to 4 MiB If PAE is enabled or the processor is in x86-64 long mode this bit is ignored.[2]
+ * 5 PAE Physical Address Extension If set, changes page table layout to translate 32-bit virtual addresses into extended 36-bit physical addresses.
+ * 6 MCE Machine Check Exception If set, enables machine check interrupts to occur.
+ * 7 PGE Page Global Enabled If set, address translations (PDE or PTE records) may be shared between address spaces.
+ * 8 PCE Performance-Monitoring Counter enable If set, RDPMC can be executed at any privilege level, else RDPMC can only be used in ring 0.
+ * 9 OSFXSR Operating system support for FXSAVE and FXRSTOR instructions If set, enables Streaming SIMD Extensions (SSE) instructions and fast FPU save & restore.
+ * 10 OSXMMEXCPT Operating System Support for Unmasked SIMD Floating-Point Exceptions If set, enables unmasked SSE exceptions.
+ * 11 UMIP User-Mode Instruction Prevention If set, the SGDT, SIDT, SLDT, SMSW and STR instructions cannot be executed if CPL > 0.[1]
+ * 12 LA57 (none specified) If set, enables 5-Level Paging.[3]
+ * 13 VMXE Virtual Machine Extensions Enable see Intel VT-x x86 virtualization.
+ * 14 SMXE Safer Mode Extensions Enable see Trusted Execution Technology (TXT)
+ * 16 FSGSBASE Enables the instructions RDFSBASE, RDGSBASE, WRFSBASE, and WRGSBASE.
+ * 17 PCIDE PCID Enable If set, enables process-context identifiers (PCIDs).
+ * 18 OSXSAVE XSAVE and Processor Extended States Enable
+ * 20 SMEP Supervisor Mode Execution Protection Enable If set, execution of code in a higher ring generates a fault.
+ * 21 SMAP Supervisor Mode Access Prevention Enable If set, access of data in a higher ring generates a fault.[5]
+ * 22 PKE Protection Key Enable See Intel 64 and IA-32 Architectures Software Developer’s Manual.
+*/
+#define I386_CR4_VME (1 << 0)
+#define I386_CR4_PVI (1 << 1)
+#define I386_CR4_TSD (1 << 2)
+#define I386_CR4_DE (1 << 3)
+#define I386_CR4_PSE (1 << 4)
+#define I386_CR4_PAE (1 << 5)
+#define I386_CR4_MCE (1 << 6)
+#define I386_CR4_PGE (1 << 7)
+#define I386_CR4_PCE (1 << 8)
+#define I386_CR4_OSFXSR (1 << 9)
+#define I386_CR4_OSXMMEXCPT (1 << 10)
+#define I386_CR4_UMIP (1 << 11)
+#define I386_CR4_LA57 (1 << 12)
+#define I386_CR4_VMXE (1 << 13)
+#define I386_CR4_SMXE (1 << 14)
+// bit15: ??
+#define I386_CR4_FSGBASE (1 << 16)
+#define I386_CR4_PCIDE (1 << 17)
+#define I386_CR4_OSXSAVE (1 << 18)
+// bit19: ??
+#define I386_CR4_SMEP (1 << 20)
+#define I386_CR4_SMAP (1 << 21)
+#define I386_CR4_PKE (1 << 22)
+
+#define I386_CR4_SET_MASK1 ~(I386_CR4_VME | I386_CR4_PVI | I386_CR4_TSD | I386_CR4_DE | I386_CR4_PSE | I386_CR4_PAE | I386_CR4_MCE | I386_CR4_PGE | I386_CR4_PCE | I386_CR4_OSFXSR)
+
+#define I386_DR6_B(r) (1 << (r))
+#define I386_DR6_BD (1 << 13)
+#define I386_DR6_BS (1 << 14)
+#define I386_DR6_BT (1 << 15)
+
+#define I386_DR7_L(r) (1 << ((r) * 2))
+#define I386_DR7_G(r) (1 << ((r) * 2 + 1))
+#define I386_DR7_LE (1 << 8)
+#define I386_DR7_GE (1 << 9)
+#define I386_DR7_GD (1 << 13)
+#define I386_DR7_RW(r) (3 << ((r) * 4 + 16))
+#define I386_DR7_LEN(r) (3 << ((r) * 4 + 16 + 2))
{
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);
+ i386_trap_with_error(cpustate,FAULT_SS,0,0,0, 0);
return false;
}
CYCLES(cpustate,CYCLES_POP_SREG);
memset(&seg, 0, sizeof(seg));
seg.selector = cpustate->ldtr.segment;
i386_load_protected_mode_segment(cpustate,&seg,NULL);
- cpustate->ldtr.limit = seg.limit;
- cpustate->ldtr.base = seg.base;
- cpustate->ldtr.flags = seg.flags;
+ {
+ cpustate->ldtr.limit = seg.limit;
+ cpustate->ldtr.base = seg.base;
+ cpustate->ldtr.flags = seg.flags;
+ }
}
else
{
}
//logerror("LMSW16 %02x <- VAL=%04x \n", modrm, b);
uint32_t cr0_bak = cpustate->cr[0];
- cpustate->cr[0] &= ~(CPU_CRx_MP | CPU_CRx_EM | CPU_CRx_TS);
- cpustate->cr[0] |= (b & (CPU_CRx_PE | CPU_CRx_MP | CPU_CRx_EM | CPU_CRx_TS));
- if(!(cr0_bak & CPU_CRx_PE) && (b & CPU_CRx_PE)) {
- i386_change_protect_mode(cpustate, 1);
- }
+ cpustate->cr[0] &= ~(I386_CR0_MP | I386_CR0_EM | I386_CR0_TS);
+ cpustate->cr[0] |= (b & (I386_CR0_PE | I386_CR0_MP | I386_CR0_EM | I386_CR0_TS));
+ //if(!(cr0_bak & I386_CR0_PE) && (b & I386_CR0_PE)) {
+ // i386_change_protect_mode(cpustate, 1);
+ //}
break;
}
default:
{
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);
+ i386_trap_with_error(cpustate,FAULT_SS,0,0,0, 0);
return false;
}
CYCLES(cpustate,CYCLES_POP_SREG);
memset(&seg, 0, sizeof(seg));
seg.selector = cpustate->ldtr.segment;
i386_load_protected_mode_segment(cpustate,&seg,NULL);
- cpustate->ldtr.limit = seg.limit;
- cpustate->ldtr.base = seg.base;
- cpustate->ldtr.flags = seg.flags;
+ {
+ cpustate->ldtr.limit = seg.limit;
+ cpustate->ldtr.base = seg.base;
+ cpustate->ldtr.flags = seg.flags;
+ }
}
else
{
}
//logerror("LMSW32 %02x <- VAL=%04x \n", modrm, b);
uint32_t cr0_bak = cpustate->cr[0];
- cpustate->cr[0] &= ~(CPU_CRx_MP | CPU_CRx_EM | CPU_CRx_TS);
- cpustate->cr[0] |= (b & (CPU_CRx_PE | CPU_CRx_MP | CPU_CRx_EM | CPU_CRx_TS));
- if(!(cr0_bak & CPU_CRx_PE) && (b & CPU_CRx_PE)) {
- i386_change_protect_mode(cpustate, 1);
- }
+ cpustate->cr[0] &= ~(I386_CR0_MP | I386_CR0_EM | I386_CR0_TS);
+ cpustate->cr[0] |= (b & (I386_CR0_PE | I386_CR0_MP | I386_CR0_EM | I386_CR0_TS));
+ //if(!(cr0_bak & I386_CR0_PE) && (b & I386_CR0_PE)) {
+ // i386_change_protect_mode(cpustate, 1);
+ //}
break;
}
default:
CYCLES(cpustate,CYCLES_MOV_IMM_MEM);
}
}
-
-// 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)
+//#include "./i386ctrlregdefs.h"
static void I386OP(mov_r32_cr)(i386_state *cpustate) // Opcode 0x0f 20
{
- UINT8 modrm = FETCH(cpustate);
- if(modrm < 0xc0) {
- FAULT(FAULT_UD, 0);
- return;
- }
- if((PROTECTED_MODE && ((V8086_MODE) || (cpustate->CPL != 0)))) {
+ //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 modrm = FETCH(cpustate);
UINT8 cr = (modrm >> 3) & 0x7;
+ logdebug("MOV r32 CR%d VAL=(%08X)\n", cr, cpustate->cr[cr]);
if(cr < 5) {
STORE_RM32(modrm, cpustate->cr[cr]);
CYCLES(cpustate,CYCLES_MOV_CR_REG);
}
}
-#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))
#if 0
#endif
void i386_change_protect_mode(i386_state *cpustate, int val)
{
-// printf("Change protect mode to %s\n", (val == 0) ? "NO" : "YES");
+// logdebug("Change protect mode to %s\n", (val == 0) ? "NO" : "YES");
#if 0
void *np[32];
int nptrs =backtrace(np, 32);
char **ss = backtrace_symbols(np, nptrs);
- printf("Backtrace: \n"); \
+ logdebug("Backtrace: \n"); \
for(int __i = 0; __i < nptrs; __i++) {
- printf("%s\n", ss[__i]);
+ logdebug("%s\n", ss[__i]);
}
#endif
cpustate->sreg[SS].d = 0;
static void I386OP(mov_r32_dr)(i386_state *cpustate) // Opcode 0x0f 21
{
- UINT8 modrm = FETCH(cpustate);
- if(modrm < 0xc0) {
- FAULT(FAULT_UD, 0);
- return;
- }
- if((PROTECTED_MODE && ((V8086_MODE) || (cpustate->CPL != 0)))) {
+ //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;
+ if((cpustate->dr[7] & I386_DR7_GD) != 0) {
+ cpustate->dr[6] |= I386_DR6_BD;
+ cpustate->dr[7] &= ~I386_DR7_GD;
FAULT(FAULT_DB, 0);
}
+ UINT8 modrm = FETCH(cpustate);
UINT8 dr = (modrm >> 3) & 0x7;
+ logdebug("MOV r32 DR%d VAL=(%08X)\n", dr, cpustate->dr[dr]);
switch(dr)
{
CYCLES(cpustate,CYCLES_MOV_REG_DR6_7);
break;
default:
+ STORE_RM32(modrm, cpustate->dr[dr]);
logerror("i386: mov_r32_dr illegal index \n", dr);
return;
break;
static void I386OP(mov_cr_r32)(i386_state *cpustate) // Opcode 0x0f 22
{
- 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)))) {
+ //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);
}
+ UINT8 modrm = FETCH(cpustate);
+ UINT8 cr = (modrm >> 3) & 0x7;
UINT32 data = LOAD_RM32(modrm);
UINT32 data_bak;
+ logdebug("MOV CR%d r32 VAL=(%08X)\n", cr, data);
switch(cr)
{
case 0:
CYCLES(cpustate,CYCLES_MOV_REG_CR0);
// if (PROTECTED_MODE != BIT(data, 0))
// debugger_privilege_hook();
- if((data & (CPU_CRx_PE | CPU_CRx_PG)) == (UINT32)CPU_CRx_PG) {
+ if((data & (I386_CR0_PE | I386_CR0_PG)) == (UINT32)I386_CR0_PG) {
FAULT(FAULT_GP, 0);
}
- if((data & (CPU_CRx_NW | CPU_CRx_CD)) == CPU_CRx_NW) {
+ if((data & (I386_CR0_NW | I386_CR0_CD)) == I386_CR0_NW) {
FAULT(FAULT_GP, 0);
}
+#if 0
data_bak = cpustate->cr[0];
- data &= CPU_CRx_ALL;
- data &= ~CPU_CRx_WP; // wp not supported on 386
- //printf("MOV CR0,xxxxh %08x -> %08x \n", data_bak, data);
+ data &= I386_CR0_ALL;
+ data &= ~I386_CR0_WP; // wp not supported on 386
+ //logdebug("MOV CR0,xxxxh %08x -> %08x \n", data_bak, data);
// ToDo: FPU
- //data |= CPU_CRx_ET; /* FPU present */
- //data &= ~CPU_CRx_EM;
- data |= CPU_CRx_EM | CPU_CRx_NE;
- data &= ~(CPU_CRx_MP | CPU_CRx_ET);
- cpustate->cr[0] = data & ~(CPU_CRx_PE | CPU_CRx_PG);
- if((data_bak & (CPU_CRx_PE | CPU_CRx_PG)) != (data & (CPU_CRx_PE | CPU_CRx_PG))) {
+ //data |= I386_CR0_ET; /* FPU present */
+ //data &= ~I386_CR0_EM;
+ data |= I386_CR0_EM | I386_CR0_NE;
+ data &= ~(I386_CR0_MP | I386_CR0_ET);
+ cpustate->cr[0] = data & ~(I386_CR0_PE | I386_CR0_PG);
+#endif
+ cpustate->cr[0] = data;
+#if 0
+ if((data_bak & (I386_CR0_PE | I386_CR0_PG)) != (data & (I386_CR0_PE | I386_CR0_PG))) {
// ToDo: TLB flush (paging)
vtlb_flush_dynamic(cpustate->vtlb);
}
- if((data_bak & CPU_CRx_PE) != (data & CPU_CRx_PE)) {
- if((data & CPU_CRx_PE) != 0) {
+ if((data_bak & I386_CR0_PE) != (data & I386_CR0_PE)) {
+ if((data & I386_CR0_PE) != 0) {
i386_change_protect_mode(cpustate, 1);
}
}
- if((data_bak & CPU_CRx_PG) != (data & CPU_CRx_PG)) {
- if((data & CPU_CRx_PG) != 0) {
- cpustate->cr[0] |= CPU_CRx_PG;
+ if((data_bak & I386_CR0_PG) != (data & I386_CR0_PG)) {
+ if((data & I386_CR0_PG) != 0) {
+ cpustate->cr[0] |= I386_CR0_PG;
} else {
- cpustate->cr[0] &= ~CPU_CRx_PG;
+ cpustate->cr[0] &= ~I386_CR0_PG;
}
}
- if((data_bak & CPU_CRx_PE) != (data & CPU_CRx_PE)) {
- if((data & CPU_CRx_PE) == 0) {
+ if((data_bak & I386_CR0_PE) != (data & I386_CR0_PE)) {
+ if((data & I386_CR0_PE) == 0) {
i386_change_protect_mode(cpustate, 0);
}
}
+#endif
return;
break;
case 2: CYCLES(cpustate,CYCLES_MOV_REG_CR2); break;
*/
data_bak = 0x00000000; // ToDo: PGE
if((data & ~data_bak) != 0) {
- if((data & 0xfffffc00) != 0) {
+ if((data & I386_CR4_SET_MASK1) != 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
+ cpustate->cr[4] = data;
+ if(((data ^ data_bak) & (I386_CR4_PSE | I386_CR4_PGE | I386_CR4_PAE)) != 0) { // PSE | PGE | PAE
vtlb_flush_dynamic(cpustate->vtlb);
}
CYCLES(cpustate,1);
static void I386OP(mov_dr_r32)(i386_state *cpustate) // Opcode 0x0f 23
{
- UINT8 modrm = FETCH(cpustate);
- if(modrm < 0xc0) {
- FAULT(FAULT_UD, 0);
- return;
- }
+ //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;
+ if ((cpustate->dr[7] & I386_DR7_GD) != 0){
+ cpustate->dr[6] |= I386_DR6_BD;
+ cpustate->dr[7] &= ~I386_DR7_GD;
FAULT(FAULT_DB, 0);
}
+ UINT8 modrm = FETCH(cpustate);
UINT8 dr = (modrm >> 3) & 0x7;
+ UINT32 data = LOAD_RM32(modrm);
+ logdebug("MOV DR%d r32 (VAL=%08X)\n", dr, data);
switch(dr)
{
case 1:
case 2:
case 3:
- cpustate->dr[dr] = LOAD_RM32(modrm);
+ cpustate->dr[dr] = data;
CYCLES(cpustate,CYCLES_MOV_DR0_3_REG);
break;
case 6:
- cpustate->dr[dr] = LOAD_RM32(modrm);
+ cpustate->dr[dr] =data;
CYCLES(cpustate,CYCLES_MOV_DR6_7_REG);
break;
case 7:
- cpustate->dr[dr] = LOAD_RM32(modrm);
+ cpustate->dr[dr] = data;
cpustate->reg.d[EBP] = 0;
CYCLES(cpustate,CYCLES_MOV_DR6_7_REG);
break;
default:
+ cpustate->dr[dr] = data;
logerror("i386: mov_dr_r32 DR%d!\n", dr);
return;
}
#include "../vtlb.h"
#include <math.h>
-
+#include "./i386ctrlregdefs.h"
//#define DEBUG_MISSING_OPCODE
#define I386OP(XX) i386_##XX
#endif
#define PROTECTED_MODE (cpustate->cr[0] & 0x1)
#define STACK_32BIT (cpustate->sreg[SS].d)
-#define V8086_MODE (cpustate->VM)
+#define V8086_MODE ((cpustate->VM) && (cpustate->cr[4] & I386_CR4_VME))
#define NESTED_TASK (cpustate->NT)
-#define WP (cpustate->cr[0] & 0x10000)
+#define WP (cpustate->cr[0] & I386_CR0_WP)
#define SetOF_Add32(r,s,d) (cpustate->OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x80000000) ? 1: 0)
#define SetOF_Add16(r,s,d) (cpustate->OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x8000) ? 1 : 0)
static int i386_translate_address(i386_state *cpustate, int intention, offs_t *address, vtlb_entry *entry)
{
UINT32 a = *address;
- UINT32 pdbr = cpustate->cr[3] & 0xfffff000;
+ UINT32 pdbr = cpustate->cr[3] & 0xfffff000;// I386_CR3_PD_MASK
UINT32 directory = (a >> 22) & 0x3ff;
UINT32 table = (a >> 12) & 0x3ff;
vtlb_entry perm = 0;
bool write = (intention & TRANSLATE_WRITE) ? true : false;
bool debug = (intention & TRANSLATE_DEBUG_MASK) ? true : false;
- if(!(cpustate->cr[0] & 0x80000000))
+ if(!(cpustate->cr[0] & I386_CR0_PG)) // paging is disabled
{
if(entry)
*entry = 0x77;
return TRUE;
}
-
+ // Paging is enabled
UINT32 page_dir = cpustate->program->read_data32(pdbr + directory * 4);
if(page_dir & 1)
{
- if ((page_dir & 0x80) && (cpustate->cr[4] & 0x10))
+ if ((page_dir & 0x80) && (cpustate->cr[4] & I386_CR4_PSE))
{
a = (page_dir & 0xffc00000) | (a & 0x003fffff);
if(debug)
INLINE int translate_address(i386_state *cpustate, int pl, int type, UINT32 *address, UINT32 *error)
{
- if(!(cpustate->cr[0] & 0x80000000)) // Some (very few) old OS's won't work with this
+ if(!(cpustate->cr[0] & I386_CR0_PG)) // Some (very few) old OS's won't work with this
return TRUE;
const vtlb_entry *table = vtlb_table(cpustate->vtlb);