OSDN Git Service

[VM][I386] Enable debug log (logerror()).
authorK.Ohta <whatisthis.sowhat@gmail.com>
Mon, 25 Mar 2019 09:36:44 +0000 (18:36 +0900)
committerK.Ohta <whatisthis.sowhat@gmail.com>
Mon, 25 Mar 2019 09:36:44 +0000 (18:36 +0900)
[VM][I386][WIP] Porting features around virtual-8086 mode from NP2.

source/src/vm/i386.cpp
source/src/vm/mame/emu/cpu/i386/i386.c
source/src/vm/mame/emu/cpu/i386/i386op16.c
source/src/vm/mame/emu/cpu/i386/i386op32.c
source/src/vm/mame/emu/cpu/i386/i386ops.c
source/src/vm/mame/emu/cpu/i386/i386priv.h

index f9827bc..57b0074 100644 (file)
@@ -256,6 +256,10 @@ typedef UINT32     offs_t;
 //#endif
 
 static CPU_TRANSLATE(i386);
+void terminate()
+{
+       printf("WARN: unexpected exception\n");
+}
 
 #include "mame/lib/softfloat/softfloat.c"
 #include "mame/lib/softfloat/fsincos.c"
index 4d09f94..fd0aaaf 100644 (file)
@@ -49,8 +49,8 @@ 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) {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)
 {
@@ -687,18 +687,26 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
        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
        {
@@ -708,8 +716,14 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
                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;
@@ -1039,6 +1053,7 @@ static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level
                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)
@@ -1066,23 +1081,36 @@ static void i386_trap_with_error(i386_state *cpustate,int irq, int irq_gate, int
                // 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);
        }
 }
 
@@ -2051,6 +2079,7 @@ static void i386_protected_mode_call(i386_state *cpustate, UINT16 seg, UINT32 of
        catch(UINT64 e)
        {
                REG32(ESP) = tempSP;
+               logerror("THROWN at I386_OP(i386_protected_mode_call)() line %d\n",  __LINE__);
                throw e;
        }
 
@@ -3536,6 +3565,7 @@ static CPU_EXECUTE( i386 )
                        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
@@ -3599,6 +3629,7 @@ static CPU_EXECUTE( i386 )
                        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
index 2eeecae..472602f 100644 (file)
@@ -495,7 +495,9 @@ static void I386OP(call_abs16)(i386_state *cpustate)        // Opcode 0x9a
        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)
@@ -1531,8 +1533,10 @@ static void I386OP(pop_ax)(i386_state *cpustate)            // Opcode 0x58
        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);
 }
 
@@ -1541,8 +1545,10 @@ static void I386OP(pop_cx)(i386_state *cpustate)            // Opcode 0x59
        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);
 }
 
@@ -1551,8 +1557,10 @@ static void I386OP(pop_dx)(i386_state *cpustate)            // Opcode 0x5a
        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);
 }
 
@@ -1561,8 +1569,10 @@ static void I386OP(pop_bx)(i386_state *cpustate)            // Opcode 0x5b
        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);
 }
 
@@ -1571,8 +1581,10 @@ static void I386OP(pop_sp)(i386_state *cpustate)            // Opcode 0x5c
        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);
 }
 
@@ -1581,8 +1593,10 @@ static void I386OP(pop_bp)(i386_state *cpustate)            // Opcode 0x5d
        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);
 }
 
@@ -1591,8 +1605,10 @@ static void I386OP(pop_si)(i386_state *cpustate)            // Opcode 0x5e
        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);
 }
 
@@ -1601,8 +1617,10 @@ static void I386OP(pop_di)(i386_state *cpustate)            // Opcode 0x5f
        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);
 }
 
@@ -1625,6 +1643,7 @@ static bool I386OP(pop_seg16)(i386_state *cpustate, int segment)
        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;
        }
@@ -1684,6 +1703,7 @@ static void I386OP(pop_rm16)(i386_state *cpustate)          // Opcode 0x8f
                        catch(UINT64 e)
                        {
                                REG32(ESP) = temp_sp;
+                               logerror("THROWN at I386_OP(pop_rm16)() line %d\n", __LINE__);
                                throw e;
                        }
                }
@@ -3039,7 +3059,9 @@ static void I386OP(groupFF_16)(i386_state *cpustate)        // Opcode 0xff
                                        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)
                                        {
@@ -3121,6 +3143,9 @@ static void I386OP(groupFF_16)(i386_state *cpustate)        // Opcode 0xff
        }
 }
 
+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;
@@ -3167,8 +3192,10 @@ static void I386OP(group0F00_16)(i386_state *cpustate)          // Opcode 0x0f 0
                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;
@@ -3194,8 +3221,10 @@ static void I386OP(group0F00_16)(i386_state *cpustate)          // Opcode 0x0f 0
                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;
@@ -3359,8 +3388,10 @@ static void I386OP(group0F01_16)(i386_state *cpustate)      // Opcode 0x0f 01
                        }
                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 );
@@ -3374,8 +3405,10 @@ static void I386OP(group0F01_16)(i386_state *cpustate)      // Opcode 0x0f 01
                        }
                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 );
@@ -3401,8 +3434,10 @@ static void I386OP(group0F01_16)(i386_state *cpustate)      // Opcode 0x0f 01
                        }
                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);
@@ -3410,12 +3445,15 @@ static void I386OP(group0F01_16)(i386_state *cpustate)      // Opcode 0x0f 01
                                } 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:
index 6f8318c..194dbf3 100644 (file)
@@ -1112,7 +1112,7 @@ static void I386OP(mov_rm32_r32)(i386_state *cpustate)      // Opcode 0x89
        } 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);
        }
 }
@@ -1471,6 +1471,7 @@ static bool I386OP(pop_seg32)(i386_state *cpustate, int segment)
        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;
        }
@@ -1532,6 +1533,7 @@ static void I386OP(pop_rm32)(i386_state *cpustate)          // Opcode 0x8f
                        catch(UINT64 e)
                        {
                                REG32(ESP) = temp_sp;
+                               logerror("THROWN at I386_OP(pop_rm32)() line %d\n", __LINE__);
                                throw e;
                        }
                }
index 9e7d7ef..dc508ed 100644 (file)
@@ -310,8 +310,10 @@ static void I386OP(cli)(i386_state *cpustate)               // Opcode 0xfa
        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);
@@ -651,61 +653,221 @@ static void I386OP(mov_rm8_i8)(i386_state *cpustate)        // Opcode 0xc6
        }
 }
 
+// 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;
@@ -715,22 +877,38 @@ static void I386OP(mov_cr_r32)(i386_state *cpustate)        // Opcode 0x0f 22
 
 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:
@@ -1252,6 +1430,7 @@ static void I386OP(repeat)(i386_state *cpustate, int invert_flag)
                catch (UINT64 e)
                {
                        cpustate->eip = cpustate->prev_eip;
+                       logerror("THROWN at I386_OP(repeat)() line %d\n", __LINE__);
                        throw e;
                }
 
@@ -1655,8 +1834,10 @@ static void I386OP(sti)(i386_state *cpustate)               // Opcode 0xfb
        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);
@@ -2332,7 +2513,19 @@ static void I386OP(int_16)(i386_state *cpustate)               // Opcode 0xcd
 {
        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;
@@ -2342,7 +2535,22 @@ static void I386OP(int_32)(i386_state *cpustate)               // Opcode 0xcd
 {
        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;
@@ -2376,8 +2584,10 @@ static void I386OP(escape)(i386_state *cpustate)            // Opcodes 0xd8 - 0x
 
 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)
@@ -2485,8 +2695,10 @@ static void I386OP(aam)(i386_state *cpustate)               // Opcode 0xd4
 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);
 }
@@ -2518,8 +2730,10 @@ static void I386OP(mov_tr_r32)(i386_state *cpustate)        // Opcode 0x0f 26
 
 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));
index 04f0de8..8194a30 100644 (file)
@@ -254,15 +254,25 @@ enum smram_intel_p5
 };
 
 /* 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
@@ -525,9 +535,38 @@ struct i386_state
 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)