1 /*
2  * PROJECT:     ReactOS kernel-mode tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Kernel-Mode Test Suite for KdSystemDebugControl (kernel-mode)
5  * COPYRIGHT:   Copyright 2024 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 #include <ndk/kdfuncs.h>
10 
11 #define ok_eq_print_test(testid, value, expected, spec) \
12     ok((value) == (expected), "In test %lu: " #value " = " spec ", expected " spec "\n", testid, value, expected)
13 
14 #define ok_eq_hex_test(testid, value, expected) \
15     ok_eq_print_test(testid, value, expected, "0x%08lx")
16 
17 #define ok_neq_print_test(testid, value, expected, spec) \
18     ok((value) != (expected), "In test %lu: " #value " = " spec ", expected != " spec "\n", testid, value, expected)
19 
20 #define ok_neq_hex_test(testid, value, expected) \
21     ok_neq_print_test(testid, value, expected, "0x%08lx")
22 
23 
24 BOOLEAN
25 (NTAPI *pKdRefreshDebuggerNotPresent)(VOID);
26 
27 NTSTATUS
28 (NTAPI *pKdSystemDebugControl)(
29     _In_ SYSDBG_COMMAND Command,
30     _In_ PVOID InputBuffer,
31     _In_ ULONG InputBufferLength,
32     _Out_ PVOID OutputBuffer,
33     _In_ ULONG OutputBufferLength,
34     _Inout_ PULONG ReturnLength,
35     _In_ KPROCESSOR_MODE PreviousMode);
36 
37 
38 static
39 NTSTATUS
40 TestSystemDebugControl(
41     _In_ SYSDBG_COMMAND Command)
42 {
43     return pKdSystemDebugControl(Command,
44                                  NULL, // _In_ PVOID InputBuffer,
45                                  0,    // _In_ ULONG InputBufferLength,
46                                  NULL, // _Out_ PVOID OutputBuffer,
47                                  0,    // _In_ ULONG OutputBufferLength,
48                                  NULL,
49                                  KernelMode);
50 }
51 
52 START_TEST(KdSystemDebugControl)
53 {
54     NTSTATUS Status;
55     ULONG Command;
56     RTL_OSVERSIONINFOEXW verInfo;
57     UNICODE_STRING fnName;
58     BOOLEAN IsNT52SP1OrHigher;
59     BOOLEAN IsVistaOrHigher;
60     BOOLEAN IsDebuggerActive;
61 
62     /* Test for OS version: KdSystemDebugControl()
63      * exists only on NT 5.2 SP1 and higher */
64     verInfo.dwOSVersionInfoSize = sizeof(verInfo);
65     Status = RtlGetVersion((PRTL_OSVERSIONINFOW)&verInfo);
66     if (skip(NT_SUCCESS(Status), "RtlGetVersion() returned 0x%08lx\n", Status))
67         return;
68 
69     // IsWindowsVersionOrGreater(5, 2, 1);
70     IsNT52SP1OrHigher =
71         (verInfo.dwMajorVersion > 5) ||
72         (verInfo.dwMajorVersion == 5 && verInfo.dwMinorVersion > 2) ||
73         (verInfo.dwMajorVersion == 5 && verInfo.dwMinorVersion == 2 && verInfo.wServicePackMajor >= 1);
74 
75     if (skip(IsNT52SP1OrHigher, "KdSystemDebugControl() only exists on NT 5.2 SP1 and higher\n"))
76         return;
77 
78     // IsWindowsVersionOrGreater(6, 0, 0);
79     IsVistaOrHigher = (verInfo.dwMajorVersion >= 6);
80 
81 
82     /* Load the Kd routines at runtime */
83 
84     /* Note: KdRefreshDebuggerNotPresent() is NT 5.2+ */
85     RtlInitUnicodeString(&fnName, L"KdRefreshDebuggerNotPresent");
86     pKdRefreshDebuggerNotPresent = MmGetSystemRoutineAddress(&fnName);
87     ok(!!pKdRefreshDebuggerNotPresent,
88        "KdRefreshDebuggerNotPresent() unavailable but OS is NT 5.2 SP1 or higher?\n");
89 
90     RtlInitUnicodeString(&fnName, L"KdSystemDebugControl");
91     pKdSystemDebugControl = MmGetSystemRoutineAddress(&fnName);
92     if (skip(!!pKdSystemDebugControl, "KdSystemDebugControl() unavailable but OS is NT 5.2 SP1 or higher?\n"))
93         return;
94 
95 
96     /* Check whether the kernel debugger is present or not */
97     IsDebuggerActive = (pKdRefreshDebuggerNotPresent
98                      ? !pKdRefreshDebuggerNotPresent()
99                      : (/*KD_DEBUGGER_ENABLED &&*/ !KD_DEBUGGER_NOT_PRESENT));
100 
101     trace("Debugger is %s\n", IsDebuggerActive ? "active" : "inactive");
102 
103     /* Unsupported commands */
104     for (Command = 0; Command <= 6; ++Command)
105     {
106         Status = TestSystemDebugControl((SYSDBG_COMMAND)Command);
107         if (!IsVistaOrHigher || IsDebuggerActive)
108             ok_eq_hex_test(Command, Status, STATUS_INVALID_INFO_CLASS);
109         else
110             ok_eq_hex_test(Command, Status, STATUS_DEBUGGER_INACTIVE);
111     }
112 
113     /*
114      * Supported commands:
115      *
116      * SysDbgQueryVersion = 7,
117      * SysDbgReadVirtual  = 8,
118      * SysDbgWriteVirtual = 9,
119      * SysDbgReadPhysical  = 10,
120      * SysDbgWritePhysical = 11,
121      * SysDbgReadControlSpace  = 12,
122      * SysDbgWriteControlSpace = 13,
123      * SysDbgReadIoSpace  = 14,
124      * SysDbgWriteIoSpace = 15,
125      * SysDbgReadMsr  = 16,
126      * SysDbgWriteMsr = 17,
127      * SysDbgReadBusData  = 18,
128      * SysDbgWriteBusData = 19,
129      * SysDbgCheckLowMemory = 20
130      */
131     for (Command = 7; Command <= 20; ++Command)
132     {
133         Status = TestSystemDebugControl((SYSDBG_COMMAND)Command);
134         if (!IsVistaOrHigher || IsDebuggerActive)
135             ok_neq_hex_test(Command, Status, STATUS_INVALID_INFO_CLASS); // Status must be != STATUS_INVALID_INFO_CLASS
136         else
137             ok_eq_hex_test(Command, Status, STATUS_DEBUGGER_INACTIVE);
138     }
139 
140     /* Unsupported commands */
141     for (Command = 21; Command <= 40; ++Command)
142     {
143         Status = TestSystemDebugControl((SYSDBG_COMMAND)Command);
144         if (!IsVistaOrHigher || IsDebuggerActive)
145             ok_eq_hex_test(Command, Status, STATUS_INVALID_INFO_CLASS);
146         else
147             ok_eq_hex_test(Command, Status, STATUS_DEBUGGER_INACTIVE);
148     }
149 }
150 
151 /* EOF */
152