205 lines
3.9 KiB
C
205 lines
3.9 KiB
C
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
npxnp.c
|
|
|
|
Abstract:
|
|
|
|
This module contains support for non-Flat mode NPX faults when
|
|
the application has it's CR0_EM bit clear.
|
|
|
|
Author:
|
|
|
|
Ken Reneris (kenr) 8-Dec-1994
|
|
|
|
Environment:
|
|
|
|
User Mode only
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "csrdll.h"
|
|
|
|
static UCHAR MOD16[] = { 0, 1, 2, 0 };
|
|
static UCHAR MOD32[] = { 0, 1, 4, 0 };
|
|
|
|
UCHAR
|
|
NpxNpReadCSEip (
|
|
IN PCONTEXT Context
|
|
)
|
|
#pragma warning(disable:4035)
|
|
{
|
|
_asm {
|
|
push es
|
|
mov ecx, Context
|
|
mov eax, [ecx] CONTEXT.SegCs
|
|
mov es, ax
|
|
mov eax, [ecx] CONTEXT.Eip
|
|
inc dword ptr [ecx] CONTEXT.Eip ; Advance EIP
|
|
mov al, es:[eax]
|
|
pop es
|
|
}
|
|
}
|
|
#pragma warning(default:4035)
|
|
|
|
|
|
VOID
|
|
NpxNpSkipInstruction (
|
|
IN PCONTEXT Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions gains control when the system has no installed
|
|
NPX support, but the thread has cleared it's EM bit in CR0.
|
|
|
|
The purpose of this function is to move the instruction
|
|
pointer forward over the current NPX instruction.
|
|
|
|
Enviroment:
|
|
|
|
16:16 mode
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN fPrefix;
|
|
UCHAR ibyte, Mod, rm;
|
|
UCHAR Address32Bits;
|
|
ULONG CallerCs;
|
|
|
|
Address32Bits = 0; // assume called from 16:16
|
|
|
|
//
|
|
// Lookup and determine callers default mode
|
|
//
|
|
|
|
CallerCs = Context->SegCs;
|
|
_asm {
|
|
mov eax, CallerCs
|
|
lar eax, eax
|
|
test eax, 400000h
|
|
jz short IsDefault16Bit
|
|
|
|
mov Address32Bits, 1
|
|
|
|
IsDefault16Bit:
|
|
}
|
|
|
|
//
|
|
// No sense in using a try-except since we are not on the
|
|
// correct stack. A fault here could occur if the start
|
|
// of an NPX instruction is near the end of a selector, and the
|
|
// end of the instruction is past the selectors end. This
|
|
// would kill the app anyway.
|
|
//
|
|
|
|
//
|
|
// Read any instruction prefixes
|
|
//
|
|
|
|
fPrefix = TRUE;
|
|
while (fPrefix) {
|
|
ibyte = NpxNpReadCSEip(Context);
|
|
|
|
switch (ibyte) {
|
|
case 0x2e: // cs override, skip it
|
|
case 0x36: // ss override, skip it
|
|
case 0x3e: // ds override, skip it
|
|
case 0x26: // es override, skip it
|
|
case 0x64: // fs override, skip it
|
|
case 0x65: // gs override, skip it
|
|
case 0x66: // operand size override, skip it
|
|
break;
|
|
|
|
case 0x67:
|
|
// address size override
|
|
Address32Bits ^= 1;
|
|
break;
|
|
|
|
default:
|
|
fPrefix = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle first byte of NPX instruction
|
|
//
|
|
|
|
if (ibyte == 0x9b) {
|
|
|
|
//
|
|
// FWait instruction - single byte opcode - all done
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
if (ibyte < 0xD8 || ibyte > 0xDF) {
|
|
|
|
//
|
|
// Not an ESC instruction
|
|
//
|
|
|
|
#if DBG
|
|
DbgPrint ("P5_FPU_PATCH: 16: Not NPX ESC instruction\n");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get ModR/M byte for NPX opcode
|
|
//
|
|
|
|
ibyte = NpxNpReadCSEip(Context);
|
|
|
|
if (ibyte > 0xbf) {
|
|
//
|
|
// Outside of ModR/M range for addressing, all done
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
Mod = ibyte >> 6;
|
|
rm = ibyte & 0x7;
|
|
if (Address32Bits) {
|
|
Context->Eip += MOD32 [Mod];
|
|
if (Mod == 0 && rm == 5) {
|
|
// disp 32
|
|
Context->Eip += 4;
|
|
}
|
|
|
|
//
|
|
// If SIB byte, read it
|
|
//
|
|
|
|
if (rm == 4) {
|
|
ibyte = NpxNpReadCSEip(Context);
|
|
|
|
if (Mod == 0 && (ibyte & 7) == 5) {
|
|
// disp 32
|
|
Context->Eip += 4;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
Context->Eip += MOD16 [Mod];
|
|
if (Mod == 0 && rm == 6) {
|
|
// disp 16
|
|
Context->Eip += 2;
|
|
}
|
|
}
|
|
}
|