|
|
/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
ctrlops.c
Abstract:
This module implements the code to emulate call, retunr, and various control operations.
Author:
David N. Cutler (davec) 10-Nov-1994
Environment:
Kernel mode only.
Revision History:
--*/
#include "nthal.h"
#include "emulate.h"
VOID XmCallOp ( PRXM_CONTEXT P )
/*++
Routine Description:
This function emulates a call opcode.
Arguments:
P - Supplies a pointer to an emulator context structure.
Return Value:
None.
--*/
{
ULONG Target; ULONG Source;
//
// Save the target address, push the current segment, if required, and
// push the current IP, set the destination segment, if required, and
// set the new IP.
//
Target = P->DstValue.Long; if (P->OpsizePrefixActive != FALSE) { P->DataType = LONG_DATA;
} else { P->DataType = WORD_DATA; }
if ((P->CurrentOpcode == 0x9a) || (P->FunctionIndex != X86_CALL_OP)) { XmPushStack(P, P->SegmentRegister[CS]); XmPushStack(P, P->Eip); P->SegmentRegister[CS] = P->DstSegment;
} else { XmPushStack(P, P->Eip); }
P->Eip = Target; XmTraceJumps(P); return; }
VOID XmEnterOp ( PRXM_CONTEXT P )
/*++
Routine Description:
This function emulates an enter opcode.
Arguments:
P - Supplies a pointer to an emulator context structure.
Return Value:
None.
--*/
{
ULONG Allocate; ULONG Frame; ULONG Number;
//
// set the number of bytes to allocate on the stack and the number
// of nesting levels.
//
Allocate = P->SrcValue.Long; Number = P->DstValue.Long;
//
// Set the data type and save the frame pointer on the stack.
//
if (P->OpsizePrefixActive != FALSE) { P->DataType = LONG_DATA; XmPushStack(P, P->Gpr[EBP].Exx); Frame = P->Gpr[ESP].Exx;
} else { P->DataType = WORD_DATA; XmPushStack(P, P->Gpr[BP].Xx); Frame = P->Gpr[SP].Xx; }
//
// Save the current stack pointer and push parameters on the stack.
//
if (Number != 0) {
//
// If the level number is not one, then raise an exception.
//
// N.B. Level numbers greater than one are not supported.
//
if (Number != 1) { longjmp(&P->JumpBuffer[0], XM_ILLEGAL_LEVEL_NUMBER); }
XmPushStack(P, Frame); }
//
// Allocate local storage on stack.
//
if (P->OpsizePrefixActive != FALSE) { P->Gpr[EBP].Exx = Frame; P->Gpr[ESP].Exx = P->Gpr[ESP].Exx - Allocate;
} else { P->Gpr[BP].Xx = (USHORT)Frame; P->Gpr[SP].Xx = (USHORT)(P->Gpr[SP].Xx - Allocate); }
return; }
VOID XmHltOp ( PRXM_CONTEXT P )
/*++
Routine Description:
This function emulates a hlt opcode.
Arguments:
P - Supplies a pointer to an emulator context structure.
Return Value:
None.
--*/
{
//
// Halt instructions are not supported by the emulator.
//
longjmp(&P->JumpBuffer[0], XM_HALT_INSTRUCTION); return; }
VOID XmIntOp ( PRXM_CONTEXT P )
/*++
Routine Description:
This function emulates an int opcode.
Arguments:
P - Supplies a pointer to an emulator context structure.
Return Value:
None.
--*/
{
ULONG Number; PULONG Vector;
//
// If the int instruction is an int 3, then set the interrupt vector
// to 3. Otherwise, if the int instruction is an into, then set the
// vector to 4 if OF is set. use the source interrupt vector.
//
if (P->OpsizePrefixActive != FALSE) { P->DataType = LONG_DATA;
} else { P->DataType = WORD_DATA; }
if (P->CurrentOpcode == 0xcc) { Number = 3;
} else if (P->CurrentOpcode == 0xce) { if (P->Eflags.EFLAG_OF == 0) { return; }
Number = 4;
} else { Number = P->SrcValue.Byte; }
//
// If the vector number is 0x42, then nop the interrupt. This is the
// standard EGA video driver entry point in a PC's motherboard BIOS
// for which there is no code.
//
#if !defined(_PURE_EMULATION_)
if (Number == 0x42) { return; }
#endif
//
// If the vector number is 0x1a, then attempt to emulate the PCI BIOS
// if it is enabled.
//
#if !defined(_PURE_EMULATION_)
if ((Number == 0x1a) && (XmExecuteInt1a(P) != FALSE)) { return; }
#endif
//
// Push the current flags, code segment, and EIP on the stack.
//
XmPushStack(P, P->AllFlags); XmPushStack(P, P->SegmentRegister[CS]); XmPushStack(P, P->Eip);
//
// Set the new coded segment and IP from the specified interrupt
// vector.
//
Vector = (PULONG)(P->TranslateAddress)(0, 0); P->SegmentRegister[CS] = (USHORT)(Vector[Number] >> 16); P->Eip = (USHORT)(Vector[Number] & 0xffff); XmTraceJumps(P); return; }
VOID XmIretOp ( PRXM_CONTEXT P )
/*++
Routine Description:
This function emulates an iret opcode.
Arguments:
P - Supplies a pointer to an emulator context structure.
Return Value:
None.
--*/
{
//
// Set the data type and restore the return address, code segment,
// and flags.
//
if (P->OpsizePrefixActive != FALSE) { P->DataType = LONG_DATA;
} else { P->DataType = WORD_DATA; }
P->Eip = XmPopStack(P); P->SegmentRegister[CS] = (USHORT)XmPopStack(P); P->AllFlags = XmPopStack(P); XmTraceJumps(P);
//
// Check for emulator exit conditions.
//
if ((P->Eip == 0xffff) && (P->SegmentRegister[CS] == 0xffff)) { longjmp(&P->JumpBuffer[0], XM_SUCCESS); }
return; }
VOID XmLeaveOp ( PRXM_CONTEXT P )
/*++
Routine Description:
This function emulates a leave opcode.
Arguments:
P - Supplies a pointer to an emulator context structure.
Return Value:
None.
--*/
{
//
// Set the data type, restore the stack pointer, and restore the frame
// pointer.
//
if (P->OpsizePrefixActive != FALSE) { P->DataType = LONG_DATA; P->Gpr[ESP].Exx = P->Gpr[EBP].Exx; P->Gpr[EBP].Exx = XmPopStack(P);
} else { P->DataType = WORD_DATA; P->Gpr[SP].Xx = P->Gpr[BP].Xx; P->Gpr[BP].Xx = (USHORT)XmPopStack(P); }
return; }
VOID XmRetOp ( PRXM_CONTEXT P )
/*++
Routine Description:
This function emulates a ret opcode.
Arguments:
P - Supplies a pointer to an emulator context structure.
Return Value:
None.
--*/
{
ULONG Adjust;
//
// Compute the number of bytes that are to be removed from the stack
// after having removed the return address and optionally the new CS
// segment value.
//
if ((P->CurrentOpcode & 0x1) == 0) { Adjust = XmGetWordImmediate(P);
} else { Adjust = 0; }
//
// Remove the return address from the stack and set the new IP.
//
if (P->OpsizePrefixActive != FALSE) { P->DataType = LONG_DATA;
} else { P->DataType = WORD_DATA; }
P->Eip = XmPopStack(P);
//
// If the current opcode is a far return, then remove the new CS segment
// value from the stack.
//
if ((P->CurrentOpcode & 0x8) != 0) { P->SegmentRegister[CS] = (USHORT)XmPopStack(P); }
//
// Remove the specified number of bytes from the stack.
//
P->Gpr[ESP].Exx += Adjust; XmTraceJumps(P);
//
// Check for emulator exit conditions.
//
if ((P->Eip == 0xffff) && (P->SegmentRegister[CS] == 0xffff)) { longjmp(&P->JumpBuffer[0], XM_SUCCESS); }
return; }
|