* Fast486 386/486 CPU Emulation Library
* opgroups.c
*
- * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
/* PRIVATE FUNCTIONS **********************************************************/
-inline
static
+inline
ULONG
Fast486ArithmeticOperation(PFAST486_STATE State,
INT Operation,
case 1:
{
Result = FirstValue | SecondValue;
+ State->Flags.Cf = State->Flags.Of = FALSE;
break;
}
case 4:
{
Result = FirstValue & SecondValue;
+ State->Flags.Cf = State->Flags.Of = FALSE;
break;
}
case 6:
{
Result = FirstValue ^ SecondValue;
+ State->Flags.Cf = State->Flags.Of = FALSE;
break;
}
case 2:
{
Result = (Value << Count) | (State->Flags.Cf << (Count - 1));
-
+
/* Complete the calculation, but make sure we don't shift by too much */
if ((Bits - Count) < 31) Result |= Value >> (Bits - Count + 1);
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Fetch the immediate operand */
if (!Fast486FetchByte(State, &Immediate))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Read the operands */
if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
/* Unless this is CMP, write back the result */
if (ModRegRm.Register != 7)
{
- return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
+ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
}
-
- return TRUE;
}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81)
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (OperandSize)
if (!Fast486FetchDword(State, &Immediate))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Read the operands */
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
/* Unless this is CMP, write back the result */
if (ModRegRm.Register != 7)
{
- return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
+ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
}
}
else
if (!Fast486FetchWord(State, &Immediate))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Read the operands */
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
/* Unless this is CMP, write back the result */
if (ModRegRm.Register != 7)
{
- return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
}
}
-
- return TRUE;
}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83)
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Fetch the immediate operand */
if (!Fast486FetchByte(State, (PUCHAR)&ImmByte))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (OperandSize)
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
/* Unless this is CMP, write back the result */
if (ModRegRm.Register != 7)
{
- return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
+ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
}
}
else
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
/* Unless this is CMP, write back the result */
if (ModRegRm.Register != 7)
{
- return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
}
}
-
- return TRUE;
}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F)
if (!Fast486StackPop(State, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
if (OperandSize) State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
else State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
- return FALSE;
+ return;
}
if (ModRegRm.Register != 0)
{
/* Invalid */
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
- if (OperandSize)
- {
- return Fast486WriteModrmDwordOperands(State,
- &ModRegRm,
- FALSE,
- Value);
- }
- else
- {
- return Fast486WriteModrmWordOperands(State,
- &ModRegRm,
- FALSE,
- LOWORD(Value));
- }
+ if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
+ else Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Value));
}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0)
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Fetch the count */
if (!Fast486FetchByte(State, &Count))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Read the operands */
if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
Count));
/* Write back the result */
- return Fast486WriteModrmByteOperands(State,
- &ModRegRm,
- FALSE,
- Value);
+ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1)
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Fetch the count */
if (!Fast486FetchByte(State, &Count))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (OperandSize)
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
Count);
/* Write back the result */
- return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
+ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
}
else
{
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
Count));
/* Write back the result */
- return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
}
}
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (ModRegRm.Register != 0)
{
/* Invalid */
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
/* Get the immediate operand */
if (!Fast486FetchByte(State, &Immediate))
{
/* Exception occurred */
- return FALSE;
+ return;
}
- return Fast486WriteModrmByteOperands(State,
- &ModRegRm,
- FALSE,
- Immediate);
+ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Immediate);
}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7)
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (ModRegRm.Register != 0)
{
/* Invalid */
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
if (OperandSize)
if (!Fast486FetchDword(State, &Immediate))
{
/* Exception occurred */
- return FALSE;
+ return;
}
- return Fast486WriteModrmDwordOperands(State,
- &ModRegRm,
- FALSE,
- Immediate);
+ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Immediate);
}
else
{
if (!Fast486FetchWord(State, &Immediate))
{
/* Exception occurred */
- return FALSE;
+ return;
}
- return Fast486WriteModrmWordOperands(State,
- &ModRegRm,
- FALSE,
- Immediate);
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Immediate);
}
}
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Read the operands */
if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
Value = LOBYTE(Fast486RotateOperation(State, ModRegRm.Register, Value, 8, 1));
/* Write back the result */
- return Fast486WriteModrmByteOperands(State,
- &ModRegRm,
- FALSE,
- Value);
+ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
}
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (OperandSize)
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
Value = Fast486RotateOperation(State, ModRegRm.Register, Value, 32, 1);
/* Write back the result */
- return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
+ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
}
else
{
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
Value = LOWORD(Fast486RotateOperation(State, ModRegRm.Register, Value, 16, 1));
/* Write back the result */
- return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
}
}
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Read the operands */
if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
State->GeneralRegs[FAST486_REG_ECX].LowByte));
/* Write back the result */
- return Fast486WriteModrmByteOperands(State,
- &ModRegRm,
- FALSE,
- Value);
+ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3)
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (OperandSize)
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
State->GeneralRegs[FAST486_REG_ECX].LowByte);
/* Write back the result */
- return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
+ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
}
else
{
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
State->GeneralRegs[FAST486_REG_ECX].LowByte));
/* Write back the result */
- return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
}
}
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Read the operands */
if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
switch (ModRegRm.Register)
if (!Fast486FetchByte(State, &Immediate))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Calculate the result */
case 2:
{
/* Write back the result */
- return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, ~Value);
+ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, ~Value);
+
+ break;
}
/* NEG */
State->Flags.Pf = Fast486CalculateParity(Result);
/* Write back the result */
- return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result);
+ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result);
+
+ break;
}
/* MUL */
/* DIV */
case 6:
{
- UCHAR Quotient, Remainder;
+ USHORT Quotient;
+ UCHAR Remainder;
if (Value == 0)
{
/* Divide error */
Fast486Exception(State, FAST486_EXCEPTION_DE);
- return FALSE;
+ return;
}
Quotient = State->GeneralRegs[FAST486_REG_EAX].LowWord / Value;
Remainder = State->GeneralRegs[FAST486_REG_EAX].LowWord % Value;
+ if (Quotient > 0xFF)
+ {
+ /* Divide error */
+ Fast486Exception(State, FAST486_EXCEPTION_DE);
+ return;
+ }
+
/* Write back the results */
- State->GeneralRegs[FAST486_REG_EAX].LowByte = Quotient;
+ State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)Quotient;
State->GeneralRegs[FAST486_REG_EAX].HighByte = Remainder;
break;
/* IDIV */
case 7:
{
- CHAR Quotient, Remainder;
+ SHORT Quotient;
+ CHAR Remainder;
if (Value == 0)
{
/* Divide error */
Fast486Exception(State, FAST486_EXCEPTION_DE);
- return FALSE;
+ return;
}
Quotient = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord / (CHAR)Value;
Remainder = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord % (CHAR)Value;
+ if (Quotient > 127 || Quotient < -128)
+ {
+ /* Divide error */
+ Fast486Exception(State, FAST486_EXCEPTION_DE);
+ return;
+ }
+
/* Write back the results */
- State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)Quotient;
+ State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)((CHAR)Quotient);
State->GeneralRegs[FAST486_REG_EAX].HighByte = (UCHAR)Remainder;
break;
}
}
-
- return TRUE;
}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Set the sign flag */
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
}
else
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
}
if (!Fast486FetchDword(State, &Immediate))
{
/* Exception occurred */
- return FALSE;
+ return;
}
}
else
if (!Fast486FetchWord(State, (PUSHORT)&Immediate))
{
/* Exception occurred */
- return FALSE;
+ return;
}
}
if (OperandSize)
{
/* 32-bit */
- return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, ~Value);
+ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, ~Value);
}
else
{
/* 16-bit */
- return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(~Value));
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(~Value));
}
+
+ break;
}
/* NEG */
case 3:
{
/* Calculate the result */
- ULONG Result = -Value;
+ ULONG Result = -(LONG)Value;
if (!OperandSize) Result &= 0xFFFF;
/* Update the flags */
if (OperandSize)
{
/* 32-bit */
- return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
+ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
}
else
{
/* 16-bit */
- return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Result));
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Result));
}
+
+ break;
}
/* MUL */
{
/* Divide error */
Fast486Exception(State, FAST486_EXCEPTION_DE);
- return FALSE;
+ return;
}
if (OperandSize)
{
ULONGLONG Dividend = (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
| ((ULONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
- ULONG Quotient = Dividend / Value;
+ ULONGLONG Quotient = Dividend / Value;
ULONG Remainder = Dividend % Value;
+ if (Quotient > 0xFFFFFFFFULL)
+ {
+ /* Divide error */
+ Fast486Exception(State, FAST486_EXCEPTION_DE);
+ return;
+ }
+
/* Write back the results */
- State->GeneralRegs[FAST486_REG_EAX].Long = Quotient;
+ State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)Quotient;
State->GeneralRegs[FAST486_REG_EDX].Long = Remainder;
}
else
{
ULONG Dividend = (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
| ((ULONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
- USHORT Quotient = Dividend / Value;
+ ULONG Quotient = Dividend / Value;
USHORT Remainder = Dividend % Value;
+ if (Quotient > 0xFFFF)
+ {
+ /* Divide error */
+ Fast486Exception(State, FAST486_EXCEPTION_DE);
+ return;
+ }
+
/* Write back the results */
- State->GeneralRegs[FAST486_REG_EAX].LowWord = Quotient;
+ State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Quotient;
State->GeneralRegs[FAST486_REG_EDX].LowWord = Remainder;
}
{
/* Divide error */
Fast486Exception(State, FAST486_EXCEPTION_DE);
- return FALSE;
+ return;
}
if (OperandSize)
{
LONGLONG Dividend = (LONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
| ((LONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
- LONG Quotient = Dividend / (LONG)Value;
+ LONGLONG Quotient = Dividend / (LONG)Value;
LONG Remainder = Dividend % (LONG)Value;
+ if (Quotient > 2147483647LL || Quotient < -2147483648LL)
+ {
+ /* Divide error */
+ Fast486Exception(State, FAST486_EXCEPTION_DE);
+ return;
+ }
+
/* Write back the results */
- State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)Quotient;
+ State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)((LONG)Quotient);
State->GeneralRegs[FAST486_REG_EDX].Long = (ULONG)Remainder;
}
else
{
LONG Dividend = (LONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
| ((LONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
- SHORT Quotient = Dividend / (SHORT)LOWORD(Value);
+ LONG Quotient = Dividend / (SHORT)LOWORD(Value);
SHORT Remainder = Dividend % (SHORT)LOWORD(Value);
+ if (Quotient > 32767 || Quotient < -32768)
+ {
+ /* Divide error */
+ Fast486Exception(State, FAST486_EXCEPTION_DE);
+ return;
+ }
+
/* Write back the results */
- State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Quotient;
+ State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)((SHORT)Quotient);
State->GeneralRegs[FAST486_REG_EDX].LowWord = (USHORT)Remainder;
}
break;
}
}
-
- return TRUE;
}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE)
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (ModRegRm.Register > 1)
{
/* Invalid */
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
/* Read the operands */
if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (ModRegRm.Register == 0)
State->Flags.Pf = Fast486CalculateParity(Value);
/* Write back the result */
- return Fast486WriteModrmByteOperands(State,
- &ModRegRm,
- FALSE,
- Value);
+ Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
}
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (ModRegRm.Register == 7)
{
/* Invalid */
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
/* Read the operands */
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (ModRegRm.Register == 0)
if (!Fast486StackPush(State, State->InstPtr.Long))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Set the EIP to the address */
sizeof(USHORT)))
{
/* Exception occurred */
- return FALSE;
+ return;
+ }
+
+ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+ {
+ if (!Fast486ProcessGate(State, Selector, Value, TRUE))
+ {
+ /* Gate processed or exception occurred */
+ return;
+ }
}
/* Push the current value of CS */
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Push the current value of EIP */
if (!Fast486StackPush(State, State->InstPtr.Long))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Load the new code segment */
if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Set the EIP to the address */
sizeof(USHORT)))
{
/* Exception occurred */
- return FALSE;
+ return;
+ }
+
+ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+ {
+ if (!Fast486ProcessGate(State, Selector, Value, FALSE))
+ {
+ /* Gate processed or exception occurred */
+ return;
+ }
}
/* Load the new code segment */
if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Set the EIP to the address */
else if (ModRegRm.Register == 6)
{
/* Push the value on to the stack */
- return Fast486StackPush(State, Value);
+ Fast486StackPush(State, Value);
+ return;
}
if (ModRegRm.Register <= 1)
State->Flags.Pf = Fast486CalculateParity(Value);
/* Write back the result */
- return Fast486WriteModrmDwordOperands(State,
- &ModRegRm,
- FALSE,
- Value);
+ Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
}
}
else
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (ModRegRm.Register == 0)
if (!Fast486StackPush(State, State->InstPtr.LowWord))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Set the IP to the address */
sizeof(USHORT)))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Push the current value of CS */
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Push the current value of IP */
if (!Fast486StackPush(State, State->InstPtr.LowWord))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Load the new code segment */
if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Set the IP to the address */
sizeof(USHORT)))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Load the new code segment */
if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Set the IP to the address */
else if (ModRegRm.Register == 6)
{
/* Push the value on to the stack */
- return Fast486StackPush(State, Value);
+ Fast486StackPush(State, Value);
+ return;
}
else
{
/* Invalid */
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
if (ModRegRm.Register <= 1)
State->Flags.Pf = Fast486CalculateParity(Value);
/* Write back the result */
- return Fast486WriteModrmWordOperands(State,
- &ModRegRm,
- FALSE,
- Value);
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
}
}
-
- return TRUE;
}
-FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
+FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
{
FAST486_MOD_REG_RM ModRegRm;
BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Check which operation this is */
|| State->Flags.Vm)
{
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
- return Fast486WriteModrmWordOperands(State,
- &ModRegRm,
- FALSE,
- State->Ldtr.Selector);
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->Ldtr.Selector);
+ break;
}
/* STR */
|| State->Flags.Vm)
{
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
- return Fast486WriteModrmWordOperands(State,
- &ModRegRm,
- FALSE,
- State->TaskReg.Selector);
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->TaskReg.Selector);
+ break;
}
/* LLDT */
case 2:
{
+ BOOLEAN Valid;
USHORT Selector;
FAST486_SYSTEM_DESCRIPTOR GdtEntry;
|| State->Flags.Vm)
{
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
/* This is a privileged instruction */
if (Fast486GetCurrentPrivLevel(State) != 0)
{
Fast486Exception(State, FAST486_EXCEPTION_GP);
- return FALSE;
+ return;
}
if (!Fast486ReadModrmWordOperands(State,
&Selector))
{
/* Exception occurred */
- return FALSE;
+ return;
}
- /* Make sure the GDT contains the entry */
- if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
+ if (Selector & SEGMENT_TABLE_INDICATOR)
{
+ /* This selector doesn't point to the GDT */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
- return FALSE;
+ return;
}
- /* Read the GDT */
- if (!Fast486ReadLinearMemory(State,
- State->Gdtr.Address
- + GET_SEGMENT_INDEX(Selector),
- &GdtEntry,
- sizeof(GdtEntry)))
+ if (!Fast486ReadDescriptorEntry(State,
+ Selector,
+ &Valid,
+ (PFAST486_GDT_ENTRY)&GdtEntry))
{
/* Exception occurred */
- return FALSE;
+ return;
+ }
+
+ if (!Valid)
+ {
+ /* Invalid selector */
+ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+ return;
}
if (GET_SEGMENT_INDEX(Selector) == 0)
{
RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
- return TRUE;
+ return;
}
if (!GdtEntry.Present)
{
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
- return FALSE;
+ return;
}
if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
{
/* This is not a LDT descriptor */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
- return FALSE;
+ return;
}
/* Update the LDTR */
State->Ldtr.Selector = Selector;
State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
- if (GdtEntry.Granularity) State->Ldtr.Limit <<= 12;
- return TRUE;
+ if (GdtEntry.Granularity)
+ {
+ State->Ldtr.Limit <<= 12;
+ State->Ldtr.Limit |= 0x00000FFF;
+ }
+
+ break;
}
/* LTR */
case 3:
{
+ BOOLEAN Valid;
USHORT Selector;
FAST486_SYSTEM_DESCRIPTOR GdtEntry;
|| State->Flags.Vm)
{
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
/* This is a privileged instruction */
if (Fast486GetCurrentPrivLevel(State) != 0)
{
Fast486Exception(State, FAST486_EXCEPTION_GP);
- return FALSE;
+ return;
}
if (!Fast486ReadModrmWordOperands(State,
&Selector))
{
/* Exception occurred */
- return FALSE;
+ return;
}
- /* Make sure the GDT contains the entry */
- if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
+ if (Selector & SEGMENT_TABLE_INDICATOR)
{
+ /* This selector doesn't point to the GDT */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
- return FALSE;
+ return;
}
- /* Read the GDT */
- if (!Fast486ReadLinearMemory(State,
- State->Gdtr.Address
- + GET_SEGMENT_INDEX(Selector),
- &GdtEntry,
- sizeof(GdtEntry)))
+ if (!Fast486ReadDescriptorEntry(State,
+ Selector,
+ &Valid,
+ (PFAST486_GDT_ENTRY)&GdtEntry))
{
/* Exception occurred */
- return FALSE;
+ return;
+ }
+
+ if (!Valid)
+ {
+ /* Invalid selector */
+ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+ return;
}
if (GET_SEGMENT_INDEX(Selector) == 0)
{
Fast486Exception(State, FAST486_EXCEPTION_GP);
- return FALSE;
+ return;
}
if (!GdtEntry.Present)
{
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
- return FALSE;
+ return;
}
if (GdtEntry.Signature != FAST486_TSS_SIGNATURE)
{
/* This is not a TSS descriptor */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
- return FALSE;
+ return;
}
/* Update the TR */
State->TaskReg.Selector = Selector;
State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
- if (GdtEntry.Granularity) State->TaskReg.Limit <<= 12;
- State->TaskReg.Busy = TRUE;
- return TRUE;
+ if (GdtEntry.Granularity)
+ {
+ State->TaskReg.Limit <<= 12;
+ State->TaskReg.Limit |= 0x00000FFF;
+ }
+
+ break;
}
/* VERR/VERW */
case 5:
{
USHORT Selector;
+ BOOLEAN Valid;
FAST486_GDT_ENTRY GdtEntry;
/* Not recognized in real mode or virtual 8086 mode */
|| State->Flags.Vm)
{
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
/* This is a privileged instruction */
if (Fast486GetCurrentPrivLevel(State) != 0)
{
Fast486Exception(State, FAST486_EXCEPTION_GP);
- return FALSE;
+ return;
}
if (!Fast486ReadModrmWordOperands(State,
&Selector))
{
/* Exception occurred */
- return FALSE;
+ return;
}
- if (!(Selector & SEGMENT_TABLE_INDICATOR))
+ if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
{
- /* Make sure the GDT contains the entry */
- if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
- {
- /* Clear ZF */
- State->Flags.Zf = FALSE;
- return TRUE;
- }
-
- /* Read the GDT */
- if (!Fast486ReadLinearMemory(State,
- State->Gdtr.Address
- + GET_SEGMENT_INDEX(Selector),
- &GdtEntry,
- sizeof(GdtEntry)))
- {
- /* Exception occurred */
- return FALSE;
- }
+ /* Exception occurred */
+ return;
}
- else
- {
- /* Make sure the LDT contains the entry */
- if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
- {
- /* Clear ZF */
- State->Flags.Zf = FALSE;
- return TRUE;
- }
- /* Read the LDT */
- if (!Fast486ReadLinearMemory(State,
- State->Ldtr.Base
- + GET_SEGMENT_INDEX(Selector),
- &GdtEntry,
- sizeof(GdtEntry)))
- {
- /* Exception occurred */
- return FALSE;
- }
+ if (!Valid)
+ {
+ /* Clear ZF */
+ State->Flags.Zf = FALSE;
+ return;
}
/* Set ZF if it is valid and accessible */
&& (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State)));
- return TRUE;
+ break;
}
/* Invalid */
default:
{
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
}
}
}
-FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01)
+FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
{
+ // FAST486_TABLE_REG TableReg;
UCHAR TableReg[6];
FAST486_MOD_REG_RM ModRegRm;
BOOLEAN OperandSize, AddressSize;
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Check for the segment override */
{
/* The second operand must be a memory location */
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
/* Fill the 6-byte table register */
- RtlCopyMemory(TableReg, &State->Gdtr.Size, sizeof(USHORT));
- RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Gdtr.Address, sizeof(ULONG));
+ // TableReg = State->Gdtr;
+ *((PUSHORT)&TableReg) = State->Gdtr.Size;
+ *((PULONG)&TableReg[sizeof(USHORT)]) = State->Gdtr.Address;
/* Store the GDTR */
- return Fast486WriteMemory(State,
- Segment,
- ModRegRm.MemoryAddress,
- TableReg,
- sizeof(TableReg));
+ Fast486WriteMemory(State,
+ Segment,
+ ModRegRm.MemoryAddress,
+ TableReg,
+ sizeof(TableReg));
+
+ break;
}
/* SIDT */
{
/* The second operand must be a memory location */
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
/* Fill the 6-byte table register */
- RtlCopyMemory(TableReg, &State->Idtr.Size, sizeof(USHORT));
- RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Idtr.Address, sizeof(ULONG));
+ // TableReg = State->Idtr;
+ *((PUSHORT)&TableReg) = State->Idtr.Size;
+ *((PULONG)&TableReg[sizeof(USHORT)]) = State->Idtr.Address;
/* Store the IDTR */
- return Fast486WriteMemory(State,
- Segment,
- ModRegRm.MemoryAddress,
- TableReg,
- sizeof(TableReg));
+ Fast486WriteMemory(State,
+ Segment,
+ ModRegRm.MemoryAddress,
+ TableReg,
+ sizeof(TableReg));
+
+ break;
}
/* LGDT */
if (Fast486GetCurrentPrivLevel(State) != 0)
{
Fast486Exception(State, FAST486_EXCEPTION_GP);
- return FALSE;
+ return;
}
if (!ModRegRm.Memory)
{
/* The second operand must be a memory location */
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
/* Read the new GDTR */
sizeof(TableReg)))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Load the new GDT */
- State->Gdtr.Size = *((PUSHORT)TableReg);
+ // State->Gdtr = TableReg;
+ State->Gdtr.Size = *((PUSHORT)&TableReg);
State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
/* In 16-bit mode the highest byte is masked out */
if (!OperandSize) State->Gdtr.Address &= 0x00FFFFFF;
- return TRUE;
+ break;
}
/* LIDT */
if (Fast486GetCurrentPrivLevel(State) != 0)
{
Fast486Exception(State, FAST486_EXCEPTION_GP);
- return FALSE;
+ return;
}
if (!ModRegRm.Memory)
{
/* The second operand must be a memory location */
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
/* Read the new IDTR */
sizeof(TableReg)))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Load the new IDT */
- State->Idtr.Size = *((PUSHORT)TableReg);
+ // State->Idtr = TableReg;
+ State->Idtr.Size = *((PUSHORT)&TableReg);
State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
/* In 16-bit mode the highest byte is masked out */
if (!OperandSize) State->Idtr.Address &= 0x00FFFFFF;
- return TRUE;
+ break;
}
/* SMSW */
case 4:
{
/* Store the lower 16 bits (Machine Status Word) of CR0 */
- return Fast486WriteModrmWordOperands(State,
- &ModRegRm,
- FALSE,
- LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
+ Fast486WriteModrmWordOperands(State,
+ &ModRegRm,
+ FALSE,
+ LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
+
+ break;
}
/* LMSW */
if (Fast486GetCurrentPrivLevel(State) != 0)
{
Fast486Exception(State, FAST486_EXCEPTION_GP);
- return FALSE;
+ return;
}
/* Read the new Machine Status Word */
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* This instruction cannot be used to return to real mode */
&& !(MachineStatusWord & FAST486_CR0_PE))
{
Fast486Exception(State, FAST486_EXCEPTION_GP);
- return FALSE;
+ return;
}
/* Set the lowest 4 bits */
State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF0;
State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
- return TRUE;
+ break;
}
/* INVLPG */
case 7:
{
- UNIMPLEMENTED;
- return FALSE;
+#ifndef FAST486_NO_PREFETCH
+ /* Invalidate the prefetch */
+ State->PrefetchValid = FALSE;
+#endif
+
+ /* This is a privileged instruction */
+ if (Fast486GetCurrentPrivLevel(State) != 0)
+ {
+ Fast486Exception(State, FAST486_EXCEPTION_GP);
+ return;
+ }
+
+ if (!ModRegRm.Memory)
+ {
+ /* The second operand must be a memory location */
+ Fast486Exception(State, FAST486_EXCEPTION_UD);
+ return;
+ }
+
+ if (State->Tlb != NULL)
+ {
+ /* Clear the TLB entry */
+ State->Tlb[ModRegRm.MemoryAddress >> 12] = INVALID_TLB_FIELD;
+ }
+
+ break;
}
/* Invalid */
default:
{
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
}
}
}
-FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9)
+FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9)
{
FAST486_MOD_REG_RM ModRegRm;
BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* All of them are reserved (UD2) */
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
-FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA)
+FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA)
{
FAST486_MOD_REG_RM ModRegRm;
BOOLEAN OperandSize, AddressSize;
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (ModRegRm.Register < 4)
{
/* Invalid */
Fast486Exception(State, FAST486_EXCEPTION_UD);
- return FALSE;
+ return;
}
/* Get the bit number */
if (!Fast486FetchByte(State, &BitNumber))
{
/* Exception occurred */
- return FALSE;
+ return;
}
if (ModRegRm.Memory)
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Set CF to the bit value */
if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
}
}
if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
/* Set CF to the bit value */
if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
{
/* Exception occurred */
- return FALSE;
+ return;
}
}
}
-
- /* Return success */
- return TRUE;
}
/* EOF */