// #define WIN32_NO_STATUS
// #define _INC_WINDOWS
#include <windef.h>
+#include <limits.h>
// #define NDEBUG
#include <debug.h>
Soft386OpcodePushImm,
Soft386OpcodeImulModrmImm,
Soft386OpcodePushByteImm,
- Soft386OpcodeImulModrmByteImm,
+ Soft386OpcodeImulModrmImm,
NULL, // TODO: OPCODE 0x6C NOT SUPPORTED
NULL, // TODO: OPCODE 0x6D NOT SUPPORTED
NULL, // TODO: OPCODE 0x6E NOT SUPPORTED
Soft386OpcodePopFlags,
Soft386OpcodeSahf,
Soft386OpcodeLahf,
- NULL, // TODO: OPCODE 0xA0 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xA1 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xA2 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xA3 NOT SUPPORTED
+ Soft386OpcodeMovAlOffset,
+ Soft386OpcodeMovEaxOffset,
+ Soft386OpcodeMovOffsetAl,
+ Soft386OpcodeMovOffsetEax,
NULL, // TODO: OPCODE 0xA4 NOT SUPPORTED
NULL, // TODO: OPCODE 0xA5 NOT SUPPORTED
NULL, // TODO: OPCODE 0xA6 NOT SUPPORTED
NULL, // TODO: OPCODE 0xC1 NOT SUPPORTED
Soft386OpcodeRet,
Soft386OpcodeRet,
- Soft386OpcodeLes,
- Soft386OpcodeLds,
+ Soft386OpcodeLdsLes,
+ Soft386OpcodeLdsLes,
NULL, // TODO: OPCODE 0xC6 NOT SUPPORTED
NULL, // TODO: OPCODE 0xC7 NOT SUPPORTED
Soft386OpcodeEnter,
/* Make sure this is the right instruction */
ASSERT(Opcode == 0x05);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
- }
- else
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
if (Size)
{
ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
/* Make sure this is the right instruction */
ASSERT(Opcode == 0x0D);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
- }
- else
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
if (Size)
{
ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
/* Make sure this is the right instruction */
ASSERT(Opcode == 0x24);
- if (State->PrefixFlags)
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
- /* This opcode doesn't take any prefixes */
+ /* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
/* Make sure this is the right instruction */
ASSERT(Opcode == 0x25);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
- }
- else
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
if (Size)
{
ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
/* Make sure this is the right instruction */
ASSERT(Opcode == 0x35);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
- }
- else
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
if (Size)
{
ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
/* Make sure this is the right instruction */
ASSERT(Opcode == 0xA9);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
- }
- else
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
if (Size)
{
ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
/* Make sure this is the right instruction */
ASSERT(Opcode == 0x15);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
- }
- else
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
if (Size)
{
ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
/* Make sure this is the right instruction */
ASSERT((Opcode & 0xEF) == 0x2D);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
- }
- else
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
if (Size)
{
ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
SOFT386_OPCODE_HANDLER(Soft386OpcodeImulModrmImm)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+ BOOLEAN OperandSize, AddressSize;
+ SOFT386_MOD_REG_RM ModRegRm;
+ LONG Multiplier;
+ LONGLONG Product;
- return FALSE;
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x69);
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the address size */
+ AddressSize = !AddressSize;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the operand size */
+ OperandSize = !OperandSize;
+ }
+
+ /* Fetch the parameters */
+ if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (Opcode == 0x6B)
+ {
+ CHAR Byte;
+
+ /* Fetch the immediate operand */
+ if (!Soft386FetchByte(State, (PUCHAR)&Byte))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ Multiplier = (LONG)Byte;
+ }
+ else
+ {
+ if (OperandSize)
+ {
+ LONG Dword;
+
+ /* Fetch the immediate operand */
+ if (!Soft386FetchDword(State, (PULONG)&Dword))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ Multiplier = Dword;
+ }
+ else
+ {
+ SHORT Word;
+
+ /* Fetch the immediate operand */
+ if (!Soft386FetchWord(State, (PUSHORT)&Word))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ Multiplier = (LONG)Word;
+ }
+ }
+
+ if (OperandSize)
+ {
+ LONG RegValue, Multiplicand;
+
+ /* Read the operands */
+ if (!Soft386ReadModrmDwordOperands(State,
+ &ModRegRm,
+ (PULONG)&RegValue,
+ (PULONG)&Multiplicand))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Multiply */
+ Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
+ }
+ else
+ {
+ SHORT RegValue, Multiplicand;
+
+ /* Read the operands */
+ if (!Soft386ReadModrmWordOperands(State,
+ &ModRegRm,
+ (PUSHORT)&RegValue,
+ (PUSHORT)&Multiplicand))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Multiply */
+ Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
+ }
+
+ /* Check for carry/overflow */
+ if ((Product < LONG_MIN) || (Product > LONG_MAX))
+ {
+ State->Flags.Cf = State->Flags.Of = TRUE;
+ }
+ else State->Flags.Cf = State->Flags.Of = FALSE;
+
+ /* Write-back the result */
+ return Soft386WriteModrmDwordOperands(State,
+ &ModRegRm,
+ TRUE,
+ (ULONG)((LONG)Product));
}
SOFT386_OPCODE_HANDLER(Soft386OpcodePushByteImm)
return Soft386StackPush(State, Data);
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeImulModrmByteImm)
-{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
-
SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteModrm)
{
UCHAR FirstValue, SecondValue, Result;
SOFT386_OPCODE_HANDLER(Soft386OpcodePushFlags)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodePopFlags)
-{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeSahf)
-{
- /* Make sure this is the right instruction */
- ASSERT(Opcode == 0x9E);
-
- /* Set the low-order byte of FLAGS to AH */
- State->Flags.Long &= 0xFFFFFF00;
- State->Flags.Long |= State->GeneralRegs[SOFT386_REG_EAX].HighByte;
-
- /* Restore the reserved bits of FLAGS */
- State->Flags.AlwaysSet = TRUE;
- State->Flags.Reserved0 = State->Flags.Reserved1 = FALSE;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- return FALSE;
-}
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLahf)
-{
- /* Make sure this is the right instruction */
- ASSERT(Opcode == 0x9F);
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* This OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
- /* Set AH to the low-order byte of FLAGS */
- State->GeneralRegs[SOFT386_REG_EAX].HighByte = LOBYTE(State->Flags.Long);
+ /* Check for VM86 mode when IOPL is not 3 */
+ if (State->Flags.Vm && (State->Flags.Iopl != 3))
+ {
+ /* Call the VM86 monitor */
+ Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
+ return FALSE;
+ }
- return FALSE;
+ /* Push the flags */
+ if (Size) return Soft386StackPush(State, State->Flags.Long);
+ else return Soft386StackPush(State, LOWORD(State->Flags.Long));
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeRet)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePopFlags)
{
- ULONG ReturnAddress;
- USHORT BytesToPop = 0;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
-
- /* Make sure this is the right instruction */
- ASSERT((Opcode & 0xFE) == 0xC2);
+ INT Cpl = Soft386GetCurrentPrivLevel(State);
+ ULONG NewFlags;
if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
return FALSE;
}
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
- /* The OPSIZE prefix toggles the size */
+ /* This OPSIZE prefix toggles the size */
Size = !Size;
}
- if (Opcode == 0xC2)
+ /* Pop the new flags */
+ if (!Soft386StackPop(State, &NewFlags))
{
- /* Fetch the number of bytes to pop after the return */
- if (!Soft386FetchWord(State, &BytesToPop)) return FALSE;
+ /* Exception occurred */
+ return FALSE;
}
- /* Pop the return address */
- if (!Soft386StackPop(State, &ReturnAddress)) return FALSE;
-
- /* Return to the calling procedure, and if necessary, pop the parameters */
- if (Size)
+ if (!State->Flags.Vm)
{
- State->InstPtr.Long = ReturnAddress;
- State->GeneralRegs[SOFT386_REG_ESP].Long += BytesToPop;
+ /* Check the current privilege level */
+ if (Cpl == 0)
+ {
+ /* Supervisor */
+
+ /* Set the flags */
+ if (Size)
+ {
+ /* Memorize the old state of RF */
+ BOOLEAN OldRf = State->Flags.Rf;
+
+ State->Flags.Long = NewFlags;
+
+ /* Restore VM and RF */
+ State->Flags.Vm = FALSE;
+ State->Flags.Rf = OldRf;
+
+ /* Clear VIF and VIP */
+ State->Flags.Vif = State->Flags.Vip = FALSE;
+ }
+ else State->Flags.LowWord = LOWORD(NewFlags);
+
+ /* Restore the reserved bits */
+ State->Flags.AlwaysSet = TRUE;
+ State->Flags.Reserved0 = FALSE;
+ State->Flags.Reserved1 = FALSE;
+ }
+ else
+ {
+ /* User */
+
+ /* Memorize the old state of IF and IOPL */
+ BOOLEAN OldIf = State->Flags.If;
+ UINT OldIopl = State->Flags.Iopl;
+
+ /* Set the flags */
+ if (Size)
+ {
+ /* Memorize the old state of RF */
+ BOOLEAN OldRf = State->Flags.Rf;
+
+ State->Flags.Long = NewFlags;
+
+ /* Restore VM and RF */
+ State->Flags.Vm = FALSE;
+ State->Flags.Rf = OldRf;
+
+ /* Clear VIF and VIP */
+ State->Flags.Vif = State->Flags.Vip = FALSE;
+ }
+ else State->Flags.LowWord = LOWORD(NewFlags);
+
+ /* Restore the reserved bits and IOPL */
+ State->Flags.AlwaysSet = TRUE;
+ State->Flags.Reserved0 = FALSE;
+ State->Flags.Reserved1 = FALSE;
+ State->Flags.Iopl = OldIopl;
+
+ /* Check if the user doesn't have the privilege to change IF */
+ if (Cpl > State->Flags.Iopl)
+ {
+ /* Restore IF */
+ State->Flags.If = OldIf;
+ }
+ }
}
else
{
- State->InstPtr.LowWord = LOWORD(ReturnAddress);
- State->GeneralRegs[SOFT386_REG_ESP].LowWord += BytesToPop;
+ /* Check the IOPL */
+ if (State->Flags.Iopl == 3)
+ {
+ if (Size)
+ {
+ /* Memorize the old state of RF, VIF and VIP */
+ BOOLEAN OldRf = State->Flags.Rf;
+ BOOLEAN OldVif = State->Flags.Vif;
+ BOOLEAN OldVip = State->Flags.Vip;
+
+ State->Flags.Long = NewFlags;
+
+ /* Restore VM, RF, VIF and VIP */
+ State->Flags.Vm = TRUE;
+ State->Flags.Rf = OldRf;
+ State->Flags.Vif = OldVif;
+ State->Flags.Vip = OldVip;
+ }
+ else State->Flags.LowWord = LOWORD(NewFlags);
+
+ /* Restore the reserved bits and IOPL */
+ State->Flags.AlwaysSet = TRUE;
+ State->Flags.Reserved0 = FALSE;
+ State->Flags.Reserved1 = FALSE;
+ State->Flags.Iopl = 3;
+ }
+ else
+ {
+ /* Call the VM86 monitor */
+ Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
+ }
+
}
return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLes)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSahf)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x9E);
+
+ /* Set the low-order byte of FLAGS to AH */
+ State->Flags.Long &= 0xFFFFFF00;
+ State->Flags.Long |= State->GeneralRegs[SOFT386_REG_EAX].HighByte;
+
+ /* Restore the reserved bits of FLAGS */
+ State->Flags.AlwaysSet = TRUE;
+ State->Flags.Reserved0 = State->Flags.Reserved1 = FALSE;
return FALSE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLds)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeLahf)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x9F);
+
+ /* Set AH to the low-order byte of FLAGS */
+ State->GeneralRegs[SOFT386_REG_EAX].HighByte = LOBYTE(State->Flags.Long);
return FALSE;
}
+SOFT386_OPCODE_HANDLER(Soft386OpcodeRet)
+{
+ ULONG ReturnAddress;
+ USHORT BytesToPop = 0;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFE) == 0xC2);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Opcode == 0xC2)
+ {
+ /* Fetch the number of bytes to pop after the return */
+ if (!Soft386FetchWord(State, &BytesToPop)) return FALSE;
+ }
+
+ /* Pop the return address */
+ if (!Soft386StackPop(State, &ReturnAddress)) return FALSE;
+
+ /* Return to the calling procedure, and if necessary, pop the parameters */
+ if (Size)
+ {
+ State->InstPtr.Long = ReturnAddress;
+ State->GeneralRegs[SOFT386_REG_ESP].Long += BytesToPop;
+ }
+ else
+ {
+ State->InstPtr.LowWord = LOWORD(ReturnAddress);
+ State->GeneralRegs[SOFT386_REG_ESP].LowWord += BytesToPop;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeLdsLes)
+{
+ UCHAR FarPointer[6];
+ BOOLEAN OperandSize, AddressSize;
+ SOFT386_MOD_REG_RM ModRegRm;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFE) == 0xC4);
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
+ }
+
+ /* Get the operands */
+ if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (!ModRegRm.Memory)
+ {
+ /* Check if this is a BOP and the host supports BOPs */
+ if ((Opcode == 0xC4)
+ && (ModRegRm.Register == SOFT386_REG_EAX)
+ && (ModRegRm.SecondRegister == SOFT386_REG_EBP)
+ && (State->BopCallback != NULL))
+ {
+ USHORT BopCode;
+
+ /* Fetch the BOP code */
+ if (!Soft386FetchWord(State, &BopCode))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Call the BOP handler */
+ State->BopCallback(State, BopCode);
+
+ /* Return success */
+ return TRUE;
+ }
+
+ /* Invalid */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (!Soft386ReadMemory(State,
+ (State->PrefixFlags & SOFT386_PREFIX_SEG)
+ ? State->SegmentOverride : SOFT386_REG_DS,
+ ModRegRm.MemoryAddress,
+ FALSE,
+ FarPointer,
+ OperandSize ? 6 : 4))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (OperandSize)
+ {
+ ULONG Offset = *((PULONG)FarPointer);
+ USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
+
+ /* Set the register to the offset */
+ State->GeneralRegs[ModRegRm.Register].Long = Offset;
+
+ /* Load the segment */
+ return Soft386LoadSegment(State,
+ (Opcode == 0xC4)
+ ? SOFT386_REG_ES : SOFT386_REG_DS,
+ Segment);
+ }
+ else
+ {
+ USHORT Offset = *((PUSHORT)FarPointer);
+ USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
+
+ /* Set the register to the offset */
+ State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
+
+ /* Load the segment */
+ return Soft386LoadSegment(State,
+ (Opcode == 0xC4)
+ ? SOFT386_REG_ES : SOFT386_REG_DS,
+ Segment);
+ }
+}
+
SOFT386_OPCODE_HANDLER(Soft386OpcodeEnter)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+ INT i;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ USHORT FrameSize;
+ UCHAR NestingLevel;
+ SOFT386_REG FramePointer;
- return FALSE;
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xC8);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (!Soft386FetchWord(State, &FrameSize))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (!Soft386FetchByte(State, &NestingLevel))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Push EBP */
+ if (!Soft386StackPush(State, State->GeneralRegs[SOFT386_REG_EBP].Long))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Save ESP */
+ FramePointer = State->GeneralRegs[SOFT386_REG_ESP];
+
+ /* Set up the nested procedure stacks */
+ for (i = 1; i < NestingLevel; i++)
+ {
+ if (Size)
+ {
+ State->GeneralRegs[SOFT386_REG_EBP].Long -= 4;
+ Soft386StackPush(State, State->GeneralRegs[SOFT386_REG_EBP].Long);
+ }
+ else
+ {
+ State->GeneralRegs[SOFT386_REG_EBP].LowWord -= 2;
+ Soft386StackPush(State, State->GeneralRegs[SOFT386_REG_EBP].LowWord);
+ }
+ }
+
+ if (NestingLevel > 0) Soft386StackPush(State, FramePointer.Long);
+
+ /* Set EBP to the frame pointer */
+ State->GeneralRegs[SOFT386_REG_EBP] = FramePointer;
+
+ /* Reserve space for the frame */
+ if (Size) State->GeneralRegs[SOFT386_REG_ESP].Long -= (ULONG)FrameSize;
+ else State->GeneralRegs[SOFT386_REG_ESP].LowWord -= FrameSize;
+
+ return TRUE;
}
SOFT386_OPCODE_HANDLER(Soft386OpcodeLeave)
return FALSE;
}
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
SOFT386_OPCODE_HANDLER(Soft386OpcodeIret)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+ INT i;
+ ULONG InstPtr, CodeSel, StackPtr, StackSel;
+ SOFT386_FLAGS_REG NewFlags;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- return FALSE;
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xCF);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ /* Pop EIP */
+ if (!Soft386StackPop(State, &InstPtr))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Pop CS */
+ if (!Soft386StackPop(State, &CodeSel))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Pop EFLAGS */
+ if (!Soft386StackPop(State, &NewFlags.Long))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Check for protected mode */
+ if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
+ {
+ INT Cpl = Soft386GetCurrentPrivLevel(State);
+
+ if (State->Flags.Vm)
+ {
+ /* Return from VM86 mode */
+
+ /* Check the IOPL */
+ if (State->Flags.Iopl == 3)
+ {
+ /* Set new EIP */
+ State->InstPtr.Long = LOWORD(InstPtr);
+
+ /* Load new CS */
+ if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Set the new flags */
+ if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
+ else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
+ State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
+ State->Flags.Iopl = 3;
+ }
+ else
+ {
+ /* Call the VM86 monitor */
+ Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ if (State->Flags.Nt)
+ {
+ /* Nested task return */
+
+ UNIMPLEMENTED;
+ return FALSE;
+ }
+
+ if (NewFlags.Vm)
+ {
+ /* Return to VM86 mode */
+ ULONG Es, Ds, Fs, Gs;
+
+ /* Pop ESP, SS, ES, FS, GS */
+ if (!Soft386StackPop(State, &StackPtr)) return FALSE;
+ if (!Soft386StackPop(State, &StackSel)) return FALSE;
+ if (!Soft386StackPop(State, &Es)) return FALSE;
+ if (!Soft386StackPop(State, &Ds)) return FALSE;
+ if (!Soft386StackPop(State, &Fs)) return FALSE;
+ if (!Soft386StackPop(State, &Gs)) return FALSE;
+
+ /* Set the new IP */
+ State->InstPtr.Long = LOWORD(InstPtr);
+
+ /* Set the new flags */
+ if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
+ else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
+ State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
+
+ /* Load the new segments */
+ if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel)) return FALSE;
+ if (!Soft386LoadSegment(State, SOFT386_REG_SS, StackSel)) return FALSE;
+ if (!Soft386LoadSegment(State, SOFT386_REG_ES, Es)) return FALSE;
+ if (!Soft386LoadSegment(State, SOFT386_REG_DS, Ds)) return FALSE;
+ if (!Soft386LoadSegment(State, SOFT386_REG_FS, Fs)) return FALSE;
+ if (!Soft386LoadSegment(State, SOFT386_REG_GS, Gs)) return FALSE;
+
+ return TRUE;
+ }
+
+ /* Load the new CS */
+ if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Set EIP */
+ if (Size) State->InstPtr.Long = InstPtr;
+ else State->InstPtr.LowWord = LOWORD(InstPtr);
+
+ if (GET_SEGMENT_RPL(CodeSel) > Cpl)
+ {
+ /* Pop ESP */
+ if (!Soft386StackPop(State, &StackPtr))
+ {
+ /* Exception */
+ return FALSE;
+ }
+
+ /* Pop SS */
+ if (!Soft386StackPop(State, &StackSel))
+ {
+ /* Exception */
+ return FALSE;
+ }
+
+ /* Load new SS */
+ if (!Soft386LoadSegment(State, SOFT386_REG_SS, StackSel))
+ {
+ /* Exception */
+ return FALSE;
+ }
+
+ /* Set ESP */
+ if (Size) State->GeneralRegs[SOFT386_REG_ESP].Long = StackPtr;
+ else State->GeneralRegs[SOFT386_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 = Soft386GetCurrentPrivLevel(State);
+
+ /* Check segment security */
+ for (i = 0; i <= SOFT386_NUM_SEG_REGS; i++)
+ {
+ /* Don't check CS or SS */
+ if ((i == SOFT386_REG_CS) || (i == SOFT386_REG_SS)) continue;
+
+ if ((Cpl > State->SegmentRegs[i].Dpl)
+ && (!State->SegmentRegs[i].Executable
+ || !State->SegmentRegs[i].DirConf))
+ {
+ /* Load the NULL descriptor in the segment */
+ if (!Soft386LoadSegment(State, i, 0)) return FALSE;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (Size && (InstPtr & 0xFFFF0000))
+ {
+ /* Invalid */
+ Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
+ return FALSE;
+ }
+
+ /* Set new EIP */
+ State->InstPtr.Long = InstPtr;
+
+ /* Load new CS */
+ if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Set the new flags */
+ if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
+ else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
+ State->Flags.AlwaysSet = TRUE;
+ }
+
+ return TRUE;
}
SOFT386_OPCODE_HANDLER(Soft386OpcodeAam)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+ UCHAR Base;
+ UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
- return FALSE;
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ /* Fetch the base */
+ if (!Soft386FetchByte(State, &Base))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Check if the base is zero */
+ if (Base == 0)
+ {
+ /* Divide error */
+ Soft386Exception(State, SOFT386_EXCEPTION_DE);
+ return FALSE;
+ }
+
+ /* Adjust */
+ State->GeneralRegs[SOFT386_REG_EAX].HighByte = Value / Base;
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Value %= Base;
+
+ /* Update flags */
+ State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Value);
+
+ return TRUE;
}
SOFT386_OPCODE_HANDLER(Soft386OpcodeAad)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+ UCHAR Base;
+ UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
- return FALSE;
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ /* Fetch the base */
+ if (!Soft386FetchByte(State, &Base))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Adjust */
+ Value += State->GeneralRegs[SOFT386_REG_EAX].HighByte * Base;
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Value;
+
+ /* Update flags */
+ State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Value);
+
+ return TRUE;
}
SOFT386_OPCODE_HANDLER(Soft386OpcodeXlat)
return FALSE;
}
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
return FALSE;
}
- /* Push the current value of the instruction pointer */
- if (!Soft386StackPush(State, State->InstPtr.Long))
- {
- /* Exception occurred */
- return FALSE;
- }
-
if (Size)
{
LONG Offset = 0;
return FALSE;
}
+ /* Push the current value of the instruction pointer */
+ if (!Soft386StackPush(State, State->InstPtr.Long))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
/* Move the instruction pointer */
State->InstPtr.Long += Offset;
}
return FALSE;
}
+ /* Push the current value of the instruction pointer */
+ if (!Soft386StackPush(State, State->InstPtr.Long))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
/* Move the instruction pointer */
State->InstPtr.LowWord += Offset;
}
return FALSE;
}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovAlOffset)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ ULONG Offset;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xA0);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ if (!Soft386FetchDword(State, &Offset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+ }
+ else
+ {
+ USHORT WordOffset;
+
+ if (!Soft386FetchWord(State, &WordOffset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ Offset = (ULONG)WordOffset;
+ }
+
+ /* Read from memory */
+ return Soft386ReadMemory(State,
+ (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
+ State->SegmentOverride : SOFT386_REG_DS,
+ Offset,
+ FALSE,
+ &State->GeneralRegs[SOFT386_REG_EAX].LowByte,
+ sizeof(UCHAR));
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovEaxOffset)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xA1);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ ULONG Offset;
+
+ if (!Soft386FetchDword(State, &Offset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Read from memory */
+ return Soft386ReadMemory(State,
+ (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
+ State->SegmentOverride : SOFT386_REG_DS,
+ Offset,
+ FALSE,
+ &State->GeneralRegs[SOFT386_REG_EAX].Long,
+ sizeof(ULONG));
+ }
+ else
+ {
+ USHORT Offset;
+
+ if (!Soft386FetchWord(State, &Offset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Read from memory */
+ return Soft386ReadMemory(State,
+ (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
+ State->SegmentOverride : SOFT386_REG_DS,
+ Offset,
+ FALSE,
+ &State->GeneralRegs[SOFT386_REG_EAX].LowWord,
+ sizeof(USHORT));
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetAl)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ ULONG Offset;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xA2);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ if (!Soft386FetchDword(State, &Offset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+ }
+ else
+ {
+ USHORT WordOffset;
+
+ if (!Soft386FetchWord(State, &WordOffset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ Offset = (ULONG)WordOffset;
+ }
+
+ /* Write to memory */
+ return Soft386WriteMemory(State,
+ (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
+ State->SegmentOverride : SOFT386_REG_DS,
+ Offset,
+ &State->GeneralRegs[SOFT386_REG_EAX].LowByte,
+ sizeof(UCHAR));
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetEax)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xA3);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (Size)
+ {
+ ULONG Offset;
+
+ if (!Soft386FetchDword(State, &Offset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Write to memory */
+ return Soft386WriteMemory(State,
+ (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
+ State->SegmentOverride : SOFT386_REG_DS,
+ Offset,
+ &State->GeneralRegs[SOFT386_REG_EAX].Long,
+ sizeof(ULONG));
+ }
+ else
+ {
+ USHORT Offset;
+
+ if (!Soft386FetchWord(State, &Offset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Write to memory */
+ return Soft386WriteMemory(State,
+ (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
+ State->SegmentOverride : SOFT386_REG_DS,
+ Offset,
+ &State->GeneralRegs[SOFT386_REG_EAX].LowWord,
+ sizeof(USHORT));
+ }
+}