/*++ Copyright (c) 1994 Microsoft Corporation Module Name: utility.c Abstract: This module implements utility functions. Author: David N. Cutler (davec) 7-Sep-1994 Environment: Kernel mode only. Revision History: --*/ #include "nthal.h" #include "emulate.h" // // Define bit count array. // UCHAR XmBitCount[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; ULONG XmComputeParity ( IN ULONG Result ) /*++ Routine Description: This function computes the parity of the low byte of the specified result. Arguments: Result - Supplies the result for which the parity flag is computed. Return Value: The parity flag value. --*/ { ULONG Count; // // Sum the bits in the result and return the complement of the low bit. // Count = XmBitCount[Result & 0xf]; Count += XmBitCount[(Result >> 4) & 0xf]; return (~Count) & 1; } UCHAR XmGetCodeByte ( IN PRXM_CONTEXT P ) /*++ Routine Description: This function gets the next code byte from the instruction stream. Arguments: P - Supplies a pointer to an emulator context structure. Return Value: The next byte form the instruction stream. --*/ { ULONG Offset; // // If the current IP is within the code segment, then return the // next byte from the instrcution stream and increment the IP value. // Otherwise, raise an exception. // Offset = P->Eip; if (Offset > P->SegmentLimit[CS]) { longjmp(&P->JumpBuffer[0], XM_SEGMENT_LIMIT_VIOLATION); } P->Ip += 1; return *(PUCHAR)((P->TranslateAddress)(P->SegmentRegister[CS], (USHORT)Offset)); } UCHAR XmGetByteImmediate ( IN PRXM_CONTEXT P ) /*++ Routine Description: This function gets an unsigned immediate byte operand from the code stream and returns a byte value. Arguments: P - Supplies a pointer to an emulator context structure. Return Value: The next byte from the instruction stream. --*/ { UCHAR Byte; // // Get immediate byte from the code stream. // Byte = XmGetCodeByte(P); XmTraceInstruction(BYTE_DATA, (ULONG)Byte); return Byte; } USHORT XmGetByteImmediateToWord ( IN PRXM_CONTEXT P ) /*++ Routine Description: This function gets an unsigned immediate byte operand from the code stream and returns a zero extended byte to word value. Arguments: P - Supplies a pointer to an emulator context structure. Return Value: The next byte from the instruction stream zero extended to a word. --*/ { USHORT Word; // // Get immediate byte from the code stream. // Word = XmGetCodeByte(P); XmTraceInstruction(BYTE_DATA, (ULONG)((UCHAR)Word)); return Word; } ULONG XmGetByteImmediateToLong ( IN PRXM_CONTEXT P ) /*++ Routine Description: This function gets an unsigned immediate byte operand from the code stream and returns a zero extended byte to long value. Arguments: P - Supplies a pointer to an emulator context structure. Return Value: The next byte from the instruction stream zero extended to a long. --*/ { ULONG Long; // // Get immediate byte from the code stream. // Long = XmGetCodeByte(P); XmTraceInstruction(BYTE_DATA, (ULONG)((UCHAR)Long)); return Long; } USHORT XmGetSignedByteImmediateToWord ( IN PRXM_CONTEXT P ) /*++ Routine Description: This function gets an unsigned immediate byte operand from the code stream and returns a sign extended byte to word value. Arguments: P - Supplies a pointer to an emulator context structure. Return Value: The next byte from the instruction stream sign extended to a word. --*/ { USHORT Word; // // Get immediate byte from the code stream. // Word = (USHORT)((SHORT)((SCHAR)XmGetCodeByte(P))); XmTraceInstruction(BYTE_DATA, (ULONG)((UCHAR)Word)); return Word; } ULONG XmGetSignedByteImmediateToLong ( IN PRXM_CONTEXT P ) /*++ Routine Description: This function gets an unsigned immediate byte operand from the code stream and returns a sign extended byte to long value. Arguments: P - Supplies a pointer to an emulator context structure. Return Value: The next byte from the instruction stream sign extended to a long. --*/ { ULONG Long; // // Get immediate byte from the code stream. // Long = (ULONG)((LONG)((SCHAR)XmGetCodeByte(P))); XmTraceInstruction(BYTE_DATA, (ULONG)((UCHAR)Long)); return Long; } USHORT XmGetWordImmediate ( IN PRXM_CONTEXT P ) /*++ Routine Description: This function gets an unsigned immediate word operand from the code stream and returns a word value. Arguments: P - Supplies a pointer to an emulator context structure. Return Value: The next word from the instruction stream. --*/ { USHORT Word; // // Get immediate word from the code stream. // Word = XmGetCodeByte(P); Word += XmGetCodeByte(P) << 8; XmTraceInstruction(WORD_DATA, (ULONG)Word); return Word; } ULONG XmGetLongImmediate ( IN PRXM_CONTEXT P ) /*++ Routine Description: This function gets an unsigned immediate long operand from the code stream and returns a long value. Arguments: P - Supplies a pointer to an emulator context structure. Return Value: The next long from the instruction stream. --*/ { ULONG Long; // // Get immediate long from the code stream. // Long = XmGetCodeByte(P); Long += XmGetCodeByte(P) << 8; Long += XmGetCodeByte(P) << 16; Long += XmGetCodeByte(P) << 24; XmTraceInstruction(LONG_DATA, Long); return Long; } ULONG XmPopStack ( IN PRXM_CONTEXT P ) /*++ Routine Description: This function pops an operand from the stack. Arguments: P - Supplies a pointer to the emulation context structure. Return Value: None. --*/ { ULONG Offset; // // Compute the new stack address and compare against the segment limit. // If the new address is greater than the limit, then raise an exception. // Otherwise, perform the push operation. // Offset = P->Gpr[ESP].Exx; if (Offset > (ULONG)(P->SegmentLimit[SS] - P->DataType)) { longjmp(&P->JumpBuffer[0], XM_STACK_UNDERFLOW); } P->Gpr[ESP].Exx += (P->DataType + 1); XmSetSourceValue(P, (P->TranslateAddress)(P->SegmentRegister[SS], (USHORT)Offset)); return P->SrcValue.Long; } VOID XmPushStack ( IN PRXM_CONTEXT P, IN ULONG Value ) /*++ Routine Description: This function pushes an operand on the stack. Arguments: P - Supplies a pointer to the emulation context structure. Value - Supplies the value to be pushed. Return Value: None. --*/ { ULONG Offset; // // Compute the new stack address and compare against the segment limit. // If the new address is greater than the limit, then raise an exception. // Otherwise, perform the push operation. // Offset = P->Gpr[ESP].Exx - P->DataType - 1; if (Offset > (ULONG)(P->SegmentLimit[SS] - P->DataType)) { longjmp(&P->JumpBuffer[0], XM_STACK_OVERFLOW); } P->Gpr[ESP].Exx = Offset; P->DstLong = (ULONG UNALIGNED *)((P->TranslateAddress)(P->SegmentRegister[SS], (USHORT)Offset)); XmStoreResult(P, Value); return; } VOID XmSetDataType ( IN PRXM_CONTEXT P ) /*++ Routine Description: This function sets the data type of the operation based on the width bit of the current opcode. Arguments: P - Supplies a pointer to an emulator context structure. Return Value: None. --*/ { // // If the width bit is zero, then the data type is byte. Otherwise, // the datatype is determined by the presence of absence of a operand // size prefix. // if ((P->CurrentOpcode & WIDTH_BIT) == 0) { P->DataType = BYTE_DATA; } else if (P->OpsizePrefixActive != FALSE) { P->DataType = LONG_DATA; } else { P->DataType = WORD_DATA; } return; } VOID XmStoreResult ( IN PRXM_CONTEXT P, IN ULONG Result ) /*++ Routine Description: This function stores the result of an operation. Arguments: P - Supplies a pointer to an emulator context structure. Result - Supplies the result value to store. Return Value: None. --*/ { // // Store result of operation. // if (P->DataType == BYTE_DATA) { *P->DstByte = (UCHAR)Result; } else if (P->DataType == WORD_DATA) { if (((ULONG_PTR)P->DstWord & 0x1) == 0) { *((PUSHORT)(P->DstWord)) = (USHORT)Result; } else { *P->DstWord = (USHORT)Result; } } else { #ifdef _IA64_ // // Hack to force the compiler to generate unaligned // accesses. We can remove it when the compiler is // fixed. // *P->DstLong = Result; #else if (((ULONG_PTR)P->DstLong & 0x3) == 0) { *((PULONG)(P->DstLong)) = Result; } else { *P->DstLong = Result; } #endif // #ifdef _IA64_ } XmTraceResult(P, Result); return; }