From ea289516070e516defb439ae272206529573c1fd Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Thu, 14 Mar 2024 20:24:33 +0200 Subject: [PATCH] [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. --- modules/rostests/apitests/CMakeLists.txt | 1 + modules/rostests/apitests/include/apitest.h | 3 + modules/rostests/apitests/umkm/CMakeLists.txt | 33 ++ modules/rostests/apitests/umkm/SystemCall.c | 314 ++++++++++++++++++ .../apitests/umkm/amd64/SystemCall_asm.s | 167 ++++++++++ .../apitests/umkm/i386/SystemCall_asm.s | 84 +++++ modules/rostests/apitests/umkm/precomp.h | 13 + modules/rostests/apitests/umkm/testlist.c | 13 + 8 files changed, 628 insertions(+) create mode 100644 modules/rostests/apitests/umkm/CMakeLists.txt create mode 100644 modules/rostests/apitests/umkm/SystemCall.c create mode 100644 modules/rostests/apitests/umkm/amd64/SystemCall_asm.s create mode 100644 modules/rostests/apitests/umkm/i386/SystemCall_asm.s create mode 100644 modules/rostests/apitests/umkm/precomp.h create mode 100644 modules/rostests/apitests/umkm/testlist.c diff --git a/modules/rostests/apitests/CMakeLists.txt b/modules/rostests/apitests/CMakeLists.txt index 4bb4e2ef024..9986da77a07 100644 --- a/modules/rostests/apitests/CMakeLists.txt +++ b/modules/rostests/apitests/CMakeLists.txt @@ -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) diff --git a/modules/rostests/apitests/include/apitest.h b/modules/rostests/apitests/include/apitest.h index d0cfb711d18..9a627e49560 100644 --- a/modules/rostests/apitests/include/apitest.h +++ b/modules/rostests/apitests/include/apitest.h @@ -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) diff --git a/modules/rostests/apitests/umkm/CMakeLists.txt b/modules/rostests/apitests/umkm/CMakeLists.txt new file mode 100644 index 00000000000..aef1929bd35 --- /dev/null +++ b/modules/rostests/apitests/umkm/CMakeLists.txt @@ -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) + diff --git a/modules/rostests/apitests/umkm/SystemCall.c b/modules/rostests/apitests/umkm/SystemCall.c new file mode 100644 index 00000000000..b3a0fe25bcc --- /dev/null +++ b/modules/rostests/apitests/umkm/SystemCall.c @@ -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 + */ + +#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(); +} diff --git a/modules/rostests/apitests/umkm/amd64/SystemCall_asm.s b/modules/rostests/apitests/umkm/amd64/SystemCall_asm.s new file mode 100644 index 00000000000..34d41852826 --- /dev/null +++ b/modules/rostests/apitests/umkm/amd64/SystemCall_asm.s @@ -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 + */ + +#include +#include + +.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 diff --git a/modules/rostests/apitests/umkm/i386/SystemCall_asm.s b/modules/rostests/apitests/umkm/i386/SystemCall_asm.s new file mode 100644 index 00000000000..3accba5aa3c --- /dev/null +++ b/modules/rostests/apitests/umkm/i386/SystemCall_asm.s @@ -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 + */ + +#include +#include + +.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 diff --git a/modules/rostests/apitests/umkm/precomp.h b/modules/rostests/apitests/umkm/precomp.h new file mode 100644 index 00000000000..3737939dc1d --- /dev/null +++ b/modules/rostests/apitests/umkm/precomp.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#define WIN32_NO_STATUS +#define _INC_WINDOWS +#define COM_NO_WINDOWS_H + +#include +#include +#include +#include +#include diff --git a/modules/rostests/apitests/umkm/testlist.c b/modules/rostests/apitests/umkm/testlist.c new file mode 100644 index 00000000000..af4d672cee4 --- /dev/null +++ b/modules/rostests/apitests/umkm/testlist.c @@ -0,0 +1,13 @@ +#define __ROS_LONG64__ + +#define STANDALONE +#include + +extern void func_SystemCall(void); + +const struct test winetest_testlist[] = +{ + { "SystemCall", func_SystemCall }, + + { 0, 0 } +};