/*
- * COPYRIGHT: GPL - See COPYING in the top level directory
- * PROJECT: 386/486 CPU Emulation Library
- * FILE: opcodes.c
- * PURPOSE: Opcode handlers.
- * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Soft386 386/486 CPU Emulation Library
+ * opcodes.c
+ *
+ * Copyright (C) 2013 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
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* INCLUDES *******************************************************************/
#include <soft386.h>
#include "opcodes.h"
#include "opgroups.h"
+#include "extraops.h"
#include "common.h"
/* PUBLIC VARIABLES ***********************************************************/
Soft386OpcodeOrAl,
Soft386OpcodeOrEax,
Soft386OpcodePushCs,
- NULL, // TODO: OPCODE 0x0F NOT SUPPORTED
+ Soft386OpcodeExtended,
Soft386OpcodeAdcByteModrm,
Soft386OpcodeAdcModrm,
Soft386OpcodeAdcByteModrm,
Soft386OpcodeImulModrmImm,
Soft386OpcodePushByteImm,
Soft386OpcodeImulModrmImm,
- NULL, // TODO: OPCODE 0x6C NOT SUPPORTED
- NULL, // TODO: OPCODE 0x6D NOT SUPPORTED
- NULL, // TODO: OPCODE 0x6E NOT SUPPORTED
- NULL, // TODO: OPCODE 0x6F NOT SUPPORTED
+ Soft386OpcodeIns,
+ Soft386OpcodeIns,
+ Soft386OpcodeOuts,
+ Soft386OpcodeOuts,
Soft386OpcodeShortConditionalJmp,
Soft386OpcodeShortConditionalJmp,
Soft386OpcodeShortConditionalJmp,
Soft386OpcodeShortConditionalJmp,
Soft386OpcodeShortConditionalJmp,
Soft386OpcodeShortConditionalJmp,
- Soft386OpcodeGroup80,
+ Soft386OpcodeGroup8082,
Soft386OpcodeGroup81,
- Soft386OpcodeGroup82,
+ Soft386OpcodeGroup8082,
Soft386OpcodeGroup83,
Soft386OpcodeTestByteModrm,
Soft386OpcodeTestModrm,
Soft386OpcodeMovEaxOffset,
Soft386OpcodeMovOffsetAl,
Soft386OpcodeMovOffsetEax,
- NULL, // TODO: OPCODE 0xA4 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xA5 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xA6 NOT SUPPORTED
- NULL, // TODO: OPCODE 0xA7 NOT SUPPORTED
+ Soft386OpcodeMovs,
+ Soft386OpcodeMovs,
+ Soft386OpcodeCmps,
+ Soft386OpcodeCmps,
Soft386OpcodeTestAl,
Soft386OpcodeTestEax,
- NULL, // TODO: OPCODE 0xAA NOT SUPPORTED
- NULL, // TODO: OPCODE 0xAB NOT SUPPORTED
- NULL, // TODO: OPCODE 0xAC NOT SUPPORTED
- NULL, // TODO: OPCODE 0xAD NOT SUPPORTED
- NULL, // TODO: OPCODE 0xAE NOT SUPPORTED
- NULL, // TODO: OPCODE 0xAF NOT SUPPORTED
+ Soft386OpcodeStos,
+ Soft386OpcodeStos,
+ Soft386OpcodeLods,
+ Soft386OpcodeLods,
+ Soft386OpcodeScas,
+ Soft386OpcodeScas,
Soft386OpcodeMovByteRegImm,
Soft386OpcodeMovByteRegImm,
Soft386OpcodeMovByteRegImm,
Soft386OpcodeGroupD3,
Soft386OpcodeAam,
Soft386OpcodeAad,
- NULL, // TODO: OPCODE 0xD6 NOT SUPPORTED
+ Soft386OpcodeSalc,
Soft386OpcodeXlat,
NULL, // TODO: OPCODE 0xD8 NOT SUPPORTED
NULL, // TODO: OPCODE 0xD9 NOT SUPPORTED
ULONG Value;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
ULONG Value;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
SOFT386_OPCODE_HANDLER(Soft386OpcodePushReg)
{
- if ((State->PrefixFlags != SOFT386_PREFIX_OPSIZE)
- && (State->PrefixFlags != 0))
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
ULONG Value;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_SS].Size;
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
INT Reg = Opcode & 0x07;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
/* Make sure this is the right instruction */
ASSERT((Opcode & 0xF7) == 0xE5);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
/* Make sure this is the right instruction */
ASSERT((Opcode & 0xF7) == 0xE7);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
/* Make sure this is the right instruction */
ASSERT((Opcode & 0xF8) == 0xB8);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
Size = !Size;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
}
SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbByteModrm)
-{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbModrm)
-{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbAl)
-{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbEax)
-{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodePushDs)
-{
- /* Call the internal API */
- return Soft386StackPush(State, State->SegmentRegs[SOFT386_REG_DS].Selector);
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodePopDs)
-{
- ULONG NewSelector;
-
- if (!Soft386StackPop(State, &NewSelector))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- /* Call the internal API */
- return Soft386LoadSegment(State, SOFT386_REG_DS, LOWORD(NewSelector));
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeDaa)
-{
- UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
- BOOLEAN Carry = State->Flags.Cf;
-
- /* Clear the carry flag */
- State->Flags.Cf = FALSE;
-
- /* Check if the first BCD digit is invalid or there was a carry from it */
- if (((Value & 0x0F) > 9) || State->Flags.Af)
- {
- /* Correct it */
- State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x06;
- if (State->GeneralRegs[SOFT386_REG_EAX].LowByte < 0x06)
- {
- /* A carry occurred */
- State->Flags.Cf = TRUE;
- }
-
- /* Set the adjust flag */
- State->Flags.Af = TRUE;
- }
-
- /* Check if the second BCD digit is invalid or there was a carry from it */
- if ((Value > 0x99) || Carry)
- {
- /* Correct it */
- State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x60;
-
- /* There was a carry */
- State->Flags.Cf = TRUE;
- }
-
- return TRUE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubByteModrm)
{
UCHAR FirstValue, SecondValue, Result;
SOFT386_MOD_REG_RM ModRegRm;
BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+ INT Carry = State->Flags.Cf ? 1 : 0;
/* Make sure this is the right instruction */
- ASSERT((Opcode & 0xED) == 0x28);
+ ASSERT((Opcode & 0xFD) == 0x18);
if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
/* The ADSIZE prefix toggles the size */
AddressSize = !AddressSize;
}
- else if (State->PrefixFlags
- & ~(SOFT386_PREFIX_ADSIZE
- | SOFT386_PREFIX_SEG
- | SOFT386_PREFIX_LOCK))
- {
- /* Invalid prefix */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
/* Get the operands */
if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
}
/* Calculate the result */
- Result = FirstValue - SecondValue;
+ Result = FirstValue - SecondValue - Carry;
/* Update the flags */
- State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Cf = FirstValue < (SecondValue + 1);
State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
&& ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
- State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + 1) & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
- /* Check if this is not a CMP */
- if (!(Opcode & 0x10))
- {
- /* Write back the result */
- return Soft386WriteModrmByteOperands(State,
- &ModRegRm,
- Opcode & SOFT386_OPCODE_WRITE_REG,
- Result);
- }
- else
- {
- /* Discard the result */
- return TRUE;
- }
+ /* Write back the result */
+ return Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbModrm)
{
SOFT386_MOD_REG_RM ModRegRm;
BOOLEAN OperandSize, AddressSize;
+ INT Carry = State->Flags.Cf ? 1 : 0;
/* Make sure this is the right instruction */
- ASSERT((Opcode & 0xED) == 0x29);
+ ASSERT((Opcode & 0xFD) == 0x19);
OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
OperandSize = !OperandSize;
}
- if (State->PrefixFlags
- & ~(SOFT386_PREFIX_ADSIZE
- | SOFT386_PREFIX_OPSIZE
- | SOFT386_PREFIX_SEG
- | SOFT386_PREFIX_LOCK))
- {
- /* Invalid prefix */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
-
/* Get the operands */
if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
{
ULONG FirstValue, SecondValue, Result;
if (!Soft386ReadModrmDwordOperands(State,
- &ModRegRm,
- &FirstValue,
- &SecondValue))
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
{
/* Exception occurred */
return FALSE;
}
/* Calculate the result */
- Result = FirstValue - SecondValue;
+ Result = FirstValue - SecondValue - Carry;
/* Update the flags */
- State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Cf = FirstValue < (SecondValue + Carry);
State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
&& ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
- State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + 1) & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
- /* Check if this is not a CMP */
- if (!(Opcode & 0x10))
- {
- /* Write back the result */
- return Soft386WriteModrmDwordOperands(State,
- &ModRegRm,
- Opcode & SOFT386_OPCODE_WRITE_REG,
- Result);
- }
- else
- {
- /* Discard the result */
- return TRUE;
- }
+ /* Write back the result */
+ return Soft386WriteModrmDwordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
}
else
{
}
/* Calculate the result */
- Result = FirstValue - SecondValue;
+ Result = FirstValue - SecondValue - Carry;
/* Update the flags */
- State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Cf = FirstValue < (SecondValue + Carry);
State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
&& ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
- State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + 1) & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
- /* Check if this is not a CMP */
- if (!(Opcode & 0x10))
- {
- /* Write back the result */
- return Soft386WriteModrmWordOperands(State,
- &ModRegRm,
- Opcode & SOFT386_OPCODE_WRITE_REG,
- Result);
- }
- else
- {
- /* Discard the result */
- return TRUE;
- }
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
}
-
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubAl)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbAl)
{
UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
UCHAR SecondValue, Result;
+ INT Carry = State->Flags.Cf ? 1 : 0;
/* Make sure this is the right instruction */
- ASSERT((Opcode & 0xEF) == 0x2C);
+ ASSERT(Opcode == 0x1C);
if (State->PrefixFlags)
{
}
/* Calculate the result */
- Result = FirstValue - SecondValue;
+ Result = FirstValue - SecondValue - Carry;
/* Update the flags */
- State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Cf = FirstValue < (SecondValue + Carry);
State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
&& ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
- State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + 1) & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
- /* Check if this is not a CMP */
- if (!(Opcode & 0x10))
- {
- /* Write back the result */
- State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
- }
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
return TRUE;
+
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbEax)
{
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ INT Carry = State->Flags.Cf ? 1 : 0;
/* Make sure this is the right instruction */
- ASSERT((Opcode & 0xEF) == 0x2D);
+ ASSERT(Opcode == 0x1D);
if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
}
/* Calculate the result */
- Result = FirstValue - SecondValue;
+ Result = FirstValue - SecondValue - Carry;
/* Update the flags */
- State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Cf = FirstValue < (SecondValue + Carry);
State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
&& ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
- State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + Carry) & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
- /* Check if this is not a CMP */
- if (!(Opcode & 0x10))
- {
- /* Write back the result */
- State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
- }
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
}
else
{
}
/* Calculate the result */
- Result = FirstValue - SecondValue;
+ Result = FirstValue - SecondValue - Carry;
/* Update the flags */
- State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Cf = FirstValue < (SecondValue + Carry);
State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
&& ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
- State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + Carry) & 0x0F);
State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
State->Flags.Pf = Soft386CalculateParity(Result);
}
return TRUE;
+
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeDas)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushDs)
{
- UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
- BOOLEAN Carry = State->Flags.Cf;
+ /* Call the internal API */
+ return Soft386StackPush(State, State->SegmentRegs[SOFT386_REG_DS].Selector);
+}
- /* Clear the carry flag */
- State->Flags.Cf = FALSE;
+SOFT386_OPCODE_HANDLER(Soft386OpcodePopDs)
+{
+ ULONG NewSelector;
- /* Check if the first BCD digit is invalid or there was a borrow */
- if (((Value & 0x0F) > 9) || State->Flags.Af)
+ if (!Soft386StackPop(State, &NewSelector))
{
- /* Correct it */
- State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x06;
- if (State->GeneralRegs[SOFT386_REG_EAX].LowByte > 0xFB)
- {
- /* A borrow occurred */
- State->Flags.Cf = TRUE;
- }
-
- /* Set the adjust flag */
- State->Flags.Af = TRUE;
- }
-
- /* Check if the second BCD digit is invalid or there was a borrow */
- if ((Value > 0x99) || Carry)
- {
- /* Correct it */
- State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x60;
-
- /* There was a borrow */
- State->Flags.Cf = TRUE;
+ /* Exception occurred */
+ return FALSE;
}
- return TRUE;
+ /* Call the internal API */
+ return Soft386LoadSegment(State, SOFT386_REG_DS, LOWORD(NewSelector));
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeAaa)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeDaa)
{
UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ BOOLEAN Carry = State->Flags.Cf;
- /*
- * Check if the value in AL is not a valid BCD digit,
- * or there was a carry from the lowest 4 bits of AL
- */
+ /* Clear the carry flag */
+ State->Flags.Cf = FALSE;
+
+ /* Check if the first BCD digit is invalid or there was a carry from it */
if (((Value & 0x0F) > 9) || State->Flags.Af)
{
/* Correct it */
State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x06;
- State->GeneralRegs[SOFT386_REG_EAX].HighByte++;
+ if (State->GeneralRegs[SOFT386_REG_EAX].LowByte < 0x06)
+ {
+ /* A carry occurred */
+ State->Flags.Cf = TRUE;
+ }
- /* Set CF and AF */
- State->Flags.Cf = State->Flags.Af = TRUE;
- }
- else
- {
- /* Clear CF and AF */
- State->Flags.Cf = State->Flags.Af = FALSE;
+ /* Set the adjust flag */
+ State->Flags.Af = TRUE;
}
- /* Keep only the lowest 4 bits of AL */
- State->GeneralRegs[SOFT386_REG_EAX].LowByte &= 0x0F;
-
- return TRUE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeAas)
-{
- UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
-
- /*
- * Check if the value in AL is not a valid BCD digit,
- * or there was a borrow from the lowest 4 bits of AL
- */
- if (((Value & 0x0F) > 9) || State->Flags.Af)
+ /* Check if the second BCD digit is invalid or there was a carry from it */
+ if ((Value > 0x99) || Carry)
{
/* Correct it */
- State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x06;
- State->GeneralRegs[SOFT386_REG_EAX].HighByte--;
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x60;
- /* Set CF and AF */
- State->Flags.Cf = State->Flags.Af = TRUE;
- }
- else
- {
- /* Clear CF and AF */
- State->Flags.Cf = State->Flags.Af = FALSE;
+ /* There was a carry */
+ State->Flags.Cf = TRUE;
}
- /* Keep only the lowest 4 bits of AL */
- State->GeneralRegs[SOFT386_REG_EAX].LowByte &= 0x0F;
-
return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodePushAll)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubByteModrm)
{
- INT i;
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- SOFT386_REG SavedEsp = State->GeneralRegs[SOFT386_REG_ESP];
+ UCHAR FirstValue, SecondValue, Result;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
/* Make sure this is the right instruction */
- ASSERT(Opcode == 0x60);
+ ASSERT((Opcode & 0xED) == 0x28);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
}
- else
+ else if (State->PrefixFlags
+ & ~(SOFT386_PREFIX_ADSIZE
+ | SOFT386_PREFIX_SEG
+ | SOFT386_PREFIX_LOCK))
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
- /* Push all the registers in order */
- for (i = 0; i < SOFT386_NUM_GEN_REGS; i++)
+ /* Get the operands */
+ if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
{
- if (i == SOFT386_REG_ESP)
- {
- /* Use the saved ESP instead */
- if (!Soft386StackPush(State, Size ? SavedEsp.Long : SavedEsp.LowWord))
- {
- /* Exception occurred */
- return FALSE;
- }
- }
- else
- {
- /* Push the register */
- if (!Soft386StackPush(State, Size ? State->GeneralRegs[i].Long
- : State->GeneralRegs[i].LowWord))
- {
- /* Exception occurred */
- return FALSE;
- }
- }
+ /* Exception occurred */
+ return FALSE;
}
- return TRUE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodePopAll)
-{
- INT i;
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- ULONG Value;
-
- /* Make sure this is the right instruction */
- ASSERT(Opcode == 0x61);
-
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
- }
- else
+ if (!Soft386ReadModrmByteOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
{
- /* Invalid prefix */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ /* Exception occurred */
return FALSE;
}
- /* Pop all the registers in reverse order */
- for (i = SOFT386_NUM_GEN_REGS - 1; i >= 0; i--)
+ /* Check if this is the instruction that writes to R/M */
+ if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
{
- /* Pop the value */
- if (!Soft386StackPop(State, &Value))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- /* Don't modify ESP */
- if (i != SOFT386_REG_ESP)
- {
- if (Size) State->GeneralRegs[i].Long = Value;
- else State->GeneralRegs[i].LowWord = LOWORD(Value);
- }
+ /* Swap the order */
+ FirstValue ^= SecondValue;
+ SecondValue ^= FirstValue;
+ FirstValue ^= SecondValue;
}
- return TRUE;
-}
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
-SOFT386_OPCODE_HANDLER(Soft386OpcodeBound)
-{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
+ && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
- return FALSE;
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ return Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+ else
+ {
+ /* Discard the result */
+ return TRUE;
+ }
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeArpl)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm)
{
- USHORT FirstValue, SecondValue;
SOFT386_MOD_REG_RM ModRegRm;
- BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+ BOOLEAN OperandSize, AddressSize;
- if (!(State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
- || State->Flags.Vm
- || (State->PrefixFlags & SOFT386_PREFIX_LOCK))
- {
- /* Cannot be used in real mode or with a LOCK prefix */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xED) == 0x29);
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
- /* The ADSIZE prefix toggles the size */
+ /* The ADSIZE prefix toggles the address size */
AddressSize = !AddressSize;
}
- /* Get the operands */
- if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
- /* Exception occurred */
+ /* The OPSIZE prefix toggles the operand size */
+ OperandSize = !OperandSize;
+ }
+
+ if (State->PrefixFlags
+ & ~(SOFT386_PREFIX_ADSIZE
+ | SOFT386_PREFIX_OPSIZE
+ | SOFT386_PREFIX_SEG
+ | SOFT386_PREFIX_LOCK))
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
- /* Read the operands */
- if (!Soft386ReadModrmWordOperands(State,
- &ModRegRm,
- &FirstValue,
- &SecondValue))
+ /* Get the operands */
+ if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
return FALSE;
}
- /* Check if the RPL needs adjusting */
- if ((SecondValue & 3) < (FirstValue & 3))
+ /* Check the operand size */
+ if (OperandSize)
{
- /* Adjust the RPL */
- SecondValue &= ~3;
- SecondValue |= FirstValue & 3;
-
- /* Set ZF */
- State->Flags.Zf = TRUE;
+ ULONG FirstValue, SecondValue, Result;
- /* Write back the result */
- return Soft386WriteModrmWordOperands(State, &ModRegRm, FALSE, SecondValue);
- }
- else
- {
- /* Clear ZF */
- State->Flags.Zf = FALSE;
- return TRUE;
- }
-}
+ if (!Soft386ReadModrmDwordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
-SOFT386_OPCODE_HANDLER(Soft386OpcodePushImm)
-{
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ /* Check if this is the instruction that writes to R/M */
+ if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
+ {
+ /* Swap the order */
+ FirstValue ^= SecondValue;
+ SecondValue ^= FirstValue;
+ FirstValue ^= SecondValue;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
- /* Make sure this is the right instruction */
- ASSERT(Opcode == 0x68);
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
+ && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ return Soft386WriteModrmDwordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+ else
+ {
+ /* Discard the result */
+ return TRUE;
+ }
}
else
{
- /* Invalid prefix */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
-
- if (Size)
- {
- ULONG Data;
+ USHORT FirstValue, SecondValue, Result;
- if (!Soft386FetchDword(State, &Data))
+ if (!Soft386ReadModrmWordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
{
/* Exception occurred */
return FALSE;
}
+
+ /* Check if this is the instruction that writes to R/M */
+ if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
+ {
+ /* Swap the order */
+ FirstValue ^= SecondValue;
+ SecondValue ^= FirstValue;
+ FirstValue ^= SecondValue;
+ }
+
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
- /* Call the internal API */
- return Soft386StackPush(State, Data);
- }
- else
- {
- USHORT Data;
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
+ && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
- if (!Soft386FetchWord(State, &Data))
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
{
- /* Exception occurred */
- return FALSE;
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
+ else
+ {
+ /* Discard the result */
+ return TRUE;
}
-
- /* Call the internal API */
- return Soft386StackPush(State, Data);
}
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeImulModrmImm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubAl)
{
- BOOLEAN OperandSize, AddressSize;
- SOFT386_MOD_REG_RM ModRegRm;
- LONG Multiplier;
- LONGLONG Product;
+ UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ UCHAR SecondValue, Result;
/* 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;
- }
+ ASSERT((Opcode & 0xEF) == 0x2C);
- if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags)
{
- /* The OPSIZE prefix toggles the operand size */
- OperandSize = !OperandSize;
+ /* This opcode doesn't take any prefixes */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
}
- /* Fetch the parameters */
- if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+ if (!Soft386FetchByte(State, &SecondValue))
{
/* Exception occurred */
return FALSE;
}
- if (Opcode == 0x6B)
- {
- CHAR Byte;
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
- /* Fetch the immediate operand */
- if (!Soft386FetchByte(State, (PUCHAR)&Byte))
- {
- /* Exception occurred */
- return FALSE;
- }
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
+ && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
- Multiplier = (LONG)Byte;
- }
- else
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
{
- if (OperandSize)
- {
- LONG Dword;
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
+ }
- /* Fetch the immediate operand */
- if (!Soft386FetchDword(State, (PULONG)&Dword))
- {
- /* Exception occurred */
- return FALSE;
- }
+ return TRUE;
+}
- Multiplier = Dword;
- }
- else
- {
- SHORT Word;
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- /* Fetch the immediate operand */
- if (!Soft386FetchWord(State, (PUSHORT)&Word))
- {
- /* Exception occurred */
- return FALSE;
- }
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xEF) == 0x2D);
- Multiplier = (LONG)Word;
- }
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
}
- if (OperandSize)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
- LONG RegValue, Multiplicand;
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
- /* Read the operands */
- if (!Soft386ReadModrmDwordOperands(State,
- &ModRegRm,
- (PULONG)&RegValue,
- (PULONG)&Multiplicand))
+ if (Size)
+ {
+ ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ ULONG SecondValue, Result;
+
+ if (!Soft386FetchDword(State, &SecondValue))
{
/* Exception occurred */
return FALSE;
}
- /* Multiply */
- Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
+ && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
+ }
}
else
{
- SHORT RegValue, Multiplicand;
+ USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+ USHORT SecondValue, Result;
- /* Read the operands */
- if (!Soft386ReadModrmWordOperands(State,
- &ModRegRm,
- (PUSHORT)&RegValue,
- (PUSHORT)&Multiplicand))
+ if (!Soft386FetchWord(State, &SecondValue))
{
/* Exception occurred */
return FALSE;
}
- /* Multiply */
- Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
- }
+ /* Calculate the result */
+ Result = FirstValue - SecondValue;
- /* Check for carry/overflow */
- if ((Product < LONG_MIN) || (Product > LONG_MAX))
- {
- State->Flags.Cf = State->Flags.Of = TRUE;
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
+ && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Check if this is not a CMP */
+ if (!(Opcode & 0x10))
+ {
+ /* Write back the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
+ }
}
- else State->Flags.Cf = State->Flags.Of = FALSE;
- /* Write-back the result */
- return Soft386WriteModrmDwordOperands(State,
- &ModRegRm,
- TRUE,
- (ULONG)((LONG)Product));
+ return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodePushByteImm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeDas)
{
- UCHAR Data;
+ UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ BOOLEAN Carry = State->Flags.Cf;
- /* Make sure this is the right instruction */
- ASSERT(Opcode == 0x6A);
+ /* Clear the carry flag */
+ State->Flags.Cf = FALSE;
- if (!Soft386FetchByte(State, &Data))
+ /* Check if the first BCD digit is invalid or there was a borrow */
+ if (((Value & 0x0F) > 9) || State->Flags.Af)
{
- /* Exception occurred */
- return FALSE;
+ /* Correct it */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x06;
+ if (State->GeneralRegs[SOFT386_REG_EAX].LowByte > 0xFB)
+ {
+ /* A borrow occurred */
+ State->Flags.Cf = TRUE;
+ }
+
+ /* Set the adjust flag */
+ State->Flags.Af = TRUE;
}
- /* Call the internal API */
- return Soft386StackPush(State, Data);
+ /* Check if the second BCD digit is invalid or there was a borrow */
+ if ((Value > 0x99) || Carry)
+ {
+ /* Correct it */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x60;
+
+ /* There was a borrow */
+ State->Flags.Cf = TRUE;
+ }
+
+ return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteModrm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAaa)
{
- UCHAR FirstValue, SecondValue, Result;
- SOFT386_MOD_REG_RM ModRegRm;
- BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
-
- /* Make sure this is the right instruction */
- ASSERT((Opcode & 0xFD) == 0x88);
+ UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
- if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ /*
+ * Check if the value in AL is not a valid BCD digit,
+ * or there was a carry from the lowest 4 bits of AL
+ */
+ if (((Value & 0x0F) > 9) || State->Flags.Af)
{
- /* The ADSIZE prefix toggles the size */
- AddressSize = !AddressSize;
+ /* Correct it */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x06;
+ State->GeneralRegs[SOFT386_REG_EAX].HighByte++;
+
+ /* Set CF and AF */
+ State->Flags.Cf = State->Flags.Af = TRUE;
}
- else if (State->PrefixFlags
- & ~(SOFT386_PREFIX_ADSIZE
- | SOFT386_PREFIX_SEG
- | SOFT386_PREFIX_LOCK))
+ else
{
- /* Invalid prefix */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
+ /* Clear CF and AF */
+ State->Flags.Cf = State->Flags.Af = FALSE;
}
- /* Get the operands */
- if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+ /* Keep only the lowest 4 bits of AL */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte &= 0x0F;
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeAas)
+{
+ UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+
+ /*
+ * Check if the value in AL is not a valid BCD digit,
+ * or there was a borrow from the lowest 4 bits of AL
+ */
+ if (((Value & 0x0F) > 9) || State->Flags.Af)
{
- /* Exception occurred */
- return FALSE;
- }
+ /* Correct it */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x06;
+ State->GeneralRegs[SOFT386_REG_EAX].HighByte--;
- if (!Soft386ReadModrmByteOperands(State,
- &ModRegRm,
- &FirstValue,
- &SecondValue))
+ /* Set CF and AF */
+ State->Flags.Cf = State->Flags.Af = TRUE;
+ }
+ else
{
- /* Exception occurred */
- return FALSE;
+ /* Clear CF and AF */
+ State->Flags.Cf = State->Flags.Af = FALSE;
}
- if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
- else Result = FirstValue;
-
- /* Write back the result */
- return Soft386WriteModrmByteOperands(State,
- &ModRegRm,
- Opcode & SOFT386_OPCODE_WRITE_REG,
- Result);
+ /* Keep only the lowest 4 bits of AL */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte &= 0x0F;
+ return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeMovModrm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushAll)
{
- SOFT386_MOD_REG_RM ModRegRm;
- BOOLEAN OperandSize, AddressSize;
+ INT i;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ SOFT386_REG SavedEsp = State->GeneralRegs[SOFT386_REG_ESP];
/* Make sure this is the right instruction */
- ASSERT((Opcode & 0xFD) == 0x89);
-
- OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
-
- if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
- {
- /* The ADSIZE prefix toggles the address size */
- AddressSize = !AddressSize;
- }
+ ASSERT(Opcode == 0x60);
if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
- /* The OPSIZE prefix toggles the operand size */
- OperandSize = !OperandSize;
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
}
- if (State->PrefixFlags
- & ~(SOFT386_PREFIX_ADSIZE
- | SOFT386_PREFIX_OPSIZE
- | SOFT386_PREFIX_SEG
- | SOFT386_PREFIX_LOCK))
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
- /* Get the operands */
- if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- /* Check the operand size */
- if (OperandSize)
+ /* Push all the registers in order */
+ for (i = 0; i < SOFT386_NUM_GEN_REGS; i++)
{
- ULONG FirstValue, SecondValue, Result;
-
- if (!Soft386ReadModrmDwordOperands(State,
- &ModRegRm,
- &FirstValue,
- &SecondValue))
+ if (i == SOFT386_REG_ESP)
{
- /* Exception occurred */
- return FALSE;
+ /* Use the saved ESP instead */
+ if (!Soft386StackPush(State, Size ? SavedEsp.Long : SavedEsp.LowWord))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
}
-
- if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
- else Result = FirstValue;
-
- /* Write back the result */
- return Soft386WriteModrmDwordOperands(State,
- &ModRegRm,
- Opcode & SOFT386_OPCODE_WRITE_REG,
- Result);
- }
- else
- {
- USHORT FirstValue, SecondValue, Result;
-
- if (!Soft386ReadModrmWordOperands(State,
- &ModRegRm,
- &FirstValue,
- &SecondValue))
+ else
{
- /* Exception occurred */
- return FALSE;
+ /* Push the register */
+ if (!Soft386StackPush(State, Size ? State->GeneralRegs[i].Long
+ : State->GeneralRegs[i].LowWord))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
}
-
- if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
- else Result = FirstValue;
-
- /* Write back the result */
- return Soft386WriteModrmWordOperands(State,
- &ModRegRm,
- Opcode & SOFT386_OPCODE_WRITE_REG,
- Result);
}
+
+ return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeMovStoreSeg)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePopAll)
{
- BOOLEAN OperandSize, AddressSize;
- SOFT386_MOD_REG_RM ModRegRm;
-
- OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+ INT i;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ ULONG Value;
/* Make sure this is the right instruction */
- ASSERT(Opcode == 0x8C);
+ ASSERT(Opcode == 0x61);
- if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
- /* The ADSIZE prefix toggles the address size */
- AddressSize = !AddressSize;
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
}
- if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
- /* The OPSIZE prefix toggles the operand size */
- OperandSize = !OperandSize;
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ /* Pop all the registers in reverse order */
+ for (i = SOFT386_NUM_GEN_REGS - 1; i >= 0; i--)
+ {
+ /* Pop the value */
+ if (!Soft386StackPop(State, &Value))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Don't modify ESP */
+ if (i != SOFT386_REG_ESP)
+ {
+ if (Size) State->GeneralRegs[i].Long = Value;
+ else State->GeneralRegs[i].LowWord = LOWORD(Value);
+ }
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeBound)
+{
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+
+ return FALSE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeArpl)
+{
+ USHORT FirstValue, SecondValue;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ if (!(State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
+ || State->Flags.Vm
+ || (State->PrefixFlags & SOFT386_PREFIX_LOCK))
+ {
+ /* Cannot be used in real mode or with a LOCK prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
}
/* Get the operands */
return FALSE;
}
- if (ModRegRm.Register >= SOFT386_NUM_SEG_REGS)
+ /* Read the operands */
+ if (!Soft386ReadModrmWordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
{
- /* Invalid */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ /* Exception occurred */
return FALSE;
}
- if (OperandSize)
+ /* Check if the RPL needs adjusting */
+ if ((SecondValue & 3) < (FirstValue & 3))
{
- return Soft386WriteModrmDwordOperands(State,
- &ModRegRm,
- FALSE,
- State->SegmentRegs[ModRegRm.Register].Selector);
+ /* Adjust the RPL */
+ SecondValue &= ~3;
+ SecondValue |= FirstValue & 3;
+
+ /* Set ZF */
+ State->Flags.Zf = TRUE;
+
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State, &ModRegRm, FALSE, SecondValue);
}
else
{
- return Soft386WriteModrmWordOperands(State,
- &ModRegRm,
- FALSE,
- State->SegmentRegs[ModRegRm.Register].Selector);
+ /* Clear ZF */
+ State->Flags.Zf = FALSE;
+ return TRUE;
}
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLea)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushImm)
{
- SOFT386_MOD_REG_RM ModRegRm;
- BOOLEAN OperandSize, AddressSize;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
/* Make sure this is the right instruction */
- ASSERT(Opcode == 0x8D);
-
- OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+ ASSERT(Opcode == 0x68);
- if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
- /* The ADSIZE prefix toggles the address size */
- AddressSize = !AddressSize;
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
}
if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
- /* The OPSIZE prefix toggles the operand size */
- OperandSize = !OperandSize;
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
}
- /* Get the operands */
- if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
+ if (Size)
{
- /* Exception occurred */
- return FALSE;
- }
+ ULONG Data;
- /* The second operand must be memory */
- if (!ModRegRm.Memory)
- {
- /* Invalid */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
+ if (!Soft386FetchDword(State, &Data))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
- /* Write the address to the register */
- if (OperandSize)
- {
- return Soft386WriteModrmDwordOperands(State,
- &ModRegRm,
- TRUE,
- ModRegRm.MemoryAddress);
+ /* Call the internal API */
+ return Soft386StackPush(State, Data);
}
else
{
- return Soft386WriteModrmWordOperands(State,
- &ModRegRm,
- TRUE,
- ModRegRm.MemoryAddress);
+ USHORT Data;
+
+ if (!Soft386FetchWord(State, &Data))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+ /* Call the internal API */
+ return Soft386StackPush(State, Data);
}
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeMovLoadSeg)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeImulModrmImm)
{
BOOLEAN OperandSize, AddressSize;
SOFT386_MOD_REG_RM ModRegRm;
-
- OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+ LONG Multiplier;
+ LONGLONG Product;
/* Make sure this is the right instruction */
- ASSERT(Opcode == 0x8E);
+ ASSERT((Opcode & 0xFD) == 0x69);
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
OperandSize = !OperandSize;
}
- /* Get the operands */
+ /* Fetch the parameters */
if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
return FALSE;
}
- if ((ModRegRm.Register >= SOFT386_NUM_SEG_REGS)
- || ((SOFT386_SEG_REGS)ModRegRm.Register == SOFT386_REG_CS))
+ if (Opcode == 0x6B)
{
- /* Invalid */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
+ 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)
{
- ULONG Dummy, Selector;
+ LONG RegValue, Multiplicand;
- if (!Soft386ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Selector))
+ /* Read the operands */
+ if (!Soft386ReadModrmDwordOperands(State,
+ &ModRegRm,
+ (PULONG)&RegValue,
+ (PULONG)&Multiplicand))
{
/* Exception occurred */
return FALSE;
}
- return Soft386LoadSegment(State, ModRegRm.Register, LOWORD(Selector));
+ /* Multiply */
+ Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
}
else
{
- USHORT Dummy, Selector;
+ SHORT RegValue, Multiplicand;
- if (!Soft386ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Selector))
+ /* Read the operands */
+ if (!Soft386ReadModrmWordOperands(State,
+ &ModRegRm,
+ (PUSHORT)&RegValue,
+ (PUSHORT)&Multiplicand))
{
/* Exception occurred */
return FALSE;
}
- return Soft386LoadSegment(State, ModRegRm.Register, Selector);
+ /* 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(Soft386OpcodeCwde)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushByteImm)
{
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ UCHAR Data;
/* Make sure this is the right instruction */
- ASSERT(Opcode == 0x98);
+ ASSERT(Opcode == 0x6A);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
- }
- else if (State->PrefixFlags != 0)
+ if (!Soft386FetchByte(State, &Data))
{
- /* Invalid prefix */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ /* Exception occurred */
return FALSE;
}
- if (Size)
- {
- /* Sign extend AX to EAX */
- State->GeneralRegs[SOFT386_REG_EAX].Long = MAKELONG
- (
- State->GeneralRegs[SOFT386_REG_EAX].LowWord,
- (State->GeneralRegs[SOFT386_REG_EAX].LowWord & SIGN_FLAG_WORD)
- ? 0xFFFF : 0x0000
- );
- }
- else
- {
- /* Sign extend AL to AX */
- State->GeneralRegs[SOFT386_REG_EAX].HighByte =
- (State->GeneralRegs[SOFT386_REG_EAX].LowByte & SIGN_FLAG_BYTE)
- ? 0xFF : 0x00;
- }
-
- return TRUE;
+ /* Call the internal API */
+ return Soft386StackPush(State, Data);
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCdq)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteModrm)
{
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ UCHAR FirstValue, SecondValue, Result;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
/* Make sure this is the right instruction */
- ASSERT(Opcode == 0x99);
+ ASSERT((Opcode & 0xFD) == 0x88);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
}
- else if (State->PrefixFlags != 0)
+ else if (State->PrefixFlags
+ & ~(SOFT386_PREFIX_ADSIZE
+ | SOFT386_PREFIX_SEG
+ | SOFT386_PREFIX_LOCK))
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
- if (Size)
+ /* Get the operands */
+ if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
{
- /* Sign extend EAX to EDX:EAX */
- State->GeneralRegs[SOFT386_REG_EDX].Long =
- (State->GeneralRegs[SOFT386_REG_EAX].Long & SIGN_FLAG_LONG)
- ? 0xFFFFFFFF : 0x00000000;
+ /* Exception occurred */
+ return FALSE;
}
- else
+
+ if (!Soft386ReadModrmByteOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
{
- /* Sign extend AX to DX:AX */
- State->GeneralRegs[SOFT386_REG_EDX].LowWord =
- (State->GeneralRegs[SOFT386_REG_EAX].LowWord & SIGN_FLAG_WORD)
- ? 0xFFFF : 0x0000;
+ /* Exception occurred */
+ return FALSE;
}
- return TRUE;
-}
+ if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
+ else Result = FirstValue;
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCallAbs)
-{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+ /* Write back the result */
+ return Soft386WriteModrmByteOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
- return FALSE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeWait)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovModrm)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN OperandSize, AddressSize;
- return FALSE;
-}
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFD) == 0x89);
-SOFT386_OPCODE_HANDLER(Soft386OpcodePushFlags)
-{
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
- if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ 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;
+ }
+
+ if (State->PrefixFlags
+ & ~(SOFT386_PREFIX_ADSIZE
+ | SOFT386_PREFIX_OPSIZE
+ | SOFT386_PREFIX_SEG
+ | SOFT386_PREFIX_LOCK))
{
/* Invalid prefix */
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
- if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ /* Get the operands */
+ if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
{
- /* This OPSIZE prefix toggles the size */
- Size = !Size;
+ /* Exception occurred */
+ return FALSE;
}
- /* Check for VM86 mode when IOPL is not 3 */
- if (State->Flags.Vm && (State->Flags.Iopl != 3))
+ /* Check the operand size */
+ if (OperandSize)
{
- /* Call the VM86 monitor */
- Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
- return FALSE;
+ ULONG FirstValue, SecondValue, Result;
+
+ if (!Soft386ReadModrmDwordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
+ else Result = FirstValue;
+
+ /* Write back the result */
+ return Soft386WriteModrmDwordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
}
+ else
+ {
+ USHORT FirstValue, SecondValue, Result;
- /* Push the flags */
- if (Size) return Soft386StackPush(State, State->Flags.Long);
- else return Soft386StackPush(State, LOWORD(State->Flags.Long));
+ if (!Soft386ReadModrmWordOperands(State,
+ &ModRegRm,
+ &FirstValue,
+ &SecondValue))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
+ else Result = FirstValue;
+
+ /* Write back the result */
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ Opcode & SOFT386_OPCODE_WRITE_REG,
+ Result);
+ }
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodePopFlags)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovStoreSeg)
{
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- INT Cpl = Soft386GetCurrentPrivLevel(State);
- ULONG NewFlags;
+ BOOLEAN OperandSize, AddressSize;
+ SOFT386_MOD_REG_RM ModRegRm;
- if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x8C);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
- /* Invalid prefix */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
+ /* The ADSIZE prefix toggles the address size */
+ AddressSize = !AddressSize;
}
if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
- /* This OPSIZE prefix toggles the size */
- Size = !Size;
+ /* The OPSIZE prefix toggles the operand size */
+ OperandSize = !OperandSize;
}
- /* Pop the new flags */
- if (!Soft386StackPop(State, &NewFlags))
+ /* Get the operands */
+ if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
{
/* Exception occurred */
return FALSE;
}
- if (!State->Flags.Vm)
+ if (ModRegRm.Register >= SOFT386_NUM_SEG_REGS)
{
- /* 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;
+ /* Invalid */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
- /* Restore VM and RF */
- State->Flags.Vm = FALSE;
- State->Flags.Rf = OldRf;
+ if (OperandSize)
+ {
+ return Soft386WriteModrmDwordOperands(State,
+ &ModRegRm,
+ FALSE,
+ State->SegmentRegs[ModRegRm.Register].Selector);
+ }
+ else
+ {
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ FALSE,
+ State->SegmentRegs[ModRegRm.Register].Selector);
+ }
+}
- /* Clear VIF and VIP */
- State->Flags.Vif = State->Flags.Vip = FALSE;
- }
- else State->Flags.LowWord = LOWORD(NewFlags);
+SOFT386_OPCODE_HANDLER(Soft386OpcodeLea)
+{
+ SOFT386_MOD_REG_RM ModRegRm;
+ BOOLEAN OperandSize, AddressSize;
- /* Restore the reserved bits */
- State->Flags.AlwaysSet = TRUE;
- State->Flags.Reserved0 = FALSE;
- State->Flags.Reserved1 = FALSE;
- }
- else
- {
- /* User */
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x8D);
- /* Memorize the old state of IF and IOPL */
- BOOLEAN OldIf = State->Flags.If;
- UINT OldIopl = State->Flags.Iopl;
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
- /* Set the flags */
- if (Size)
- {
- /* Memorize the old state of RF */
- BOOLEAN OldRf = State->Flags.Rf;
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the address size */
+ AddressSize = !AddressSize;
+ }
- State->Flags.Long = NewFlags;
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the operand size */
+ OperandSize = !OperandSize;
+ }
- /* 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
+ /* Get the operands */
+ if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
{
- /* 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);
- }
-
+ /* Exception occurred */
+ return FALSE;
}
- return TRUE;
-}
-
-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;
-
- return FALSE;
-}
-
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLahf)
-{
- /* 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)
+ /* The second operand must be memory */
+ if (!ModRegRm.Memory)
{
- /* Invalid prefix */
+ /* Invalid */
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)
+ /* Write the address to the register */
+ if (OperandSize)
{
- State->InstPtr.Long = ReturnAddress;
- State->GeneralRegs[SOFT386_REG_ESP].Long += BytesToPop;
+ return Soft386WriteModrmDwordOperands(State,
+ &ModRegRm,
+ TRUE,
+ ModRegRm.MemoryAddress);
}
else
{
- State->InstPtr.LowWord = LOWORD(ReturnAddress);
- State->GeneralRegs[SOFT386_REG_ESP].LowWord += BytesToPop;
- }
+ return Soft386WriteModrmWordOperands(State,
+ &ModRegRm,
+ TRUE,
+ ModRegRm.MemoryAddress);
- return TRUE;
+ }
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLdsLes)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovLoadSeg)
{
- 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;
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0x8E);
+
if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
- /* The ADSIZE prefix toggles the size */
+ /* The ADSIZE prefix toggles the address size */
AddressSize = !AddressSize;
}
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the operand size */
+ OperandSize = !OperandSize;
+ }
+
/* Get the operands */
if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
{
return FALSE;
}
- if (!ModRegRm.Memory)
+ if ((ModRegRm.Register >= SOFT386_NUM_SEG_REGS)
+ || ((SOFT386_SEG_REGS)ModRegRm.Register == SOFT386_REG_CS))
{
- /* Check if this is a BOP and the host supports BOPs */
- if ((Opcode == 0xC4)
- && (ModRegRm.Register == SOFT386_REG_EAX)
- && (ModRegRm.SecondRegister == SOFT386_REG_ESP)
- && (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)]);
+ ULONG Dummy, Selector;
- /* Set the register to the offset */
- State->GeneralRegs[ModRegRm.Register].Long = Offset;
+ if (!Soft386ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Selector))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
- /* Load the segment */
- return Soft386LoadSegment(State,
- (Opcode == 0xC4)
- ? SOFT386_REG_ES : SOFT386_REG_DS,
- Segment);
+ return Soft386LoadSegment(State, ModRegRm.Register, LOWORD(Selector));
}
else
{
- USHORT Offset = *((PUSHORT)FarPointer);
- USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
+ USHORT Dummy, Selector;
- /* Set the register to the offset */
- State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
+ if (!Soft386ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Selector))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
- /* Load the segment */
- return Soft386LoadSegment(State,
- (Opcode == 0xC4)
- ? SOFT386_REG_ES : SOFT386_REG_DS,
- Segment);
+ return Soft386LoadSegment(State, ModRegRm.Register, Selector);
}
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeEnter)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCwde)
{
- INT i;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- USHORT FrameSize;
- UCHAR NestingLevel;
- SOFT386_REG FramePointer;
/* 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;
- }
+ ASSERT(Opcode == 0x98);
if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
Size = !Size;
}
- if (!Soft386FetchWord(State, &FrameSize))
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
- /* Exception occurred */
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
- if (!Soft386FetchByte(State, &NestingLevel))
+ if (Size)
{
- /* Exception occurred */
- return FALSE;
+ /* Sign extend AX to EAX */
+ State->GeneralRegs[SOFT386_REG_EAX].Long = MAKELONG
+ (
+ State->GeneralRegs[SOFT386_REG_EAX].LowWord,
+ (State->GeneralRegs[SOFT386_REG_EAX].LowWord & SIGN_FLAG_WORD)
+ ? 0xFFFF : 0x0000
+ );
}
-
- /* 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++)
+ else
{
- 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);
- }
+ /* Sign extend AL to AX */
+ State->GeneralRegs[SOFT386_REG_EAX].HighByte =
+ (State->GeneralRegs[SOFT386_REG_EAX].LowByte & SIGN_FLAG_BYTE)
+ ? 0xFF : 0x00;
}
- 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)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCdq)
{
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
/* Make sure this is the right instruction */
- ASSERT(Opcode == 0xC9);
+ ASSERT(Opcode == 0x99);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
return FALSE;
}
- if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
- }
-
if (Size)
{
- /* Set the stack pointer (ESP) to the base pointer (EBP) */
- State->GeneralRegs[SOFT386_REG_ESP].Long = State->GeneralRegs[SOFT386_REG_EBP].Long;
-
- /* Pop the saved base pointer from the stack */
- return Soft386StackPop(State, &State->GeneralRegs[SOFT386_REG_EBP].Long);
+ /* Sign extend EAX to EDX:EAX */
+ State->GeneralRegs[SOFT386_REG_EDX].Long =
+ (State->GeneralRegs[SOFT386_REG_EAX].Long & SIGN_FLAG_LONG)
+ ? 0xFFFFFFFF : 0x00000000;
}
else
{
- ULONG Value;
-
- /* Set the stack pointer (SP) to the base pointer (BP) */
- State->GeneralRegs[SOFT386_REG_ESP].LowWord = State->GeneralRegs[SOFT386_REG_EBP].LowWord;
-
- /* Pop the saved base pointer from the stack */
- if (Soft386StackPop(State, &Value))
- {
- State->GeneralRegs[SOFT386_REG_EBP].LowWord = LOWORD(Value);
- return TRUE;
- }
- else return FALSE;
+ /* Sign extend AX to DX:AX */
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord =
+ (State->GeneralRegs[SOFT386_REG_EAX].LowWord & SIGN_FLAG_WORD)
+ ? 0xFFFF : 0x0000;
}
+
+ return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFarImm)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCallAbs)
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
return FALSE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFar)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeWait)
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
return FALSE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeInt)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePushFlags)
{
- UCHAR IntNum;
- SOFT386_IDT_ENTRY IdtEntry;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- switch (Opcode)
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
- case 0xCC:
- {
- /* This is the INT3 instruction */
- IntNum = 3;
- break;
- }
-
- case 0xCD:
- {
- /* Fetch the interrupt number */
- if (!Soft386FetchByte(State, &IntNum))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- break;
- }
-
- case 0xCE:
- {
- /* Don't do anything if OF is cleared */
- if (!State->Flags.Of) return TRUE;
-
- /* Exception #OF */
- IntNum = SOFT386_EXCEPTION_OF;
-
- break;
- }
-
- default:
- {
- /* Should not happen */
- ASSERT(FALSE);
- }
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
}
- /* Get the interrupt vector */
- if (!Soft386GetIntVector(State, IntNum, &IdtEntry))
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
- /* Exception occurred */
- return FALSE;
+ /* This OPSIZE prefix toggles the size */
+ Size = !Size;
}
- /* Perform the interrupt */
- if (!Soft386InterruptInternal(State,
- IdtEntry.Selector,
- MAKELONG(IdtEntry.Offset, IdtEntry.OffsetHigh),
- IdtEntry.Type))
+ /* Check for VM86 mode when IOPL is not 3 */
+ if (State->Flags.Vm && (State->Flags.Iopl != 3))
{
- /* Exception occurred */
+ /* Call the VM86 monitor */
+ Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
return FALSE;
}
- return TRUE;
+ /* Push the flags */
+ if (Size) return Soft386StackPush(State, State->Flags.Long);
+ else return Soft386StackPush(State, LOWORD(State->Flags.Long));
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeIret)
+SOFT386_OPCODE_HANDLER(Soft386OpcodePopFlags)
{
- INT i;
- ULONG InstPtr, CodeSel, StackPtr, StackSel;
- SOFT386_FLAGS_REG NewFlags;
BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
-
- /* Make sure this is the right instruction */
- ASSERT(Opcode == 0xCF);
+ INT Cpl = Soft386GetCurrentPrivLevel(State);
+ ULONG NewFlags;
if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
- /* The OPSIZE prefix toggles the size */
+ /* This 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))
+ /* Pop the new flags */
+ if (!Soft386StackPop(State, &NewFlags))
{
/* Exception occurred */
return FALSE;
}
- /* Check for protected mode */
- if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
+ if (!State->Flags.Vm)
{
- INT Cpl = Soft386GetCurrentPrivLevel(State);
-
- if (State->Flags.Vm)
+ /* Check the current privilege level */
+ if (Cpl == 0)
{
- /* Return from VM86 mode */
+ /* Supervisor */
- /* Check the IOPL */
- if (State->Flags.Iopl == 3)
+ /* Set the flags */
+ if (Size)
{
- /* Set new EIP */
- State->InstPtr.Long = LOWORD(InstPtr);
+ /* Memorize the old state of RF */
+ BOOLEAN OldRf = State->Flags.Rf;
- /* Load new CS */
- if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel))
- {
- /* Exception occurred */
- return FALSE;
- }
+ State->Flags.Long = NewFlags;
- /* 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;
+ /* 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);
- return TRUE;
+ /* Restore the reserved bits */
+ State->Flags.AlwaysSet = TRUE;
+ State->Flags.Reserved0 = FALSE;
+ State->Flags.Reserved1 = FALSE;
}
-
- if (State->Flags.Nt)
+ else
{
- /* Nested task return */
+ /* User */
- UNIMPLEMENTED;
- return FALSE;
- }
+ /* Memorize the old state of IF and IOPL */
+ BOOLEAN OldIf = State->Flags.If;
+ UINT OldIopl = State->Flags.Iopl;
- if (NewFlags.Vm)
- {
- /* Return to VM86 mode */
- ULONG Es, Ds, Fs, Gs;
+ /* Set the flags */
+ if (Size)
+ {
+ /* Memorize the old state of RF */
+ BOOLEAN OldRf = State->Flags.Rf;
- /* 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;
+ State->Flags.Long = NewFlags;
- /* Set the new IP */
- State->InstPtr.Long = LOWORD(InstPtr);
+ /* 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
+ {
+ /* 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(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;
+
+ return FALSE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeLahf)
+{
+ /* 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_ESP)
+ && (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)
+{
+ INT i;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ USHORT FrameSize;
+ UCHAR NestingLevel;
+ SOFT386_REG FramePointer;
+
+ /* 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)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xC9);
+
+ 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)
+ {
+ /* Set the stack pointer (ESP) to the base pointer (EBP) */
+ State->GeneralRegs[SOFT386_REG_ESP].Long = State->GeneralRegs[SOFT386_REG_EBP].Long;
+
+ /* Pop the saved base pointer from the stack */
+ return Soft386StackPop(State, &State->GeneralRegs[SOFT386_REG_EBP].Long);
+ }
+ else
+ {
+ ULONG Value;
+
+ /* Set the stack pointer (SP) to the base pointer (BP) */
+ State->GeneralRegs[SOFT386_REG_ESP].LowWord = State->GeneralRegs[SOFT386_REG_EBP].LowWord;
+
+ /* Pop the saved base pointer from the stack */
+ if (Soft386StackPop(State, &Value))
+ {
+ State->GeneralRegs[SOFT386_REG_EBP].LowWord = LOWORD(Value);
+ return TRUE;
+ }
+ else return FALSE;
+ }
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFarImm)
+{
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+
+ return FALSE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFar)
+{
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+
+ return FALSE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeInt)
+{
+ UCHAR IntNum;
+ SOFT386_IDT_ENTRY IdtEntry;
+
+ switch (Opcode)
+ {
+ case 0xCC:
+ {
+ /* This is the INT3 instruction */
+ IntNum = 3;
+ break;
+ }
+
+ case 0xCD:
+ {
+ /* Fetch the interrupt number */
+ if (!Soft386FetchByte(State, &IntNum))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ break;
+ }
+
+ case 0xCE:
+ {
+ /* Don't do anything if OF is cleared */
+ if (!State->Flags.Of) return TRUE;
+
+ /* Exception #OF */
+ IntNum = SOFT386_EXCEPTION_OF;
+
+ break;
+ }
+
+ default:
+ {
+ /* Should not happen */
+ ASSERT(FALSE);
+ }
+ }
+
+ /* Get the interrupt vector */
+ if (!Soft386GetIntVector(State, IntNum, &IdtEntry))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Perform the interrupt */
+ if (!Soft386InterruptInternal(State,
+ IdtEntry.Selector,
+ MAKELONG(IdtEntry.Offset, IdtEntry.OffsetHigh),
+ IdtEntry.Type))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeIret)
+{
+ INT i;
+ ULONG InstPtr, CodeSel, StackPtr, StackSel;
+ SOFT386_FLAGS_REG NewFlags;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* 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)
+{
+ UCHAR Base;
+ UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+
+ 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)
+{
+ UCHAR Base;
+ UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+
+ 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)
+{
+ UCHAR Value;
+ BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
+ }
+
+ /* Read a byte from DS:[(E)BX + AL] */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_DS,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EBX].Long
+ : State->GeneralRegs[SOFT386_REG_EBX].LowWord
+ + State->GeneralRegs[SOFT386_REG_EAX].LowByte,
+ FALSE,
+ &Value,
+ sizeof(UCHAR)))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ /* Set AL to the result */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Value;
+
+ /* Return success */
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeLoop)
+{
+ BOOLEAN Condition;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ CHAR Offset = 0;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode >= 0xE0) && (Opcode <= 0xE2));
+
+ 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) Condition = ((--State->GeneralRegs[SOFT386_REG_ECX].Long) != 0);
+ else Condition = ((--State->GeneralRegs[SOFT386_REG_ECX].LowWord) != 0);
+
+ if (Opcode == 0xE0)
+ {
+ /* Additional rule for LOOPNZ */
+ if (State->Flags.Zf) Condition = FALSE;
+ }
+
+ if (Opcode == 0xE1)
+ {
+ /* Additional rule for LOOPZ */
+ if (!State->Flags.Zf) Condition = FALSE;
+ }
+
+ /* Fetch the offset */
+ if (!Soft386FetchByte(State, (PUCHAR)&Offset))
+ {
+ /* An exception occurred */
+ return FALSE;
+ }
+
+ if (Condition)
+ {
+ /* Move the instruction pointer */
+ State->InstPtr.Long += Offset;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeJecxz)
+{
+ BOOLEAN Condition;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ CHAR Offset = 0;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xE3);
+
+ 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) Condition = (State->GeneralRegs[SOFT386_REG_ECX].Long == 0);
+ else Condition = (State->GeneralRegs[SOFT386_REG_ECX].LowWord == 0);
+
+ /* Fetch the offset */
+ if (!Soft386FetchByte(State, (PUCHAR)&Offset))
+ {
+ /* An exception occurred */
+ return FALSE;
+ }
+
+ if (Condition)
+ {
+ /* Move the instruction pointer */
+ State->InstPtr.Long += Offset;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCall)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xE8);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (Size)
+ {
+ LONG Offset = 0;
+
+ /* Fetch the offset */
+ if (!Soft386FetchDword(State, (PULONG)&Offset))
+ {
+ /* An exception occurred */
+ 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;
+ }
+ else
+ {
+ SHORT Offset = 0;
+
+ /* Fetch the offset */
+ if (!Soft386FetchWord(State, (PUSHORT)&Offset))
+ {
+ /* An exception occurred */
+ 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 TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeJmp)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xE9);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ {
+ /* Invalid prefix */
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
+ }
+
+ if (Size)
+ {
+ LONG Offset = 0;
+
+ /* Fetch the offset */
+ if (!Soft386FetchDword(State, (PULONG)&Offset))
+ {
+ /* An exception occurred */
+ return FALSE;
+ }
+
+ /* Move the instruction pointer */
+ State->InstPtr.Long += Offset;
+ }
+ else
+ {
+ SHORT Offset = 0;
+
+ /* Fetch the offset */
+ if (!Soft386FetchWord(State, (PUSHORT)&Offset))
+ {
+ /* An exception occurred */
+ return FALSE;
+ }
+
+ /* Move the instruction pointer */
+ State->InstPtr.LowWord += Offset;
+ }
+
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeJmpAbs)
+{
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
- /* 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;
+ return FALSE;
+}
- /* 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;
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovAlOffset)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ ULONG Offset;
- return TRUE;
- }
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xA0);
- /* Load the new CS */
- if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel))
+ 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;
- /* Set EIP */
- if (Size) State->InstPtr.Long = InstPtr;
- else State->InstPtr.LowWord = LOWORD(InstPtr);
-
- if (GET_SEGMENT_RPL(CodeSel) > Cpl)
+ if (!Soft386FetchWord(State, &WordOffset))
{
- /* Pop ESP */
- if (!Soft386StackPop(State, &StackPtr))
- {
- /* Exception */
- return FALSE;
- }
-
- /* Pop SS */
- if (!Soft386StackPop(State, &StackSel))
- {
- /* Exception */
- return FALSE;
- }
+ /* Exception occurred */
+ return FALSE;
+ }
- /* Load new SS */
- if (!Soft386LoadSegment(State, SOFT386_REG_SS, StackSel))
- {
- /* Exception */
- return FALSE;
- }
+ Offset = (ULONG)WordOffset;
+ }
- /* Set ESP */
- if (Size) State->GeneralRegs[SOFT386_REG_ESP].Long = StackPtr;
- else State->GeneralRegs[SOFT386_REG_ESP].LowWord = LOWORD(StackPtr);
- }
+ /* 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));
+}
- /* 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;
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovEaxOffset)
+{
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- /* Set additional flags */
- if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
- if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xA1);
- if (GET_SEGMENT_RPL(CodeSel) > Cpl)
- {
- /* Update the CPL */
- Cpl = Soft386GetCurrentPrivLevel(State);
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
+ }
- /* 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 (Size)
+ {
+ ULONG Offset;
- 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;
- }
- }
+ 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
{
- if (Size && (InstPtr & 0xFFFF0000))
+ USHORT Offset;
+
+ if (!Soft386FetchWord(State, &Offset))
{
- /* Invalid */
- Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
+ /* Exception occurred */
return FALSE;
}
- /* Set new EIP */
- State->InstPtr.Long = InstPtr;
+ /* 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));
+ }
+}
- /* Load new CS */
- if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel))
+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;
- /* 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;
+ if (!Soft386FetchWord(State, &WordOffset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ Offset = (ULONG)WordOffset;
}
- return TRUE;
+ /* 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(Soft386OpcodeAam)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetEax)
{
- UCHAR Base;
- UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
- {
- /* Invalid prefix */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xA3);
- /* Fetch the base */
- if (!Soft386FetchByte(State, &Base))
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
- /* Exception occurred */
- return FALSE;
+ /* The OPSIZE prefix toggles the size */
+ Size = !Size;
}
- /* Check if the base is zero */
- if (Base == 0)
+ if (Size)
{
- /* Divide error */
- Soft386Exception(State, SOFT386_EXCEPTION_DE);
- return FALSE;
- }
+ ULONG Offset;
- /* Adjust */
- State->GeneralRegs[SOFT386_REG_EAX].HighByte = Value / Base;
- State->GeneralRegs[SOFT386_REG_EAX].LowByte = Value %= Base;
+ if (!Soft386FetchDword(State, &Offset))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
- /* Update flags */
- State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
- State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
- State->Flags.Pf = Soft386CalculateParity(Value);
+ /* 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;
- return TRUE;
+ 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));
+ }
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeAad)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeSalc)
{
- UCHAR Base;
- UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
+ /* Make sure this is the right instruction */
+ ASSERT(Opcode == 0xD6);
if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
{
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);
+ /* Set all the bits of AL to CF */
+ State->GeneralRegs[SOFT386_REG_EAX].LowByte = State->Flags.Cf ? 0xFF : 0x00;
return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeXlat)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeMovs)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
+ ULONG Data, DataSize;
+ BOOLEAN OperandSize, AddressSize;
-SOFT386_OPCODE_HANDLER(Soft386OpcodeLoop)
-{
- BOOLEAN Condition;
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- CHAR Offset = 0;
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
/* Make sure this is the right instruction */
- ASSERT((Opcode >= 0xE0) && (Opcode <= 0xE2));
-
- if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
- {
- /* Invalid prefix */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
- }
+ ASSERT((Opcode & 0xFE) == 0xA4);
if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
- Size = !Size;
+ OperandSize = !OperandSize;
}
- if (Size) Condition = ((--State->GeneralRegs[SOFT386_REG_ECX].Long) == 0);
- else Condition = ((--State->GeneralRegs[SOFT386_REG_ECX].LowWord) == 0);
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
+ }
- if (Opcode == 0xE0)
+ if ((State->PrefixFlags & SOFT386_PREFIX_REP)
+ || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
{
- /* Additional rule for LOOPNZ */
- if (State->Flags.Zf) Condition = FALSE;
+ // TODO: The REP/REPZ/REPNZ prefixes need to be implemented!
+ Soft386Exception(State, SOFT386_EXCEPTION_UD);
+ return FALSE;
}
- if (Opcode == 0xE1)
+ /* Calculate the size */
+ if (Opcode == 0xA4) DataSize = sizeof(UCHAR);
+ else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+
+ /* Read from the source operand */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_DS,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
+ : State->GeneralRegs[SOFT386_REG_ESI].LowWord,
+ FALSE,
+ &Data,
+ DataSize))
{
- /* Additional rule for LOOPZ */
- if (!State->Flags.Zf) Condition = FALSE;
+ /* Exception occurred */
+ return FALSE;
}
- /* Fetch the offset */
- if (!Soft386FetchByte(State, (PUCHAR)&Offset))
+ /* Write to the destination operand */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ &Data,
+ DataSize))
{
- /* An exception occurred */
+ /* Exception occurred */
return FALSE;
}
- if (Condition)
+ /* Increment/decrement ESI and EDI */
+ if (OperandSize)
{
- /* Move the instruction pointer */
- State->InstPtr.Long += Offset;
+ if (!State->Flags.Df)
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
+ }
+ else
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].Long -= DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ }
+ }
+ else
+ {
+ if (!State->Flags.Df)
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ }
+ else
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].LowWord -= DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ }
}
+ /* Return success */
return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeJecxz)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeCmps)
{
- BOOLEAN Condition;
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- CHAR Offset = 0;
+ ULONG FirstValue = 0, SecondValue = 0, Result;
+ ULONG DataSize, DataMask, SignFlag;
+ BOOLEAN OperandSize, AddressSize;
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
/* Make sure this is the right instruction */
- ASSERT(Opcode == 0xE3);
+ ASSERT((Opcode & 0xFE) == 0xA6);
- if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
- /* Invalid prefix */
+ /* The OPSIZE prefix toggles the size */
+ OperandSize = !OperandSize;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
+ }
+
+ if ((State->PrefixFlags & SOFT386_PREFIX_REP)
+ || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
+ {
+ // TODO: The REP/REPZ/REPNZ prefixes need to be implemented!
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ /* Calculate the size */
+ if (Opcode == 0xA6) DataSize = sizeof(UCHAR);
+ else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+
+ /* Calculate the mask and sign flag */
+ DataMask = (1 << (DataSize * 8)) - 1;
+ SignFlag = 1 << ((DataSize * 8) - 1);
+
+ /* Read from the first source operand */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_DS,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
+ : State->GeneralRegs[SOFT386_REG_ESI].LowWord,
+ FALSE,
+ &FirstValue,
+ DataSize))
{
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
+ /* Exception occurred */
+ return FALSE;
}
- if (Size) Condition = (State->GeneralRegs[SOFT386_REG_ECX].Long == 0);
- else Condition = (State->GeneralRegs[SOFT386_REG_ECX].LowWord == 0);
-
- /* Fetch the offset */
- if (!Soft386FetchByte(State, (PUCHAR)&Offset))
+ /* Read from the second source operand */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ FALSE,
+ &SecondValue,
+ DataSize))
{
- /* An exception occurred */
+ /* Exception occurred */
return FALSE;
}
- if (Condition)
+ /* Calculate the result */
+ FirstValue &= DataMask;
+ SecondValue &= DataMask;
+ Result = (FirstValue - SecondValue) & DataMask;
+
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
+ && ((FirstValue & SignFlag) != (Result & SignFlag));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Increment/decrement ESI and EDI */
+ if (OperandSize)
{
- /* Move the instruction pointer */
- State->InstPtr.Long += Offset;
+ if (!State->Flags.Df)
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
+ }
+ else
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].Long -= DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ }
+ }
+ else
+ {
+ if (!State->Flags.Df)
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ }
+ else
+ {
+ State->GeneralRegs[SOFT386_REG_ESI].LowWord -= DataSize;
+ State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ }
}
+ /* Return success */
return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeCall)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeStos)
{
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ ULONG DataSize;
+ BOOLEAN OperandSize, AddressSize;
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
/* Make sure this is the right instruction */
- ASSERT(Opcode == 0xE8);
+ ASSERT((Opcode & 0xFE) == 0xAA);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
- Size = !Size;
+ OperandSize = !OperandSize;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
- /* Invalid prefix */
- Soft386Exception(State, SOFT386_EXCEPTION_UD);
- return FALSE;
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
}
- if (Size)
+ /* Calculate the size */
+ if (Opcode == 0xAA) DataSize = sizeof(UCHAR);
+ else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_REP)
{
- LONG Offset = 0;
+ UCHAR Block[STRING_BLOCK_SIZE];
+ ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+ : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
- /* Fetch the offset */
- if (!Soft386FetchDword(State, (PULONG)&Offset))
+ /* Fill the memory block with the data */
+ if (DataSize == sizeof(UCHAR))
{
- /* An exception occurred */
- return FALSE;
+ RtlFillMemory(Block, sizeof(Block), State->GeneralRegs[SOFT386_REG_EAX].LowByte);
}
+ else
+ {
+ ULONG i;
- /* Push the current value of the instruction pointer */
- if (!Soft386StackPush(State, State->InstPtr.Long))
+ for (i = 0; i < STRING_BLOCK_SIZE / DataSize; i++)
+ {
+ if (DataSize == sizeof(USHORT))
+ {
+ ((PUSHORT)Block)[i] = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
+ }
+ else
+ {
+ ((PULONG)Block)[i] = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ }
+ }
+ }
+
+ /* Transfer until finished */
+ while (Count)
{
- /* Exception occurred */
- return FALSE;
+ ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
+
+ if (State->Flags.Df)
+ {
+ /* Reduce EDI by the number of bytes to transfer */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long -= Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= Processed * DataSize;
+ }
+
+ /* Write to memory */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
+
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (!State->Flags.Df)
+ {
+ /* Increase EDI by the number of bytes transfered */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long += Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord += Processed * DataSize;
+ }
+
+ /* Reduce the total count by the number processed in this run */
+ Count -= Processed;
}
- /* Move the instruction pointer */
- State->InstPtr.Long += Offset;
+ /* Clear ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
}
else
{
- SHORT Offset = 0;
-
- /* Fetch the offset */
- if (!Soft386FetchWord(State, (PUSHORT)&Offset))
+ /* Write to the destination operand */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ &State->GeneralRegs[SOFT386_REG_EAX].Long,
+ DataSize))
{
- /* An exception occurred */
+ /* Exception occurred */
return FALSE;
}
- /* Push the current value of the instruction pointer */
- if (!Soft386StackPush(State, State->InstPtr.Long))
+ /* Increment/decrement EDI */
+ if (OperandSize)
{
- /* Exception occurred */
- return FALSE;
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ }
+ else
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ }
+ }
+
+ /* Return success */
+ return TRUE;
+}
+
+SOFT386_OPCODE_HANDLER(Soft386OpcodeLods)
+{
+ ULONG DataSize;
+ BOOLEAN OperandSize, AddressSize;
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
+
+ /* Make sure this is the right instruction */
+ ASSERT((Opcode & 0xFE) == 0xAC);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
+ {
+ /* The OPSIZE prefix toggles the size */
+ OperandSize = !OperandSize;
+ }
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
+ {
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
+ }
+
+ /* Calculate the size */
+ if (Opcode == 0xAC) DataSize = sizeof(UCHAR);
+ else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_REP)
+ {
+ ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+ : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
+
+ /* If the count is 0, do nothing */
+ if (Count == 0) return TRUE;
+
+ /* Only the last entry will be loaded */
+ if (!State->Flags.Df)
+ {
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_ESI].Long += (Count - 1) * DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].LowWord += (Count - 1) * DataSize;
+ }
+ else
+ {
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_ESI].Long -= (Count - 1) * DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].LowWord -= (Count - 1) * DataSize;
}
+ }
+
+ /* Read from the source operand */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_DS,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
+ : State->GeneralRegs[SOFT386_REG_ESI].LowWord,
+ FALSE,
+ &State->GeneralRegs[SOFT386_REG_EAX].Long,
+ DataSize))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
- /* Move the instruction pointer */
- State->InstPtr.LowWord += Offset;
+ /* Increment/decrement ESI */
+ if (OperandSize)
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].Long -= DataSize;
+ }
+ else
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].LowWord -= DataSize;
}
+ /* Return success */
return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeJmp)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeScas)
{
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
+ ULONG SecondValue = 0;
+ ULONG Result;
+ ULONG DataSize, DataMask, SignFlag;
+ BOOLEAN OperandSize, AddressSize;
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
/* Make sure this is the right instruction */
- ASSERT(Opcode == 0xE9);
+ ASSERT((Opcode & 0xFE) == 0xAE);
- if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
+ if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
- Size = !Size;
+ OperandSize = !OperandSize;
}
- else if (State->PrefixFlags != 0)
+
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
- /* Invalid prefix */
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
+ }
+
+ if ((State->PrefixFlags & SOFT386_PREFIX_REP)
+ || (State->PrefixFlags & SOFT386_PREFIX_REPNZ))
+ {
+ // TODO: The REP/REPZ/REPNZ prefixes need to be implemented!
Soft386Exception(State, SOFT386_EXCEPTION_UD);
return FALSE;
}
- if (Size)
+ /* Calculate the size */
+ if (Opcode == 0xA6) DataSize = sizeof(UCHAR);
+ else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+
+ /* Calculate the mask and sign flag */
+ DataMask = (1 << (DataSize * 8)) - 1;
+ SignFlag = 1 << ((DataSize * 8) - 1);
+
+ /* Read from the source operand */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ FALSE,
+ &SecondValue,
+ DataSize))
{
- LONG Offset = 0;
+ /* Exception occurred */
+ return FALSE;
+ }
- /* Fetch the offset */
- if (!Soft386FetchDword(State, (PULONG)&Offset))
- {
- /* An exception occurred */
- return FALSE;
- }
+ /* Calculate the result */
+ FirstValue &= DataMask;
+ SecondValue &= DataMask;
+ Result = (FirstValue - SecondValue) & DataMask;
- /* Move the instruction pointer */
- State->InstPtr.Long += Offset;
+ /* Update the flags */
+ State->Flags.Cf = FirstValue < SecondValue;
+ State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
+ && ((FirstValue & SignFlag) != (Result & SignFlag));
+ State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
+ State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
+ State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
+ State->Flags.Pf = Soft386CalculateParity(Result);
+
+ /* Increment/decrement EDI */
+ if (OperandSize)
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
}
else
{
- SHORT Offset = 0;
-
- /* Fetch the offset */
- if (!Soft386FetchWord(State, (PUSHORT)&Offset))
- {
- /* An exception occurred */
- return FALSE;
- }
-
- /* Move the instruction pointer */
- State->InstPtr.LowWord += Offset;
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
}
+ /* Return success */
return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeJmpAbs)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeIns)
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
- return FALSE;
-}
+ ULONG DataSize;
+ BOOLEAN OperandSize, AddressSize;
-SOFT386_OPCODE_HANDLER(Soft386OpcodeMovAlOffset)
-{
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- ULONG Offset;
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
/* Make sure this is the right instruction */
- ASSERT(Opcode == 0xA0);
+ ASSERT((Opcode & 0xFE) == 0x6C);
if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
- Size = !Size;
+ OperandSize = !OperandSize;
}
- if (Size)
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
- if (!Soft386FetchDword(State, &Offset))
- {
- /* Exception occurred */
- return FALSE;
- }
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
}
- else
+
+ /* Calculate the size */
+ if (Opcode == 0x6C) DataSize = sizeof(UCHAR);
+ else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_REP)
{
- USHORT WordOffset;
+ UCHAR Block[STRING_BLOCK_SIZE];
+ ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+ : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
- if (!Soft386FetchWord(State, &WordOffset))
+ /* Clear the memory block */
+ RtlZeroMemory(Block, sizeof(Block));
+
+ /* Transfer until finished */
+ while (Count)
{
- /* Exception occurred */
- return FALSE;
- }
+ ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
- Offset = (ULONG)WordOffset;
- }
+ /* Read from the I/O port */
+ State->IoReadCallback(State,
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord,
+ Block,
+ Processed * DataSize);
- /* 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));
-}
+ if (State->Flags.Df)
+ {
+ ULONG i, j;
-SOFT386_OPCODE_HANDLER(Soft386OpcodeMovEaxOffset)
-{
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ /* Reduce EDI by the number of bytes to transfer */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long -= Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= Processed * DataSize;
- /* Make sure this is the right instruction */
- ASSERT(Opcode == 0xA1);
+ /* Reverse the block data */
+ for (i = 0; i < Processed / 2; i++)
+ {
+ /* Swap the values */
+ for (j = 0; j < DataSize; j++)
+ {
+ UCHAR Temp = Block[i * DataSize + j];
+ Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
+ Block[(Processed - i - 1) * DataSize + j] = Temp;
+ }
+ }
+ }
- if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
- }
+ /* Write to memory */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
- if (Size)
- {
- ULONG Offset;
+ /* Exception occurred */
+ return FALSE;
+ }
- if (!Soft386FetchDword(State, &Offset))
- {
- /* Exception occurred */
- return FALSE;
+ if (!State->Flags.Df)
+ {
+ /* Increase EDI by the number of bytes transfered */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long += Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord += Processed * DataSize;
+ }
+
+ /* Reduce the total count by the number processed in this run */
+ Count -= Processed;
}
- /* 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));
+ /* Clear ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
}
else
{
- USHORT Offset;
-
- if (!Soft386FetchWord(State, &Offset))
+ ULONG Data = 0;
+
+ /* Read from the I/O port */
+ State->IoReadCallback(State,
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord,
+ &Data,
+ DataSize);
+
+ /* Write to the destination operand */
+ if (!Soft386WriteMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ &Data,
+ DataSize))
{
/* 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));
+ /* Increment/decrement EDI */
+ if (OperandSize)
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].Long += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].Long -= DataSize;
+ }
+ else
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_EDI].LowWord += DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= DataSize;
+ }
}
+
+ /* Return success */
+ return TRUE;
}
-SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetAl)
+SOFT386_OPCODE_HANDLER(Soft386OpcodeOuts)
{
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
- ULONG Offset;
+ ULONG DataSize;
+ BOOLEAN OperandSize, AddressSize;
+
+ OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
/* Make sure this is the right instruction */
- ASSERT(Opcode == 0xA2);
+ ASSERT((Opcode & 0xFE) == 0x6E);
if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
{
/* The OPSIZE prefix toggles the size */
- Size = !Size;
+ OperandSize = !OperandSize;
}
- if (Size)
+ if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
{
- if (!Soft386FetchDword(State, &Offset))
- {
- /* Exception occurred */
- return FALSE;
- }
+ /* The ADSIZE prefix toggles the size */
+ AddressSize = !AddressSize;
}
- else
+
+ /* Calculate the size */
+ if (Opcode == 0x6E) DataSize = sizeof(UCHAR);
+ else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
+
+ if (State->PrefixFlags & SOFT386_PREFIX_REP)
{
- USHORT WordOffset;
+ UCHAR Block[STRING_BLOCK_SIZE];
+ ULONG Count = OperandSize ? State->GeneralRegs[SOFT386_REG_ECX].Long
+ : State->GeneralRegs[SOFT386_REG_ECX].LowWord;
- if (!Soft386FetchWord(State, &WordOffset))
+ /* Clear the memory block */
+ RtlZeroMemory(Block, sizeof(Block));
+
+ /* Transfer until finished */
+ while (Count)
{
- /* Exception occurred */
- return FALSE;
- }
+ ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
+
+ /* Read from memory */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_ES,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_EDI].Long
+ : State->GeneralRegs[SOFT386_REG_EDI].LowWord,
+ FALSE,
+ Block,
+ Processed * DataSize))
+ {
+ /* Set ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = Count;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = LOWORD(Count);
- Offset = (ULONG)WordOffset;
- }
+ /* 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].LowByte,
- sizeof(UCHAR));
-}
+ if (State->Flags.Df)
+ {
+ ULONG i, j;
-SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetEax)
-{
- BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
+ /* Reduce EDI by the number of bytes to transfer */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long -= Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord -= Processed * DataSize;
- /* Make sure this is the right instruction */
- ASSERT(Opcode == 0xA3);
+ /* Reverse the block data */
+ for (i = 0; i < Processed / 2; i++)
+ {
+ /* Swap the values */
+ for (j = 0; j < DataSize; j++)
+ {
+ UCHAR Temp = Block[i * DataSize + j];
+ Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
+ Block[(Processed - i - 1) * DataSize + j] = Temp;
+ }
+ }
+ }
- if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
- {
- /* The OPSIZE prefix toggles the size */
- Size = !Size;
- }
+ /* Write to the I/O port */
+ State->IoWriteCallback(State,
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord,
+ Block,
+ Processed * DataSize);
- if (Size)
- {
- ULONG Offset;
+ if (!State->Flags.Df)
+ {
+ /* Increase EDI by the number of bytes transfered */
+ if (AddressSize) State->GeneralRegs[SOFT386_REG_EDI].Long += Processed * DataSize;
+ else State->GeneralRegs[SOFT386_REG_EDI].LowWord += Processed * DataSize;
+ }
- if (!Soft386FetchDword(State, &Offset))
- {
- /* Exception occurred */
- return FALSE;
+ /* Reduce the total count by the number processed in this run */
+ Count -= Processed;
}
- /* 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));
+ /* Clear ECX */
+ if (OperandSize) State->GeneralRegs[SOFT386_REG_ECX].Long = 0;
+ else State->GeneralRegs[SOFT386_REG_ECX].LowWord = 0;
}
else
{
- USHORT Offset;
+ ULONG Data = 0;
- if (!Soft386FetchWord(State, &Offset))
+ /* Read from the source operand */
+ if (!Soft386ReadMemory(State,
+ SOFT386_REG_DS,
+ AddressSize ? State->GeneralRegs[SOFT386_REG_ESI].Long
+ : State->GeneralRegs[SOFT386_REG_ESI].LowWord,
+ FALSE,
+ &Data,
+ DataSize))
{
/* 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));
+ /* Write to the I/O port */
+ State->IoWriteCallback(State,
+ State->GeneralRegs[SOFT386_REG_EDX].LowWord,
+ &Data,
+ DataSize);
+
+ /* Increment/decrement ESI */
+ if (OperandSize)
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].Long += DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].Long -= DataSize;
+ }
+ else
+ {
+ if (!State->Flags.Df) State->GeneralRegs[SOFT386_REG_ESI].LowWord += DataSize;
+ else State->GeneralRegs[SOFT386_REG_ESI].LowWord -= DataSize;
+ }
}
+
+ /* Return success */
+ return TRUE;
}