OSDN Git Service

[VM][I386][WIP] FLAGS around IRET/POPF/POPFD.This is WIP.
authorK.Ohta <whatisthis.sowhat@gmail.com>
Tue, 9 Apr 2019 11:07:44 +0000 (20:07 +0900)
committerK.Ohta <whatisthis.sowhat@gmail.com>
Tue, 9 Apr 2019 11:07:44 +0000 (20:07 +0900)
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

index df5b8c2..b7a3c51 100644 (file)
@@ -2451,7 +2451,7 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
        UINT8 CPL, RPL, DPL;
        UINT32 newflags;
        UINT8 IOPL = cpustate->IOP1 | (cpustate->IOP2 << 1);
-
+       UINT32 stack_size = 6;
        CPL = cpustate->CPL;
        UINT32 ea = i386_translate(cpustate, SS, (STACK_32BIT)?REG32(ESP):REG16(SP), 0, (operand32)?12:6);
        if(operand32 == 0)
@@ -2459,12 +2459,14 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
                newEIP = READ16(cpustate, ea) & 0xffff;
                newCS = READ16(cpustate, ea+2) & 0xffff;
                newflags = READ16(cpustate, ea+4) & 0xffff;
+               stack_size = 6;
        }
        else
        {
                newEIP = READ32(cpustate, ea);
                newCS = READ32(cpustate, ea+4) & 0xffff;
                newflags = READ32(cpustate, ea+8);
+               stack_size = 12;
        }
 
        if(V8086_MODE)
@@ -2489,9 +2491,9 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
                        newflags |= (oldflags & I386_EFLAGS_IOPL);
                        set_flags(cpustate,(newflags & 0xffff) | (oldflags & ~0xffff));
                        if(STACK_32BIT) {
-                               REG32(ESP) += 6;
+                               REG32(ESP) += stack_size;
                        } else {
-                               REG16(SP) += 6;
+                               REG16(SP) += stack_size;
                        }
                }
                else
@@ -2508,9 +2510,9 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
                        newflags |= (oldflags & I386_EFLAGS_IOPL) | I386_EFLAGS_VM;
                        set_flags(cpustate,newflags);
                        if(STACK_32BIT) {
-                               REG32(ESP) += 12;
+                               REG32(ESP) += stack_size;
                        } else {
-                               REG16(SP) += 12;
+                               REG16(SP) += stack_size;
                        }
                }
                
@@ -2552,7 +2554,7 @@ static void i386_protected_mode_iret(i386_state* cpustate, int operand32)
        }
        else
        {
-               if(newflags & 0x00020000) // if returning to virtual 8086 mode
+               if((newflags & 0x00020000) && (cpustate->CPL == 0)) // if returning to virtual 8086 mode
                {
                        // 16-bit iret can't reach here
                        newESP = READ32(cpustate, ea+12);
index 7692ee7..b4d6a61 100644 (file)
@@ -1744,18 +1744,18 @@ static void I386OP(popf)(i386_state *cpustate)              // Opcode 0x9d
        UINT32 value;
        UINT32 current = get_flags(cpustate);
        UINT8 IOPL = (current >> 12) & 0x03;
-       UINT32 mask = 0x7fd5;
+       //UINT32 mask = 0x7fd5;
+       UINT32 mask = I386_EFLAGS_IF | I386_EFLAGS_IOPL | I386_EFLAGS_SZAPC | I386_EFLAGS_T | I386_EFLAGS_D | I386_EFLAGS_O | I386_EFLAGS_NT /*| I386_EFLAGS_AC | I386_EFLAGS_ID*/;
        UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
 
+#if 1
        // IOPL can only change if CPL is 0
        if(cpustate->CPL != 0) {
-               //mask &= ~0x00003000;
                mask &= ~I386_EFLAGS_IOPL;
        }
 
        // IF can only change if CPL is at least as privileged as IOPL
        if(cpustate->CPL > IOPL) {
-               //mask &= ~0x00000200;
                mask &= ~I386_EFLAGS_IF;
        }
 
@@ -1766,10 +1766,30 @@ static void I386OP(popf)(i386_state *cpustate)              // Opcode 0x9d
                        logerror("POPFD(%08x): IOPL < 3 while in V86 mode.\n",cpustate->pc);
                        FAULT(FAULT_GP,0)  // #GP(0)
                }
-               //mask &= ~0x00003000;  // IOPL cannot be changed while in V8086 mode
                mask &= ~I386_EFLAGS_IOPL; // IOPL cannot be changed while in V8086 mode
        }
-
+#else  
+       // Port from NP2
+       if(!(PROTECTED_MODE)) {
+               mask |= (I386_EFLAGS_IF | I386_EFLAGS_IOPL);
+       } else if(!(V8086_MODE)) {
+               
+               if(cpustate->CPL == 0) {
+                       mask |= (I386_EFLAGS_IF | I386_EFLAGS_IOPL);
+               } else if(cpustate->CPL <= IOPL) {
+                       mask |= I386_EFLAGS_IF;
+               }
+       } else if(IOPL == 3) {
+               mask |= I386_EFLAGS_IF;
+       } else {
+               mask = 0;
+               logerror("POPF(%08x): Wrong mode and IOPL.PC=%08X\n",cpustate->pc);
+               FAULT(FAULT_GP,0);  // #GP(0)
+               set_flags(cpustate,current);  // mask out reserved bits
+               return;
+       }
+#endif         
+                       
        if(i386_limit_check(cpustate,SS,offset,2) == 0)
        {
                value = POP16(cpustate);
@@ -2024,7 +2044,7 @@ static void I386OP(pushf)(i386_state *cpustate)             // Opcode 0x9c
                offset = (REG16(SP) - 2) & 0xffff;
        if(!PROTECTED_MODE || !V8086_MODE || ((cpustate->IOP1) && (cpustate->IOP2))) { 
                if(i386_limit_check(cpustate,SS,offset,2) == 0)
-                       PUSH16(cpustate, get_flags(cpustate) & 0xffff );
+                       PUSH16(cpustate, (get_flags(cpustate) & 0xffff) | 0x0002 );
                else
                        FAULT(FAULT_SS,0)
        } else {
index 3e99304..a2ea4d3 100644 (file)
@@ -1572,19 +1572,20 @@ static void I386OP(popfd)(i386_state *cpustate)             // Opcode 0x9d
 {
        UINT32 value;
        UINT32 current = get_flags(cpustate);
+       UINT32 expect_flags = 0xffffffff;
        UINT8 IOPL = (current >> 12) & 0x03;
+       //UINT32 mask = I386_EFLAGS_SZAPC | I386_EFLAGS_T | I386_EFLAGS_D | I386_EFLAGS_O | I386_EFLAGS_NT | I386_EFLAGS_AC | I386_EFLAGS_ID;
        UINT32 mask = 0x00257fd5;  // VM, VIP and VIF cannot be set by POPF/POPFD
        UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
 
        // IOPL can only change if CPL is 0
+#if 1  
        if(cpustate->CPL != 0) {
-               //mask &= ~0x00003000;
                mask &= ~I386_EFLAGS_IOPL;
        }
        // IF can only change if CPL is at least as privileged as IOPL
        if(cpustate->CPL > IOPL) {
                mask &= ~I386_EFLAGS_IF;
-               //mask &= ~0x00000200;
        }
 
        if(V8086_MODE)
@@ -1596,19 +1597,34 @@ static void I386OP(popfd)(i386_state *cpustate)             // Opcode 0x9d
                        //set_flags(cpustate,0 );  // EXCEPTION
                }
                mask &= ~I386_EFLAGS_IOPL;   // IOPL cannot be changed while in V8086 mode
-               //mask &= ~0x00003000;  // IOPL cannot be changed while in V8086 mode
        }
-       
+#else
+       if(!(PROTECTED_MODE)) {
+               expect_flags = ~(I386_EFLAGS_RF | I386_EFLAGS_VIF | I386_EFLAGS_VIP);
+               mask |= I386_EFLAGS_IF | I386_EFLAGS_IOP1 | I386_EFLAGS_IOP2 | I386_EFLAGS_RF | I386_EFLAGS_VIP | I386_EFLAGS_VIF; 
+       } else if(!(V8086_MODE)) {
+               expect_flags = ~(I386_EFLAGS_RF);
+               if(cpustate->CPL == 0) {
+                       expect_flags &= ~(I386_EFLAGS_VIP | I386_EFLAGS_VIF);
+                       mask |= I386_EFLAGS_IF | I386_EFLAGS_IOP1 | I386_EFLAGS_IOP2 | I386_EFLAGS_RF | I386_EFLAGS_VIP | I386_EFLAGS_VIF; 
+               } else if(cpustate->CPL <= IOPL) {
+                       expect_flags &= ~(I386_EFLAGS_VIP | I386_EFLAGS_VIF);
+                       mask |= I386_EFLAGS_IF | I386_EFLAGS_RF | I386_EFLAGS_VIP | I386_EFLAGS_VIF; 
+               } else {
+                       mask |= I386_EFLAGS_RF;
+               }
+       } else if(IOPL == 3) {
+               mask |= I386_EFLAGS_IF;
+       } else {
+               FAULT(FAULT_GP, 0);
+               set_flags(cpustate,current);  // mask out reserved bits
+               return;
+       }
+#endif
        if(i386_limit_check(cpustate,SS,offset,4) == 0)
        {
                value = POP32(cpustate);
-               //value &= ~0x00010000;  // RF will always return zero
-               if(!V8086_MODE) { // RF maybe clear only not V86 mode
-                       value &= ~I386_EFLAGS_RF;
-                       if((cpustate->CPL == 0) || (cpustate->CPL <= IOPL)) {
-                               value &= ~(I386_EFLAGS_VIF | I386_EFLAGS_VIP);  // RF will always return zero
-                       }
-               }
+               value = value & expect_flags;
                set_flags(cpustate,(current & ~mask) | (value & mask));  // mask out reserved bits
        }
        else
@@ -1862,7 +1878,7 @@ static void I386OP(pushfd)(i386_state *cpustate)            // Opcode 0x9c
                offset = (REG16(SP) - 4) & 0xffff;
        if(!PROTECTED_MODE || !V8086_MODE || ((cpustate->IOP1) && (cpustate->IOP2))) { 
                if(i386_limit_check(cpustate,SS,offset,4) == 0)
-                       PUSH32(cpustate, get_flags(cpustate) & 0x00fcffff );
+                       PUSH32(cpustate, (get_flags(cpustate) & 0x00fcffff) | 0x00000002 );
                else
                        FAULT(FAULT_SS,0)
        } else {