ReactOS 0.4.16-dev-1537-g4e425b5
XStateConfig.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS API Tests
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Tests for extended state
5 * COPYRIGHT: Copyright 2025 Timo Kreuzer <timo.kreuzer@reactos.org>
6 */
7
8#include "precomp.h"
9#include <windows.h>
10#include <versionhelpers.h>
11#include <x86x64/Cpuid.h>
12
13// These are not officially documented
14#define XSTATE_PKRU 9
15#define XSTATE_HDC 13
16#define XSTATE_UINTR 14
17#define XSTATE_LBR 15
18#define XSTATE_MASK_PKRU (1LL << (XSTATE_PKRU))
19#define XSTATE_MASK_HDC (1LL << (XSTATE_HDC))
20#define XSTATE_MASK_UINTR (1LL << (XSTATE_UINTR))
21#define XSTATE_MASK_LBR (1LL << (XSTATE_LBR))
22
23#define XSTATE_MASK_SUPERVISOR \
24 (XSTATE_MASK_IPT | \
25 XSTATE_MASK_PASID | \
26 XSTATE_MASK_CET_U | \
27 XSTATE_MASK_CET_S | \
28 XSTATE_MASK_HDC | \
29 XSTATE_MASK_UINTR | \
30 XSTATE_MASK_LBR)
31
32template<ULONG NtDdiVersion>
34
35template<>
37{
39 ULONG Size; //0x8
41 struct _XSTATE_FEATURE Features[64]; //0x10
42};
43
44template<>
46{
49 ULONG Size; //0x10
50 union
51 {
53 struct
54 {
58 };
59 };
60 struct _XSTATE_FEATURE Features[64]; //0x18
61};
62
63template<>
65{
69 ULONG AllFeatures[64]; //0x22c
70};
71
72template<>
74{
76};
77
78template<>
80{
83 ULONG Spare; //0x344
84};
85
87{
88 if (IsReactOS())
89 {
90 return NTDDI_WIN11;
91 }
92
93 /* Get the NTDDI_VERSION from the PEB fields */
95 ULONG WinVersion = (Peb->OSMajorVersion << 8) | Peb->OSMinorVersion;
96 switch (WinVersion)
97 {
99 return NTDDI_WIN7;
100
102 return NTDDI_WIN8;
103
105 return NTDDI_WIN8; // same as Win8
106
108 {
109 switch (Peb->OSBuildNumber)
110 {
111 case 10240: // 10.0.10240 / 1507 / Threshold 1
112 case 10586: // 10.0.10586 / 1511 / Threshold 2
113 case 14393: // 10.0.14393 / 1607 / Redstone 1
114 case 15063: // 10.0.15063 / 1703 / Redstone 2
115 case 16299: // 10.0.16299 / 1709 / Redstone 3
116 case 17134: // 10.0.17134 / 1803 / Redstone 4
117 return NTDDI_WIN10;
118 case 17763: // 10.0.17763 / 1809 / Redstone 5
119 case 18362: // 10.0.18362 / 1903 / 19H1 "Titanium"
120 case 18363: // 10.0.18363 / Vanadium
121 case 19041: // 10.0.19041 / 2004 / Vibranium R1
122 case 19042: // 10.0.19042 / 20H2 / Vibranium R2 aka Manganese
123 case 19043: // 10.0.19043 / 21H1 / Vibranium R3 aka Ferrum
124 case 19044: // 10.0.19044 / 21H2 / Vibranium R4 aka Cobalt
125 case 19045: // 10.0.19045 / 22H2 / Vibranium R5
126 return NTDDI_WIN10_RS5;
127
128 // Win 11
129 case 22000: // Cobalt
130 case 22621: // 22H2 Nickel R1
131 case 22631: // 23H2 Nickel R2
132 case 26100: // 24H2 Germanium
133 return NTDDI_WIN11;
134
135 default:
136 trace("Unknown Windows 10 build number: %d\n", Peb->OSBuildNumber);
137 return 0;
138 }
139 }
140
141 default:
142 trace("UnsuUnknown Windows version: 0x%lX\n", WinVersion);
143 return 0;
144 }
145
146 return 0;
147}
148
149template<ULONG NtDdiVersion>
151{
152 if (IsReactOS())
153 {
154 return FIELD_OFFSET(KUSER_SHARED_DATA, XState); // ReactOS
155 }
156 if (NtDdiVersion < NTDDI_WIN8)
157 {
158 return 0x3e0; // Win 7
159 }
160 else
161 {
162 return 0x3d8; // Win 8 - Win 11
163 }
164}
165
166template<ULONG NtDdiVersion>
168{
169 SIZE_T Offset = GetXStateOffset<NtDdiVersion>();
170 PVOID Pointer = (PVOID)((ULONG_PTR)SharedUserData + Offset);
172}
173
175{
176 ULONG64 SupportedUserMask;
177 ULONG64 SupportedSupervisorMask;
178 ULONG64 SupportedComponentMask;
179 ULONG NextUserOffset, NextSupervisorOffset, NextOffset;
180
181 RtlZeroMemory(XStateConfig, sizeof(*XStateConfig));
182
184 {
185 trace("XSAVE not supported\n");
186 return;
187 }
188
189 /* Read CPUID_EXTENDED_STATE main leaf (0x0D, 0x00) */
191 __cpuidex(ExtStateMain.AsInt32,
194
195 /* Get the supported XCR0 bits */
196 SupportedUserMask = (ULONG64)ExtStateMain.Edx << 32 |
197 (ULONG64)ExtStateMain.Eax.Uint32;
198
199 /* Mask the allowed components */
200 SupportedUserMask &= XSTATE_MASK_ALLOWED;
201 XStateConfig->EnabledFeatures = SupportedUserMask;
202 XStateConfig->EnabledVolatileFeatures = SupportedUserMask & ~XSTATE_MASK_PERSISTENT;
203
204 /* Read CPUID_EXTENDED_STATE sub-leaf (0x0D, 0x01) */
206 __cpuidex(ExtStateSub.AsInt32,
209
210 /* Save control flags */
211 XStateConfig->OptimizedSave = ExtStateSub.Eax.Bits.XSAVEOPT;
212 XStateConfig->CompactionEnabled = ExtStateSub.Eax.Bits.XSAVEC;
213 XStateConfig->ExtendedFeatureDisable = ExtStateSub.Eax.Bits.Xfd;
214
215 /* Determine supported supervisor features */
216 SupportedSupervisorMask = 0;
217 if (ExtStateSub.Eax.Bits.XSAVES)
218 {
219 SupportedSupervisorMask = (ULONG64)ExtStateSub.Edx << 32 |
220 (ULONG64)ExtStateSub.Ecx.Uint32;
221 SupportedSupervisorMask &= XSTATE_MASK_ALLOWED & XSTATE_MASK_SUPERVISOR;
222 }
223
224 /* Save the supervisor features */
225 XStateConfig->EnabledSupervisorFeatures = SupportedSupervisorMask;
226 XStateConfig->EnabledUserVisibleSupervisorFeatures = SupportedSupervisorMask & XSTATE_MASK_USER_VISIBLE_SUPERVISOR;
227
228 /* Calculate full mask */
229 SupportedComponentMask = SupportedUserMask | SupportedSupervisorMask;
230
231 /* Basic features (always enabled) */
232 XStateConfig->Features[XSTATE_LEGACY_FLOATING_POINT].Offset = 0;
233 XStateConfig->Features[XSTATE_LEGACY_FLOATING_POINT].Size = FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters);
234 XStateConfig->AllFeatures[XSTATE_LEGACY_FLOATING_POINT] = FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters);
235 XStateConfig->Features[XSTATE_LEGACY_SSE].Offset = FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters);
236 XStateConfig->Features[XSTATE_LEGACY_SSE].Size = RTL_FIELD_SIZE(XSAVE_FORMAT, XmmRegisters);
237 XStateConfig->AllFeatures[XSTATE_LEGACY_SSE] = RTL_FIELD_SIZE(XSAVE_FORMAT, XmmRegisters);
238
239 /* Other components start after legacy state + header */
240 NextUserOffset = NextSupervisorOffset = sizeof(XSAVE_AREA);
241
242 /* Loop all components from 2 up */
244 {
245 ULONG64 ComponentBit = (1ULL << Component);
246
247 /* Query component features */
249 __cpuidex(ExtStateComponent.AsInt32,
251 Component);
252
253 /* Save size for all features */
254 XStateConfig->AllFeatures[Component] = ExtStateComponent.Size;
255
256 /* If the offset is 0, this component isn't valid */
257 if (ExtStateComponent.Size == 0) continue;
258
259 /* Check for components that are not OS supported */
260 if ((ComponentBit & SupportedComponentMask) == 0)
261 {
262 /* This emulates weird (broken) Windows behavior */
263 if ((ComponentBit & XSTATE_MASK_SUPERVISOR) == 0)
264 {
265 XStateConfig->Features[Component].Offset = ExtStateComponent.Offset;
266 XStateConfig->Features[Component].Size = ExtStateComponent.Size;
267 }
268
269 /* Skip the rest */
270 continue;
271 }
272
273 /* Check if compaction is enabled */
274 if (XStateConfig->CompactionEnabled)
275 {
276 /* Align the offsets, if needed */
277 if (ExtStateComponent.Ecx.Bits.Aligned)
278 {
279 XStateConfig->AlignedFeatures |= ComponentBit;
280 NextSupervisorOffset = ALIGN_UP(NextSupervisorOffset, 64);
281 if ((ComponentBit & SupportedUserMask) != 0)
282 {
283 NextUserOffset = ALIGN_UP(NextUserOffset, 64);
284 }
285 }
286
287 /* Update the supervisor offset */
288 NextSupervisorOffset += ExtStateComponent.Size;
289
290 /* For user components save and update the offset and size */
291 if ((ComponentBit & SupportedUserMask) != 0)
292 {
293 XStateConfig->Features[Component].Offset = NextUserOffset;
294 XStateConfig->Features[Component].Size = ExtStateComponent.Size;
295 NextUserOffset += ExtStateComponent.Size;
296 }
297 }
298 else
299 {
300 /* Not compacted, use the offset and size specified by the CPUID */
301 NextOffset = ExtStateComponent.Offset + ExtStateComponent.Size;
302 NextSupervisorOffset = max(NextSupervisorOffset, NextOffset);
303
304 /* For user components save and update the offset and size */
305 if ((ComponentBit & SupportedUserMask) != 0)
306 {
307 XStateConfig->Features[Component].Offset = ExtStateComponent.Offset;
308 XStateConfig->Features[Component].Size = ExtStateComponent.Size;
309 NextUserOffset = max(NextUserOffset, NextOffset);
310 }
311 }
312 }
313
314 XStateConfig->Size = NextUserOffset;
315 XStateConfig->AllFeatureSize = NextSupervisorOffset;
316}
317
318template<ULONG NtDdiVersion>
321 TXSTATE_CONFIGURATION<NTDDI_WIN11>* ExpectedConfig);
322
323template<>
327{
328 ok_eq_hex64(XStateConfig->EnabledFeatures, ExpectedConfig->EnabledFeatures);
329 ok_eq_ulong(XStateConfig->Size, ExpectedConfig->Size);
330 ok_eq_ulong(XStateConfig->OptimizedSave, ExpectedConfig->OptimizedSave);
331 for (ULONG i = 0; i < 64; i++)
332 {
333 ok(XStateConfig->Features[i].Offset == ExpectedConfig->Features[i].Offset,
334 "XStateConfig->Features[%lu].Offset = 0x%lx, expected 0x%lx\n",
335 i, XStateConfig->Features[i].Offset, ExpectedConfig->Features[i].Offset);
336 ok(XStateConfig->Features[i].Offset == ExpectedConfig->Features[i].Offset,
337 "XStateConfig->Features[%lu].Size = 0x%lx, expected 0x%lx\n",
338 i, XStateConfig->Features[i].Size, ExpectedConfig->Features[i].Size);
339 }
340};
341
342template<>
346{
347 ok_eq_hex64(XStateConfig->EnabledFeatures, ExpectedConfig->EnabledFeatures);
348 ok_eq_hex64(XStateConfig->EnabledVolatileFeatures, ExpectedConfig->EnabledVolatileFeatures);
349 ok_eq_ulong(XStateConfig->Size, ExpectedConfig->Size);
350 ok_eq_ulong(XStateConfig->OptimizedSave, ExpectedConfig->OptimizedSave);
351 for (ULONG i = 0; i < 64; i++)
352 {
353 ok(XStateConfig->Features[i].Offset == ExpectedConfig->Features[i].Offset,
354 "XStateConfig->Features[%lu].Offset = 0x%lx, expected 0x%lx\n",
355 i, XStateConfig->Features[i].Offset, ExpectedConfig->Features[i].Offset);
356 ok(XStateConfig->Features[i].Size == ExpectedConfig->Features[i].Size,
357 "XStateConfig->Features[%lu].Size = 0x%lx, expected 0x%lx\n",
358 i, XStateConfig->Features[i].Size, ExpectedConfig->Features[i].Size);
359 }
360}
361
362template<>
366{
367 ValidateXState<NTDDI_WIN8>(XStateConfig, ExpectedConfig);
368 ok_eq_hex64(XStateConfig->EnabledSupervisorFeatures, ExpectedConfig->EnabledSupervisorFeatures);
369 ok_eq_hex64(XStateConfig->AlignedFeatures, ExpectedConfig->AlignedFeatures);
370 ok_eq_ulong(XStateConfig->AllFeatureSize, ExpectedConfig->AllFeatureSize);
371 for (ULONG i = 0; i < 64; i++)
372 {
373 ok(XStateConfig->AllFeatures[i] == ExpectedConfig->AllFeatures[i],
374 "XStateConfig->AllFeatures[%lu] = 0x%lx, expected 0x%lx\n",
375 i, XStateConfig->AllFeatures[i], ExpectedConfig->AllFeatures[i]);
376 }
377}
378
379template<>
383{
384 ValidateXState<NTDDI_WIN10>(XStateConfig, ExpectedConfig);
385 ok_eq_hex64(XStateConfig->EnabledUserVisibleSupervisorFeatures, ExpectedConfig->EnabledUserVisibleSupervisorFeatures);
386}
387
388template<>
392{
393 ValidateXState<NTDDI_WIN10_RS5>(XStateConfig, ExpectedConfig);
394 ok_eq_hex64(XStateConfig->ExtendedFeatureDisableFeatures, ExpectedConfig->ExtendedFeatureDisableFeatures);
395 ok_eq_ulong(XStateConfig->AllNonLargeFeatureSize, ExpectedConfig->AllNonLargeFeatureSize);
396 ok_eq_ulong(XStateConfig->Spare, ExpectedConfig->Spare);
397}
398
399template<ULONG NtDdiVersion>
401{
403 TXSTATE_CONFIGURATION<NtDdiVersion>* ActualXState = GetOsXState<NtDdiVersion>();
404
405 GetExpectedXStateConfig(&ExpectedXState);
406
407 ValidateXState<NtDdiVersion>(ActualXState, &ExpectedXState);
408
410 {
411 ULONG64 xcr0 = _xgetbv(0);
412 ok_eq_hex64(ActualXState->EnabledFeatures, xcr0);
413 }
414}
415
416START_TEST(XStateConfig)
417{
418 ULONG NtDdiVersion = GetXStateNtDdiVersion();
419
420 switch (NtDdiVersion)
421 {
422 case NTDDI_WIN7:
423 TestXStateConfig<NTDDI_WIN7>();
424 break;
425 case NTDDI_WIN8:
426 TestXStateConfig<NTDDI_WIN8>();
427 break;
428 case NTDDI_WIN10:
429 TestXStateConfig<NTDDI_WIN10>();
430 break;
431 case NTDDI_WIN10_RS5:
432 TestXStateConfig<NTDDI_WIN10_RS5>();
433 break;
434 case NTDDI_WIN11:
435 TestXStateConfig<NTDDI_WIN11>();
436 break;
437
438 default:
439 skip("Skipping XStateConfig test on usupported Windows version\n");
440 break;
441 }
442}
#define NtCurrentPeb()
Definition: FLS.c:22
#define CPUID_EXTENDED_STATE
Definition: Cpuid.h:1918
#define CPUID_EXTENDED_STATE_SUB_LEAF
Definition: Cpuid.h:2033
#define CPUID_EXTENDED_STATE_MAIN_LEAF
Definition: Cpuid.h:1953
#define XSTATE_MASK_SUPERVISOR
void GetExpectedXStateConfig(TXSTATE_CONFIGURATION< NTDDI_WIN11 > *XStateConfig)
void ValidateXState< NTDDI_WIN7 >(TXSTATE_CONFIGURATION< NTDDI_WIN7 > *XStateConfig, TXSTATE_CONFIGURATION< NTDDI_WIN11 > *ExpectedConfig)
void ValidateXState< NTDDI_WIN8 >(TXSTATE_CONFIGURATION< NTDDI_WIN8 > *XStateConfig, TXSTATE_CONFIGURATION< NTDDI_WIN11 > *ExpectedConfig)
ULONG GetXStateNtDdiVersion(void)
void ValidateXState< NTDDI_WIN10_RS5 >(TXSTATE_CONFIGURATION< NTDDI_WIN10_RS5 > *XStateConfig, TXSTATE_CONFIGURATION< NTDDI_WIN11 > *ExpectedConfig)
TXSTATE_CONFIGURATION< NtDdiVersion > * GetOsXState(void)
void ValidateXState< NTDDI_WIN10 >(TXSTATE_CONFIGURATION< NTDDI_WIN10 > *XStateConfig, TXSTATE_CONFIGURATION< NTDDI_WIN11 > *ExpectedConfig)
SIZE_T GetXStateOffset(void)
void TestXStateConfig(void)
void ValidateXState< NTDDI_WIN11 >(TXSTATE_CONFIGURATION< NTDDI_WIN11 > *XStateConfig, TXSTATE_CONFIGURATION< NTDDI_WIN11 > *ExpectedConfig)
void ValidateXState(TXSTATE_CONFIGURATION< NtDdiVersion > *XStateConfig, TXSTATE_CONFIGURATION< NTDDI_WIN11 > *ExpectedConfig)
#define ok_eq_ulong(value, expected)
Definition: apitest.h:48
#define ok_eq_hex64(value, expected)
Definition: apitest.h:74
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
PPEB Peb
Definition: dllmain.c:27
BOOL WINAPI IsProcessorFeaturePresent(IN DWORD ProcessorFeature)
Definition: sysinfo.c:169
switch(r->id)
Definition: btrfs.c:3046
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
unsigned __int64 __cdecl _xgetbv(unsigned int)
Definition: immintrin.h:343
__INTRIN_INLINE void __cpuidex(int CPUInfo[4], int InfoType, int ECXValue)
Definition: intrin_x86.h:1662
#define RTL_FIELD_SIZE(type, field)
Definition: kdb_expr.c:86
unsigned __int64 ULONG64
Definition: imports.h:198
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
#define SharedUserData
#define _WIN32_WINNT_WIN10
Definition: sdkddkver.h:32
#define NTDDI_WIN8
Definition: sdkddkver.h:113
#define NTDDI_WIN11
Definition: sdkddkver.h:130
#define _WIN32_WINNT_WINBLUE
Definition: sdkddkver.h:30
#define _WIN32_WINNT_WIN8
Definition: sdkddkver.h:29
#define NTDDI_WIN7
Definition: sdkddkver.h:112
#define NTDDI_WIN10_RS5
Definition: sdkddkver.h:122
#define NTDDI_WIN10
Definition: sdkddkver.h:116
#define _WIN32_WINNT_WIN7
Definition: sdkddkver.h:28
ULONG OSMinorVersion
Definition: ntddk_ex.h:301
ULONG OSMajorVersion
Definition: ntddk_ex.h:300
ULONG OSBuildNumber
Definition: ntddk_ex.h:302
#define max(a, b)
Definition: svc.c:63
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
void * PVOID
Definition: typedefs.h:50
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define ALIGN_UP(size, type)
Definition: umtypes.h:91
CPUID_EXTENDED_STATE_MAIN_LEAF_EAX Eax
Definition: Cpuid.h:93
struct CPUID_EXTENDED_STATE_SIZE_OFFSET_ECX::@4047 Bits
CPUID_EXTENDED_STATE_SIZE_OFFSET_ECX Ecx
Definition: Cpuid.h:126
struct CPUID_EXTENDED_STATE_SUB_LEAF_EAX::@4045 Bits
CPUID_EXTENDED_STATE_SUB_LEAF_EAX Eax
Definition: Cpuid.h:107
CPUID_EXTENDED_STATE_SUB_LEAF_ECX Ecx
Definition: Cpuid.h:112
XSAVE_AREA
Definition: ketypes.h:977
XSAVE_FORMAT
Definition: ketypes.h:966
#define PF_XSAVE_ENABLED
Definition: ketypes.h:141
#define MAXIMUM_XSTATE_FEATURES
KUSER_SHARED_DATA
Definition: ketypes.h:1571
#define XSTATE_LEGACY_SSE
#define XSTATE_LEGACY_FLOATING_POINT
#define XSTATE_MASK_USER_VISIBLE_SUPERVISOR
_In_ ULONG Component
Definition: potypes.h:499