summaryrefslogtreecommitdiffstats
path: root/private/ntos/dll/i386/npxnp.c
blob: 7457090332db9e6565ac434b60912fc046f3bd3a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/*++

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