1*f659ac52STimo Kreuzer /*
2*f659ac52STimo Kreuzer * PROJECT: ReactOS API tests
3*f659ac52STimo Kreuzer * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4*f659ac52STimo Kreuzer * PURPOSE: Tests for user mode exceptions
5*f659ac52STimo Kreuzer * COPYRIGHT: Copyright 2021 Timo Kreuzer <timo.kreuzer@reactos.org>
6*f659ac52STimo Kreuzer */
7*f659ac52STimo Kreuzer
8*f659ac52STimo Kreuzer #include "precomp.h"
9*f659ac52STimo Kreuzer #include <pseh/pseh2.h>
10*f659ac52STimo Kreuzer
11*f659ac52STimo Kreuzer typedef enum _CPU_VENDOR
12*f659ac52STimo Kreuzer {
13*f659ac52STimo Kreuzer CPU_VENDOR_INTEL,
14*f659ac52STimo Kreuzer CPU_VENDOR_AMD,
15*f659ac52STimo Kreuzer CPU_VENDOR_CYRIX,
16*f659ac52STimo Kreuzer CPU_VENDOR_VIA,
17*f659ac52STimo Kreuzer CPU_VENDOR_TRANSMETA,
18*f659ac52STimo Kreuzer CPU_VENDOR_UNKNOWN
19*f659ac52STimo Kreuzer } CPU_VENDOR;
20*f659ac52STimo Kreuzer
21*f659ac52STimo Kreuzer CPU_VENDOR g_CpuVendor;
22*f659ac52STimo Kreuzer ULONG g_CpuFeatures;
23*f659ac52STimo Kreuzer
24*f659ac52STimo Kreuzer #define CPU_FEATURE_VMX 0x01
25*f659ac52STimo Kreuzer #define CPU_FEATURE_HV 0x02
26*f659ac52STimo Kreuzer
27*f659ac52STimo Kreuzer typedef void (*PFUNC)(void);
28*f659ac52STimo Kreuzer
29*f659ac52STimo Kreuzer #define FL_INVALID 0
30*f659ac52STimo Kreuzer #define FL_AMD 0x01
31*f659ac52STimo Kreuzer #define FL_INTEL 0x02
32*f659ac52STimo Kreuzer #define FL_CYRIX 0x04
33*f659ac52STimo Kreuzer #define FL_VIA 0x08
34*f659ac52STimo Kreuzer #define FL_TM 0x10
35*f659ac52STimo Kreuzer #define FL_ANY (FL_AMD | FL_INTEL | FL_CYRIX | FL_VIA | FL_TM)
36*f659ac52STimo Kreuzer
37*f659ac52STimo Kreuzer #define FL_VMX 0x20
38*f659ac52STimo Kreuzer #define FL_HV 0x40
39*f659ac52STimo Kreuzer
40*f659ac52STimo Kreuzer #define FL_PRIV 0x100
41*f659ac52STimo Kreuzer #define FL_ACC 0x200
42*f659ac52STimo Kreuzer #define FL_INVLS 0x400
43*f659ac52STimo Kreuzer
44*f659ac52STimo Kreuzer typedef struct _TEST_ENTRY
45*f659ac52STimo Kreuzer {
46*f659ac52STimo Kreuzer ULONG Line;
47*f659ac52STimo Kreuzer UCHAR InstructionBytes[64];
48*f659ac52STimo Kreuzer ULONG ExpectedAddressOffset;
49*f659ac52STimo Kreuzer ULONG Flags;
50*f659ac52STimo Kreuzer } TEST_ENTRY, *PTEST_ENTRY;
51*f659ac52STimo Kreuzer
52*f659ac52STimo Kreuzer static
53*f659ac52STimo Kreuzer CPU_VENDOR
DetermineCpuVendor(void)54*f659ac52STimo Kreuzer DetermineCpuVendor(void)
55*f659ac52STimo Kreuzer {
56*f659ac52STimo Kreuzer INT CpuInfo[4];
57*f659ac52STimo Kreuzer union
58*f659ac52STimo Kreuzer {
59*f659ac52STimo Kreuzer INT ShuffledInts[3];
60*f659ac52STimo Kreuzer CHAR VendorString[13];
61*f659ac52STimo Kreuzer } Vendor;
62*f659ac52STimo Kreuzer
63*f659ac52STimo Kreuzer __cpuid(CpuInfo, 0);
64*f659ac52STimo Kreuzer Vendor.ShuffledInts[0] = CpuInfo[1];
65*f659ac52STimo Kreuzer Vendor.ShuffledInts[1] = CpuInfo[3];
66*f659ac52STimo Kreuzer Vendor.ShuffledInts[2] = CpuInfo[2];
67*f659ac52STimo Kreuzer Vendor.VendorString[12] = 0;
68*f659ac52STimo Kreuzer trace("Vendor: %s\n", Vendor.VendorString);
69*f659ac52STimo Kreuzer
70*f659ac52STimo Kreuzer if (strcmp(Vendor.VendorString, "GenuineIntel") == 0)
71*f659ac52STimo Kreuzer {
72*f659ac52STimo Kreuzer return CPU_VENDOR_INTEL;
73*f659ac52STimo Kreuzer }
74*f659ac52STimo Kreuzer else if (strcmp(Vendor.VendorString, "AuthenticAMD") == 0)
75*f659ac52STimo Kreuzer {
76*f659ac52STimo Kreuzer return CPU_VENDOR_AMD;
77*f659ac52STimo Kreuzer }
78*f659ac52STimo Kreuzer else if (strcmp(Vendor.VendorString, "CyrixInstead") == 0)
79*f659ac52STimo Kreuzer {
80*f659ac52STimo Kreuzer return CPU_VENDOR_CYRIX;
81*f659ac52STimo Kreuzer }
82*f659ac52STimo Kreuzer else if (strcmp(Vendor.VendorString, "CentaurHauls") == 0)
83*f659ac52STimo Kreuzer {
84*f659ac52STimo Kreuzer return CPU_VENDOR_VIA;
85*f659ac52STimo Kreuzer }
86*f659ac52STimo Kreuzer else if (strcmp(Vendor.VendorString, "GenuineTMx86") == 0)
87*f659ac52STimo Kreuzer {
88*f659ac52STimo Kreuzer return CPU_VENDOR_TRANSMETA;
89*f659ac52STimo Kreuzer }
90*f659ac52STimo Kreuzer else
91*f659ac52STimo Kreuzer {
92*f659ac52STimo Kreuzer return CPU_VENDOR_UNKNOWN;
93*f659ac52STimo Kreuzer }
94*f659ac52STimo Kreuzer }
95*f659ac52STimo Kreuzer
96*f659ac52STimo Kreuzer static
97*f659ac52STimo Kreuzer void
DetermineCpuFeatures(void)98*f659ac52STimo Kreuzer DetermineCpuFeatures(void)
99*f659ac52STimo Kreuzer {
100*f659ac52STimo Kreuzer INT CpuInfo[4];
101*f659ac52STimo Kreuzer ULONG Features = 0;
102*f659ac52STimo Kreuzer
103*f659ac52STimo Kreuzer g_CpuVendor = DetermineCpuVendor();
104*f659ac52STimo Kreuzer
105*f659ac52STimo Kreuzer __cpuid(CpuInfo, 1);
106*f659ac52STimo Kreuzer if (CpuInfo[2] & (1 << 5)) Features |= CPU_FEATURE_VMX;
107*f659ac52STimo Kreuzer if (CpuInfo[2] & (1 << 31)) Features |= CPU_FEATURE_HV;
108*f659ac52STimo Kreuzer trace("CPUID 1: 0x%x, 0x%x, 0x%x, 0x%x\n", CpuInfo[0], CpuInfo[1], CpuInfo[2], CpuInfo[3]);
109*f659ac52STimo Kreuzer
110*f659ac52STimo Kreuzer g_CpuFeatures = Features;
111*f659ac52STimo Kreuzer }
112*f659ac52STimo Kreuzer
113*f659ac52STimo Kreuzer TEST_ENTRY TestEntries[] =
114*f659ac52STimo Kreuzer {
115*f659ac52STimo Kreuzer /* Some invalid instruction encodings */
116*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x0B, 0xC3 }, 0, FL_INVALID },
117*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x38, 0x0C, 0xC3 }, 0, FL_INVALID },
118*f659ac52STimo Kreuzer #ifdef _M_AMD64
119*f659ac52STimo Kreuzer { __LINE__, { 0x06, 0xC3 }, 0, FL_INVALID },
120*f659ac52STimo Kreuzer #endif
121*f659ac52STimo Kreuzer
122*f659ac52STimo Kreuzer /* Privileged instructions */
123*f659ac52STimo Kreuzer { __LINE__, { 0xF4, 0xC3 }, 0, FL_ANY | FL_PRIV }, // HLT
124*f659ac52STimo Kreuzer { __LINE__, { 0xFA, 0xC3 }, 0, FL_ANY | FL_PRIV }, // CLI
125*f659ac52STimo Kreuzer { __LINE__, { 0xFB, 0xC3 }, 0, FL_ANY | FL_PRIV }, // STI
126*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x06, 0xC3 }, 0, FL_ANY | FL_PRIV }, // CLTS
127*f659ac52STimo Kreuzer #ifdef _M_AMD64
128*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x07, 0xC3 }, 0, FL_ANY | FL_PRIV }, // SYSRET
129*f659ac52STimo Kreuzer #endif
130*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x08, 0xC3 }, 0, FL_ANY | FL_PRIV }, // INVD
131*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x09, 0xC3 }, 0, FL_ANY | FL_PRIV }, // WBINVD
132*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x20, 0xC3 }, 0, FL_ANY | FL_PRIV }, // MOV CR, XXX
133*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x21, 0xC3 }, 0, FL_ANY | FL_PRIV }, // MOV DR, XXX
134*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x22, 0xC3 }, 0, FL_ANY | FL_PRIV }, // MOV XXX, CR
135*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x23, 0xC3 }, 0, FL_ANY | FL_PRIV }, // MOV YYY, DR
136*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x30, 0xC3 }, 0, FL_ANY | FL_PRIV }, // WRMSR
137*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x32, 0xC3 }, 0, FL_ANY | FL_PRIV }, // RDMSR
138*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x33, 0xC3 }, 0, FL_ANY | FL_PRIV }, // RDPMC
139*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x35, 0xC3 }, 0, FL_ANY | FL_PRIV }, // SYSEXIT
140*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x78, 0xC8, 0xC3 }, 0, FL_INTEL | FL_HV | FL_ACC }, // VMREAD EAX, ECX
141*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x79, 0xC1, 0xC3 }, 0, FL_INTEL | FL_HV | FL_ACC }, // VMWRITE EAX, ECX
142*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x00, 0x10, 0xC3 }, 0, FL_ANY | FL_PRIV }, // LLDT WORD PTR [EAX]
143*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x00, 0x50, 0x00, 0xC3 }, 0, FL_ANY | FL_PRIV }, // LLDT WORD PTR [EAX + 0x00]
144*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x00, 0x18, 0xC3 }, 0, FL_ANY | FL_PRIV }, // LTR WORD PTR [EAX]
145*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x00, 0x58, 0x00, 0xC3 }, 0, FL_ANY | FL_PRIV }, // LTR WORD PTR [EAX + 0x00]
146*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x01, 0xC1, 0xC3 }, 0, FL_INTEL | FL_HV }, // VMCALL
147*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x01, 0xC2, 0xC3 }, 0, FL_INTEL | FL_HV | FL_ACC }, // VMLAUNCH
148*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x01, 0xC3, 0xC3 }, 0, FL_INTEL | FL_HV | FL_ACC }, // VMRESUME
149*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x01, 0xC4, 0xC3 }, 0, FL_INTEL | FL_HV | FL_ACC }, // VMXOFF
150*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x01, 0xC8, 0xC3 }, 0, FL_INVALID }, // MONITOR
151*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x01, 0xC9, 0xC3 }, 0, FL_INVALID }, // MWAIT
152*f659ac52STimo Kreuzer // { __LINE__, { 0x0F, 0x01, 0xD1, 0xC3 }, 0, FL_ANY | FL_PRIV }, // XSETBV FIXME: privileged or access violation?
153*f659ac52STimo Kreuzer #ifdef _M_AMD64
154*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x01, 0xF8, 0xC3 }, 0, FL_ANY | FL_PRIV }, // SWAPGS
155*f659ac52STimo Kreuzer #endif
156*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x01, 0x10, 0xC3 }, 0, FL_ANY | FL_PRIV }, // LGDT [EAX]
157*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x01, 0x18, 0xC3 }, 0, FL_ANY | FL_PRIV }, // LIDT [EAX]
158*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x01, 0x30, 0xC3 }, 0, FL_ANY | FL_PRIV }, // LMSW [EAX]
159*f659ac52STimo Kreuzer #ifdef _M_AMD64 // Gives access violation on Test WHS for some reason
160*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0x01, 0x38, 0xC3 }, 0, FL_ANY | FL_PRIV }, // INVLPG [EAX]
161*f659ac52STimo Kreuzer #endif
162*f659ac52STimo Kreuzer { __LINE__, { 0x66, 0x0F, 0x38, 0x80, 0x01, 0xC3 }, 0, FL_INTEL | FL_HV | FL_ACC }, // INVEPT EAX,OWORD PTR [ECX]
163*f659ac52STimo Kreuzer { __LINE__, { 0x66, 0x0F, 0x38, 0x81, 0x01, 0xC3 }, 0, FL_INTEL | FL_HV | FL_ACC }, // INVVPID EAX,OWORD PTR [ECX]
164*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0xC7, 0x31, 0xC3 }, 0, FL_INTEL | FL_HV | FL_ACC }, // VMPTRLD QWORD PTR [ECX]
165*f659ac52STimo Kreuzer { __LINE__, { 0x66, 0x0F, 0xC7, 0x31, 0xC3 }, 0, FL_INTEL | FL_HV | FL_ACC }, // VMCLEAR QWORD PTR [ECX]
166*f659ac52STimo Kreuzer { __LINE__, { 0xF3, 0x0F, 0xC7, 0x31, 0xC3 }, 0, FL_INVALID }, // VMXON QWORD PTR [ECX]
167*f659ac52STimo Kreuzer { __LINE__, { 0x0F, 0xC7, 0xE0, 0xC3 }, 0, FL_INVALID }, // VMPTRST
168*f659ac52STimo Kreuzer
169*f659ac52STimo Kreuzer /* Test prefixes */
170*f659ac52STimo Kreuzer { __LINE__, { 0x26, 0xF4, 0xC3 }, 0, FL_ANY | FL_PRIV }, // ES HLT
171*f659ac52STimo Kreuzer { __LINE__, { 0x2E, 0xF4, 0xC3 }, 0, FL_ANY | FL_PRIV }, // CS: HLT
172*f659ac52STimo Kreuzer { __LINE__, { 0x36, 0xF4, 0xC3 }, 0, FL_ANY | FL_PRIV }, // SS: HLT
173*f659ac52STimo Kreuzer { __LINE__, { 0x3E, 0xF4, 0xC3 }, 0, FL_ANY | FL_PRIV }, // DS: HLT
174*f659ac52STimo Kreuzer { __LINE__, { 0x64, 0xF4, 0xC3 }, 0, FL_ANY | FL_PRIV }, // FS: HLT
175*f659ac52STimo Kreuzer { __LINE__, { 0x65, 0xF4, 0xC3 }, 0, FL_ANY | FL_PRIV }, // GS: HLT
176*f659ac52STimo Kreuzer { __LINE__, { 0x66, 0xF4, 0xC3 }, 0, FL_ANY | FL_PRIV }, // DATA HLT
177*f659ac52STimo Kreuzer { __LINE__, { 0x67, 0xF4, 0xC3 }, 0, FL_ANY | FL_PRIV }, // ADDR HLT
178*f659ac52STimo Kreuzer { __LINE__, { 0xF0, 0xF4, 0xC3 }, 0, FL_ANY | FL_INVLS | FL_PRIV }, // LOCK HLT
179*f659ac52STimo Kreuzer { __LINE__, { 0xF2, 0xF4, 0xC3 }, 0, FL_ANY | FL_PRIV }, // REP HLT
180*f659ac52STimo Kreuzer { __LINE__, { 0xF3, 0xF4, 0xC3 }, 0, FL_ANY | FL_PRIV }, // REPZ HLT
181*f659ac52STimo Kreuzer { __LINE__, { 0x9B, 0xF4, 0xC3 }, 1, FL_ANY | FL_PRIV }, // WAIT // not a prefix
182*f659ac52STimo Kreuzer #ifdef _M_AMD64
183*f659ac52STimo Kreuzer { __LINE__, { 0x40, 0xF4, 0xC3 }, 0, FL_ANY | FL_PRIV }, // REX HLT
184*f659ac52STimo Kreuzer #endif
185*f659ac52STimo Kreuzer { __LINE__, { 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0xC3 }, 0, FL_ANY }, // This one is OK
186*f659ac52STimo Kreuzer #ifdef _M_AMD64
187*f659ac52STimo Kreuzer { __LINE__, { 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0xC3 }, 0, FL_ANY | FL_ACC }, // Too many prefixes
188*f659ac52STimo Kreuzer #else
189*f659ac52STimo Kreuzer { __LINE__, { 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0xC3 }, 0, FL_INVALID }, // Too many prefixes
190*f659ac52STimo Kreuzer #endif
191*f659ac52STimo Kreuzer { __LINE__, { 0xF0, 0x90, 0xC3 }, 0, FL_INVLS }, // LOCK NOP
192*f659ac52STimo Kreuzer { __LINE__, { 0xF0, 0x83, 0x0C, 0x24, 0x00, 0xC3 }, 0, FL_ANY }, // LOCK OR DWORD PTR [ESP], 0x0
193*f659ac52STimo Kreuzer { __LINE__, { 0x3E, 0x66, 0x67, 0xF0, 0xF3, 0xF4, 0xC3 }, 0, FL_ANY | FL_INVLS | FL_PRIV }, // DS: DATA ADDR LOCK REPZ HLT
194*f659ac52STimo Kreuzer #ifdef _M_AMD64
195*f659ac52STimo Kreuzer /* Check non-canonical address access (causes a #GP) */
196*f659ac52STimo Kreuzer { __LINE__, { 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xC3 }, 0, FL_ANY | FL_ACC }, // MOV AL, [0x1000000000000000]
197*f659ac52STimo Kreuzer #endif
198*f659ac52STimo Kreuzer
199*f659ac52STimo Kreuzer };
200*f659ac52STimo Kreuzer
Test_SingleInstruction(PVOID RwxMemory,PTEST_ENTRY TestEntry)201*f659ac52STimo Kreuzer void Test_SingleInstruction(
202*f659ac52STimo Kreuzer PVOID RwxMemory,
203*f659ac52STimo Kreuzer PTEST_ENTRY TestEntry)
204*f659ac52STimo Kreuzer {
205*f659ac52STimo Kreuzer PEXCEPTION_POINTERS ExcPtrs;
206*f659ac52STimo Kreuzer EXCEPTION_RECORD ExceptionRecord;
207*f659ac52STimo Kreuzer NTSTATUS ExpectedStatus, Status = STATUS_SUCCESS;
208*f659ac52STimo Kreuzer PFUNC Func = (PFUNC)RwxMemory;
209*f659ac52STimo Kreuzer ULONG Flags;
210*f659ac52STimo Kreuzer
211*f659ac52STimo Kreuzer RtlZeroMemory(&ExceptionRecord, sizeof(ExceptionRecord));
212*f659ac52STimo Kreuzer
213*f659ac52STimo Kreuzer RtlCopyMemory(RwxMemory,
214*f659ac52STimo Kreuzer TestEntry->InstructionBytes,
215*f659ac52STimo Kreuzer sizeof(TestEntry->InstructionBytes));
216*f659ac52STimo Kreuzer
217*f659ac52STimo Kreuzer _SEH2_TRY
218*f659ac52STimo Kreuzer {
219*f659ac52STimo Kreuzer Func();
220*f659ac52STimo Kreuzer }
221*f659ac52STimo Kreuzer _SEH2_EXCEPT(ExcPtrs = _SEH2_GetExceptionInformation(),
222*f659ac52STimo Kreuzer ExceptionRecord = *ExcPtrs->ExceptionRecord,
223*f659ac52STimo Kreuzer EXCEPTION_EXECUTE_HANDLER)
224*f659ac52STimo Kreuzer {
225*f659ac52STimo Kreuzer Status = _SEH2_GetExceptionCode();
226*f659ac52STimo Kreuzer }
227*f659ac52STimo Kreuzer _SEH2_END;
228*f659ac52STimo Kreuzer
229*f659ac52STimo Kreuzer Flags = TestEntry->Flags;
230*f659ac52STimo Kreuzer #ifdef _M_IX86
231*f659ac52STimo Kreuzer if (Flags & FL_INVLS)
232*f659ac52STimo Kreuzer {
233*f659ac52STimo Kreuzer ExpectedStatus = STATUS_INVALID_LOCK_SEQUENCE;
234*f659ac52STimo Kreuzer }
235*f659ac52STimo Kreuzer else
236*f659ac52STimo Kreuzer #endif
237*f659ac52STimo Kreuzer if (((g_CpuVendor == CPU_VENDOR_INTEL) && !(Flags & FL_INTEL)) ||
238*f659ac52STimo Kreuzer ((g_CpuVendor == CPU_VENDOR_AMD) && !(Flags & FL_AMD)) ||
239*f659ac52STimo Kreuzer ((g_CpuVendor == CPU_VENDOR_CYRIX) && !(Flags & FL_CYRIX)) ||
240*f659ac52STimo Kreuzer ((g_CpuVendor == CPU_VENDOR_VIA) && !(Flags & FL_VIA)))
241*f659ac52STimo Kreuzer {
242*f659ac52STimo Kreuzer ExpectedStatus = STATUS_ILLEGAL_INSTRUCTION;
243*f659ac52STimo Kreuzer }
244*f659ac52STimo Kreuzer else if (((Flags & FL_VMX) && !(g_CpuFeatures & CPU_FEATURE_VMX)) ||
245*f659ac52STimo Kreuzer ((Flags & FL_HV) && !(g_CpuFeatures & CPU_FEATURE_HV)))
246*f659ac52STimo Kreuzer {
247*f659ac52STimo Kreuzer ExpectedStatus = STATUS_ILLEGAL_INSTRUCTION;
248*f659ac52STimo Kreuzer }
249*f659ac52STimo Kreuzer else if (Flags & FL_PRIV)
250*f659ac52STimo Kreuzer {
251*f659ac52STimo Kreuzer ExpectedStatus = STATUS_PRIVILEGED_INSTRUCTION;
252*f659ac52STimo Kreuzer }
253*f659ac52STimo Kreuzer else if (Flags & FL_ACC)
254*f659ac52STimo Kreuzer {
255*f659ac52STimo Kreuzer ExpectedStatus = STATUS_ACCESS_VIOLATION;
256*f659ac52STimo Kreuzer }
257*f659ac52STimo Kreuzer else
258*f659ac52STimo Kreuzer {
259*f659ac52STimo Kreuzer ExpectedStatus = STATUS_SUCCESS;
260*f659ac52STimo Kreuzer }
261*f659ac52STimo Kreuzer
262*f659ac52STimo Kreuzer ok_hex_(__FILE__, TestEntry->Line, Status, ExpectedStatus);
263*f659ac52STimo Kreuzer ok_hex_(__FILE__, TestEntry->Line, ExceptionRecord.ExceptionCode, Status);
264*f659ac52STimo Kreuzer ok_hex_(__FILE__, TestEntry->Line, ExceptionRecord.ExceptionFlags, 0);
265*f659ac52STimo Kreuzer ok_ptr_(__FILE__, TestEntry->Line, ExceptionRecord.ExceptionRecord, NULL);
266*f659ac52STimo Kreuzer
267*f659ac52STimo Kreuzer if (Status == STATUS_SUCCESS)
268*f659ac52STimo Kreuzer {
269*f659ac52STimo Kreuzer ok_ptr_(__FILE__, TestEntry->Line, ExceptionRecord.ExceptionAddress, NULL);
270*f659ac52STimo Kreuzer }
271*f659ac52STimo Kreuzer else
272*f659ac52STimo Kreuzer {
273*f659ac52STimo Kreuzer ok_ptr_(__FILE__, TestEntry->Line, ExceptionRecord.ExceptionAddress, (PUCHAR)Func + TestEntry->ExpectedAddressOffset);
274*f659ac52STimo Kreuzer }
275*f659ac52STimo Kreuzer
276*f659ac52STimo Kreuzer if (Status == STATUS_ACCESS_VIOLATION)
277*f659ac52STimo Kreuzer {
278*f659ac52STimo Kreuzer ok_dec_(__FILE__, TestEntry->Line, ExceptionRecord.NumberParameters, 2);
279*f659ac52STimo Kreuzer ok_size_t_(__FILE__, TestEntry->Line, ExceptionRecord.ExceptionInformation[0], 0);
280*f659ac52STimo Kreuzer ok_size_t_(__FILE__, TestEntry->Line, ExceptionRecord.ExceptionInformation[1], (LONG_PTR)-1);
281*f659ac52STimo Kreuzer }
282*f659ac52STimo Kreuzer else
283*f659ac52STimo Kreuzer {
284*f659ac52STimo Kreuzer ok_dec_(__FILE__, TestEntry->Line, ExceptionRecord.NumberParameters, 0);
285*f659ac52STimo Kreuzer #if 0 // FIXME: These are inconsistent between Windows versions (simply uninitialized?)
286*f659ac52STimo Kreuzer ok_size_t_(__FILE__, TestEntry->Line, ExceptionRecord.ExceptionInformation[0], 0);
287*f659ac52STimo Kreuzer ok_size_t_(__FILE__, TestEntry->Line, ExceptionRecord.ExceptionInformation[1], 0);
288*f659ac52STimo Kreuzer #endif
289*f659ac52STimo Kreuzer }
290*f659ac52STimo Kreuzer }
291*f659ac52STimo Kreuzer
292*f659ac52STimo Kreuzer static
293*f659ac52STimo Kreuzer void
Test_InstructionFaults(void)294*f659ac52STimo Kreuzer Test_InstructionFaults(void)
295*f659ac52STimo Kreuzer {
296*f659ac52STimo Kreuzer PVOID RwxMemory;
297*f659ac52STimo Kreuzer ULONG i;
298*f659ac52STimo Kreuzer
299*f659ac52STimo Kreuzer /* Allocate a page of RWX memory */
300*f659ac52STimo Kreuzer RwxMemory = VirtualAlloc(NULL,
301*f659ac52STimo Kreuzer PAGE_SIZE,
302*f659ac52STimo Kreuzer MEM_RESERVE | MEM_COMMIT,
303*f659ac52STimo Kreuzer PAGE_EXECUTE_READWRITE);
304*f659ac52STimo Kreuzer ok(RwxMemory != NULL, "Failed to allocate RWX memory!\n");
305*f659ac52STimo Kreuzer if (RwxMemory == NULL)
306*f659ac52STimo Kreuzer {
307*f659ac52STimo Kreuzer return;
308*f659ac52STimo Kreuzer }
309*f659ac52STimo Kreuzer
310*f659ac52STimo Kreuzer for (i = 0; i < ARRAYSIZE(TestEntries); i++)
311*f659ac52STimo Kreuzer {
312*f659ac52STimo Kreuzer Test_SingleInstruction(RwxMemory, &TestEntries[i]);
313*f659ac52STimo Kreuzer }
314*f659ac52STimo Kreuzer
315*f659ac52STimo Kreuzer /* Clean up */
316*f659ac52STimo Kreuzer VirtualFree(RwxMemory, 0, MEM_RELEASE);
317*f659ac52STimo Kreuzer }
318*f659ac52STimo Kreuzer
START_TEST(UserModeException)319*f659ac52STimo Kreuzer START_TEST(UserModeException)
320*f659ac52STimo Kreuzer {
321*f659ac52STimo Kreuzer DetermineCpuFeatures();
322*f659ac52STimo Kreuzer
323*f659ac52STimo Kreuzer Test_InstructionFaults();
324*f659ac52STimo Kreuzer }
325