windows-nt/Source/XPSP1/NT/base/ntdll/i386/npxnp.c
2020-09-26 16:20:57 +08:00

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;
}
}
}