ReactOS 0.4.15-dev-8145-ga541a46
SystemCall.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS API Tests
3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4 * PURPOSE: Tests for system calls
5 * COPYRIGHT: Copyright 2024 Timo Kreuzer <timo.kreuzer@reactos.org>
6 */
7
8#include "precomp.h"
9
10#define EFLAGS_TF 0x100L
11#define EFLAGS_INTERRUPT_MASK 0x200L
12
15ULONG g_RandomSeed = 0x63c28b49;
16
17VOID
19 _In_ ULONG SyscallNumber,
20 _Out_ PCONTEXT PreContext,
21 _Out_ PCONTEXT PostContext);
22
23extern const UCHAR SyscallReturn;
24
27 _In_ ULONG64 SyscallNumber);
28
29#ifdef _M_IX86
30__declspec(dllimport)
31VOID
33KiFastSystemCallRet(VOID);
34#endif
35
36static
39{
40 /* Scan instructions in NtFlushWriteBuffer to find the syscall number
41 for NtFlushWriteBuffer, which is a noop syscall on x86/x64 */
42 PUCHAR Instructions = (PUCHAR)NtFlushWriteBuffer;
43 for (ULONG i = 0; i < 32; i++)
44 {
45 if (Instructions[i] == 0xB8)
46 {
47 g_NoopSyscallNumber = *(PULONG)&Instructions[i + 1];
48 return TRUE;
49 }
50 }
51
52 return FALSE;
53}
54
55static
56VOID
58{
59 HMODULE hUser32 = LoadLibraryW(L"user32.dll");
60 ok(hUser32 != NULL, "Failed to load user32.dll\n");
61}
62
63static
64LONG
67 struct _EXCEPTION_POINTERS *ExceptionInfo)
68{
70
71 /* Return from the callback */
72 NtCallbackReturn(NULL, 0, 0xdeadbeef);
73
74 /* If that failed, we were not in a callback, keep searching */
76}
77
78VOID
82 _In_ ULONG_PTR SyscallId,
84{
85 CONTEXT PreContext, PostContext;
86
87#ifdef _M_IX86
88 DoSyscallAndCaptureContext(SyscallId, &PreContext, &PostContext);
89
90 /* Non-volatile registers and rsp are unchanged */
91 ok_eq_hex_(File, Line, PostContext.Esp, PreContext.Esp);
92 ok_eq_hex_(File, Line, PostContext.Ebx, PreContext.Ebx);
93 ok_eq_hex_(File, Line, PostContext.Esi, PreContext.Esi);
94 ok_eq_hex_(File, Line, PostContext.Edi, PreContext.Edi);
95 ok_eq_hex_(File, Line, PostContext.Ebp, PreContext.Ebp);
96
97 /* Special cases */
98 ok_eq_hex_(File, Line, PostContext.Ecx, PreContext.Esp - 0x4C);
99 ok_eq_hex_(File, Line, PostContext.Edx, (ULONG)KiFastSystemCallRet);
100 ok_eq_hex_(File, Line, PostContext.Eax, Result);
101
102#elif defined(_M_AMD64)
103 /* Initiaize the pre-contex with random numbers */
104 PULONG64 IntegerRegs = &PreContext.Rax;
105 PM128A XmmRegs = &PreContext.Xmm0;
106 for (ULONG Index = 0; Index < 16; Index++)
107 {
108 IntegerRegs[Index] = (ULONG64)RtlRandom(&g_RandomSeed) << 32 | RtlRandom(&g_RandomSeed);
109 XmmRegs[Index].Low = (ULONG64)RtlRandom(&g_RandomSeed) << 32 | RtlRandom(&g_RandomSeed);
110 XmmRegs[Index].High = (ULONG64)RtlRandom(&g_RandomSeed) << 32 | RtlRandom(&g_RandomSeed);
111 }
112 PreContext.EFlags = RtlRandom(&g_RandomSeed);
113 PreContext.EFlags &= ~(EFLAGS_TF | 0x20 | 0x40000);
114 PreContext.EFlags |= EFLAGS_INTERRUPT_MASK;
115
116 PreContext.SegDs = 0; //0x0028;
117 PreContext.SegEs = 0; //0x002B;
118 PreContext.SegFs = 0; //0x0053;
119 PreContext.SegGs = 0; //0x002B;
120 PreContext.SegSs = 0; // 0x002B;
121
122 DoSyscallAndCaptureContext(SyscallId, &PreContext, &PostContext);
123
124 /* Non-volatile registers and rsp are unchanged */
125 ok_eq_hex64_(File, Line, PostContext.Rsp, PreContext.Rsp);
126 ok_eq_hex64_(File, Line, PostContext.Rbx, PreContext.Rbx);
127 ok_eq_hex64_(File, Line, PostContext.Rsi, PreContext.Rsi);
128 ok_eq_hex64_(File, Line, PostContext.Rdi, PreContext.Rdi);
129 ok_eq_hex64_(File, Line, PostContext.Rbp, PreContext.Rbp);
130 ok_eq_hex64_(File, Line, PostContext.R12, PreContext.R12);
131 ok_eq_hex64_(File, Line, PostContext.R13, PreContext.R13);
132 ok_eq_hex64_(File, Line, PostContext.R14, PreContext.R14);
133 ok_eq_hex64_(File, Line, PostContext.R15, PreContext.R15);
134 ok_eq_hex64_(File, Line, PostContext.Xmm6.Low, PreContext.Xmm6.Low);
135 ok_eq_hex64_(File, Line, PostContext.Xmm6.High, PreContext.Xmm6.High);
136 ok_eq_hex64_(File, Line, PostContext.Xmm7.Low, PreContext.Xmm7.Low);
137 ok_eq_hex64_(File, Line, PostContext.Xmm7.High, PreContext.Xmm7.High);
138 ok_eq_hex64_(File, Line, PostContext.Xmm8.Low, PreContext.Xmm8.Low);
139 ok_eq_hex64_(File, Line, PostContext.Xmm8.High, PreContext.Xmm8.High);
140 ok_eq_hex64_(File, Line, PostContext.Xmm9.Low, PreContext.Xmm9.Low);
141 ok_eq_hex64_(File, Line, PostContext.Xmm9.High, PreContext.Xmm9.High);
142 ok_eq_hex64_(File, Line, PostContext.Xmm10.Low, PreContext.Xmm10.Low);
143 ok_eq_hex64_(File, Line, PostContext.Xmm10.High, PreContext.Xmm10.High);
144 ok_eq_hex64_(File, Line, PostContext.Xmm11.Low, PreContext.Xmm11.Low);
145 ok_eq_hex64_(File, Line, PostContext.Xmm11.High, PreContext.Xmm11.High);
146 ok_eq_hex64_(File, Line, PostContext.Xmm12.Low, PreContext.Xmm12.Low);
147 ok_eq_hex64_(File, Line, PostContext.Xmm12.High, PreContext.Xmm12.High);
148 ok_eq_hex64_(File, Line, PostContext.Xmm13.Low, PreContext.Xmm13.Low);
149 ok_eq_hex64_(File, Line, PostContext.Xmm13.High, PreContext.Xmm13.High);
150 ok_eq_hex64_(File, Line, PostContext.Xmm14.Low, PreContext.Xmm14.Low);
151 ok_eq_hex64_(File, Line, PostContext.Xmm14.High, PreContext.Xmm14.High);
152 ok_eq_hex64_(File, Line, PostContext.Xmm15.Low, PreContext.Xmm15.Low);
153 ok_eq_hex64_(File, Line, PostContext.Xmm15.High, PreContext.Xmm15.High);
154
155 /* Parity flag is flaky */
156 ok_eq_hex64_(File, Line, PostContext.EFlags & ~0x4, PreContext.EFlags & ~0x9F5);
157
158 ok_eq_hex64_(File, Line, PostContext.SegCs, 0x0033);
159 ok_eq_hex64_(File, Line, PostContext.SegSs, 0x002B);
160 ok_(File, Line)(PostContext.SegDs == PreContext.SegDs || PostContext.SegDs == 0x002B,
161 "Expected 0x002B, got 0x%04X\n", PostContext.SegDs);
162 ok_(File, Line)(PostContext.SegEs == PreContext.SegEs || PostContext.SegEs == 0x002B,
163 "Expected 0x002B, got 0x%04X\n", PostContext.SegEs);
164 ok_(File, Line)(PostContext.SegFs == PreContext.SegFs || PostContext.SegFs == 0x0053,
165 "Expected 0x002B, got 0x%04X\n", PostContext.SegFs);
166 ok_(File, Line)(PostContext.SegGs == PreContext.SegGs || PostContext.SegGs == 0x002B,
167 "Expected 0x002B, got 0x%04X\n", PostContext.SegGs);
168 ok_eq_hex64_(File, Line, PostContext.SegSs, 0x002B);
169
170 /* These volatile registers are zeroed */
171 ok_eq_hex64_(File, Line, PostContext.Rdx, 0);
172 ok_eq_hex64_(File, Line, PostContext.R10, 0);
173 ok_eq_hex64_(File, Line, PostContext.Xmm0.Low, 0);
174 ok_eq_hex64_(File, Line, PostContext.Xmm0.High, 0);
175 ok_eq_hex64_(File, Line, PostContext.Xmm1.Low, 0);
176 ok_eq_hex64_(File, Line, PostContext.Xmm1.High, 0);
177 ok_eq_hex64_(File, Line, PostContext.Xmm2.Low, 0);
178 ok_eq_hex64_(File, Line, PostContext.Xmm2.High, 0);
179 ok_eq_hex64_(File, Line, PostContext.Xmm3.Low, 0);
180 ok_eq_hex64_(File, Line, PostContext.Xmm3.High, 0);
181 ok_eq_hex64_(File, Line, PostContext.Xmm4.Low, 0);
182 ok_eq_hex64_(File, Line, PostContext.Xmm4.High, 0);
183 ok_eq_hex64_(File, Line, PostContext.Xmm5.Low, 0);
184 ok_eq_hex64_(File, Line, PostContext.Xmm5.High, 0);
185
186 /* Special cases */
187 ok_eq_hex64_(File, Line, PostContext.Rax, Result);
188 ok_eq_hex64_(File, Line, PostContext.Rcx, (ULONG64)&SyscallReturn);
189 ok_eq_hex64_(File, Line, PostContext.R8, PreContext.Rsp);
190 ok_eq_hex64_(File, Line, PostContext.R9, PreContext.Rbp);
191 ok_eq_hex64_(File, Line, PostContext.R11, PostContext.EFlags);
192
193 // TODO:Debug regs, mxcsr, floating point, etc.
194#else
195#error Unsupported architecture
196#endif
197}
198
199#define ValidateSyscall(SyscallId, Result) ValidateSyscall_(__FILE__, __LINE__, SyscallId, Result)
200
201static
202VOID
204{
205 BOOL Wow64Process;
206
207 if (IsWow64Process(NtCurrentProcess(), &Wow64Process) && Wow64Process)
208 {
209 skip("Skipping syscall tests on WOW64\n");
210 return;
211 }
212
213 /* Test valid syscall number */
215
216 /* Test invalid syscall number */
218
219 /* Add a vectored exception handler to catch the exception we will get
220 when KiUserCallbackDispatcher is called and user32.dll is not loaded
221 We cannot use SEH here, because the exception is outside of the try block */
222 PVOID hHandler = AddVectoredExceptionHandler(TRUE, VectoredExceptionHandlerForUserModeCallback);
223 ok(hHandler != NULL, "Failed to add vectored exception handler\n");
224
225 /* Test win32k syscall number without user32.dll loaded */
226#ifdef _M_AMD64
228#else
230#endif
232
233 /* Test invalid win32k syscall number without user32.dll loaded */
234#ifdef _M_IX86
235 ValidateSyscall(0x1FFF, 0xffffffbf);
236#else
238#endif
239
241
242 RemoveVectoredExceptionHandler(hHandler);
243
244 LoadUser32();
245
246 /* Test invalid win32k syscall number */
247#ifdef _M_IX86
248 ValidateSyscall(0x1FFF, 0xffffffbf);
249#else
251#endif
252
253 /* Test invalid syscall table number */
256
257#if 0 // This only happens, when running the test from VS, but not from the command line
258 /* For some unknown reason the result gets sign extended in this case */
261#endif
262
263 /* Test invalid upper bits in syscall number */
264 ValidateSyscall(0xFFFFFFFFFFF70000ULL + g_NoopSyscallNumber, STATUS_SUCCESS);
265}
266
267static
268VOID
270{
271 ULONG64 Start, End, Cycles;
272 ULONG64 TotalCycles = 0, Min = -1, Max = 0;
273 ULONG64 Count = 100000;
274 ULONG Outliers = 0;
275 ULONG_PTR OldAffinityMask;
276 double AvgCycles;
277
278 OldAffinityMask = SetThreadAffinityMask(GetCurrentThread(), 1);
279
280 for (ULONG64 i = 0; i < Count; i++)
281 {
282 Start = __rdtsc();
284 End = __rdtsc();
285 Cycles = End - Start;
286 if (Cycles > 2000)
287 {
288 Outliers++;
289 continue;
290 }
291 TotalCycles += Cycles;
292 Min = min(Min, Cycles);
293 Max = max(Max, Cycles);
294 }
295
296 AvgCycles = (double)TotalCycles / (Count - Outliers);
297
298 trace("NtFlushWriteBuffer: avg %.2f cycles, min %I64u, max %I64u, Outliers %lu\n",
299 AvgCycles, Min, Max, Outliers);
300
301 SetThreadAffinityMask(GetCurrentThread(), OldAffinityMask);
302}
303
304START_TEST(SystemCall)
305{
306 if (!InitSysCalls())
307 {
308 skip("Failed to initialize.\n");
309 return;
310 }
311
314}
unsigned char BOOLEAN
#define EFLAGS_INTERRUPT_MASK
Definition: SystemCall.c:11
ULONG_PTR DoSyscallWithUnalignedStack(_In_ ULONG64 SyscallNumber)
static VOID LoadUser32()
Definition: SystemCall.c:57
VOID DoSyscallAndCaptureContext(_In_ ULONG SyscallNumber, _Out_ PCONTEXT PreContext, _Out_ PCONTEXT PostContext)
ULONG g_HandlerCalled
Definition: SystemCall.c:14
static BOOLEAN InitSysCalls()
Definition: SystemCall.c:38
const UCHAR SyscallReturn
VOID ValidateSyscall_(_In_ PCCH File, _In_ ULONG Line, _In_ ULONG_PTR SyscallId, _In_ ULONG_PTR Result)
Definition: SystemCall.c:79
#define EFLAGS_TF
Definition: SystemCall.c:10
ULONG g_NoopSyscallNumber
Definition: SystemCall.c:13
static VOID Test_SyscallPerformance()
Definition: SystemCall.c:269
#define ValidateSyscall(SyscallId, Result)
Definition: SystemCall.c:199
ULONG g_RandomSeed
Definition: SystemCall.c:15
static VOID Test_SyscallNumbers()
Definition: SystemCall.c:203
static LONG WINAPI VectoredExceptionHandlerForUserModeCallback(struct _EXCEPTION_POINTERS *ExceptionInfo)
Definition: SystemCall.c:66
NTSTATUS NTAPI NtCallbackReturn(_In_ PVOID Result, _In_ ULONG ResultLength, _In_ NTSTATUS CallbackStatus)
Definition: usercall.c:329
#define ok_eq_ulong(value, expected)
Definition: apitest.h:63
#define ok_eq_hex64(value, expected)
Definition: apitest.h:89
#define ok_eq_hex_(file, line, value, expected)
Definition: apitest.h:87
#define ok_eq_hex64_(file, line, value, expected)
Definition: apitest.h:88
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
#define ok_(x1, x2)
Definition: atltest.h:61
#define Max(a, b)
Definition: cdprocs.h:78
#define Min(a, b)
Definition: cdprocs.h:74
Definition: File.h:16
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define IsWow64Process
Definition: compat.h:760
#define LoadLibraryW(x)
Definition: compat.h:747
DWORD_PTR WINAPI SetThreadAffinityMask(IN HANDLE hThread, IN DWORD_PTR dwThreadAffinityMask)
Definition: thread.c:662
__declspec(noinline) int TestFunc(int
Definition: ehthrow.cxx:232
unsigned int BOOL
Definition: ntddk_ex.h:94
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define EXCEPTION_CONTINUE_SEARCH
Definition: excpt.h:86
PPC_QUAL unsigned long long __rdtsc(void)
Definition: intrin_ppc.h:688
unsigned __int64 * PULONG64
Definition: imports.h:198
unsigned __int64 ULONG64
Definition: imports.h:198
static const char mbstate_t *static wchar_t const char mbstate_t *static const wchar_t int *static double
Definition: string.c:80
#define min(a, b)
Definition: monoChain.cc:55
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
NTSYSAPI ULONG NTAPI RtlRandom(_Inout_ PULONG Seed)
int Count
Definition: noreturn.cpp:7
#define NtCurrentProcess()
Definition: nt_native.h:1657
CONST CHAR * PCCH
Definition: ntbasedef.h:392
NTSTATUS NTAPI NtFlushWriteBuffer(VOID)
Definition: file.c:3938
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:242
#define STATUS_INVALID_SYSTEM_SERVICE
Definition: ntstatus.h:265
#define L(x)
Definition: ntvdm.h:50
long LONG
Definition: pedump.c:60
#define STATUS_SUCCESS
Definition: shellext.h:65
Definition: ncftp.h:79
ULONG Esp
Definition: nt_native.h:1479
ULONG SegFs
Definition: nt_native.h:1454
ULONG Edx
Definition: nt_native.h:1466
ULONG Esi
Definition: nt_native.h:1464
ULONG Ebp
Definition: nt_native.h:1475
ULONG R8
Definition: ke.h:263
ULONG SegSs
Definition: nt_native.h:1480
ULONG Ecx
Definition: nt_native.h:1467
ULONG R12
Definition: ke.h:267
ULONG SegCs
Definition: nt_native.h:1477
ULONG SegDs
Definition: nt_native.h:1456
ULONG R9
Definition: ke.h:264
ULONG EFlags
Definition: nt_native.h:1478
ULONG SegGs
Definition: nt_native.h:1453
ULONG R10
Definition: ke.h:265
ULONG Eax
Definition: nt_native.h:1468
ULONG SegEs
Definition: nt_native.h:1455
ULONG Ebx
Definition: nt_native.h:1465
ULONG Edi
Definition: nt_native.h:1463
ULONG R11
Definition: ke.h:266
#define max(a, b)
Definition: svc.c:63
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG_PTR
Definition: typedefs.h:65
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
@ Start
Definition: partlist.h:33
_In_ WDFCOLLECTION _In_ ULONG Index
HANDLE WINAPI GetCurrentThread(void)
Definition: proc.c:1148
#define WINAPI
Definition: msvc.h:6
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
* PM128A
Definition: ketypes.h:937
unsigned char UCHAR
Definition: xmlstorage.h:181