558 lines
9.1 KiB
C
558 lines
9.1 KiB
C
/*++
|
||
|
||
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;
|
||
}
|