diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/x86new/ctrlops.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/nthals/x86new/ctrlops.c')
-rw-r--r-- | private/ntos/nthals/x86new/ctrlops.c | 468 |
1 files changed, 468 insertions, 0 deletions
diff --git a/private/ntos/nthals/x86new/ctrlops.c b/private/ntos/nthals/x86new/ctrlops.c new file mode 100644 index 000000000..e4158f88d --- /dev/null +++ b/private/ntos/nthals/x86new/ctrlops.c @@ -0,0 +1,468 @@ +/*++ + +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.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; +} |