/*++ 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; }