Fast486OpcodeAad, /* 0xD5 */
Fast486OpcodeSalc, /* 0xD6 */
Fast486OpcodeXlat, /* 0xD7 */
- Fast486FpuOpcodeD8DC, /* 0xD8 - 0xDF */
+ Fast486FpuOpcodeD8, /* 0xD8 - 0xDF */
Fast486FpuOpcodeD9,
Fast486FpuOpcodeDA,
Fast486FpuOpcodeDB,
- Fast486FpuOpcodeD8DC,
+ Fast486FpuOpcodeDC,
Fast486FpuOpcodeDD,
Fast486FpuOpcodeDE,
Fast486FpuOpcodeDF,
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
{
/* Check IOPL */
- if (State->Flags.Iopl >= State->SegmentRegs[FAST486_REG_CS].Dpl)
+ if (State->Flags.Iopl >= Fast486GetCurrentPrivLevel(State))
{
/* Clear the interrupt flag */
State->Flags.If = FALSE;
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
{
/* Check IOPL */
- if (State->Flags.Iopl >= State->SegmentRegs[FAST486_REG_CS].Dpl)
+ if (State->Flags.Iopl >= Fast486GetCurrentPrivLevel(State))
{
/* Set the interrupt flag */
State->Flags.If = TRUE;
}
/* Call the internal API */
- Fast486LoadSegment(State, FAST486_REG_SS, LOWORD(NewSelector));
+ if (Fast486LoadSegment(State, FAST486_REG_SS, LOWORD(NewSelector)))
+ {
+ /* Inhibit all interrupts until the next instruction */
+ State->DoNotInterrupt = TRUE;
+ }
}
FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm)
FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg)
{
- BOOLEAN OperandSize, AddressSize;
+ BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
FAST486_MOD_REG_RM ModRegRm;
- OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
-
/* Make sure this is the right instruction */
ASSERT(Opcode == 0x8C);
TOGGLE_ADSIZE(AddressSize);
- TOGGLE_OPSIZE(OperandSize);
/* Get the operands */
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
return;
}
- if (OperandSize)
- {
- Fast486WriteModrmDwordOperands(State,
- &ModRegRm,
- FALSE,
- State->SegmentRegs[ModRegRm.Register].Selector);
- }
- else
- {
- Fast486WriteModrmWordOperands(State,
- &ModRegRm,
- FALSE,
- State->SegmentRegs[ModRegRm.Register].Selector);
- }
+ Fast486WriteModrmWordOperands(State,
+ &ModRegRm,
+ FALSE,
+ State->SegmentRegs[ModRegRm.Register].Selector);
}
FAST486_OPCODE_HANDLER(Fast486OpcodeLea)
FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg)
{
- BOOLEAN OperandSize, AddressSize;
+ BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
FAST486_MOD_REG_RM ModRegRm;
-
- OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
+ USHORT Selector;
/* Make sure this is the right instruction */
ASSERT(Opcode == 0x8E);
TOGGLE_ADSIZE(AddressSize);
- TOGGLE_OPSIZE(OperandSize);
/* Get the operands */
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
return;
}
- if (OperandSize)
+ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
{
- ULONG Selector;
-
- if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Selector))
- {
- /* Exception occurred */
- return;
- }
-
- Fast486LoadSegment(State, ModRegRm.Register, LOWORD(Selector));
+ /* Exception occurred */
+ return;
}
- else
- {
- USHORT Selector;
- if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
- {
- /* Exception occurred */
- return;
- }
+ if (!Fast486LoadSegment(State, ModRegRm.Register, Selector))
+ {
+ /* Exception occurred */
+ return;
+ }
- Fast486LoadSegment(State, ModRegRm.Register, Selector);
+ if ((INT)ModRegRm.Register == FAST486_REG_SS)
+ {
+ /* Inhibit all interrupts until the next instruction */
+ State->DoNotInterrupt = TRUE;
}
}
return;
}
+ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+ {
+ if (!Fast486ProcessGate(State, Segment, Offset, TRUE))
+ {
+ /* Gate processed or exception occurred */
+ return;
+ }
+ }
+
/* Push the current code segment selector */
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
{
FAST486_OPCODE_HANDLER(Fast486OpcodeWait)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+#ifndef FAST486_NO_FPU
+
+ if ((!State->FpuControl.Pm && State->FpuStatus.Pe)
+ || (!State->FpuControl.Um && State->FpuStatus.Ue)
+ || (!State->FpuControl.Om && State->FpuStatus.Oe)
+ || (!State->FpuControl.Zm && State->FpuStatus.Ze)
+ || (!State->FpuControl.Dm && State->FpuStatus.De)
+ || (!State->FpuControl.Im && State->FpuStatus.Ie))
+ {
+ Fast486FpuException(State);
+ }
+
+#endif
}
FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags)
FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags)
{
BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
- INT Cpl = Fast486GetCurrentPrivLevel(State);
+ UINT Cpl = Fast486GetCurrentPrivLevel(State);
FAST486_FLAGS_REG NewFlags;
NO_LOCK_PREFIX();
{
UCHAR BopCode;
-#ifndef FAST486_NO_PREFETCH
- /* Invalidate the prefetch since BOP handlers can alter the memory */
- State->PrefetchValid = FALSE;
-#endif
-
/* Fetch the BOP code */
if (!Fast486FetchByte(State, &BopCode))
{
return;
}
+#ifndef FAST486_NO_PREFETCH
+ /* Invalidate the prefetch since BOP handlers can alter the memory */
+ State->PrefetchValid = FALSE;
+#endif
+
/* Call the BOP handler */
State->BopCallback(State, BopCode);
* changes the CS:IP, the interrupt handler won't execute and the
* stack pointer will never be restored.
*/
- if (State->IntStatus == FAST486_INT_EXECUTE)
- {
- State->IntStatus = FAST486_INT_DELAYED;
- }
+ State->DoNotInterrupt = TRUE;
return;
}
if (NestingLevel > 0) Fast486StackPush(State, FramePointer.Long);
/* Set EBP to the frame pointer */
- State->GeneralRegs[FAST486_REG_EBP] = FramePointer;
+ if (Size) State->GeneralRegs[FAST486_REG_EBP].Long = FramePointer.Long;
+ else State->GeneralRegs[FAST486_REG_EBP].LowWord = FramePointer.LowWord;
/* Reserve space for the frame */
- if (Size) State->GeneralRegs[FAST486_REG_ESP].Long -= (ULONG)FrameSize;
- else State->GeneralRegs[FAST486_REG_ESP].LowWord -= FrameSize;
+ if (State->SegmentRegs[FAST486_REG_SS].Size)
+ {
+ State->GeneralRegs[FAST486_REG_ESP].Long -= (ULONG)FrameSize;
+ }
+ else
+ {
+ State->GeneralRegs[FAST486_REG_ESP].LowWord -= FrameSize;
+ }
}
FAST486_OPCODE_HANDLER(Fast486OpcodeLeave)
{
BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
+ ULONG Value;
/* Make sure this is the right instruction */
ASSERT(Opcode == 0xC9);
NO_LOCK_PREFIX();
TOGGLE_OPSIZE(Size);
- if (Size)
+ if (State->SegmentRegs[FAST486_REG_SS].Size)
{
/* Set the stack pointer (ESP) to the base pointer (EBP) */
State->GeneralRegs[FAST486_REG_ESP].Long = State->GeneralRegs[FAST486_REG_EBP].Long;
-
- /* Pop the saved base pointer from the stack */
- Fast486StackPop(State, &State->GeneralRegs[FAST486_REG_EBP].Long);
}
else
{
- ULONG Value;
-
/* Set the stack pointer (SP) to the base pointer (BP) */
State->GeneralRegs[FAST486_REG_ESP].LowWord = State->GeneralRegs[FAST486_REG_EBP].LowWord;
+ }
- /* Pop the saved base pointer from the stack */
- if (Fast486StackPop(State, &Value))
- {
- State->GeneralRegs[FAST486_REG_EBP].LowWord = LOWORD(Value);
- }
+ /* Pop the saved base pointer from the stack */
+ if (Fast486StackPop(State, &Value))
+ {
+ if (Size) State->GeneralRegs[FAST486_REG_EBP].Long = Value;
+ else State->GeneralRegs[FAST486_REG_EBP].LowWord = LOWORD(Value);
}
}
return;
}
+ if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
+ {
+ UINT i;
+ UINT OldCpl = Fast486GetCurrentPrivLevel(State);
+ ULONG StackPtr;
+ ULONG StackSel;
+
+ if (GET_SEGMENT_RPL(Segment) > OldCpl)
+ {
+ /* Pop ESP */
+ if (!Fast486StackPop(State, &StackPtr))
+ {
+ /* Exception */
+ return;
+ }
+
+ /* Pop SS */
+ if (!Fast486StackPop(State, &StackSel))
+ {
+ /* Exception */
+ return;
+ }
+ }
+
+ /* Update the CPL */
+ State->Cpl = GET_SEGMENT_RPL(Segment);
+
+ if (State->Cpl > OldCpl)
+ {
+ /* Load new SS */
+ if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel))
+ {
+ /* Exception */
+ return;
+ }
+
+ /* Set ESP */
+ if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr;
+ else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
+
+ /* Check segment security */
+ for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
+ {
+ /* Don't check CS or SS */
+ if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
+
+ if ((State->Cpl > State->SegmentRegs[i].Dpl)
+ && (!State->SegmentRegs[i].Executable
+ || !State->SegmentRegs[i].DirConf))
+ {
+ /* Load the NULL descriptor in the segment */
+ if (!Fast486LoadSegment(State, i, 0)) return;
+ }
+ }
+ }
+ }
+
/* Load new (E)IP, and if necessary, pop the parameters */
if (Size)
{
{
UCHAR IntNum;
+ /* Check for V86 mode */
+ if (State->Flags.Vm && (State->Flags.Iopl != 3))
+ {
+ /* Call the V86 monitor */
+ Fast486Exception(State, FAST486_EXCEPTION_GP);
+ return;
+ }
+
switch (Opcode)
{
case 0xCC: // INT 3
NO_LOCK_PREFIX();
TOGGLE_OPSIZE(Size);
+ /* Check if this is a nested task return */
+ if (State->Flags.Nt && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE))
+ {
+ /* Clear the NT flag of the current task */
+ State->Flags.Nt = FALSE;
+
+ /* Switch to the old task */
+ Fast486TaskSwitch(State, FAST486_TASK_RETURN, 0);
+ return;
+ }
+
/* Pop EIP */
if (!Fast486StackPop(State, &InstPtr))
{
/* Check for protected mode */
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
{
- INT Cpl = Fast486GetCurrentPrivLevel(State);
+ UINT OldCpl = Fast486GetCurrentPrivLevel(State);
if (State->Flags.Vm)
{
return;
}
- if (State->Flags.Nt)
- {
- /* Nested task return */
-
- UNIMPLEMENTED;
- return;
- }
-
if (NewFlags.Vm)
{
/* Return to VM86 mode */
ULONG Es, Ds, Fs, Gs;
- /* Pop ESP, SS, ES, FS, GS */
+ /* Pop ESP, SS, ES, DS, FS, GS */
if (!Fast486StackPop(State, &StackPtr)) return;
if (!Fast486StackPop(State, &StackSel)) return;
if (!Fast486StackPop(State, &Es)) return;
if (Size) State->InstPtr.Long = InstPtr;
else State->InstPtr.LowWord = LOWORD(InstPtr);
- if (GET_SEGMENT_RPL(CodeSel) > Cpl)
+ if (GET_SEGMENT_RPL(CodeSel) > OldCpl)
{
/* Pop ESP */
if (!Fast486StackPop(State, &StackPtr))
/* Exception */
return;
}
+ }
+
+ /* Update the CPL */
+ State->Cpl = GET_SEGMENT_RPL(CodeSel);
+ /* Set the new flags */
+ if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
+ else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
+ State->Flags.AlwaysSet = TRUE;
+
+ /* Set additional flags */
+ if (OldCpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
+ if (OldCpl == 0) State->Flags.Iopl = NewFlags.Iopl;
+
+ if (State->Cpl > OldCpl)
+ {
/* Load new SS */
if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel))
{
/* Set ESP */
if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr;
else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
- }
-
- /* Set the new flags */
- if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
- else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
- State->Flags.AlwaysSet = TRUE;
-
- /* Set additional flags */
- if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
- if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
-
- if (GET_SEGMENT_RPL(CodeSel) > Cpl)
- {
- /* Update the CPL */
- Cpl = Fast486GetCurrentPrivLevel(State);
/* Check segment security */
for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
/* Don't check CS or SS */
if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
- if ((Cpl > State->SegmentRegs[i].Dpl)
+ if ((State->Cpl > State->SegmentRegs[i].Dpl)
&& (!State->SegmentRegs[i].Executable
|| !State->SegmentRegs[i].DirConf))
{
return;
}
+ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+ {
+ if (!Fast486ProcessGate(State, Segment, Offset, FALSE))
+ {
+ /* Gate processed or exception occurred */
+ return;
+ }
+ }
+
/* Load the new CS */
if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
{
FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax)
{
BOOLEAN OperandSize, AddressSize;
-
+
OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
/* Make sure this is the right instruction */
|| (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
{
/* Do nothing */
- return;
+ return;
}
}