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)
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)
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
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;
}
}
}
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);
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;
}
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);
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 {
{
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)
//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
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 {