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