You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
496 lines
9.3 KiB
496 lines
9.3 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
stringop.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the code to emulate the string opcodes.
|
|
|
|
Author:
|
|
|
|
David N. Cutler (davec) 7-Nov-1994
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "nthal.h"
|
|
#include "emulate.h"
|
|
|
|
//
|
|
// Define forward referenced prototypes.
|
|
//
|
|
|
|
VOID
|
|
XmCompareOperands (
|
|
IN PRXM_CONTEXT P
|
|
);
|
|
|
|
VOID
|
|
XmCmpsOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates a cmpsb/w/d opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG Count;
|
|
|
|
//
|
|
// If a repeat prefix is active, then the loop count is specified
|
|
// by eCX. Otherwise, the loop count is one.
|
|
//
|
|
|
|
Count = 1;
|
|
if (P->RepeatPrefixActive != FALSE) {
|
|
if (P->OpaddrPrefixActive != FALSE) {
|
|
Count = P->Gpr[ECX].Exx;
|
|
|
|
} else {
|
|
Count = P->Gpr[CX].Xx;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Compare items from source and destination.
|
|
//
|
|
|
|
while (Count != 0) {
|
|
|
|
//
|
|
// Set source and destination values.
|
|
//
|
|
|
|
XmSetSourceValue(P, XmGetStringAddress(P, P->DataSegment, ESI));
|
|
XmSetDestinationValue(P, XmGetStringAddress(P, ES, EDI));
|
|
|
|
//
|
|
// Compare source with destination operand and decrement loop count.
|
|
// If ZF is not equal to the repeat Z flag condition, then terminate
|
|
// the loop.
|
|
//
|
|
|
|
XmCompareOperands(P);
|
|
Count -= 1;
|
|
if (P->Eflags.EFLAG_ZF != P->RepeatZflag) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If a repeat prefix is active, then set the final count value.
|
|
//
|
|
|
|
if (P->RepeatPrefixActive != FALSE) {
|
|
if (P->OpaddrPrefixActive != FALSE) {
|
|
P->Gpr[ECX].Exx = Count;
|
|
|
|
} else {
|
|
P->Gpr[CX].Xx = (USHORT)Count;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmLodsOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates a lodsb/w/d opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG Count;
|
|
|
|
//
|
|
// If a repeat prefix is active, then the loop count is specified
|
|
// by eCX. Otherwise, the loop count is one.
|
|
//
|
|
|
|
Count = 1;
|
|
if (P->RepeatPrefixActive != FALSE) {
|
|
if (P->OpaddrPrefixActive != FALSE) {
|
|
Count = P->Gpr[ECX].Exx;
|
|
P->Gpr[ECX].Exx = 0;
|
|
|
|
} else {
|
|
Count = P->Gpr[CX].Xx;
|
|
P->Gpr[CX].Xx = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set destination address.
|
|
//
|
|
|
|
P->DstLong = (ULONG UNALIGNED *)&P->Gpr[EAX].Exx;
|
|
|
|
//
|
|
// Move items from source to destination.
|
|
//
|
|
|
|
while (Count != 0) {
|
|
|
|
//
|
|
// Set source value and store result.
|
|
//
|
|
|
|
XmSetSourceValue(P, XmGetStringAddress(P, P->DataSegment, ESI));
|
|
XmStoreResult(P, P->SrcValue.Long);
|
|
Count -= 1;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmMovsOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates a movsb/w/d opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG Count;
|
|
|
|
//
|
|
// If a repeat prefix is active, then the loop count is specified
|
|
// by eCX. Otherwise, the loop count is one.
|
|
//
|
|
|
|
Count = 1;
|
|
if (P->RepeatPrefixActive != FALSE) {
|
|
if (P->OpaddrPrefixActive != FALSE) {
|
|
Count = P->Gpr[ECX].Exx;
|
|
P->Gpr[ECX].Exx = 0;
|
|
|
|
} else {
|
|
Count = P->Gpr[CX].Xx;
|
|
P->Gpr[CX].Xx = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Move items from source to destination.
|
|
//
|
|
|
|
while (Count != 0) {
|
|
|
|
//
|
|
// Set source value, set destination address, and store result.
|
|
//
|
|
|
|
XmSetSourceValue(P, XmGetStringAddress(P, P->DataSegment, ESI));
|
|
P->DstLong = (ULONG UNALIGNED *)XmGetStringAddress(P, ES, EDI);
|
|
XmStoreResult(P, P->SrcValue.Long);
|
|
Count -= 1;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmScasOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates a scasb/w/d opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG Count;
|
|
|
|
//
|
|
// If a repeat prefix is active, then the loop count is specified
|
|
// by eCX. Otherwise, the loop count is one.
|
|
//
|
|
|
|
Count = 1;
|
|
if (P->RepeatPrefixActive != FALSE) {
|
|
if (P->OpaddrPrefixActive != FALSE) {
|
|
Count = P->Gpr[ECX].Exx;
|
|
|
|
} else {
|
|
Count = P->Gpr[CX].Xx;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set source value.
|
|
//
|
|
|
|
XmSetSourceValue(P, (PVOID)&P->Gpr[EAX].Exx);
|
|
|
|
//
|
|
// Compare items from source and destination.
|
|
//
|
|
|
|
while (Count != 0) {
|
|
|
|
//
|
|
// Set destination value.
|
|
//
|
|
|
|
XmSetDestinationValue(P, XmGetStringAddress(P, ES, EDI));
|
|
|
|
//
|
|
// Compare source with destination operand and decrement loop count.
|
|
// If ZF is not equal to the repeat Z flag condition, then terminate
|
|
// the loop.
|
|
//
|
|
|
|
XmCompareOperands(P);
|
|
Count -= 1;
|
|
if (P->Eflags.EFLAG_ZF != P->RepeatZflag) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If a repeat prefix is active, then set the final count value.
|
|
//
|
|
|
|
if (P->RepeatPrefixActive != FALSE) {
|
|
if (P->OpaddrPrefixActive != FALSE) {
|
|
P->Gpr[ECX].Exx = Count;
|
|
|
|
} else {
|
|
P->Gpr[CX].Xx = (USHORT)Count;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmStosOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates a stosb/w/d opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG Count;
|
|
|
|
//
|
|
// If a repeat prefix is active, then the loop count is specified
|
|
// by eCX. Otherwise, the loop count is one.
|
|
//
|
|
|
|
Count = 1;
|
|
if (P->RepeatPrefixActive != FALSE) {
|
|
if (P->OpaddrPrefixActive != FALSE) {
|
|
Count = P->Gpr[ECX].Exx;
|
|
P->Gpr[ECX].Exx = 0;
|
|
|
|
} else {
|
|
Count = P->Gpr[CX].Xx;
|
|
P->Gpr[CX].Xx = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set source value.
|
|
//
|
|
|
|
XmSetSourceValue(P, (PVOID)&P->Gpr[EAX].Exx);
|
|
|
|
//
|
|
// Move items from source to destination.
|
|
//
|
|
|
|
while (Count != 0) {
|
|
|
|
//
|
|
// Set destination address and store result.
|
|
//
|
|
|
|
P->DstLong = (ULONG UNALIGNED *)XmGetStringAddress(P, ES, EDI);
|
|
XmStoreResult(P, P->SrcValue.Long);
|
|
Count -= 1;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmCompareOperands (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function compares two operands and computes the resulting condition
|
|
codes.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG CarryFlag;
|
|
ULONG OverflowFlag;
|
|
ULONG SignFlag;
|
|
ULONG ZeroFlag;
|
|
union {
|
|
UCHAR ResultByte;
|
|
ULONG ResultLong;
|
|
USHORT ResultWord;
|
|
} u;
|
|
|
|
//
|
|
// Switch on data type.
|
|
//
|
|
|
|
switch (P->DataType) {
|
|
|
|
//
|
|
// The operation datatype is byte.
|
|
//
|
|
|
|
case BYTE_DATA:
|
|
CarryFlag = (P->SrcValue.Byte < P->DstValue.Byte);
|
|
u.ResultByte = P->SrcValue.Byte - P->DstValue.Byte;
|
|
OverflowFlag = (((u.ResultByte ^ P->SrcValue.Byte) &
|
|
(u.ResultByte ^ P->DstValue.Byte)) >> 7) & 0x1;
|
|
|
|
SignFlag = (u.ResultByte >> 7) & 0x1;
|
|
ZeroFlag = (u.ResultByte == 0);
|
|
u.ResultLong = u.ResultByte;
|
|
break;
|
|
|
|
//
|
|
// The operation datatype is word.
|
|
//
|
|
|
|
case WORD_DATA:
|
|
CarryFlag = (P->SrcValue.Word < P->DstValue.Word);
|
|
u.ResultWord = P->SrcValue.Word - P->DstValue.Word;
|
|
OverflowFlag = (((u.ResultWord ^ P->SrcValue.Word) &
|
|
(u.ResultWord ^ P->DstValue.Word)) >> 15) & 0x1;
|
|
|
|
SignFlag = (u.ResultWord >> 15) & 0x1;
|
|
ZeroFlag = (u.ResultWord == 0);
|
|
u.ResultLong = u.ResultWord;
|
|
break;
|
|
|
|
//
|
|
// The operation datatype is long.
|
|
//
|
|
|
|
case LONG_DATA:
|
|
CarryFlag = (P->SrcValue.Long < P->DstValue.Long);
|
|
u.ResultLong = P->SrcValue.Long - P->DstValue.Long;
|
|
OverflowFlag = (((u.ResultLong ^ P->SrcValue.Long) &
|
|
(u.ResultLong ^ P->DstValue.Long)) >> 31) & 0x1;
|
|
|
|
SignFlag = (u.ResultLong >> 31) & 0x1;
|
|
ZeroFlag = (u.ResultLong == 0);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Compute auxilary carry flag, parity flag, and store all flags in
|
|
// the flags register.
|
|
//
|
|
|
|
P->Eflags.EFLAG_CF = CarryFlag;
|
|
P->Eflags.EFLAG_PF = XmComputeParity(u.ResultLong);
|
|
P->Eflags.EFLAG_AF = ((P->DstValue.Byte & 0xf) + (P->SrcValue.Byte & 0xf)) >> 4;
|
|
P->Eflags.EFLAG_ZF = ZeroFlag;
|
|
P->Eflags.EFLAG_SF = SignFlag;
|
|
P->Eflags.EFLAG_OF = OverflowFlag;
|
|
return;
|
|
}
|