Reactos

[KMTESTS:HAL] Add a test for string I/O intrinsic functions

CORE-20078

authored by

Dmitry Borisov and committed by
Stanislav Motylkov
7c3a119d 4a3a446b

+153 -1
+2 -1
modules/rostests/kmtests/CMakeLists.txt
··· 124 124 add_asm_files(KMTEST_DRV_ASM 125 125 kmtest_drv/vm_detect.S) 126 126 list(APPEND KMTEST_DRV_SOURCE 127 - ${KMTEST_DRV_ASM}) 127 + ${KMTEST_DRV_ASM} 128 + hal/HalPortIo.c) 128 129 endif() 129 130 130 131 add_library(kmtest_drv MODULE ${KMTEST_DRV_SOURCE})
+145
modules/rostests/kmtests/hal/HalPortIo.c
··· 1 + /* 2 + * PROJECT: ReactOS Kernel-Mode Tests 3 + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 + * PURPOSE: Tests for string I/O intrinsic functions 5 + * COPYRIGHT: Copyright 2025 Dmitry Borisov <di.sean@protonmail.com> 6 + */ 7 + 8 + /* INCLUDES *******************************************************************/ 9 + 10 + #include <kmt_test.h> 11 + 12 + #define NDEBUG 13 + #include <debug.h> 14 + 15 + /* GLOBALS ********************************************************************/ 16 + 17 + /* Compile with the highest optimization level to trigger a bug (See CORE-20078) */ 18 + #ifdef _MSC_VER 19 + #pragma optimize("gst", on) 20 + #pragma auto_inline(on) 21 + #else 22 + #pragma GCC optimize("O3") 23 + #endif 24 + 25 + /* Used to isolate the effects of intrinsics from each other */ 26 + typedef struct _TEST_CONTEXT 27 + { 28 + PVOID OldBuffer; 29 + UCHAR Pad[78]; 30 + USHORT Port; 31 + ULONG Size; 32 + PVOID Buffer; 33 + } TEST_CONTEXT, *PTEST_CONTEXT; 34 + 35 + /* TEST FUNCTIONS *************************************************************/ 36 + 37 + static 38 + /* 39 + * Isolate the effects of intrinsics from each other 40 + * and hide the TEST_CONTEXT initialization from the optimizer. 41 + */ 42 + DECLSPEC_NOINLINE 43 + VOID 44 + TestWriteStringUshort( 45 + _In_ PTEST_CONTEXT Context) 46 + { 47 + __outwordstring(Context->Port, Context->Buffer, Context->Size / sizeof(USHORT)); 48 + 49 + /* 50 + * The 'rep outsw' instruction increments or decrements the address in ESI by Size * 2. 51 + * Test for CORE-20078: the ESI value should be preserved across calls. 52 + */ 53 + ok_eq_pointer(Context->Buffer, Context->OldBuffer); 54 + } 55 + 56 + static 57 + DECLSPEC_NOINLINE 58 + VOID 59 + TestWriteStringUlong( 60 + _In_ PTEST_CONTEXT Context) 61 + { 62 + __outdwordstring(Context->Port, Context->Buffer, Context->Size / sizeof(ULONG)); 63 + 64 + ok_eq_pointer(Context->Buffer, Context->OldBuffer); 65 + } 66 + 67 + static 68 + DECLSPEC_NOINLINE 69 + VOID 70 + TestWriteStringUchar( 71 + _In_ PTEST_CONTEXT Context) 72 + { 73 + __inbytestring(Context->Port, Context->Buffer, Context->Size); 74 + 75 + ok_eq_pointer(Context->Buffer, Context->OldBuffer); 76 + } 77 + 78 + static 79 + DECLSPEC_NOINLINE 80 + VOID 81 + TestReadStringUshort( 82 + _In_ PTEST_CONTEXT Context) 83 + { 84 + __inwordstring(Context->Port, Context->Buffer, Context->Size / sizeof(USHORT)); 85 + 86 + ok_eq_pointer(Context->Buffer, Context->OldBuffer); 87 + } 88 + 89 + static 90 + DECLSPEC_NOINLINE 91 + VOID 92 + TestReadStringUlong( 93 + _In_ PTEST_CONTEXT Context) 94 + { 95 + __outdwordstring(Context->Port, Context->Buffer, Context->Size / sizeof(ULONG)); 96 + 97 + ok_eq_pointer(Context->Buffer, Context->OldBuffer); 98 + } 99 + 100 + static 101 + DECLSPEC_NOINLINE 102 + VOID 103 + TestReadStringUchar( 104 + _In_ PTEST_CONTEXT Context) 105 + { 106 + __inbytestring(Context->Port, Context->Buffer, Context->Size); 107 + 108 + ok_eq_pointer(Context->Buffer, Context->OldBuffer); 109 + } 110 + 111 + static 112 + VOID 113 + TestStringIo(VOID) 114 + { 115 + TEST_CONTEXT Context; 116 + UCHAR Buffer[20]; 117 + 118 + /* End of the x86 I/O range */ 119 + Context.Port = 0xFFFF - sizeof(ULONG); 120 + 121 + Context.Buffer = Buffer; 122 + Context.OldBuffer = Buffer; 123 + Context.Size = sizeof(Buffer); 124 + 125 + TestReadStringUchar(&Context); 126 + TestReadStringUshort(&Context); 127 + TestReadStringUlong(&Context); 128 + 129 + /* 130 + * Check whether the driver is running inside a virtual machine 131 + * as it's not safe to write to I/O ports 132 + * without having the port resources assigned. 133 + */ 134 + if (!skip(KmtIsVirtualMachine, "Please run those tests in a supported virtual machine\n")) 135 + { 136 + TestWriteStringUchar(&Context); 137 + TestWriteStringUshort(&Context); 138 + TestWriteStringUlong(&Context); 139 + } 140 + } 141 + 142 + START_TEST(HalPortIo) 143 + { 144 + TestStringIo(); 145 + }
+6
modules/rostests/kmtests/kmtest_drv/testlist.c
··· 26 26 KMT_TESTFUNC Test_FsRtlMcb; 27 27 KMT_TESTFUNC Test_FsRtlRemoveDotsFromPath; 28 28 KMT_TESTFUNC Test_FsRtlTunnel; 29 + #if defined(_M_IX86) || defined(_M_AMD64) 30 + KMT_TESTFUNC Test_HalPortIo; 31 + #endif 29 32 KMT_TESTFUNC Test_HalSystemInfo; 30 33 KMT_TESTFUNC Test_IoCreateFile; 31 34 KMT_TESTFUNC Test_IoDeviceInterface; ··· 110 113 { "FsRtlMcb", Test_FsRtlMcb }, 111 114 { "FsRtlRemoveDotsFromPath", Test_FsRtlRemoveDotsFromPath }, 112 115 { "FsRtlTunnel", Test_FsRtlTunnel }, 116 + #if defined(_M_IX86) || defined(_M_AMD64) 117 + { "HalPortIo", Test_HalPortIo }, 118 + #endif 113 119 { "HalSystemInfo", Test_HalSystemInfo }, 114 120 { "IoCreateFile", Test_IoCreateFile }, 115 121 { "IoDeviceInterface", Test_IoDeviceInterface },