3163 lines
70 KiB
C
3163 lines
70 KiB
C
/*++
|
||
|
||
Copyright (c) 2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ia32emul.c
|
||
|
||
Abstract:
|
||
|
||
This module implements an x86 instruction decoder and emulator.
|
||
|
||
Author:
|
||
|
||
Samer Arafeh (samera) 30-Oct-2000
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "ki.h"
|
||
#include "ia32def.h"
|
||
#include "wow64t.h"
|
||
|
||
|
||
#if DBG
|
||
BOOLEAN KiIa32InstructionEmulationDbg = 0;
|
||
#endif
|
||
|
||
#define KiIa32GetX86Eflags(efl) efl.Value = __getReg(CV_IA64_AR24)
|
||
#define KiIa32SetX86Eflags(efl) __setReg(CV_IA64_AR24, efl.Value)
|
||
|
||
#define IA32_GETEFLAGS_CF(efl) (efl & 0x01UI64)
|
||
|
||
//
|
||
// Ia32 instruction handlers
|
||
//
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionAdc (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
);
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionAdd (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
);
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionArithmeticBitwiseHelper (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
);
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionBitTestHelper (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
);
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionOneParamHelper (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
);
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionXadd (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
);
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionXchg (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
);
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionCmpXchg (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
);
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionCmpXchg8b (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
);
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionMoveSeg (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
);
|
||
|
||
//
|
||
// Opcode Ids
|
||
//
|
||
|
||
typedef enum _IA32_OPCODE
|
||
{
|
||
Ia32_Adc,
|
||
Ia32_Add,
|
||
Ia32_And,
|
||
Ia32_Bt,
|
||
Ia32_Btc,
|
||
Ia32_Btr,
|
||
Ia32_Bts,
|
||
Ia32_Cmpxchg,
|
||
Ia32_Cmpxchg8b,
|
||
Ia32_Dec,
|
||
Ia32_Inc,
|
||
Ia32_Neg,
|
||
Ia32_Not,
|
||
Ia32_Or,
|
||
Ia32_Sbb,
|
||
Ia32_Sub,
|
||
Ia32_Xadd,
|
||
Ia32_Xchg,
|
||
Ia32_Xor,
|
||
Ia32_MovToSeg,
|
||
|
||
//
|
||
// This needs always to be the last element
|
||
//
|
||
|
||
Ia32_LastOpcode
|
||
|
||
} IA32_OPCODE;
|
||
|
||
|
||
//
|
||
// Array of Ia32 instruction handlers
|
||
// NOTE : The following table must be in sync with the above enum.
|
||
//
|
||
|
||
typedef NTSTATUS (*IA32_INSTRUCTION_HANDLER) (PKTRAP_FRAME, PIA32_INSTRUCTION);
|
||
IA32_INSTRUCTION_HANDLER KiIa32InstructionHandler [] =
|
||
{
|
||
KiIa32InstructionAdc,
|
||
KiIa32InstructionAdd,
|
||
KiIa32InstructionArithmeticBitwiseHelper,
|
||
KiIa32InstructionBitTestHelper,
|
||
KiIa32InstructionBitTestHelper,
|
||
KiIa32InstructionBitTestHelper,
|
||
KiIa32InstructionBitTestHelper,
|
||
KiIa32InstructionCmpXchg,
|
||
KiIa32InstructionCmpXchg8b,
|
||
KiIa32InstructionOneParamHelper,
|
||
KiIa32InstructionOneParamHelper,
|
||
KiIa32InstructionOneParamHelper,
|
||
KiIa32InstructionOneParamHelper,
|
||
KiIa32InstructionArithmeticBitwiseHelper,
|
||
KiIa32InstructionAdc,
|
||
KiIa32InstructionAdd,
|
||
KiIa32InstructionXadd,
|
||
KiIa32InstructionXchg,
|
||
KiIa32InstructionArithmeticBitwiseHelper,
|
||
KiIa32InstructionMoveSeg,
|
||
NULL
|
||
};
|
||
|
||
#if DBG
|
||
PCHAR KiIa32InstructionHandlerNames [] =
|
||
{
|
||
"KiIa32InstructionAdc",
|
||
"KiIa32InstructionAdd",
|
||
"KiIa32InstructionAnd",
|
||
"KiIa32InstructionBt",
|
||
"KiIa32InstructionBtc",
|
||
"KiIa32InstructionBtr",
|
||
"KiIa32InstructionBts",
|
||
"KiIa32InstructionCmpXchg",
|
||
"KiIa32InstructionCmpXchg8b",
|
||
"KiIa32InstructionDec",
|
||
"KiIa32InstructionInc",
|
||
"KiIa32InstructionNeg",
|
||
"KiIa32InstructionNot",
|
||
"KiIa32InstructionOr",
|
||
"KiIa32InstructionSbb",
|
||
"KiIa32InstructionSub",
|
||
"KiIa32InstructionXadd",
|
||
"KiIa32InstructionXchg",
|
||
"KiIa32InstructionXor",
|
||
"KiIa32InstructionMoveSeg",
|
||
NULL,
|
||
};
|
||
#endif
|
||
|
||
|
||
IA32_OPCODE_DESCRIPTION OpcodesDescription[] =
|
||
{
|
||
//
|
||
// Adc
|
||
//
|
||
|
||
// Adc r/m8, imm8
|
||
{
|
||
0x80, 0x00, 0x02, 0x11, IA32_PARAM_RM8_IMM8, Ia32_Adc
|
||
},
|
||
// Adc r/m, imm
|
||
{
|
||
0x81, 0x00, 0x02, 0x11, IA32_PARAM_RM_IMM, Ia32_Adc
|
||
},
|
||
// Adc r/m, imm8 (sign)
|
||
{
|
||
0x83, 0x00, 0x02, 0x11, IA32_PARAM_RM_IMM8SIGN, Ia32_Adc
|
||
},
|
||
// Adc r/m8, r8
|
||
{
|
||
0x10, 0x00, 0x00, 0x01, IA32_PARAM_RM8_R, Ia32_Adc
|
||
},
|
||
// Adc r/m, r
|
||
{
|
||
0x11, 0x00, 0x00, 0x01, IA32_PARAM_RM_R, Ia32_Adc
|
||
},
|
||
// Adc r, r/m8
|
||
{
|
||
0x12, 0x00, 0x00, 0x01, IA32_PARAM_R_RM8, Ia32_Adc
|
||
},
|
||
// Adc r, r/m
|
||
{
|
||
0x13, 0x00, 0x00, 0x01, IA32_PARAM_R_RM, Ia32_Adc
|
||
},
|
||
|
||
//
|
||
// Add
|
||
//
|
||
|
||
// Add r/m8, imm8
|
||
{
|
||
0x80, 0x00, 0x00, 0x11, IA32_PARAM_RM8_IMM8, Ia32_Add
|
||
},
|
||
// Add r/m, imm
|
||
{
|
||
0x81, 0x00, 0x00, 0x11, IA32_PARAM_RM_IMM, Ia32_Add
|
||
},
|
||
// Add r/m, imm8 (sign)
|
||
{
|
||
0x83, 0x00, 0x00, 0x11, IA32_PARAM_RM_IMM8SIGN, Ia32_Add
|
||
},
|
||
// Add r/m8, r8
|
||
{
|
||
0x00, 0x00, 0x00, 0x01, IA32_PARAM_RM8_R, Ia32_Add
|
||
},
|
||
// Add r/m, r
|
||
{
|
||
0x01, 0x00, 0x00, 0x01, IA32_PARAM_RM_R, Ia32_Add
|
||
},
|
||
// Add r, r/m8
|
||
{
|
||
0x02, 0x00, 0x00, 0x01, IA32_PARAM_R_RM8, Ia32_Add
|
||
},
|
||
// Add r, r/m
|
||
{
|
||
0x03, 0x00, 0x00, 0x01, IA32_PARAM_R_RM, Ia32_Add
|
||
},
|
||
|
||
|
||
//
|
||
// And
|
||
//
|
||
|
||
// And r/m8, imm8
|
||
{
|
||
0x80, 0x00, 0x04, 0x11, IA32_PARAM_RM8_IMM8, Ia32_And
|
||
},
|
||
// And r/m, imm
|
||
{
|
||
0x81, 0x00, 0x04, 0x11, IA32_PARAM_RM_IMM, Ia32_And
|
||
},
|
||
// And r/m, imm8
|
||
{
|
||
0x83, 0x00, 0x04, 0x11, IA32_PARAM_RM_IMM8SIGN, Ia32_And
|
||
},
|
||
// And r/m8, r8
|
||
{
|
||
0x20, 0x00, 0x00, 0x01, IA32_PARAM_RM8_R, Ia32_And
|
||
},
|
||
// And rm, r
|
||
{
|
||
0x21, 0x00, 0x00, 0x01, IA32_PARAM_RM_R, Ia32_And
|
||
},
|
||
// And r8, r/m8
|
||
{
|
||
0x22, 0x00, 0x00, 0x01, IA32_PARAM_R_RM8, Ia32_And
|
||
},
|
||
// And r, r/m
|
||
{
|
||
0x23, 0x00, 0x00, 0x01, IA32_PARAM_R_RM, Ia32_And
|
||
},
|
||
|
||
|
||
//
|
||
// Or
|
||
//
|
||
|
||
// Or r/m8, imm8
|
||
{
|
||
0x80, 0x00, 0x01, 0x11, IA32_PARAM_RM8_IMM8, Ia32_Or
|
||
},
|
||
// Or r/m, imm
|
||
{
|
||
0x81, 0x00, 0x01, 0x11, IA32_PARAM_RM_IMM, Ia32_Or
|
||
},
|
||
// Or r/m, imm8
|
||
{
|
||
0x83, 0x00, 0x01, 0x11, IA32_PARAM_RM_IMM8SIGN, Ia32_Or
|
||
},
|
||
// Or r/m8, r8
|
||
{
|
||
0x08, 0x00, 0x00, 0x01, IA32_PARAM_RM8_R, Ia32_Or
|
||
},
|
||
// Or rm, r
|
||
{
|
||
0x09, 0x00, 0x00, 0x01, IA32_PARAM_RM_R, Ia32_Or
|
||
},
|
||
// Or r8, r/m8
|
||
{
|
||
0x0a, 0x00, 0x00, 0x01, IA32_PARAM_R_RM8, Ia32_Or
|
||
},
|
||
// Or r, r/m
|
||
{
|
||
0x0b, 0x00, 0x00, 0x01, IA32_PARAM_R_RM, Ia32_Or
|
||
},
|
||
|
||
//
|
||
// Xor
|
||
//
|
||
|
||
// Xor r/m8, imm8
|
||
{
|
||
0x80, 0x00, 0x06, 0x11, IA32_PARAM_RM8_IMM8, Ia32_Xor
|
||
},
|
||
// Xor r/m, imm
|
||
{
|
||
0x81, 0x00, 0x06, 0x11, IA32_PARAM_RM_IMM, Ia32_Xor
|
||
},
|
||
// Xor r/m, imm8
|
||
{
|
||
0x83, 0x00, 0x06, 0x11, IA32_PARAM_RM_IMM8SIGN, Ia32_Xor
|
||
},
|
||
// Xor r/m8, r8
|
||
{
|
||
0x30, 0x00, 0x00, 0x01, IA32_PARAM_RM8_R, Ia32_Xor
|
||
},
|
||
// Xor rm, r
|
||
{
|
||
0x31, 0x00, 0x00, 0x01, IA32_PARAM_RM_R, Ia32_Xor
|
||
},
|
||
// Xor r8, r/m8
|
||
{
|
||
0x32, 0x00, 0x00, 0x01, IA32_PARAM_R_RM8, Ia32_Xor
|
||
},
|
||
// Xor r, r/m
|
||
{
|
||
0x33, 0x00, 0x00, 0x01, IA32_PARAM_R_RM, Ia32_Xor
|
||
},
|
||
|
||
//
|
||
// Inc
|
||
//
|
||
|
||
// Inc r/m8
|
||
{
|
||
0xfe, 0x00, 0x00, 0x11, IA32_PARAM_RM8, Ia32_Inc
|
||
},
|
||
// Inc r/m
|
||
{
|
||
0xff, 0x00, 0x00, 0x11, IA32_PARAM_RM, Ia32_Inc
|
||
},
|
||
|
||
//
|
||
// Dec
|
||
//
|
||
|
||
// Dec r/m8
|
||
{
|
||
0xfe, 0x00, 0x01, 0x11, IA32_PARAM_RM8, Ia32_Dec
|
||
},
|
||
// Dec r/m
|
||
{
|
||
0xff, 0x00, 0x01, 0x11, IA32_PARAM_RM, Ia32_Dec
|
||
},
|
||
|
||
//
|
||
// Xchg
|
||
//
|
||
|
||
// Xchg r/m8, r
|
||
{
|
||
0x86, 0x00, 0x00, 0x01, IA32_PARAM_RM8_R, Ia32_Xchg
|
||
},
|
||
// Xchg r/m, r
|
||
{
|
||
0x87, 0x00, 0x00, 0x01, IA32_PARAM_RM_R, Ia32_Xchg
|
||
},
|
||
|
||
|
||
//
|
||
// Cmpxchg
|
||
//
|
||
|
||
// Cmpxchg r/m8, r
|
||
{
|
||
0x0f, 0xb0, 0x00, 0x02, IA32_PARAM_RM8_R, Ia32_Cmpxchg
|
||
},
|
||
// Cmpxchg r/m, r
|
||
{
|
||
0x0f, 0xb1, 0x00, 0x02, IA32_PARAM_RM_R, Ia32_Cmpxchg
|
||
},
|
||
|
||
//
|
||
// Cmpxchg8b
|
||
//
|
||
|
||
// Cmpxchg8b m64
|
||
{
|
||
0x0f, 0xc7, 0x01, 0x12, IA32_PARAM_RM, Ia32_Cmpxchg8b
|
||
},
|
||
|
||
//
|
||
// Xadd
|
||
//
|
||
|
||
// Xadd r/m8, r
|
||
{
|
||
0x0f, 0xc0, 0x00, 0x02, IA32_PARAM_RM8_R, Ia32_Xadd
|
||
},
|
||
// Xadd r/m, r
|
||
{
|
||
0x0f, 0xc1, 0x00, 0x02, IA32_PARAM_RM_R, Ia32_Xadd
|
||
},
|
||
|
||
|
||
//
|
||
// Neg
|
||
//
|
||
|
||
// Neg r/m8
|
||
{
|
||
0xf6, 0x00, 0x03, 0x11, IA32_PARAM_RM8, Ia32_Neg
|
||
},
|
||
// Neg r/m
|
||
{
|
||
0xf7, 0x00, 0x03, 0x11, IA32_PARAM_RM, Ia32_Neg
|
||
},
|
||
|
||
//
|
||
// Not
|
||
//
|
||
|
||
// Not r/m8
|
||
{
|
||
0xf6, 0x00, 0x02, 0x11, IA32_PARAM_RM8, Ia32_Not
|
||
},
|
||
// Not r/m
|
||
{
|
||
0xf7, 0x00, 0x02, 0x11, IA32_PARAM_RM, Ia32_Not
|
||
},
|
||
|
||
//
|
||
// Bt (Bit Test)
|
||
//
|
||
|
||
// Bt r/m, r
|
||
{
|
||
0x0f, 0xa3, 0x00, 0x02, IA32_PARAM_RM_R, Ia32_Bt
|
||
},
|
||
// Bt r/m, imm8
|
||
{
|
||
0x0f, 0xba, 0x04, 0x12, IA32_PARAM_RM_IMM8SIGN, Ia32_Bt
|
||
},
|
||
|
||
//
|
||
// Btc
|
||
//
|
||
|
||
// Btc r/m, r
|
||
{
|
||
0x0f, 0xbb, 0x00, 0x02, IA32_PARAM_RM_R, Ia32_Btc
|
||
},
|
||
// Btc r/m, imm8
|
||
{
|
||
0x0f, 0xba, 0x07, 0x12, IA32_PARAM_RM_IMM8SIGN, Ia32_Btc
|
||
},
|
||
|
||
//
|
||
// Btr
|
||
//
|
||
|
||
// Btr r/m, r
|
||
{
|
||
0x0f, 0xb3, 0x00, 0x02, IA32_PARAM_RM_R, Ia32_Btr
|
||
},
|
||
// Btr r/m, imm8
|
||
{
|
||
0x0f, 0xba, 0x06, 0x12, IA32_PARAM_RM_IMM8SIGN, Ia32_Btr
|
||
},
|
||
|
||
//
|
||
// Bts
|
||
//
|
||
|
||
// Bts r/m, r
|
||
{
|
||
0x0f, 0xab, 0x00, 0x02, IA32_PARAM_RM_R, Ia32_Bts
|
||
},
|
||
// Bts r/m, imm8
|
||
{
|
||
0x0f, 0xba, 0x05, 0x12, IA32_PARAM_RM_IMM8SIGN, Ia32_Bts
|
||
},
|
||
|
||
//
|
||
// Sub
|
||
//
|
||
|
||
// Sub r/m8, imm8
|
||
{
|
||
0x80, 0x00, 0x05, 0x11, IA32_PARAM_RM8_IMM8, Ia32_Sub
|
||
},
|
||
// Sub r/m, imm
|
||
{
|
||
0x81, 0x00, 0x05, 0x11, IA32_PARAM_RM_IMM, Ia32_Sub
|
||
},
|
||
// Sub r/m, imm8 (sign)
|
||
{
|
||
0x83, 0x00, 0x05, 0x11, IA32_PARAM_RM_IMM8SIGN, Ia32_Sub
|
||
},
|
||
// Sub r/m8, r8
|
||
{
|
||
0x28, 0x00, 0x00, 0x01, IA32_PARAM_RM8_R, Ia32_Sub
|
||
},
|
||
// Sub r/m, r
|
||
{
|
||
0x29, 0x00, 0x00, 0x01, IA32_PARAM_RM_R, Ia32_Sub
|
||
},
|
||
// Sub r, r/m8
|
||
{
|
||
0x2a, 0x00, 0x00, 0x01, IA32_PARAM_R_RM8, Ia32_Sub
|
||
},
|
||
// Sub r, r/m
|
||
{
|
||
0x2b, 0x00, 0x00, 0x01, IA32_PARAM_R_RM, Ia32_Sub
|
||
},
|
||
|
||
//
|
||
// Sbb
|
||
//
|
||
|
||
// Sbb r/m8, imm8
|
||
{
|
||
0x80, 0x00, 0x03, 0x11, IA32_PARAM_RM8_IMM8, Ia32_Sbb
|
||
},
|
||
// Sbb r/m, imm
|
||
{
|
||
0x81, 0x00, 0x03, 0x11, IA32_PARAM_RM_IMM, Ia32_Sbb
|
||
},
|
||
// Sbb r/m, imm8 (sign)
|
||
{
|
||
0x83, 0x00, 0x03, 0x11, IA32_PARAM_RM_IMM8SIGN, Ia32_Sbb
|
||
},
|
||
// Sbb r/m8, r8
|
||
{
|
||
0x18, 0x00, 0x00, 0x01, IA32_PARAM_RM8_R, Ia32_Sbb
|
||
},
|
||
// Sbb r/m, r
|
||
{
|
||
0x19, 0x00, 0x00, 0x01, IA32_PARAM_RM_R, Ia32_Sbb
|
||
},
|
||
// Sbb r, r/m8
|
||
{
|
||
0x1a, 0x00, 0x00, 0x01, IA32_PARAM_R_RM8, Ia32_Sbb
|
||
},
|
||
// Sbb r, r/m
|
||
{
|
||
0x1b, 0x00, 0x00, 0x01, IA32_PARAM_R_RM, Ia32_Sbb
|
||
},
|
||
|
||
|
||
//
|
||
// Mov
|
||
//
|
||
|
||
// Mov seg-reg, r/m8
|
||
{
|
||
0x8e, 0x00, 0x00, 0x01, IA32_PARAM_SEGREG_RM8, Ia32_MovToSeg
|
||
},
|
||
|
||
// Mov seg-reg, r/m
|
||
{
|
||
0x8e, 0x00, 0x00, 0x01, IA32_PARAM_SEGREG_RM, Ia32_MovToSeg
|
||
},
|
||
|
||
};
|
||
|
||
//
|
||
// Fast mutex that will serialize access to the instruction
|
||
// emulator when the lock prefix is set.
|
||
//
|
||
|
||
FAST_MUTEX KiIa32MisalignedLockFastMutex;
|
||
|
||
#define KiIa32AcquireMisalignedLockFastMutex() ExAcquireFastMutex(&KiIa32MisalignedLockFastMutex)
|
||
#define KiIa32ReleaseMisalignedLockFastMutex() ExReleaseFastMutex(&KiIa32MisalignedLockFastMutex)
|
||
|
||
|
||
//
|
||
// This table contains the offset into the KTRAP_FRAME
|
||
// for the appropriate register. This table is based on the
|
||
// needs of the x86 instruction R/M bits
|
||
//
|
||
|
||
const ULONG RegOffsetTable[8] =
|
||
{
|
||
FIELD_OFFSET(KTRAP_FRAME, IntV0), // EAX
|
||
FIELD_OFFSET(KTRAP_FRAME, IntT2), // ECX
|
||
FIELD_OFFSET(KTRAP_FRAME, IntT3), // EDX
|
||
FIELD_OFFSET(KTRAP_FRAME, IntT4), // EBX
|
||
FIELD_OFFSET(KTRAP_FRAME, IntSp), // ESP
|
||
FIELD_OFFSET(KTRAP_FRAME, IntTeb), // EBP
|
||
FIELD_OFFSET(KTRAP_FRAME, IntT5), // ESI
|
||
FIELD_OFFSET(KTRAP_FRAME, IntT6) // EDI
|
||
};
|
||
|
||
|
||
|
||
|
||
ULONG_PTR GetX86RegOffset (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN ULONG RegisterBase
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retreives the offset into the aliased ia64 register for the ia32 register
|
||
inside the trap frame.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame on the stack.
|
||
|
||
RegisterBase - Register number to retrieve the offset for.
|
||
|
||
Return Value:
|
||
|
||
Address of ia64 alias register for the ia32 register.
|
||
|
||
--*/
|
||
|
||
{
|
||
return (ULONG_PTR)((PCHAR)TrapFrame + RegOffsetTable[RegisterBase]);
|
||
}
|
||
|
||
|
||
ULONG GetX86Reg (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN ULONG RegisterBase
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retreives the ia32 register value.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame on the stack.
|
||
|
||
RegisterBase - Register number to retrieve the value for.
|
||
|
||
Return Value:
|
||
|
||
Ia32 register context.
|
||
|
||
--*/
|
||
|
||
{
|
||
return (ULONG)(*(PULONG_PTR)GetX86RegOffset(TrapFrame, RegisterBase));
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InitializeLockFastMutex (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initializes the misaligned lock fast mutex. Used to serialize
|
||
access if the r/m address is misaligned.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS.
|
||
|
||
--*/
|
||
|
||
{
|
||
ExInitializeFastMutex (&KiIa32MisalignedLockFastMutex);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
LONG
|
||
KiIa32ComputeSIBAddress(
|
||
IN PKTRAP_FRAME Frame,
|
||
IN LONG Displacement,
|
||
IN UCHAR Sib,
|
||
IN UCHAR ModRm
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Compute an effective address based on the SIB bytes in an instruction
|
||
using the register values in the trap frame
|
||
|
||
Arguments:
|
||
|
||
Frame - Pointer to iA32 TrapFrame in the stack.
|
||
|
||
Displacement - The value of the displacement byte. If no displacement, this
|
||
value should be passed in as zero.
|
||
|
||
Sib - The sib byte that is causing all the trouble.
|
||
|
||
ModRm - ModRm instruction value
|
||
|
||
Return Value:
|
||
|
||
The effective address to use for the memory operation
|
||
|
||
--*/
|
||
|
||
{
|
||
LONG Base;
|
||
LONG Index;
|
||
LONG Scale;
|
||
|
||
//
|
||
// First get the base address that we will be using
|
||
//
|
||
|
||
if ((Sib & MI_SIB_BASEMASK) == 5)
|
||
{
|
||
//
|
||
// Handle the special case where we don't use EBP for the base
|
||
//
|
||
|
||
//
|
||
// EBP is an implicit reg-base if the Mod is not zero.
|
||
//
|
||
if ((ModRm >> MI_MODSHIFT) != 0) {
|
||
Base = GetX86Reg (Frame, IA32_REG_EBP);
|
||
} else {
|
||
Base = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Base = GetX86Reg (Frame, (Sib & MI_SIB_BASEMASK) >> MI_SIB_BASESHIFT);
|
||
}
|
||
|
||
//
|
||
// Now get the Index
|
||
//
|
||
|
||
if ((Sib & MI_SIB_INDEXMASK) == MI_SIB_INDEXNONE)
|
||
{
|
||
//
|
||
// Handle the special case where we don't have an index
|
||
//
|
||
|
||
Index = 0;
|
||
}
|
||
else
|
||
{
|
||
Index = GetX86Reg (Frame, (Sib & MI_SIB_INDEXMASK) >> MI_SIB_INDEXSHIFT);
|
||
}
|
||
|
||
Scale = 1 << ((Sib & MI_SIB_SSMASK) >> MI_SIB_SSSHIFT);
|
||
|
||
return (Base + (Index * Scale) + Displacement);
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
KiIa32Compute32BitEffectiveAddress(
|
||
IN PKTRAP_FRAME Frame,
|
||
IN OUT PUCHAR *InstAddr,
|
||
OUT PUINT_PTR Addr,
|
||
OUT PBOOLEAN RegisterMode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Compute an effective address based on bytes in memory and the register
|
||
values passed in via the ia64 stack frame. The addressing mode is assumed to
|
||
be 32-bit.
|
||
|
||
Arguments:
|
||
|
||
Frame - Pointer to iA32 TrapFrame in the stack
|
||
|
||
InstAddr - Pointer to the first byte after the opcode.
|
||
|
||
Addr - Effective address.
|
||
|
||
RegisterMode - Indicates whether the effective address is inside a register or memory.
|
||
|
||
Return Value:
|
||
|
||
Returns TRUE if able to compute the EA, else returns FALSE.
|
||
|
||
Note:
|
||
|
||
Does not verify permission on an Effective Address. It only computes the
|
||
value and lets someone else worry if the process should have access to
|
||
that memory location.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
UNALIGNED ULONG * UlongAddress;
|
||
UCHAR ModRm;
|
||
UCHAR Sib = 0;
|
||
LONG UNALIGNED *DisplacementPtr;
|
||
BOOLEAN ReturnCode = TRUE;
|
||
|
||
|
||
//
|
||
// This needs to be a signed value. Start off assuming no displacement
|
||
//
|
||
|
||
LONG Displacement = 0;
|
||
|
||
try
|
||
{
|
||
|
||
ModRm = *(*InstAddr)++;
|
||
|
||
//
|
||
// handle the register case first
|
||
//
|
||
|
||
if ((ModRm >> MI_MODSHIFT) == 3)
|
||
{
|
||
|
||
//
|
||
// yup, we have a register - the easy case...
|
||
//
|
||
|
||
*Addr = GetX86RegOffset (Frame, ModRm & MI_RMMASK);
|
||
*RegisterMode = TRUE;
|
||
return ReturnCode;
|
||
}
|
||
|
||
*RegisterMode = FALSE;
|
||
|
||
//
|
||
// See if we have a SIB
|
||
//
|
||
|
||
if ((ModRm & MI_RMMASK) == 4)
|
||
{
|
||
Sib = *(*InstAddr)++;
|
||
}
|
||
|
||
//
|
||
// Now decode the destination bits
|
||
//
|
||
|
||
switch (ModRm >> MI_MODSHIFT)
|
||
{
|
||
case 0:
|
||
|
||
//
|
||
// We have an indirect through a register
|
||
//
|
||
|
||
switch (ModRm & MI_RMMASK)
|
||
{
|
||
case 4:
|
||
|
||
//
|
||
// Deal with the SIB
|
||
//
|
||
|
||
*Addr = KiIa32ComputeSIBAddress (Frame, Displacement, Sib, ModRm);
|
||
break;
|
||
|
||
case 5:
|
||
|
||
//
|
||
// We have a 32-bit indirect...
|
||
//
|
||
|
||
UlongAddress = (UNALIGNED ULONG *)*InstAddr;
|
||
*Addr = *UlongAddress;
|
||
*InstAddr = (PUCHAR) (UlongAddress + 1);
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// The default case is get the address from the register
|
||
//
|
||
|
||
*Addr = GetX86Reg (Frame, (ModRm & MI_RMMASK));
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 1:
|
||
|
||
//
|
||
// we have an 8 bit displacement, so grab the next byte
|
||
//
|
||
|
||
Displacement = (signed char) (*(*InstAddr)++);
|
||
if ((ModRm & MI_RMMASK) == 4)
|
||
{
|
||
//
|
||
// Have a SIB, so do that
|
||
//
|
||
|
||
*Addr = KiIa32ComputeSIBAddress (Frame, Displacement, Sib, ModRm);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// No SIB, life is easy
|
||
//
|
||
*Addr = GetX86Reg (Frame, (ModRm & MI_RMMASK)) + Displacement;
|
||
}
|
||
break;
|
||
|
||
case 2:
|
||
//
|
||
// we have a 32-bit displacement, so grab the next 4 bytes
|
||
//
|
||
|
||
DisplacementPtr = (PLONG) (*InstAddr);
|
||
Displacement = *DisplacementPtr++;
|
||
*InstAddr = (PUCHAR)DisplacementPtr;
|
||
|
||
if ((ModRm & MI_RMMASK) == 4)
|
||
{
|
||
//
|
||
// Have a SIB, so do that
|
||
//
|
||
|
||
*Addr = KiIa32ComputeSIBAddress (Frame, Displacement, Sib, ModRm);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// No SIB, life is easy
|
||
//
|
||
|
||
*Addr = GetX86Reg (Frame, (ModRm & MI_RMMASK)) + Displacement;
|
||
}
|
||
break;
|
||
|
||
|
||
default:
|
||
|
||
//
|
||
// we should have handled case 3 (register access)
|
||
// before getting here...
|
||
//
|
||
|
||
ReturnCode = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
ReturnCode = FALSE;
|
||
|
||
#if DBG
|
||
if (KiIa32InstructionEmulationDbg)
|
||
{
|
||
DbgPrint("KE: KiIa32Compute32BitEffectiveAddress - Exception %lx\n",
|
||
GetExceptionCode());
|
||
}
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// Make sure the address stays within 4GB range
|
||
//
|
||
if (ReturnCode == TRUE) {
|
||
|
||
*Addr = (*Addr & 0x000000007fffffffI64);
|
||
}
|
||
|
||
return ReturnCode;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
KiIa32Compute16BitEffectiveAddress (
|
||
IN PKTRAP_FRAME Frame,
|
||
IN OUT PUCHAR *InstAddr,
|
||
OUT PUINT_PTR Addr,
|
||
OUT PBOOLEAN RegisterMode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Compute an effective address based on bytes in memory and
|
||
the register values passed in via the ia64 stack frame. The addressing
|
||
mode is assumed to be 16-bit.
|
||
|
||
Arguments:
|
||
|
||
Frame - Pointer to iA32 TrapFrame in the stack.
|
||
|
||
InstAddr - Pointer to the first byte after the opcode.
|
||
|
||
Addr - Effective address.
|
||
|
||
RegisterMode - Indicates whether the effective address is inside a register or memory.
|
||
|
||
Return Value:
|
||
|
||
Returns TRUE if able to compute the EA, else returns FALSE.
|
||
|
||
Note:
|
||
|
||
Does not verify permission on an Effective Address. It only computes the
|
||
value and lets someone else worry if the process should have access to
|
||
that memory location.
|
||
|
||
--*/
|
||
|
||
{
|
||
UCHAR ModRm;
|
||
UCHAR DisplacementType = IA32_DISP_NONE;
|
||
USHORT UNALIGNED *Disp16;
|
||
LONG EffectiveAddress = 0;
|
||
BOOLEAN ReturnCode = TRUE;
|
||
|
||
|
||
try
|
||
{
|
||
//
|
||
// Read in the Mod/Rm and increment the instruction address
|
||
//
|
||
|
||
ModRm = *(*InstAddr)++;
|
||
|
||
*RegisterMode = FALSE;
|
||
|
||
//
|
||
// First pass
|
||
//
|
||
|
||
switch (ModRm >> MI_MODSHIFT)
|
||
{
|
||
case 0:
|
||
if ((ModRm & MI_RMMASK) == 6)
|
||
{
|
||
Disp16 = (USHORT UNALIGNED *) InstAddr;
|
||
*Addr = *Disp16;
|
||
*InstAddr = (*InstAddr + 2);
|
||
return ReturnCode;
|
||
}
|
||
|
||
DisplacementType = IA32_DISP_NONE;
|
||
break;
|
||
|
||
case 1:
|
||
DisplacementType = IA32_DISP8;
|
||
break;
|
||
|
||
case 2:
|
||
DisplacementType = IA32_DISP16;
|
||
break;
|
||
|
||
case 3:
|
||
*Addr = GetX86RegOffset (Frame, ModRm & MI_RMMASK);
|
||
*RegisterMode = TRUE;
|
||
return ReturnCode;
|
||
}
|
||
|
||
//
|
||
// Second pass
|
||
//
|
||
|
||
switch (ModRm & MI_RMMASK)
|
||
{
|
||
case 0:
|
||
EffectiveAddress = (GetX86Reg(Frame, IA32_REG_EBX) & 0xffff) +
|
||
(GetX86Reg(Frame, IA32_REG_ESI) & 0xffff) ;
|
||
break;
|
||
case 1:
|
||
EffectiveAddress = (GetX86Reg(Frame, IA32_REG_EBX) & 0xffff) +
|
||
(GetX86Reg(Frame, IA32_REG_EDI) & 0xffff) ;
|
||
break;
|
||
case 2:
|
||
EffectiveAddress = (GetX86Reg(Frame, IA32_REG_EBP) & 0xffff) +
|
||
(GetX86Reg(Frame, IA32_REG_ESI) & 0xffff) ;
|
||
break;
|
||
case 3:
|
||
EffectiveAddress = (GetX86Reg(Frame, IA32_REG_EBP) & 0xffff) +
|
||
(GetX86Reg(Frame, IA32_REG_EDI) & 0xffff) ;
|
||
break;
|
||
case 4:
|
||
EffectiveAddress = (GetX86Reg(Frame, IA32_REG_ESI) & 0xffff);
|
||
break;
|
||
case 5:
|
||
EffectiveAddress = (GetX86Reg(Frame, IA32_REG_EDI) & 0xffff);
|
||
break;
|
||
case 6:
|
||
EffectiveAddress = (GetX86Reg(Frame, IA32_REG_EBP) & 0xffff);
|
||
break;
|
||
case 7:
|
||
EffectiveAddress = (GetX86Reg(Frame, IA32_REG_EBX) & 0xffff);
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Read the displacement, if any
|
||
//
|
||
|
||
if (DisplacementType != IA32_DISP_NONE)
|
||
{
|
||
switch (DisplacementType)
|
||
{
|
||
case IA32_DISP8:
|
||
{
|
||
EffectiveAddress += (LONG) (**InstAddr);
|
||
*InstAddr = *InstAddr + 1;
|
||
}
|
||
break;
|
||
|
||
case IA32_DISP16:
|
||
{
|
||
Disp16 = (USHORT UNALIGNED *) InstAddr;
|
||
EffectiveAddress += (LONG) *Disp16;
|
||
*InstAddr = *InstAddr + 2;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
#if DBG
|
||
DbgPrint("KE: KiIa32Compute16BitEffectiveAddress - Invalid displacement type %lx\n",
|
||
DisplacementType);
|
||
#endif
|
||
ReturnCode = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
*Addr = EffectiveAddress;
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
#if DBG
|
||
if (KiIa32InstructionEmulationDbg)
|
||
{
|
||
DbgPrint("KE: KiIa32Compute16BitEffectiveAddress - Exception %lx\n",
|
||
GetExceptionCode());
|
||
}
|
||
#endif
|
||
ReturnCode = FALSE;
|
||
}
|
||
|
||
//
|
||
// Make sure the address stays within 4GB range
|
||
//
|
||
if (ReturnCode == TRUE) {
|
||
|
||
*Addr = (*Addr & 0x000000007fffffffI64);
|
||
}
|
||
|
||
return ReturnCode;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32UpdateFlags (
|
||
IN PIA32_INSTRUCTION Instruction,
|
||
IN ULONGLONG Operand1,
|
||
IN ULONGLONG Result,
|
||
IN ULONG Ia32Eflags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Updates the Ia32 specified eflags according to the result value.
|
||
|
||
Arguments:
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Operand1 - First operand (value) of the instruction being emulated.
|
||
|
||
Result - Result value.
|
||
|
||
Ia32Eflags - Specific flags to update based on the result value.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONGLONG Temp = 0;
|
||
IA32_EFLAGS Eflags = Instruction->Eflags;
|
||
|
||
|
||
//
|
||
// Sanitize the destination value.
|
||
//
|
||
|
||
Result = (Result & MAXULONG);
|
||
|
||
if ((Ia32Eflags & IA32_EFLAGS_CF) != 0)
|
||
{
|
||
if (Result > Instruction->OperandMask)
|
||
{
|
||
Eflags.u.cf = 1;
|
||
}
|
||
else
|
||
{
|
||
Eflags.u.cf = 0;
|
||
}
|
||
}
|
||
|
||
if ((Ia32Eflags & IA32_EFLAGS_OF) != 0)
|
||
{
|
||
if (((Operand1 & Result) & 0x80000000UI64) != 0)
|
||
{
|
||
Eflags.u.of = 1;
|
||
}
|
||
else
|
||
{
|
||
Eflags.u.of = 0;
|
||
}
|
||
}
|
||
|
||
if ((Ia32Eflags & IA32_EFLAGS_SF) != 0)
|
||
{
|
||
switch (Instruction->OperandSize)
|
||
{
|
||
case 0xff:
|
||
Temp = 0x80UI64;
|
||
break;
|
||
|
||
case 0xffff:
|
||
Temp = 0x8000UI64;
|
||
break;
|
||
|
||
case 0xffffffff:
|
||
Temp = 0x80000000UI64;
|
||
break;
|
||
}
|
||
|
||
if (Result & Temp)
|
||
{
|
||
Eflags.u.sf = 1;
|
||
}
|
||
else
|
||
{
|
||
Eflags.u.sf = 0;
|
||
}
|
||
}
|
||
|
||
if ((Ia32Eflags & IA32_EFLAGS_ZF) != 0)
|
||
{
|
||
if (Result == 0)
|
||
{
|
||
Eflags.u.zf = 1;
|
||
}
|
||
else
|
||
{
|
||
Eflags.u.zf = 0;
|
||
}
|
||
}
|
||
|
||
if ((Ia32Eflags & IA32_EFLAGS_AF) != 0)
|
||
{
|
||
Eflags.u.af = (((Operand1 ^ Result) >> 4) & 0x01UI64);
|
||
}
|
||
|
||
//
|
||
// This needs to be the last one as it modifies the 'Result'
|
||
//
|
||
|
||
if ((Ia32Eflags & IA32_EFLAGS_PF) != 0)
|
||
{
|
||
Result = Result & Instruction->OperandMask;
|
||
|
||
Temp = 0;
|
||
while (Result)
|
||
{
|
||
Result = (Result & (Result - 1));
|
||
Temp++;
|
||
}
|
||
|
||
if ((Temp & 0x01UI64) == 0)
|
||
{
|
||
Eflags.u.pf = 1;
|
||
}
|
||
else
|
||
{
|
||
Eflags.u.pf = 1;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Reset reserved values.
|
||
//
|
||
|
||
Eflags.u.v1 = 1;
|
||
Eflags.u.v2 = 0;
|
||
Eflags.u.v3 = 0;
|
||
Eflags.u.v4 = 0;
|
||
|
||
//
|
||
// Sanitize the flags
|
||
//
|
||
|
||
Eflags.Value = SANITIZE_AR24_EFLAGS (Eflags.Value, UserMode);
|
||
|
||
Instruction->Eflags = Eflags;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32UpdateResult (
|
||
IN PIA32_INSTRUCTION Instruction,
|
||
IN PIA32_OPERAND DestinationOperand,
|
||
IN ULONGLONG Result
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes the result value taking into consideration operand size.
|
||
|
||
Arguments:
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
DestinationOperand - Operand to receive the result.
|
||
|
||
Result - Result value to write
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
UNALIGNED USHORT *UshortPtr;
|
||
UNALIGNED ULONG *UlongPtr;
|
||
NTSTATUS NtStatus = STATUS_SUCCESS;
|
||
PVOID MaxWowAddress;
|
||
|
||
MaxWowAddress = MmGetMaxWowAddress ();
|
||
|
||
//
|
||
// Update results according to operand size
|
||
//
|
||
|
||
try
|
||
{
|
||
if (DestinationOperand->RegisterMode == FALSE)
|
||
{
|
||
if ((PVOID)DestinationOperand->v >= MaxWowAddress)
|
||
{
|
||
return STATUS_ACCESS_VIOLATION;
|
||
}
|
||
}
|
||
|
||
switch (Instruction->OperandSize)
|
||
{
|
||
case OPERANDSIZE_ONEBYTE:
|
||
*(PUCHAR)DestinationOperand->v = (UCHAR)Result;
|
||
break;
|
||
|
||
case OPERANDSIZE_TWOBYTES:
|
||
UshortPtr = (UNALIGNED USHORT *) DestinationOperand->v;
|
||
*UshortPtr = (USHORT)Result;
|
||
break;
|
||
|
||
case OPERANDSIZE_FOURBYTES:
|
||
UlongPtr =(UNALIGNED ULONG *) DestinationOperand->v;
|
||
*UlongPtr = (ULONG)Result;
|
||
break;
|
||
|
||
default:
|
||
#if DBG
|
||
if (KiIa32InstructionEmulationDbg)
|
||
{
|
||
DbgPrint("KE: KiIa32UpdateResult() - Invalid operand size - %lx - %p\n",
|
||
Instruction->OperandSize, Instruction);
|
||
}
|
||
#endif
|
||
NtStatus = STATUS_UNSUCCESSFUL;
|
||
break;
|
||
}
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
NtStatus = GetExceptionCode ();
|
||
|
||
#if DBG
|
||
DbgPrint("KE: KiIa32UpdateResult - Exception %lx - %p\n",
|
||
NtStatus, Instruction);
|
||
#endif
|
||
}
|
||
|
||
return NtStatus;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32ReadOperand1 (
|
||
IN PIA32_INSTRUCTION Instruction,
|
||
OUT PULONGLONG Operand1
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the first (destination) operand of an instruction.
|
||
|
||
Arguments:
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Operand1 - Buffer to receive the operand value.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
UNALIGNED ULONG *UlongPtr;
|
||
UNALIGNED USHORT *UshortPtr;
|
||
NTSTATUS NtStatus = STATUS_SUCCESS;
|
||
|
||
|
||
try
|
||
{
|
||
switch (Instruction->Description->Type)
|
||
{
|
||
case IA32_PARAM_RM_IMM8SIGN:
|
||
case IA32_PARAM_RM_IMM:
|
||
case IA32_PARAM_RM_R:
|
||
case IA32_PARAM_R_RM8:
|
||
case IA32_PARAM_R_RM:
|
||
case IA32_PARAM_RM:
|
||
case IA32_PARAM_SEGREG_RM:
|
||
if (Instruction->OperandSize == OPERANDSIZE_TWOBYTES)
|
||
{
|
||
UshortPtr = (UNALIGNED USHORT *) Instruction->Operand1.v;
|
||
*Operand1 = (ULONGLONG) *UshortPtr;
|
||
}
|
||
else
|
||
{
|
||
UlongPtr = (UNALIGNED ULONG *) Instruction->Operand1.v;
|
||
*Operand1 = (ULONGLONG) *UlongPtr;
|
||
}
|
||
break;
|
||
|
||
case IA32_PARAM_RM8_IMM8:
|
||
case IA32_PARAM_RM8_R:
|
||
case IA32_PARAM_RM8:
|
||
case IA32_PARAM_SEGREG_RM8:
|
||
*Operand1 = (ULONGLONG) (*(PUCHAR)Instruction->Operand1.v);
|
||
break;
|
||
|
||
default:
|
||
#if DBG
|
||
if (KiIa32InstructionEmulationDbg)
|
||
{
|
||
DbgPrint("KE: KiIa32ReadRm - Invalid opcode type %lx - %p\n",
|
||
Instruction->Description->Type, Instruction);
|
||
}
|
||
NtStatus = STATUS_UNSUCCESSFUL;
|
||
#endif
|
||
break;
|
||
}
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
NtStatus = GetExceptionCode ();
|
||
#if DBG
|
||
DbgPrint("KE: KiIa32ReadOperand1 - Exception %lx - %p\n",
|
||
NtStatus, Instruction);
|
||
#endif
|
||
}
|
||
|
||
return NtStatus;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32ReadOperand2 (
|
||
IN PIA32_INSTRUCTION Instruction,
|
||
OUT PULONGLONG Operand2
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the second (source) operand of an instruction.
|
||
|
||
Arguments:
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Operand1 - Buffer to receive the operand value.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
UNALIGNED ULONG *UlongPtr;
|
||
UNALIGNED USHORT *UshortPtr;
|
||
NTSTATUS NtStatus = STATUS_SUCCESS;
|
||
|
||
try
|
||
{
|
||
switch (Instruction->Description->Type)
|
||
{
|
||
case IA32_PARAM_RM8_IMM8:
|
||
case IA32_PARAM_RM_IMM8SIGN:
|
||
*Operand2 = (UCHAR)Instruction->Operand2.v;
|
||
break;
|
||
|
||
case IA32_PARAM_RM_IMM:
|
||
*Operand2 = Instruction->Operand2.v & Instruction->OperandMask;
|
||
break;
|
||
|
||
case IA32_PARAM_RM8_R:
|
||
case IA32_PARAM_R_RM8:
|
||
*Operand2 = (ULONGLONG)(*(PUCHAR)Instruction->Operand2.v);
|
||
break;
|
||
|
||
case IA32_PARAM_RM_R:
|
||
case IA32_PARAM_R_RM:
|
||
if (Instruction->OperandSize == OPERANDSIZE_TWOBYTES)
|
||
{
|
||
UshortPtr = (UNALIGNED USHORT *) Instruction->Operand2.v;
|
||
*Operand2 = (ULONGLONG) *UshortPtr;
|
||
}
|
||
else
|
||
{
|
||
UlongPtr = (UNALIGNED ULONG *) Instruction->Operand2.v;
|
||
*Operand2 = (ULONGLONG) *UlongPtr;
|
||
}
|
||
break;
|
||
|
||
case IA32_PARAM_SEGREG_RM8:
|
||
case IA32_PARAM_SEGREG_RM:
|
||
break;
|
||
|
||
default:
|
||
#if DBG
|
||
if (KiIa32InstructionEmulationDbg)
|
||
{
|
||
DbgPrint("KE: KiIa32ReadOperand2 - Invalid type %lx - %p\n",
|
||
Instruction->Description->Type, Instruction);
|
||
}
|
||
NtStatus = STATUS_UNSUCCESSFUL;
|
||
#endif
|
||
break;
|
||
}
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
NtStatus = GetExceptionCode ();
|
||
#if DBG
|
||
DbgPrint("KE: KiIa32ReadOperand2 - Exception %lx - %p\n",
|
||
NtStatus, Instruction);
|
||
#endif
|
||
}
|
||
|
||
return NtStatus;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionAddWithIncrement (
|
||
IN PIA32_INSTRUCTION Instruction,
|
||
IN ULONG Increment
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Common routine implementing Ia32 add, adc, sub and sbb instructions.
|
||
|
||
Arguments:
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Increment - Specifies the carry value.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONGLONG UlongDst;
|
||
ULONGLONG UlongSrc;
|
||
ULONGLONG Operand1;
|
||
UCHAR Imm8;
|
||
char SignImm8;
|
||
BOOLEAN Subtract;
|
||
NTSTATUS NtStatus;
|
||
|
||
|
||
switch (Instruction->Description->Opcode)
|
||
{
|
||
case Ia32_Add:
|
||
case Ia32_Adc:
|
||
Subtract = FALSE;
|
||
break;
|
||
|
||
case Ia32_Sub:
|
||
case Ia32_Sbb:
|
||
Subtract = TRUE;
|
||
break;
|
||
|
||
default:
|
||
#if DBG
|
||
if (KiIa32InstructionEmulationDbg)
|
||
{
|
||
DbgPrint("KE: KiIa32InstructionAddWithIncrement - Invalid opcode %lx - %p\n",
|
||
Instruction->Description->Opcode, Instruction);
|
||
}
|
||
#endif
|
||
return STATUS_UNSUCCESSFUL;
|
||
break;
|
||
|
||
}
|
||
|
||
NtStatus = KiIa32ReadOperand1 (Instruction, &UlongDst);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
Operand1 = UlongDst;
|
||
|
||
NtStatus = KiIa32ReadOperand2 (Instruction, &UlongSrc);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
switch (Instruction->Description->Type)
|
||
{
|
||
case IA32_PARAM_RM_IMM8SIGN:
|
||
SignImm8 = (char) UlongSrc;
|
||
if (Subtract)
|
||
UlongDst = (UlongDst - (Increment + SignImm8));
|
||
else
|
||
UlongDst = UlongDst + Increment + SignImm8;
|
||
break;
|
||
|
||
case IA32_PARAM_RM8_IMM8:
|
||
Imm8 = (UCHAR) UlongSrc;
|
||
if (Subtract)
|
||
UlongDst = (UlongDst - (Increment + Imm8));
|
||
else
|
||
UlongDst = UlongDst + Increment + Imm8;
|
||
break;
|
||
|
||
case IA32_PARAM_RM_IMM:
|
||
default:
|
||
if (Subtract)
|
||
UlongDst = (UlongDst - (Increment + UlongSrc));
|
||
else
|
||
UlongDst = UlongDst + Increment + UlongSrc;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Update results according to operand size
|
||
//
|
||
|
||
NtStatus = KiIa32UpdateResult (
|
||
Instruction,
|
||
&Instruction->Operand1,
|
||
UlongDst
|
||
);
|
||
|
||
//
|
||
// Eflags update
|
||
//
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
KiIa32UpdateFlags (
|
||
Instruction,
|
||
Operand1,
|
||
UlongDst,
|
||
(IA32_EFLAGS_CF | IA32_EFLAGS_SF | IA32_EFLAGS_OF |
|
||
IA32_EFLAGS_PF | IA32_EFLAGS_ZF | IA32_EFLAGS_AF)
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
return NtStatus;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionAdc (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Adc instruction handler.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
return KiIa32InstructionAddWithIncrement (
|
||
Instruction,
|
||
(ULONG)Instruction->Eflags.u.cf);
|
||
|
||
UNREFERENCED_PARAMETER (TrapFrame);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionAdd (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Add instruction handler.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
return KiIa32InstructionAddWithIncrement (
|
||
Instruction,
|
||
0);
|
||
|
||
UNREFERENCED_PARAMETER (TrapFrame);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionArithmeticBitwiseHelper (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
And, Or & Xor instructions handler.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONGLONG UlongDst;
|
||
ULONGLONG UlongSrc;
|
||
ULONGLONG Operand1;
|
||
NTSTATUS NtStatus;
|
||
|
||
|
||
NtStatus = KiIa32ReadOperand1 (Instruction, &UlongDst);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
Operand1 = UlongDst;
|
||
|
||
NtStatus = KiIa32ReadOperand2 (Instruction, &UlongSrc);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
switch (Instruction->Description->Opcode)
|
||
{
|
||
case Ia32_And:
|
||
UlongDst = UlongDst & UlongSrc;
|
||
break;
|
||
|
||
case Ia32_Or:
|
||
UlongDst = UlongDst | UlongSrc;
|
||
break;
|
||
|
||
case Ia32_Xor:
|
||
UlongDst = UlongDst ^ UlongSrc;
|
||
break;
|
||
|
||
default:
|
||
#if DBG
|
||
NtStatus = STATUS_UNSUCCESSFUL;
|
||
if (KiIa32InstructionEmulationDbg)
|
||
{
|
||
DbgPrint("KE: KiIa32InstructionBitwiseHelper - Invalid operation %lx - %p\n",
|
||
Instruction->Description->Opcode, Instruction);
|
||
}
|
||
#endif
|
||
break;
|
||
}
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
NtStatus = KiIa32UpdateResult (
|
||
Instruction,
|
||
&Instruction->Operand1,
|
||
UlongDst
|
||
);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
NtStatus = KiIa32UpdateFlags (
|
||
Instruction,
|
||
Operand1,
|
||
UlongDst,
|
||
(IA32_EFLAGS_SF | IA32_EFLAGS_PF | IA32_EFLAGS_ZF)
|
||
);
|
||
|
||
Instruction->Eflags.u.cf = 0;
|
||
Instruction->Eflags.u.of = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return NtStatus;
|
||
|
||
UNREFERENCED_PARAMETER (TrapFrame);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionBitTestHelper (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Bt, Bts, Btr & Btc instructions handler.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONGLONG UlongDst;
|
||
ULONGLONG UlongSrc;
|
||
ULONGLONG BitTestResult;
|
||
NTSTATUS NtStatus;
|
||
|
||
|
||
|
||
NtStatus = KiIa32ReadOperand2 (Instruction, &UlongSrc);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
if (Instruction->Operand2.RegisterMode == TRUE)
|
||
{
|
||
if (Instruction->Prefix.b.AddressOverride == 1)
|
||
{
|
||
Instruction->Operand1.v += ((UlongSrc >> 4) << 1);
|
||
UlongSrc &= 0x0f;
|
||
}
|
||
else
|
||
{
|
||
Instruction->Operand1.v += ((UlongSrc >> 5) << 2);
|
||
UlongSrc &= 0x1f;
|
||
}
|
||
}
|
||
|
||
NtStatus = KiIa32ReadOperand1 (Instruction, &UlongDst);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
|
||
BitTestResult = (UlongDst & (1 << UlongSrc));
|
||
|
||
if (BitTestResult)
|
||
{
|
||
Instruction->Eflags.u.cf = 1;
|
||
}
|
||
else
|
||
{
|
||
Instruction->Eflags.u.cf = 0;
|
||
}
|
||
|
||
switch (Instruction->Description->Opcode)
|
||
{
|
||
case Ia32_Btc:
|
||
UlongDst ^= (1 << UlongSrc);
|
||
break;
|
||
|
||
case Ia32_Btr:
|
||
UlongDst &= (~(1 << UlongSrc));
|
||
break;
|
||
|
||
case Ia32_Bts:
|
||
UlongDst |= (1 << UlongSrc);
|
||
break;
|
||
}
|
||
|
||
NtStatus = KiIa32UpdateResult (
|
||
Instruction,
|
||
&Instruction->Operand1,
|
||
UlongDst
|
||
);
|
||
}
|
||
}
|
||
|
||
return NtStatus;
|
||
|
||
UNREFERENCED_PARAMETER (TrapFrame);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionOneParamHelper (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Inc, Dec, Neg & Not instructions handler.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
UCHAR Opcode;
|
||
ULONG FlagsAffected = 0;
|
||
ULONGLONG UlongDst;
|
||
ULONGLONG UlongSrc;
|
||
NTSTATUS NtStatus;
|
||
|
||
|
||
NtStatus = KiIa32ReadOperand1 (
|
||
Instruction,
|
||
&UlongDst
|
||
);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
|
||
UlongSrc = UlongDst;
|
||
Opcode = Instruction->Description->Opcode;
|
||
|
||
switch (Opcode)
|
||
{
|
||
case Ia32_Inc:
|
||
UlongDst += 1;
|
||
break;
|
||
|
||
case Ia32_Dec:
|
||
UlongDst -= 1;
|
||
break;
|
||
|
||
case Ia32_Neg:
|
||
UlongDst = -(LONGLONG)UlongDst;
|
||
break;
|
||
|
||
case Ia32_Not:
|
||
UlongDst = ~UlongDst;
|
||
break;
|
||
}
|
||
|
||
NtStatus = KiIa32UpdateResult (
|
||
Instruction,
|
||
&Instruction->Operand1,
|
||
UlongDst
|
||
);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
|
||
switch (Opcode)
|
||
{
|
||
case Ia32_Inc:
|
||
case Ia32_Dec:
|
||
FlagsAffected = (IA32_EFLAGS_SF | IA32_EFLAGS_PF |
|
||
IA32_EFLAGS_ZF);
|
||
|
||
break;
|
||
|
||
case Ia32_Neg:
|
||
if (UlongDst == 0)
|
||
Instruction->Eflags.u.cf = 0;
|
||
else
|
||
Instruction->Eflags.u.cf = 1;
|
||
|
||
FlagsAffected = (IA32_EFLAGS_SF | IA32_EFLAGS_PF |
|
||
IA32_EFLAGS_ZF | IA32_EFLAGS_AF | IA32_EFLAGS_OF);
|
||
break;
|
||
}
|
||
|
||
|
||
if (FlagsAffected != 0)
|
||
{
|
||
NtStatus = KiIa32UpdateFlags (
|
||
Instruction,
|
||
UlongSrc,
|
||
UlongDst,
|
||
FlagsAffected
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
return NtStatus;
|
||
|
||
UNREFERENCED_PARAMETER (TrapFrame);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionXadd (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Xadd instruction handler.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONGLONG UlongDst;
|
||
ULONGLONG UlongSrc;
|
||
ULONGLONG Operand1;
|
||
ULONGLONG Temp;
|
||
NTSTATUS NtStatus;
|
||
|
||
|
||
NtStatus = KiIa32ReadOperand1 (Instruction, &UlongDst);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
Operand1 = UlongDst;
|
||
|
||
NtStatus = KiIa32ReadOperand2 (Instruction, &UlongSrc);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
Temp = UlongDst;
|
||
UlongDst += UlongSrc;
|
||
|
||
NtStatus = KiIa32UpdateResult (
|
||
Instruction,
|
||
&Instruction->Operand1,
|
||
UlongDst
|
||
);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
NtStatus = KiIa32UpdateResult (
|
||
Instruction,
|
||
&Instruction->Operand2,
|
||
Temp
|
||
);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
NtStatus = KiIa32UpdateFlags (
|
||
Instruction,
|
||
Operand1,
|
||
UlongDst,
|
||
(IA32_EFLAGS_CF | IA32_EFLAGS_SF | IA32_EFLAGS_PF |
|
||
IA32_EFLAGS_ZF | IA32_EFLAGS_OF | IA32_EFLAGS_AF)
|
||
);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return NtStatus;
|
||
|
||
UNREFERENCED_PARAMETER (TrapFrame);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionXchg (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Xchg instruction handler.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONGLONG UlongDst;
|
||
ULONGLONG UlongSrc;
|
||
NTSTATUS NtStatus;
|
||
|
||
|
||
NtStatus = KiIa32ReadOperand1 (Instruction, &UlongDst);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
NtStatus = KiIa32ReadOperand2 (Instruction, &UlongSrc);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
NtStatus = KiIa32UpdateResult (
|
||
Instruction,
|
||
&Instruction->Operand1,
|
||
UlongSrc
|
||
);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
NtStatus = KiIa32UpdateResult (
|
||
Instruction,
|
||
&Instruction->Operand2,
|
||
UlongDst
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
return NtStatus;
|
||
|
||
UNREFERENCED_PARAMETER (TrapFrame);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionCmpXchg (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Cmpxchg instruction handler.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONGLONG UlongDst;
|
||
ULONGLONG UlongSrc;
|
||
ULONGLONG Accumulator;
|
||
IA32_OPERAND AccumulatorOperand;
|
||
NTSTATUS NtStatus;
|
||
|
||
|
||
NtStatus = KiIa32ReadOperand1 (Instruction, &UlongDst);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
NtStatus = KiIa32ReadOperand2 (Instruction, &UlongSrc);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
Accumulator = GetX86Reg (TrapFrame, IA32_REG_EAX);
|
||
Accumulator &= Instruction->OperandMask;
|
||
|
||
if (Accumulator == UlongDst)
|
||
{
|
||
Instruction->Eflags.u.zf = 1;
|
||
|
||
NtStatus = KiIa32UpdateResult (
|
||
Instruction,
|
||
&Instruction->Operand1,
|
||
UlongSrc
|
||
);
|
||
}
|
||
else
|
||
{
|
||
Instruction->Eflags.u.zf = 0;
|
||
|
||
AccumulatorOperand.RegisterMode = TRUE;
|
||
AccumulatorOperand.v = GetX86RegOffset (TrapFrame, IA32_REG_EAX);
|
||
|
||
NtStatus = KiIa32UpdateResult (
|
||
Instruction,
|
||
&AccumulatorOperand,
|
||
UlongDst
|
||
);
|
||
}
|
||
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
NtStatus = KiIa32UpdateFlags (
|
||
Instruction,
|
||
UlongDst,
|
||
UlongDst,
|
||
(IA32_EFLAGS_CF | IA32_EFLAGS_SF |
|
||
IA32_EFLAGS_PF | IA32_EFLAGS_OF |
|
||
IA32_EFLAGS_AF)
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
return NtStatus;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionCmpXchg8b (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Cmpxchg8b instruction handler.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
UNALIGNED ULONGLONG *UlongDst;
|
||
UNALIGNED ULONGLONG *UlongSrc;
|
||
ULONGLONG EdxEax;
|
||
|
||
|
||
EdxEax = GetX86Reg (TrapFrame, IA32_REG_EDX);
|
||
EdxEax <<= 32;
|
||
EdxEax |= GetX86Reg (TrapFrame, IA32_REG_EAX);
|
||
|
||
UlongDst = (PULONGLONG)Instruction->Operand1.v;
|
||
|
||
if (*UlongDst == EdxEax)
|
||
{
|
||
Instruction->Eflags.u.zf = 1;
|
||
|
||
*UlongDst = ((((ULONGLONG) GetX86Reg (TrapFrame, IA32_REG_ECX)) << 32) |
|
||
((ULONGLONG) GetX86Reg (TrapFrame, IA32_REG_EBX)));
|
||
|
||
}
|
||
else
|
||
{
|
||
Instruction->Eflags.u.zf = 0;
|
||
|
||
UlongSrc = (PULONGLONG) GetX86RegOffset (TrapFrame, IA32_REG_EDX);
|
||
*UlongSrc = ((*UlongDst) >> 32);
|
||
|
||
UlongSrc = (PULONGLONG) GetX86RegOffset (TrapFrame, IA32_REG_EAX);
|
||
*UlongSrc = ((*UlongDst) & 0xffffffff);
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InstructionMoveSeg (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Mov Seg-Reg instruction handler.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
|
||
UNREFERENCED_PARAMETER (TrapFrame);
|
||
UNREFERENCED_PARAMETER (Instruction);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32LocateInstruction (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
OUT PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Searches the OpcodeDescription table for matching instruction. Fills any relevant
|
||
prefix values inside the Instruction structure.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to an Instruction structure to receive the opcode description.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN PrefixLoop;
|
||
BOOLEAN Match;
|
||
UCHAR ByteValue;
|
||
UCHAR ByteBuffer[4];
|
||
PUCHAR RegOpcodeByte;
|
||
PIA32_OPCODE_DESCRIPTION OpcodeDescription;
|
||
ULONG Count;
|
||
NTSTATUS NtStatus = STATUS_SUCCESS;
|
||
|
||
|
||
PrefixLoop = TRUE;
|
||
|
||
while (PrefixLoop)
|
||
{
|
||
try
|
||
{
|
||
ByteValue = ProbeAndReadUchar ((PUCHAR)Instruction->Eip);
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
NtStatus = GetExceptionCode();
|
||
break;
|
||
}
|
||
|
||
switch (ByteValue)
|
||
{
|
||
case MI_LOCK_PREFIX:
|
||
Instruction->Prefix.b.Lock = 1;
|
||
break;
|
||
case MI_REPNE_PREFIX:
|
||
Instruction->Prefix.b.RepNe = 1;
|
||
break;
|
||
case MI_REP_PREFIX:
|
||
Instruction->Prefix.b.Rep = 1;
|
||
break;
|
||
case MI_SEGCS_PREFIX:
|
||
Instruction->Prefix.b.CsOverride = 1;
|
||
break;
|
||
case MI_SEGSS_PREFIX:
|
||
Instruction->Prefix.b.SsOverride = 1;
|
||
break;
|
||
case MI_SEGDS_PREFIX:
|
||
Instruction->Prefix.b.DsOverride = 1;
|
||
break;
|
||
case MI_SEGES_PREFIX:
|
||
Instruction->Prefix.b.EsOverride = 1;
|
||
break;
|
||
case MI_SEGFS_PREFIX:
|
||
Instruction->Prefix.b.FsOverride = 1;
|
||
break;
|
||
case MI_SEGGS_PREFIX:
|
||
Instruction->Prefix.b.GsOverride = 1;
|
||
break;
|
||
case MI_OPERANDSIZE_PREFIX:
|
||
Instruction->Prefix.b.SizeOverride = 1;
|
||
break;
|
||
case MI_ADDRESSOVERRIDE_PREFIX:
|
||
Instruction->Prefix.b.AddressOverride = 1;
|
||
break;
|
||
|
||
default:
|
||
PrefixLoop = FALSE;
|
||
break;
|
||
}
|
||
|
||
if (PrefixLoop == TRUE)
|
||
{
|
||
Instruction->Eip++;
|
||
}
|
||
}
|
||
|
||
try
|
||
{
|
||
RtlCopyMemory(ByteBuffer, Instruction->Eip, sizeof (ByteBuffer));
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
NtStatus = GetExceptionCode();
|
||
}
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
//
|
||
// Locate the opcode
|
||
//
|
||
|
||
Match = FALSE;
|
||
OpcodeDescription = OpcodesDescription;
|
||
Count = (sizeof (OpcodesDescription) / sizeof (IA32_OPCODE_DESCRIPTION));
|
||
while (Count != 0)
|
||
{
|
||
Count--;
|
||
if (OpcodeDescription->Byte1 == ByteBuffer[0])
|
||
{
|
||
Match = TRUE;
|
||
if (OpcodeDescription->Count.m.Bytes == 2)
|
||
{
|
||
RegOpcodeByte = &ByteBuffer[2];
|
||
if (OpcodeDescription->Byte2 != ByteBuffer[1])
|
||
{
|
||
Match = FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
RegOpcodeByte = &ByteBuffer[1];
|
||
}
|
||
|
||
if ((Match == TRUE) &&
|
||
(OpcodeDescription->Count.m.RegOpcode))
|
||
{
|
||
if (OpcodeDescription->Byte3 != ((*RegOpcodeByte & MI_REGMASK) >> MI_REGSHIFT))
|
||
{
|
||
Match = FALSE;
|
||
}
|
||
}
|
||
|
||
if (Match == TRUE)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
OpcodeDescription++;
|
||
}
|
||
|
||
if (Match != TRUE)
|
||
{
|
||
#if DBG
|
||
if (KiIa32InstructionEmulationDbg)
|
||
{
|
||
DbgPrint("KE: KiIa32LocateInstruction - Unable to locate instruction %p\n",
|
||
Instruction);
|
||
}
|
||
#endif
|
||
NtStatus = STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
Instruction->Description = OpcodeDescription;
|
||
Instruction->Eip += OpcodeDescription->Count.m.Bytes;
|
||
}
|
||
}
|
||
|
||
return NtStatus;
|
||
|
||
UNREFERENCED_PARAMETER (TrapFrame);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32DecodeInstruction (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
OUT PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Decodes the instruction prefixes and operands.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to an Instruction structure to receive the opcode description.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
UCHAR InstructionType;
|
||
UCHAR ModRm;
|
||
UNALIGNED USHORT *UnalignedUshort;
|
||
UNALIGNED ULONG *UnalignedUlong;
|
||
IA32_OPERAND Temp;
|
||
BOOLEAN ReturnCode;
|
||
NTSTATUS NtStatus;
|
||
PVOID MaxWowAddress;
|
||
|
||
MaxWowAddress = MmGetMaxWowAddress ();
|
||
|
||
//
|
||
// Check instruction pointer validity
|
||
//
|
||
|
||
if (TrapFrame->StIIP >= (ULONGLONG) MaxWowAddress) {
|
||
return STATUS_ACCESS_VIOLATION;
|
||
}
|
||
|
||
//
|
||
// Initialize the instruction pointer
|
||
//
|
||
|
||
Instruction->Eip = (PCHAR) TrapFrame->StIIP;
|
||
KiIa32GetX86Eflags (Instruction->Eflags);
|
||
|
||
//
|
||
// Locate a description for the instruction
|
||
//
|
||
|
||
NtStatus = KiIa32LocateInstruction (TrapFrame, Instruction);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
//
|
||
// Let's parse the arguments
|
||
//
|
||
|
||
InstructionType = Instruction->Description->Type;
|
||
switch (InstructionType)
|
||
{
|
||
case IA32_PARAM_RM8_IMM8:
|
||
case IA32_PARAM_RM8_R:
|
||
case IA32_PARAM_R_RM8:
|
||
case IA32_PARAM_RM8:
|
||
case IA32_PARAM_SEGREG_RM8:
|
||
Instruction->OperandSize = OPERANDSIZE_ONEBYTE;
|
||
Instruction->OperandMask = 0xff;
|
||
break;
|
||
|
||
case IA32_PARAM_RM_IMM:
|
||
case IA32_PARAM_RM_IMM8SIGN:
|
||
case IA32_PARAM_RM_R:
|
||
case IA32_PARAM_R_RM:
|
||
case IA32_PARAM_RM:
|
||
if (Instruction->Prefix.b.SizeOverride)
|
||
{
|
||
Instruction->OperandSize = OPERANDSIZE_TWOBYTES;
|
||
Instruction->OperandMask = 0xffff;
|
||
}
|
||
else
|
||
{
|
||
Instruction->OperandSize = OPERANDSIZE_FOURBYTES;
|
||
Instruction->OperandMask = 0xffffffff;
|
||
}
|
||
break;
|
||
|
||
break;
|
||
|
||
case IA32_PARAM_SEGREG_RM:
|
||
Instruction->OperandSize = OPERANDSIZE_TWOBYTES;
|
||
Instruction->OperandMask = 0xffff;
|
||
break;
|
||
|
||
default:
|
||
#if DBG
|
||
if (KiIa32InstructionEmulationDbg)
|
||
{
|
||
DbgPrint("KE: KiIa32DecodeInstruction - Invalid Instruction type %lx, %p\n",
|
||
Instruction->Description->Type, Instruction);
|
||
}
|
||
#endif
|
||
return STATUS_UNSUCCESSFUL;
|
||
break;
|
||
}
|
||
|
||
try
|
||
{
|
||
ModRm = ProbeAndReadUchar ((PUCHAR)Instruction->Eip);
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
return GetExceptionCode();
|
||
}
|
||
|
||
//
|
||
// Eip should be pointing now at the bytes following the opcode
|
||
//
|
||
|
||
if (Instruction->Prefix.b.AddressOverride == 0)
|
||
{
|
||
ReturnCode = KiIa32Compute32BitEffectiveAddress (
|
||
TrapFrame,
|
||
(PUCHAR *)&Instruction->Eip,
|
||
&Instruction->Operand1.v,
|
||
&Instruction->Operand1.RegisterMode
|
||
);
|
||
}
|
||
else
|
||
{
|
||
ReturnCode = KiIa32Compute16BitEffectiveAddress (
|
||
TrapFrame,
|
||
(PUCHAR *)&Instruction->Eip,
|
||
&Instruction->Operand1.v,
|
||
&Instruction->Operand1.RegisterMode
|
||
);
|
||
}
|
||
|
||
if (ReturnCode != TRUE)
|
||
{
|
||
NtStatus = STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
if (Instruction->Prefix.b.FsOverride)
|
||
{
|
||
try
|
||
{
|
||
Instruction->Operand1.v += (ULONGLONG)NtCurrentTeb32();
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
NtStatus = GetExceptionCode ();
|
||
#if DBG
|
||
if (KiIa32InstructionEmulationDbg)
|
||
{
|
||
DbgPrint("KE: KiIa32DecodeInstruction - Exception while reading NtCurrentTeb32() - %p\n",
|
||
Instruction);
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
//
|
||
// Read in more args
|
||
//
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
switch (InstructionType)
|
||
{
|
||
case IA32_PARAM_RM8_IMM8:
|
||
case IA32_PARAM_RM_IMM8SIGN:
|
||
try
|
||
{
|
||
Instruction->Operand2.v = (ULONG_PTR) ProbeAndReadUchar ((PUCHAR)Instruction->Eip);
|
||
Instruction->Eip += 1;
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
NtStatus = GetExceptionCode();
|
||
}
|
||
break;
|
||
|
||
case IA32_PARAM_RM_IMM:
|
||
try
|
||
{
|
||
if (Instruction->OperandSize == OPERANDSIZE_TWOBYTES)
|
||
{
|
||
UnalignedUshort = (UNALIGNED USHORT *) Instruction->Eip;
|
||
Instruction->Operand2.v = (ULONG_PTR) *UnalignedUshort;
|
||
Instruction->Eip += sizeof (USHORT);
|
||
}
|
||
else
|
||
{
|
||
UnalignedUlong = (UNALIGNED ULONG *) Instruction->Eip;
|
||
Instruction->Operand2.v = (ULONG_PTR) *UnalignedUlong;
|
||
Instruction->Eip += sizeof (ULONG);
|
||
}
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
NtStatus = GetExceptionCode();
|
||
}
|
||
break;
|
||
|
||
case IA32_PARAM_RM8_R:
|
||
case IA32_PARAM_R_RM8:
|
||
case IA32_PARAM_RM_R:
|
||
case IA32_PARAM_R_RM:
|
||
Instruction->Operand2.v = GetX86RegOffset (
|
||
TrapFrame,
|
||
(ModRm & MI_REGMASK) >> MI_REGSHIFT);
|
||
Instruction->Operand2.RegisterMode = TRUE;
|
||
break;
|
||
|
||
case IA32_PARAM_RM8:
|
||
case IA32_PARAM_RM:
|
||
case IA32_PARAM_SEGREG_RM8:
|
||
case IA32_PARAM_SEGREG_RM:
|
||
break;
|
||
|
||
default:
|
||
NtStatus = STATUS_UNSUCCESSFUL;
|
||
#if DBG
|
||
DbgPrint("KE: KiIa32DecodeInstruction - Invalid instruction type %lx - %p\n",
|
||
InstructionType, Instruction);
|
||
#endif
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// Adjust operands order
|
||
//
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
switch (InstructionType)
|
||
{
|
||
case IA32_PARAM_R_RM8:
|
||
case IA32_PARAM_R_RM:
|
||
Temp = Instruction->Operand2;
|
||
Instruction->Operand2 = Instruction->Operand1;
|
||
Instruction->Operand1 = Temp;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return NtStatus;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32ExecuteInstruction (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Executes the instruction handler.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS NtStatus;
|
||
|
||
#if DBG
|
||
if (KiIa32InstructionEmulationDbg)
|
||
{
|
||
DbgPrint("KE: KiIa32ExecuteInstruction - Calling %s %lx, %lx. Instruction = %p\n",
|
||
KiIa32InstructionHandlerNames[Instruction->Description->Opcode],
|
||
Instruction->Operand1.v,
|
||
Instruction->Operand2.v,
|
||
Instruction);
|
||
}
|
||
#endif
|
||
|
||
NtStatus = KiIa32InstructionHandler[Instruction->Description->Opcode] (
|
||
TrapFrame,
|
||
Instruction
|
||
);
|
||
|
||
//
|
||
// If all is good...
|
||
//
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
TrapFrame->StIIP = (ULONGLONG) Instruction->Eip;
|
||
KiIa32SetX86Eflags (Instruction->Eflags);
|
||
}
|
||
|
||
return NtStatus;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32EmulateInstruction (
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN PIA32_INSTRUCTION Instruction
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Emulates the instruction and emulates the lock prefix, if any.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Instruction - Pointer to the instruction being processed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS NtStatus;
|
||
|
||
|
||
//
|
||
// Acquire the lock mutex
|
||
//
|
||
|
||
if (Instruction->Prefix.b.Lock)
|
||
{
|
||
if (ExAcquireRundownProtection (&PsGetCurrentThread()->RundownProtect) == FALSE)
|
||
{
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
KiIa32AcquireMisalignedLockFastMutex ();
|
||
}
|
||
|
||
try
|
||
{
|
||
NtStatus = KiIa32ExecuteInstruction (TrapFrame, Instruction);
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
NtStatus = GetExceptionCode();
|
||
}
|
||
|
||
//
|
||
// Release the lock mutex
|
||
//
|
||
|
||
if (Instruction->Prefix.b.Lock)
|
||
{
|
||
KiIa32ReleaseMisalignedLockFastMutex ();
|
||
|
||
ExReleaseRundownProtection (&PsGetCurrentThread()->RundownProtect);
|
||
}
|
||
|
||
return NtStatus;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32InterceptUnalignedLock (
|
||
IN PKTRAP_FRAME TrapFrame
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handles misaligned lock interception raised by the iVE.
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS NtStatus;
|
||
IA32_INSTRUCTION Instruction;
|
||
|
||
|
||
RtlZeroMemory (&Instruction, sizeof (Instruction));
|
||
|
||
//
|
||
// Decode the faulting instruction
|
||
//
|
||
|
||
NtStatus = KiIa32DecodeInstruction (TrapFrame, &Instruction);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
|
||
//
|
||
// xchg instruction asserts the lock by default
|
||
//
|
||
|
||
if (Instruction.Description->Opcode == Ia32_Xchg)
|
||
{
|
||
Instruction.Prefix.b.Lock = 1;
|
||
}
|
||
|
||
//
|
||
// Execute the x86 instruction by emulating its behaviour
|
||
//
|
||
|
||
NtStatus = KiIa32EmulateInstruction (TrapFrame, &Instruction);
|
||
|
||
}
|
||
|
||
if (NtStatus == STATUS_UNSUCCESSFUL)
|
||
{
|
||
NtStatus = STATUS_PRIVILEGED_INSTRUCTION;
|
||
}
|
||
|
||
return NtStatus;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiIa32ValidateInstruction (
|
||
IN PKTRAP_FRAME TrapFrame
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine valiates the instruction that we trapped for. Currently,
|
||
the following instructions are checked:
|
||
|
||
- mov ss, r/m : the register/memory is validated to contain
|
||
a valid stack-selector value.
|
||
|
||
NOTE: This routine is only called for trap instructions (i.e. IIP is incremented
|
||
after the fault).
|
||
|
||
Arguments:
|
||
|
||
TrapFrame - Pointer to TrapFrame.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS NtStatus;
|
||
IA32_INSTRUCTION Instruction;
|
||
ULONGLONG UlongSrc;
|
||
ULONGLONG StIIP;
|
||
|
||
|
||
RtlZeroMemory (&Instruction, sizeof (Instruction));
|
||
|
||
//
|
||
// Adjust the instruction
|
||
//
|
||
StIIP = TrapFrame->StIIP;
|
||
TrapFrame->StIIP = TrapFrame->StIIPA;
|
||
|
||
//
|
||
// Decode the faulting instruction
|
||
//
|
||
|
||
NtStatus = KiIa32DecodeInstruction (TrapFrame, &Instruction);
|
||
|
||
if (NT_SUCCESS (NtStatus))
|
||
{
|
||
|
||
//
|
||
// Parse the opcode here
|
||
//
|
||
|
||
switch (Instruction.Description->Opcode)
|
||
{
|
||
case Ia32_MovToSeg:
|
||
{
|
||
//
|
||
// Validate the stack-selector being loaded
|
||
//
|
||
|
||
NtStatus = KiIa32ReadOperand1 (&Instruction, &UlongSrc);
|
||
|
||
if (NT_SUCCESS (NtStatus)) {
|
||
|
||
//
|
||
// If not a valid selector value
|
||
//
|
||
|
||
if ((UlongSrc != 0x23) &&
|
||
(UlongSrc != 0x1b) &&
|
||
(UlongSrc != 0x3b)) {
|
||
|
||
NtStatus = STATUS_ILLEGAL_INSTRUCTION;
|
||
}
|
||
}
|
||
|
||
}
|
||
break;
|
||
|
||
default:
|
||
NtStatus = STATUS_ILLEGAL_INSTRUCTION;
|
||
break;
|
||
}
|
||
|
||
} else {
|
||
NtStatus = STATUS_ILLEGAL_INSTRUCTION;
|
||
}
|
||
|
||
//
|
||
// Restore the saved IIP
|
||
//
|
||
|
||
if (NT_SUCCESS (NtStatus)) {
|
||
TrapFrame->StIIP = StIIP;
|
||
}
|
||
|
||
return NtStatus;
|
||
}
|