[UMKM_APITEST] Add a test for syscall handling

This is intentionally not part of ntdll_apitest, because that links to advapi32, which links to rpcrt4, which (wrongly!) links to ws2_32, which (wrongly!) links to user32, which breaks the test.
This commit is contained in:
Timo Kreuzer 2024-03-14 20:24:33 +02:00
parent a771729e69
commit ea28951607
8 changed files with 628 additions and 0 deletions

View file

@ -49,6 +49,7 @@ add_subdirectory(shell32)
add_subdirectory(shlwapi)
add_subdirectory(spoolss)
add_subdirectory(psapi)
add_subdirectory(umkm)
add_subdirectory(user32)
add_subdirectory(user32_dynamic)
add_subdirectory(userenv)

View file

@ -55,6 +55,7 @@
#define ok_hr_(file, line, status, expected) ok_hex_(file, line, status, expected)
#define ok_eq_print(value, expected, spec) ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
#define ok_eq_print_(file, line, value, expected, spec) ok_(file,line)((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
#define ok_eq_pointer(value, expected) ok_eq_print(value, expected, "%p")
#define ok_eq_int(value, expected) ok_eq_print(value, expected, "%d")
#define ok_eq_uint(value, expected) ok_eq_print(value, expected, "%u")
@ -83,6 +84,8 @@
#define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)
#define ok_eq_tag(value, expected) ok_eq_print(value, expected, "0x%08lx")
#define ok_eq_hex_(file, line, value, expected) ok_eq_print_(file, line, value, expected, "0x%08lx")
#define ok_eq_hex64_(file, line, value, expected) ok_eq_print_(file, line, value, expected, "%I64x")
#define ok_eq_hex64(value, expected) ok_eq_print(value, expected, "%I64x")
#define ok_eq_xmm(value, expected) ok((value).Low == (expected).Low, #value " = %I64x'%08I64x, expected %I64x'%08I64x\n", (value).Low, (value).High, (expected).Low, (expected).High)

View file

@ -0,0 +1,33 @@
include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include)
list(APPEND SOURCE
SystemCall.c
precomp.h)
if(ARCH STREQUAL "i386")
add_asm_files(umkm_apitest_asm
i386/SystemCall_asm.s
)
elseif(ARCH STREQUAL "amd64")
add_asm_files(umkm_apitest_asm
amd64/SystemCall_asm.s
)
endif()
list(APPEND PCH_SKIP_SOURCE
testlist.c)
add_executable(umkm_apitest
${SOURCE}
${umkm_apitest_asm}
${PCH_SKIP_SOURCE})
target_link_libraries(umkm_apitest wine uuid ${PSEH_LIB})
set_module_type(umkm_apitest win32cui)
add_importlibs(umkm_apitest msvcrt kernel32 ntdll)
add_pch(umkm_apitest precomp.h "${PCH_SKIP_SOURCE}")
add_dependencies(umkm_apitest load_notifications)
add_rostests_file(TARGET umkm_apitest)

View file

@ -0,0 +1,314 @@
/*
* PROJECT: ReactOS API Tests
* LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
* PURPOSE: Tests for system calls
* COPYRIGHT: Copyright 2024 Timo Kreuzer <timo.kreuzer@reactos.org>
*/
#include "precomp.h"
#define EFLAGS_TF 0x100L
#define EFLAGS_INTERRUPT_MASK 0x200L
ULONG g_NoopSyscallNumber = 0;
ULONG g_HandlerCalled = 0;
ULONG g_RandomSeed = 0x63c28b49;
VOID
DoSyscallAndCaptureContext(
_In_ ULONG SyscallNumber,
_Out_ PCONTEXT PreContext,
_Out_ PCONTEXT PostContext);
extern const UCHAR SyscallReturn;
ULONG_PTR
DoSyscallWithUnalignedStack(
_In_ ULONG64 SyscallNumber);
#ifdef _M_IX86
__declspec(dllimport)
VOID
NTAPI
KiFastSystemCallRet(VOID);
#endif
static
BOOLEAN
InitSysCalls()
{
/* Scan instructions in NtFlushWriteBuffer to find the syscall number
for NtFlushWriteBuffer, which is a noop syscall on x86/x64 */
PUCHAR Instructions = (PUCHAR)NtFlushWriteBuffer;
for (ULONG i = 0; i < 32; i++)
{
if (Instructions[i] == 0xB8)
{
g_NoopSyscallNumber = *(PULONG)&Instructions[i + 1];
return TRUE;
}
}
return FALSE;
}
static
VOID
LoadUser32()
{
HMODULE hUser32 = LoadLibraryW(L"user32.dll");
ok(hUser32 != NULL, "Failed to load user32.dll\n");
}
static
LONG
WINAPI
VectoredExceptionHandlerForUserModeCallback(
struct _EXCEPTION_POINTERS *ExceptionInfo)
{
g_HandlerCalled++;
/* Return from the callback */
NtCallbackReturn(NULL, 0, 0xdeadbeef);
/* If that failed, we were not in a callback, keep searching */
return EXCEPTION_CONTINUE_SEARCH;
}
VOID
ValidateSyscall_(
_In_ PCCH File,
_In_ ULONG Line,
_In_ ULONG_PTR SyscallId,
_In_ ULONG_PTR Result)
{
CONTEXT PreContext, PostContext;
#ifdef _M_IX86
DoSyscallAndCaptureContext(SyscallId, &PreContext, &PostContext);
/* Non-volatile registers and rsp are unchanged */
ok_eq_hex_(File, Line, PostContext.Esp, PreContext.Esp);
ok_eq_hex_(File, Line, PostContext.Ebx, PreContext.Ebx);
ok_eq_hex_(File, Line, PostContext.Esi, PreContext.Esi);
ok_eq_hex_(File, Line, PostContext.Edi, PreContext.Edi);
ok_eq_hex_(File, Line, PostContext.Ebp, PreContext.Ebp);
/* Special cases */
ok_eq_hex_(File, Line, PostContext.Ecx, PreContext.Esp - 0x4C);
ok_eq_hex_(File, Line, PostContext.Edx, (ULONG)KiFastSystemCallRet);
ok_eq_hex_(File, Line, PostContext.Eax, Result);
#elif defined(_M_AMD64)
/* Initiaize the pre-contex with random numbers */
PULONG64 IntegerRegs = &PreContext.Rax;
PM128A XmmRegs = &PreContext.Xmm0;
for (ULONG Index = 0; Index < 16; Index++)
{
IntegerRegs[Index] = (ULONG64)RtlRandom(&g_RandomSeed) << 32 | RtlRandom(&g_RandomSeed);
XmmRegs[Index].Low = (ULONG64)RtlRandom(&g_RandomSeed) << 32 | RtlRandom(&g_RandomSeed);
XmmRegs[Index].High = (ULONG64)RtlRandom(&g_RandomSeed) << 32 | RtlRandom(&g_RandomSeed);
}
PreContext.EFlags = RtlRandom(&g_RandomSeed);
PreContext.EFlags &= ~(EFLAGS_TF | 0x20 | 0x40000);
PreContext.EFlags |= EFLAGS_INTERRUPT_MASK;
PreContext.SegDs = 0; //0x0028;
PreContext.SegEs = 0; //0x002B;
PreContext.SegFs = 0; //0x0053;
PreContext.SegGs = 0; //0x002B;
PreContext.SegSs = 0; // 0x002B;
DoSyscallAndCaptureContext(SyscallId, &PreContext, &PostContext);
/* Non-volatile registers and rsp are unchanged */
ok_eq_hex64_(File, Line, PostContext.Rsp, PreContext.Rsp);
ok_eq_hex64_(File, Line, PostContext.Rbx, PreContext.Rbx);
ok_eq_hex64_(File, Line, PostContext.Rsi, PreContext.Rsi);
ok_eq_hex64_(File, Line, PostContext.Rdi, PreContext.Rdi);
ok_eq_hex64_(File, Line, PostContext.Rbp, PreContext.Rbp);
ok_eq_hex64_(File, Line, PostContext.R12, PreContext.R12);
ok_eq_hex64_(File, Line, PostContext.R13, PreContext.R13);
ok_eq_hex64_(File, Line, PostContext.R14, PreContext.R14);
ok_eq_hex64_(File, Line, PostContext.R15, PreContext.R15);
ok_eq_hex64_(File, Line, PostContext.Xmm6.Low, PreContext.Xmm6.Low);
ok_eq_hex64_(File, Line, PostContext.Xmm6.High, PreContext.Xmm6.High);
ok_eq_hex64_(File, Line, PostContext.Xmm7.Low, PreContext.Xmm7.Low);
ok_eq_hex64_(File, Line, PostContext.Xmm7.High, PreContext.Xmm7.High);
ok_eq_hex64_(File, Line, PostContext.Xmm8.Low, PreContext.Xmm8.Low);
ok_eq_hex64_(File, Line, PostContext.Xmm8.High, PreContext.Xmm8.High);
ok_eq_hex64_(File, Line, PostContext.Xmm9.Low, PreContext.Xmm9.Low);
ok_eq_hex64_(File, Line, PostContext.Xmm9.High, PreContext.Xmm9.High);
ok_eq_hex64_(File, Line, PostContext.Xmm10.Low, PreContext.Xmm10.Low);
ok_eq_hex64_(File, Line, PostContext.Xmm10.High, PreContext.Xmm10.High);
ok_eq_hex64_(File, Line, PostContext.Xmm11.Low, PreContext.Xmm11.Low);
ok_eq_hex64_(File, Line, PostContext.Xmm11.High, PreContext.Xmm11.High);
ok_eq_hex64_(File, Line, PostContext.Xmm12.Low, PreContext.Xmm12.Low);
ok_eq_hex64_(File, Line, PostContext.Xmm12.High, PreContext.Xmm12.High);
ok_eq_hex64_(File, Line, PostContext.Xmm13.Low, PreContext.Xmm13.Low);
ok_eq_hex64_(File, Line, PostContext.Xmm13.High, PreContext.Xmm13.High);
ok_eq_hex64_(File, Line, PostContext.Xmm14.Low, PreContext.Xmm14.Low);
ok_eq_hex64_(File, Line, PostContext.Xmm14.High, PreContext.Xmm14.High);
ok_eq_hex64_(File, Line, PostContext.Xmm15.Low, PreContext.Xmm15.Low);
ok_eq_hex64_(File, Line, PostContext.Xmm15.High, PreContext.Xmm15.High);
/* Parity flag is flaky */
ok_eq_hex64_(File, Line, PostContext.EFlags & ~0x4, PreContext.EFlags & ~0x9F5);
ok_eq_hex64_(File, Line, PostContext.SegCs, 0x0033);
ok_eq_hex64_(File, Line, PostContext.SegSs, 0x002B);
ok_(File, Line)(PostContext.SegDs == PreContext.SegDs || PostContext.SegDs == 0x002B,
"Expected 0x002B, got 0x%04X\n", PostContext.SegDs);
ok_(File, Line)(PostContext.SegEs == PreContext.SegEs || PostContext.SegEs == 0x002B,
"Expected 0x002B, got 0x%04X\n", PostContext.SegEs);
ok_(File, Line)(PostContext.SegFs == PreContext.SegFs || PostContext.SegFs == 0x0053,
"Expected 0x002B, got 0x%04X\n", PostContext.SegFs);
ok_(File, Line)(PostContext.SegGs == PreContext.SegGs || PostContext.SegGs == 0x002B,
"Expected 0x002B, got 0x%04X\n", PostContext.SegGs);
ok_eq_hex64_(File, Line, PostContext.SegSs, 0x002B);
/* These volatile registers are zeroed */
ok_eq_hex64_(File, Line, PostContext.Rdx, 0);
ok_eq_hex64_(File, Line, PostContext.R10, 0);
ok_eq_hex64_(File, Line, PostContext.Xmm0.Low, 0);
ok_eq_hex64_(File, Line, PostContext.Xmm0.High, 0);
ok_eq_hex64_(File, Line, PostContext.Xmm1.Low, 0);
ok_eq_hex64_(File, Line, PostContext.Xmm1.High, 0);
ok_eq_hex64_(File, Line, PostContext.Xmm2.Low, 0);
ok_eq_hex64_(File, Line, PostContext.Xmm2.High, 0);
ok_eq_hex64_(File, Line, PostContext.Xmm3.Low, 0);
ok_eq_hex64_(File, Line, PostContext.Xmm3.High, 0);
ok_eq_hex64_(File, Line, PostContext.Xmm4.Low, 0);
ok_eq_hex64_(File, Line, PostContext.Xmm4.High, 0);
ok_eq_hex64_(File, Line, PostContext.Xmm5.Low, 0);
ok_eq_hex64_(File, Line, PostContext.Xmm5.High, 0);
/* Special cases */
ok_eq_hex64_(File, Line, PostContext.Rax, Result);
ok_eq_hex64_(File, Line, PostContext.Rcx, (ULONG64)&SyscallReturn);
ok_eq_hex64_(File, Line, PostContext.R8, PreContext.Rsp);
ok_eq_hex64_(File, Line, PostContext.R9, PreContext.Rbp);
ok_eq_hex64_(File, Line, PostContext.R11, PostContext.EFlags);
// TODO:Debug regs, mxcsr, floating point, etc.
#else
#error Unsupported architecture
#endif
}
#define ValidateSyscall(SyscallId, Result) ValidateSyscall_(__FILE__, __LINE__, SyscallId, Result)
static
VOID
Test_SyscallNumbers()
{
BOOL Wow64Process;
if (IsWow64Process(NtCurrentProcess(), &Wow64Process) && Wow64Process)
{
skip("Skipping syscall tests on WOW64\n");
return;
}
/* Test valid syscall number */
ValidateSyscall(g_NoopSyscallNumber, STATUS_SUCCESS);
/* Test invalid syscall number */
ValidateSyscall(0x0FFF, (ULONG)STATUS_INVALID_SYSTEM_SERVICE);
/* Add a vectored exception handler to catch the exception we will get
when KiUserCallbackDispatcher is called and user32.dll is not loaded
We cannot use SEH here, because the exception is outside of the try block */
PVOID hHandler = AddVectoredExceptionHandler(TRUE, VectoredExceptionHandlerForUserModeCallback);
ok(hHandler != NULL, "Failed to add vectored exception handler\n");
/* Test win32k syscall number without user32.dll loaded */
#ifdef _M_AMD64
ValidateSyscall(0x1000, STATUS_SUCCESS);
#else
ValidateSyscall(0x1000, (ULONG)STATUS_INVALID_SYSTEM_SERVICE);
#endif
ok_eq_ulong(g_HandlerCalled, 1UL);
/* Test invalid win32k syscall number without user32.dll loaded */
#ifdef _M_IX86
ValidateSyscall(0x1FFF, 0xffffffbf);
#else
ValidateSyscall(0x1FFF, (ULONG)STATUS_INVALID_SYSTEM_SERVICE);
#endif
ok_eq_ulong(g_HandlerCalled, 2UL);
RemoveVectoredExceptionHandler(hHandler);
LoadUser32();
/* Test invalid win32k syscall number */
#ifdef _M_IX86
ValidateSyscall(0x1FFF, 0xffffffbf);
#else
ValidateSyscall(0x1FFF, (ULONG)STATUS_INVALID_SYSTEM_SERVICE);
#endif
/* Test invalid syscall table number */
ValidateSyscall(0x2000 + g_NoopSyscallNumber, STATUS_SUCCESS);
ValidateSyscall(0x3000 + g_NoopSyscallNumber, STATUS_SUCCESS);
#if 0 // This only happens, when running the test from VS, but not from the command line
/* For some unknown reason the result gets sign extended in this case */
ULONG64 Result = DoSyscallWithUnalignedStack(0x2000);
ok_eq_hex64(Result, (LONG)STATUS_ACCESS_VIOLATION);
#endif
/* Test invalid upper bits in syscall number */
ValidateSyscall(0xFFFFFFFFFFF70000ULL + g_NoopSyscallNumber, STATUS_SUCCESS);
}
static
VOID
Test_SyscallPerformance()
{
ULONG64 Start, End, Cycles;
ULONG64 TotalCycles = 0, Min = -1, Max = 0;
ULONG64 Count = 100000;
ULONG Outliers = 0;
ULONG_PTR OldAffinityMask;
double AvgCycles;
OldAffinityMask = SetThreadAffinityMask(GetCurrentThread(), 1);
for (ULONG64 i = 0; i < Count; i++)
{
Start = __rdtsc();
NtFlushWriteBuffer();
End = __rdtsc();
Cycles = End - Start;
if (Cycles > 2000)
{
Outliers++;
continue;
}
TotalCycles += Cycles;
Min = min(Min, Cycles);
Max = max(Max, Cycles);
}
AvgCycles = (double)TotalCycles / (Count - Outliers);
trace("NtFlushWriteBuffer: avg %.2f cycles, min %I64u, max %I64u, Outliers %lu\n",
AvgCycles, Min, Max, Outliers);
SetThreadAffinityMask(GetCurrentThread(), OldAffinityMask);
}
START_TEST(SystemCall)
{
if (!InitSysCalls())
{
skip("Failed to initialize.\n");
return;
}
Test_SyscallNumbers();
Test_SyscallPerformance();
}

View file

@ -0,0 +1,167 @@
/*
* PROJECT: ReactOS API Tests
* LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
* PURPOSE: x64 ASM helper functions for syscall tests
* COPYRIGHT: Copyright 2024 Timo Kreuzer <timo.kreuzer@reactos.org>
*/
#include <asm.inc>
#include <ksamd64.inc>
.data
g_Rcx:
.quad 0
g_SegSs:
.short 0
.code64
EXTERN RtlCaptureContext:PROC
EXTERN g_NoopSyscallNumber:DWORD
#define STACK_ARGUMENT_SPACE 16*8
LoadContext:
push qword ptr [rcx + CxEFlags]
popfq
movdqu xmm0, [rcx + CxXmm0]
movdqu xmm1, [rcx + CxXmm1]
movdqu xmm2, [rcx + CxXmm2]
movdqu xmm3, [rcx + CxXmm3]
movdqu xmm4, [rcx + CxXmm4]
movdqu xmm5, [rcx + CxXmm5]
movdqu xmm6, [rcx + CxXmm6]
movdqu xmm7, [rcx + CxXmm7]
movdqu xmm8, [rcx + CxXmm8]
movdqu xmm9, [rcx + CxXmm9]
movdqu xmm10, [rcx + CxXmm10]
movdqu xmm11, [rcx + CxXmm11]
movdqu xmm12, [rcx + CxXmm12]
movdqu xmm13, [rcx + CxXmm13]
movdqu xmm14, [rcx + CxXmm14]
movdqu xmm15, [rcx + CxXmm15]
mov rax, [rcx + CxRax]
mov rbx, [rcx + CxRbx]
mov rdx, [rcx + CxRdx]
mov rsi, [rcx + CxRsi]
mov rdi, [rcx + CxRdi]
mov rbp, [rcx + CxRbp]
mov r8, [rcx + CxR8]
mov r9, [rcx + CxR9]
mov r10, [rcx + CxR10]
mov r11, [rcx + CxR11]
mov r12, [rcx + CxR12]
mov r13, [rcx + CxR13]
mov r14, [rcx + CxR14]
mov r15, [rcx + CxR15]
//mov rcx, [rcx + CxRcx]
mov ax, [rcx + CxSegDs]
mov ds, ax
mov ax, [rcx + CxSegEs]
mov es, ax
mov ax, [rcx + CxSegFs]
mov fs, ax
mov ax, [rcx + CxSegGs]
//mov gs, ax // FIXME: ReactOS does not like this
ret
PUBLIC SyscallReturn
.PROC DoSyscallAndCaptureContext2
/* Allocate enough space for the system call handler */
sub rsp, STACK_ARGUMENT_SPACE + 5*8
.ALLOCSTACK STACK_ARGUMENT_SPACE + 5*8
.ENDPROLOG
/* Save rcx and r8 in the home space */
mov [rsp + STACK_ARGUMENT_SPACE + 6*8], rcx
mov [rsp + STACK_ARGUMENT_SPACE + 8*8], r8
/* Load the pre-context */
mov rcx, rdx
call LoadContext
call RtlCaptureContext
mov ax, word ptr [rcx + CxSegSs]
mov ss, ax
/* Do the syscall */
mov rax, [rsp + STACK_ARGUMENT_SPACE + 6*8]
syscall
GLOBAL_LABEL SyscallReturn
/* Save returned ss */
mov qword ptr g_Rcx[rip], rcx
mov cx, ss
mov word ptr g_SegSs[rip], cx
mov cx, HEX(2B)
mov ss, cx
/* Save the post-context */
mov rcx, [rsp + STACK_ARGUMENT_SPACE + 8*8]
call RtlCaptureContext
mov rcx, qword ptr g_Rcx[rip]
mov rax, [rsp + STACK_ARGUMENT_SPACE + 8*8]
mov [rax + CxRcx], rcx
mov ax, HEX(2B)
mov ds, ax
mov es, ax
//mov gs, ax // FIXME: ReactOS does not like this
mov ss, ax
mov ax, HEX(53)
mov fs, ax
cld
mov rcx, [rsp + STACK_ARGUMENT_SPACE + 8*8]
mov ax, word ptr g_SegSs[rip]
mov [rcx + CxSegSs], ax
add rsp, STACK_ARGUMENT_SPACE + 5*8
ret
.ENDP
/*
* VOID
* DoSyscallAndCaptureContext(
* _In_ ULONG64 SyscallNumber,
* _Out_ PCONTEXT PreContext,
* _Out_ PCONTEXT PostContext);
*/
PUBLIC DoSyscallAndCaptureContext
.PROC DoSyscallAndCaptureContext
GENERATE_EXCEPTION_FRAME
call DoSyscallAndCaptureContext2
RESTORE_EXCEPTION_STATE
ret
.ENDP
/*
* ULONG64
* DoSyscallWithUnalignedStack(
* _In_ ULONG64 SyscallNumber);
*/
PUBLIC DoSyscallWithUnalignedStack
.PROC DoSyscallWithUnalignedStack
/* Allocate enough space for the system call handler */
sub rsp, STACK_ARGUMENT_SPACE + 6*8
.ALLOCSTACK STACK_ARGUMENT_SPACE + 6*8
.ENDPROLOG
mov rax, rcx
syscall
add rsp, STACK_ARGUMENT_SPACE + 6*8
ret
.ENDP
END

View file

@ -0,0 +1,84 @@
/*
* PROJECT: ReactOS API Tests
* LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
* PURPOSE: x86 ASM helper functions for syscall tests
* COPYRIGHT: Copyright 2024 Timo Kreuzer <timo.kreuzer@reactos.org>
*/
#include <asm.inc>
#include <ks386.inc>
.code
#define STACK_ARGUMENT_SPACE 16*4
EXTERN _RtlCaptureContext@4:PROC
DoSyscall:
mov edx, esp
sysenter
ret
/*
* VOID
* DoSyscallAndCaptureContext(
* _In_ ULONG64 SyscallNumber,
* _Out_ PCONTEXT PreContext,
* _Out_ PCONTEXT PostContext);
*/
PUBLIC _DoSyscallAndCaptureContext
.PROC _DoSyscallAndCaptureContext
push ebp
mov ebp, esp
/* Allocate enough space for the system call handler */
sub esp, STACK_ARGUMENT_SPACE
/* Save the pre-context */
push [ebp + 12]
call _RtlCaptureContext@4
/* Do the system call */
mov eax, [ebp + 8]
Call DoSyscall
/* Save eax */
push eax
/* Save the post-context */
push dword ptr [ebp + 16]
call _RtlCaptureContext@4
/* Restore eax and save it in the context */
pop eax
mov ecx, [ebp + 16]
mov [ecx + CsEax], eax
mov esp, ebp
pop ebp
ret
.ENDP
/*
* ULONG64
* DoSyscallWithUnalignedStack(
* _In_ ULONG64 SyscallNumber);
*/
PUBLIC _DoSyscallWithUnalignedStack
.PROC _DoSyscallWithUnalignedStack
push ebp
mov ebp, esp
/* Allocate enough space for the system call handler */
sub esp, STACK_ARGUMENT_SPACE
/* Do the sysenter */
mov eax, [ebp + 8]
sysenter
mov esp, ebp
pop ebp
ret
.ENDP
END

View file

@ -0,0 +1,13 @@
#pragma once
#include <stdio.h>
#define WIN32_NO_STATUS
#define _INC_WINDOWS
#define COM_NO_WINDOWS_H
#include <apitest.h>
#include <apitest_guard.h>
#include <ndk/ntndk.h>
#include <strsafe.h>
#include <pseh/pseh2.h>

View file

@ -0,0 +1,13 @@
#define __ROS_LONG64__
#define STANDALONE
#include <apitest.h>
extern void func_SystemCall(void);
const struct test winetest_testlist[] =
{
{ "SystemCall", func_SystemCall },
{ 0, 0 }
};