1*ea289516STimo Kreuzer /*
2*ea289516STimo Kreuzer * PROJECT: ReactOS API Tests
3*ea289516STimo Kreuzer * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4*ea289516STimo Kreuzer * PURPOSE: Tests for system calls
5*ea289516STimo Kreuzer * COPYRIGHT: Copyright 2024 Timo Kreuzer <timo.kreuzer@reactos.org>
6*ea289516STimo Kreuzer */
7*ea289516STimo Kreuzer
8*ea289516STimo Kreuzer #include "precomp.h"
9*ea289516STimo Kreuzer
10*ea289516STimo Kreuzer #define EFLAGS_TF 0x100L
11*ea289516STimo Kreuzer #define EFLAGS_INTERRUPT_MASK 0x200L
12*ea289516STimo Kreuzer
13*ea289516STimo Kreuzer ULONG g_NoopSyscallNumber = 0;
14*ea289516STimo Kreuzer ULONG g_HandlerCalled = 0;
15*ea289516STimo Kreuzer ULONG g_RandomSeed = 0x63c28b49;
16*ea289516STimo Kreuzer
17*ea289516STimo Kreuzer VOID
18*ea289516STimo Kreuzer DoSyscallAndCaptureContext(
19*ea289516STimo Kreuzer _In_ ULONG SyscallNumber,
20*ea289516STimo Kreuzer _Out_ PCONTEXT PreContext,
21*ea289516STimo Kreuzer _Out_ PCONTEXT PostContext);
22*ea289516STimo Kreuzer
23*ea289516STimo Kreuzer extern const UCHAR SyscallReturn;
24*ea289516STimo Kreuzer
25*ea289516STimo Kreuzer ULONG_PTR
26*ea289516STimo Kreuzer DoSyscallWithUnalignedStack(
27*ea289516STimo Kreuzer _In_ ULONG64 SyscallNumber);
28*ea289516STimo Kreuzer
29*ea289516STimo Kreuzer #ifdef _M_IX86
30*ea289516STimo Kreuzer __declspec(dllimport)
31*ea289516STimo Kreuzer VOID
32*ea289516STimo Kreuzer NTAPI
33*ea289516STimo Kreuzer KiFastSystemCallRet(VOID);
34*ea289516STimo Kreuzer #endif
35*ea289516STimo Kreuzer
36*ea289516STimo Kreuzer static
37*ea289516STimo Kreuzer BOOLEAN
InitSysCalls()38*ea289516STimo Kreuzer InitSysCalls()
39*ea289516STimo Kreuzer {
40*ea289516STimo Kreuzer /* Scan instructions in NtFlushWriteBuffer to find the syscall number
41*ea289516STimo Kreuzer for NtFlushWriteBuffer, which is a noop syscall on x86/x64 */
42*ea289516STimo Kreuzer PUCHAR Instructions = (PUCHAR)NtFlushWriteBuffer;
43*ea289516STimo Kreuzer for (ULONG i = 0; i < 32; i++)
44*ea289516STimo Kreuzer {
45*ea289516STimo Kreuzer if (Instructions[i] == 0xB8)
46*ea289516STimo Kreuzer {
47*ea289516STimo Kreuzer g_NoopSyscallNumber = *(PULONG)&Instructions[i + 1];
48*ea289516STimo Kreuzer return TRUE;
49*ea289516STimo Kreuzer }
50*ea289516STimo Kreuzer }
51*ea289516STimo Kreuzer
52*ea289516STimo Kreuzer return FALSE;
53*ea289516STimo Kreuzer }
54*ea289516STimo Kreuzer
55*ea289516STimo Kreuzer static
56*ea289516STimo Kreuzer VOID
LoadUser32()57*ea289516STimo Kreuzer LoadUser32()
58*ea289516STimo Kreuzer {
59*ea289516STimo Kreuzer HMODULE hUser32 = LoadLibraryW(L"user32.dll");
60*ea289516STimo Kreuzer ok(hUser32 != NULL, "Failed to load user32.dll\n");
61*ea289516STimo Kreuzer }
62*ea289516STimo Kreuzer
63*ea289516STimo Kreuzer static
64*ea289516STimo Kreuzer LONG
65*ea289516STimo Kreuzer WINAPI
VectoredExceptionHandlerForUserModeCallback(struct _EXCEPTION_POINTERS * ExceptionInfo)66*ea289516STimo Kreuzer VectoredExceptionHandlerForUserModeCallback(
67*ea289516STimo Kreuzer struct _EXCEPTION_POINTERS *ExceptionInfo)
68*ea289516STimo Kreuzer {
69*ea289516STimo Kreuzer g_HandlerCalled++;
70*ea289516STimo Kreuzer
71*ea289516STimo Kreuzer /* Return from the callback */
72*ea289516STimo Kreuzer NtCallbackReturn(NULL, 0, 0xdeadbeef);
73*ea289516STimo Kreuzer
74*ea289516STimo Kreuzer /* If that failed, we were not in a callback, keep searching */
75*ea289516STimo Kreuzer return EXCEPTION_CONTINUE_SEARCH;
76*ea289516STimo Kreuzer }
77*ea289516STimo Kreuzer
78*ea289516STimo Kreuzer VOID
ValidateSyscall_(_In_ PCCH File,_In_ ULONG Line,_In_ ULONG_PTR SyscallId,_In_ ULONG_PTR Result)79*ea289516STimo Kreuzer ValidateSyscall_(
80*ea289516STimo Kreuzer _In_ PCCH File,
81*ea289516STimo Kreuzer _In_ ULONG Line,
82*ea289516STimo Kreuzer _In_ ULONG_PTR SyscallId,
83*ea289516STimo Kreuzer _In_ ULONG_PTR Result)
84*ea289516STimo Kreuzer {
85*ea289516STimo Kreuzer CONTEXT PreContext, PostContext;
86*ea289516STimo Kreuzer
87*ea289516STimo Kreuzer #ifdef _M_IX86
88*ea289516STimo Kreuzer DoSyscallAndCaptureContext(SyscallId, &PreContext, &PostContext);
89*ea289516STimo Kreuzer
90*ea289516STimo Kreuzer /* Non-volatile registers and rsp are unchanged */
91*ea289516STimo Kreuzer ok_eq_hex_(File, Line, PostContext.Esp, PreContext.Esp);
92*ea289516STimo Kreuzer ok_eq_hex_(File, Line, PostContext.Ebx, PreContext.Ebx);
93*ea289516STimo Kreuzer ok_eq_hex_(File, Line, PostContext.Esi, PreContext.Esi);
94*ea289516STimo Kreuzer ok_eq_hex_(File, Line, PostContext.Edi, PreContext.Edi);
95*ea289516STimo Kreuzer ok_eq_hex_(File, Line, PostContext.Ebp, PreContext.Ebp);
96*ea289516STimo Kreuzer
97*ea289516STimo Kreuzer /* Special cases */
98*ea289516STimo Kreuzer ok_eq_hex_(File, Line, PostContext.Ecx, PreContext.Esp - 0x4C);
99*ea289516STimo Kreuzer ok_eq_hex_(File, Line, PostContext.Edx, (ULONG)KiFastSystemCallRet);
100*ea289516STimo Kreuzer ok_eq_hex_(File, Line, PostContext.Eax, Result);
101*ea289516STimo Kreuzer
102*ea289516STimo Kreuzer #elif defined(_M_AMD64)
103*ea289516STimo Kreuzer /* Initiaize the pre-contex with random numbers */
104*ea289516STimo Kreuzer PULONG64 IntegerRegs = &PreContext.Rax;
105*ea289516STimo Kreuzer PM128A XmmRegs = &PreContext.Xmm0;
106*ea289516STimo Kreuzer for (ULONG Index = 0; Index < 16; Index++)
107*ea289516STimo Kreuzer {
108*ea289516STimo Kreuzer IntegerRegs[Index] = (ULONG64)RtlRandom(&g_RandomSeed) << 32 | RtlRandom(&g_RandomSeed);
109*ea289516STimo Kreuzer XmmRegs[Index].Low = (ULONG64)RtlRandom(&g_RandomSeed) << 32 | RtlRandom(&g_RandomSeed);
110*ea289516STimo Kreuzer XmmRegs[Index].High = (ULONG64)RtlRandom(&g_RandomSeed) << 32 | RtlRandom(&g_RandomSeed);
111*ea289516STimo Kreuzer }
112*ea289516STimo Kreuzer PreContext.EFlags = RtlRandom(&g_RandomSeed);
113*ea289516STimo Kreuzer PreContext.EFlags &= ~(EFLAGS_TF | 0x20 | 0x40000);
114*ea289516STimo Kreuzer PreContext.EFlags |= EFLAGS_INTERRUPT_MASK;
115*ea289516STimo Kreuzer
116*ea289516STimo Kreuzer PreContext.SegDs = 0; //0x0028;
117*ea289516STimo Kreuzer PreContext.SegEs = 0; //0x002B;
118*ea289516STimo Kreuzer PreContext.SegFs = 0; //0x0053;
119*ea289516STimo Kreuzer PreContext.SegGs = 0; //0x002B;
120*ea289516STimo Kreuzer PreContext.SegSs = 0; // 0x002B;
121*ea289516STimo Kreuzer
122*ea289516STimo Kreuzer DoSyscallAndCaptureContext(SyscallId, &PreContext, &PostContext);
123*ea289516STimo Kreuzer
124*ea289516STimo Kreuzer /* Non-volatile registers and rsp are unchanged */
125*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Rsp, PreContext.Rsp);
126*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Rbx, PreContext.Rbx);
127*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Rsi, PreContext.Rsi);
128*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Rdi, PreContext.Rdi);
129*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Rbp, PreContext.Rbp);
130*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.R12, PreContext.R12);
131*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.R13, PreContext.R13);
132*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.R14, PreContext.R14);
133*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.R15, PreContext.R15);
134*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm6.Low, PreContext.Xmm6.Low);
135*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm6.High, PreContext.Xmm6.High);
136*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm7.Low, PreContext.Xmm7.Low);
137*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm7.High, PreContext.Xmm7.High);
138*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm8.Low, PreContext.Xmm8.Low);
139*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm8.High, PreContext.Xmm8.High);
140*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm9.Low, PreContext.Xmm9.Low);
141*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm9.High, PreContext.Xmm9.High);
142*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm10.Low, PreContext.Xmm10.Low);
143*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm10.High, PreContext.Xmm10.High);
144*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm11.Low, PreContext.Xmm11.Low);
145*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm11.High, PreContext.Xmm11.High);
146*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm12.Low, PreContext.Xmm12.Low);
147*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm12.High, PreContext.Xmm12.High);
148*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm13.Low, PreContext.Xmm13.Low);
149*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm13.High, PreContext.Xmm13.High);
150*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm14.Low, PreContext.Xmm14.Low);
151*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm14.High, PreContext.Xmm14.High);
152*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm15.Low, PreContext.Xmm15.Low);
153*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm15.High, PreContext.Xmm15.High);
154*ea289516STimo Kreuzer
155*ea289516STimo Kreuzer /* Parity flag is flaky */
156*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.EFlags & ~0x4, PreContext.EFlags & ~0x9F5);
157*ea289516STimo Kreuzer
158*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.SegCs, 0x0033);
159*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.SegSs, 0x002B);
160*ea289516STimo Kreuzer ok_(File, Line)(PostContext.SegDs == PreContext.SegDs || PostContext.SegDs == 0x002B,
161*ea289516STimo Kreuzer "Expected 0x002B, got 0x%04X\n", PostContext.SegDs);
162*ea289516STimo Kreuzer ok_(File, Line)(PostContext.SegEs == PreContext.SegEs || PostContext.SegEs == 0x002B,
163*ea289516STimo Kreuzer "Expected 0x002B, got 0x%04X\n", PostContext.SegEs);
164*ea289516STimo Kreuzer ok_(File, Line)(PostContext.SegFs == PreContext.SegFs || PostContext.SegFs == 0x0053,
165*ea289516STimo Kreuzer "Expected 0x002B, got 0x%04X\n", PostContext.SegFs);
166*ea289516STimo Kreuzer ok_(File, Line)(PostContext.SegGs == PreContext.SegGs || PostContext.SegGs == 0x002B,
167*ea289516STimo Kreuzer "Expected 0x002B, got 0x%04X\n", PostContext.SegGs);
168*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.SegSs, 0x002B);
169*ea289516STimo Kreuzer
170*ea289516STimo Kreuzer /* These volatile registers are zeroed */
171*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Rdx, 0);
172*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.R10, 0);
173*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm0.Low, 0);
174*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm0.High, 0);
175*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm1.Low, 0);
176*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm1.High, 0);
177*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm2.Low, 0);
178*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm2.High, 0);
179*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm3.Low, 0);
180*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm3.High, 0);
181*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm4.Low, 0);
182*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm4.High, 0);
183*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm5.Low, 0);
184*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Xmm5.High, 0);
185*ea289516STimo Kreuzer
186*ea289516STimo Kreuzer /* Special cases */
187*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Rax, Result);
188*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.Rcx, (ULONG64)&SyscallReturn);
189*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.R8, PreContext.Rsp);
190*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.R9, PreContext.Rbp);
191*ea289516STimo Kreuzer ok_eq_hex64_(File, Line, PostContext.R11, PostContext.EFlags);
192*ea289516STimo Kreuzer
193*ea289516STimo Kreuzer // TODO:Debug regs, mxcsr, floating point, etc.
194*ea289516STimo Kreuzer #else
195*ea289516STimo Kreuzer #error Unsupported architecture
196*ea289516STimo Kreuzer #endif
197*ea289516STimo Kreuzer }
198*ea289516STimo Kreuzer
199*ea289516STimo Kreuzer #define ValidateSyscall(SyscallId, Result) ValidateSyscall_(__FILE__, __LINE__, SyscallId, Result)
200*ea289516STimo Kreuzer
201*ea289516STimo Kreuzer static
202*ea289516STimo Kreuzer VOID
Test_SyscallNumbers()203*ea289516STimo Kreuzer Test_SyscallNumbers()
204*ea289516STimo Kreuzer {
205*ea289516STimo Kreuzer BOOL Wow64Process;
206*ea289516STimo Kreuzer
207*ea289516STimo Kreuzer if (IsWow64Process(NtCurrentProcess(), &Wow64Process) && Wow64Process)
208*ea289516STimo Kreuzer {
209*ea289516STimo Kreuzer skip("Skipping syscall tests on WOW64\n");
210*ea289516STimo Kreuzer return;
211*ea289516STimo Kreuzer }
212*ea289516STimo Kreuzer
213*ea289516STimo Kreuzer /* Test valid syscall number */
214*ea289516STimo Kreuzer ValidateSyscall(g_NoopSyscallNumber, STATUS_SUCCESS);
215*ea289516STimo Kreuzer
216*ea289516STimo Kreuzer /* Test invalid syscall number */
217*ea289516STimo Kreuzer ValidateSyscall(0x0FFF, (ULONG)STATUS_INVALID_SYSTEM_SERVICE);
218*ea289516STimo Kreuzer
219*ea289516STimo Kreuzer /* Add a vectored exception handler to catch the exception we will get
220*ea289516STimo Kreuzer when KiUserCallbackDispatcher is called and user32.dll is not loaded
221*ea289516STimo Kreuzer We cannot use SEH here, because the exception is outside of the try block */
222*ea289516STimo Kreuzer PVOID hHandler = AddVectoredExceptionHandler(TRUE, VectoredExceptionHandlerForUserModeCallback);
223*ea289516STimo Kreuzer ok(hHandler != NULL, "Failed to add vectored exception handler\n");
224*ea289516STimo Kreuzer
225*ea289516STimo Kreuzer /* Test win32k syscall number without user32.dll loaded */
226*ea289516STimo Kreuzer #ifdef _M_AMD64
227*ea289516STimo Kreuzer ValidateSyscall(0x1000, STATUS_SUCCESS);
228*ea289516STimo Kreuzer #else
229*ea289516STimo Kreuzer ValidateSyscall(0x1000, (ULONG)STATUS_INVALID_SYSTEM_SERVICE);
230*ea289516STimo Kreuzer #endif
231*ea289516STimo Kreuzer ok_eq_ulong(g_HandlerCalled, 1UL);
232*ea289516STimo Kreuzer
233*ea289516STimo Kreuzer /* Test invalid win32k syscall number without user32.dll loaded */
234*ea289516STimo Kreuzer #ifdef _M_IX86
235*ea289516STimo Kreuzer ValidateSyscall(0x1FFF, 0xffffffbf);
236*ea289516STimo Kreuzer #else
237*ea289516STimo Kreuzer ValidateSyscall(0x1FFF, (ULONG)STATUS_INVALID_SYSTEM_SERVICE);
238*ea289516STimo Kreuzer #endif
239*ea289516STimo Kreuzer
240*ea289516STimo Kreuzer ok_eq_ulong(g_HandlerCalled, 2UL);
241*ea289516STimo Kreuzer
242*ea289516STimo Kreuzer RemoveVectoredExceptionHandler(hHandler);
243*ea289516STimo Kreuzer
244*ea289516STimo Kreuzer LoadUser32();
245*ea289516STimo Kreuzer
246*ea289516STimo Kreuzer /* Test invalid win32k syscall number */
247*ea289516STimo Kreuzer #ifdef _M_IX86
248*ea289516STimo Kreuzer ValidateSyscall(0x1FFF, 0xffffffbf);
249*ea289516STimo Kreuzer #else
250*ea289516STimo Kreuzer ValidateSyscall(0x1FFF, (ULONG)STATUS_INVALID_SYSTEM_SERVICE);
251*ea289516STimo Kreuzer #endif
252*ea289516STimo Kreuzer
253*ea289516STimo Kreuzer /* Test invalid syscall table number */
254*ea289516STimo Kreuzer ValidateSyscall(0x2000 + g_NoopSyscallNumber, STATUS_SUCCESS);
255*ea289516STimo Kreuzer ValidateSyscall(0x3000 + g_NoopSyscallNumber, STATUS_SUCCESS);
256*ea289516STimo Kreuzer
257*ea289516STimo Kreuzer #if 0 // This only happens, when running the test from VS, but not from the command line
258*ea289516STimo Kreuzer /* For some unknown reason the result gets sign extended in this case */
259*ea289516STimo Kreuzer ULONG64 Result = DoSyscallWithUnalignedStack(0x2000);
260*ea289516STimo Kreuzer ok_eq_hex64(Result, (LONG)STATUS_ACCESS_VIOLATION);
261*ea289516STimo Kreuzer #endif
262*ea289516STimo Kreuzer
263*ea289516STimo Kreuzer /* Test invalid upper bits in syscall number */
264*ea289516STimo Kreuzer ValidateSyscall(0xFFFFFFFFFFF70000ULL + g_NoopSyscallNumber, STATUS_SUCCESS);
265*ea289516STimo Kreuzer }
266*ea289516STimo Kreuzer
267*ea289516STimo Kreuzer static
268*ea289516STimo Kreuzer VOID
Test_SyscallPerformance()269*ea289516STimo Kreuzer Test_SyscallPerformance()
270*ea289516STimo Kreuzer {
271*ea289516STimo Kreuzer ULONG64 Start, End, Cycles;
272*ea289516STimo Kreuzer ULONG64 TotalCycles = 0, Min = -1, Max = 0;
273*ea289516STimo Kreuzer ULONG64 Count = 100000;
274*ea289516STimo Kreuzer ULONG Outliers = 0;
275*ea289516STimo Kreuzer ULONG_PTR OldAffinityMask;
276*ea289516STimo Kreuzer double AvgCycles;
277*ea289516STimo Kreuzer
278*ea289516STimo Kreuzer OldAffinityMask = SetThreadAffinityMask(GetCurrentThread(), 1);
279*ea289516STimo Kreuzer
280*ea289516STimo Kreuzer for (ULONG64 i = 0; i < Count; i++)
281*ea289516STimo Kreuzer {
282*ea289516STimo Kreuzer Start = __rdtsc();
283*ea289516STimo Kreuzer NtFlushWriteBuffer();
284*ea289516STimo Kreuzer End = __rdtsc();
285*ea289516STimo Kreuzer Cycles = End - Start;
286*ea289516STimo Kreuzer if (Cycles > 2000)
287*ea289516STimo Kreuzer {
288*ea289516STimo Kreuzer Outliers++;
289*ea289516STimo Kreuzer continue;
290*ea289516STimo Kreuzer }
291*ea289516STimo Kreuzer TotalCycles += Cycles;
292*ea289516STimo Kreuzer Min = min(Min, Cycles);
293*ea289516STimo Kreuzer Max = max(Max, Cycles);
294*ea289516STimo Kreuzer }
295*ea289516STimo Kreuzer
296*ea289516STimo Kreuzer AvgCycles = (double)TotalCycles / (Count - Outliers);
297*ea289516STimo Kreuzer
298*ea289516STimo Kreuzer trace("NtFlushWriteBuffer: avg %.2f cycles, min %I64u, max %I64u, Outliers %lu\n",
299*ea289516STimo Kreuzer AvgCycles, Min, Max, Outliers);
300*ea289516STimo Kreuzer
301*ea289516STimo Kreuzer SetThreadAffinityMask(GetCurrentThread(), OldAffinityMask);
302*ea289516STimo Kreuzer }
303*ea289516STimo Kreuzer
START_TEST(SystemCall)304*ea289516STimo Kreuzer START_TEST(SystemCall)
305*ea289516STimo Kreuzer {
306*ea289516STimo Kreuzer if (!InitSysCalls())
307*ea289516STimo Kreuzer {
308*ea289516STimo Kreuzer skip("Failed to initialize.\n");
309*ea289516STimo Kreuzer return;
310*ea289516STimo Kreuzer }
311*ea289516STimo Kreuzer
312*ea289516STimo Kreuzer Test_SyscallNumbers();
313*ea289516STimo Kreuzer Test_SyscallPerformance();
314*ea289516STimo Kreuzer }
315