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: Kernel-Mode Test Suite Reserved Mapping test 5 * COPYRIGHT: Copyright 2015,2023 Thomas Faber (thomas.faber@reactos.org) 6 * COPYRIGHT: Copyright 2015 Pierre Schweitzer (pierre@reactos.org) 7 */ 8 9 #include <kmt_test.h> 10 11 static BOOLEAN g_IsPae; 12 static ULONG g_OsVersion; 13 static BOOLEAN g_IsReactOS; 14 15 #ifdef _M_IX86 16 17 #define IS_PAE() (g_IsPae) 18 19 #define PTE_BASE 0xC0000000 20 21 #define MiAddressToPteX86(x) \ 22 ((PULONG)(((((ULONG)(x)) >> 12) << 2) + PTE_BASE)) 23 #define MiAddressToPtePAE(x) \ 24 ((PULONGLONG)(((((ULONG)(x)) >> 12) << 3) + PTE_BASE)) 25 26 #define GET_PTE_VALUE_X86(Addr) (*MiAddressToPteX86(Addr)) 27 #define GET_PTE_VALUE_PAE(Addr) (*MiAddressToPtePAE(Addr)) 28 #define GET_PTE_VALUE(Addr) (IS_PAE() ? GET_PTE_VALUE_PAE(Addr) : GET_PTE_VALUE_X86(Addr)) 29 30 #define PTE_IS_VALID(PteValue) ((PteValue) & 1) 31 32 #define PTE_GET_PFN_X86(PteValue) (((PteValue) >> PAGE_SHIFT) & 0x0fffffULL) 33 #define PTE_GET_PFN_PAE(PteValue) (((PteValue) >> PAGE_SHIFT) & 0xffffffULL) 34 #define PTE_GET_PFN(PteValue) (IS_PAE() ? PTE_GET_PFN_PAE(PteValue) : PTE_GET_PFN_X86(PteValue)) 35 36 #elif defined(_M_AMD64) 37 38 #define PTI_SHIFT 12L 39 #define PTE_BASE 0xFFFFF68000000000ULL 40 PULONGLONG 41 FORCEINLINE 42 _MiAddressToPte(PVOID Address) 43 { 44 ULONG64 Offset = (ULONG64)Address >> (PTI_SHIFT - 3); 45 Offset &= 0xFFFFFFFFFULL << 3; 46 return (PULONGLONG)(PTE_BASE + Offset); 47 } 48 #define MiAddressToPte(x) _MiAddressToPte((PVOID)(x)) 49 50 #define GET_PTE_VALUE(Addr) (*_MiAddressToPte((PVOID)(Addr))) 51 #define PTE_IS_VALID(PteValue) ((PteValue) & 1) 52 #define PTE_GET_PFN(PteValue) (((PteValue) >> PAGE_SHIFT) & 0xFffffffffULL) 53 54 #endif 55 56 static 57 _Must_inspect_result_ 58 _IRQL_requires_max_ (DISPATCH_LEVEL) 59 PMDL 60 (NTAPI 61 *pMmAllocatePagesForMdlEx)( 62 _In_ PHYSICAL_ADDRESS LowAddress, 63 _In_ PHYSICAL_ADDRESS HighAddress, 64 _In_ PHYSICAL_ADDRESS SkipBytes, 65 _In_ SIZE_T TotalBytes, 66 _In_ MEMORY_CACHING_TYPE CacheType, 67 _In_ ULONG Flags); 68 69 static 70 BOOLEAN 71 ValidateMapping( 72 _In_ PVOID BaseAddress, 73 _In_ ULONG TotalPtes, 74 _In_ ULONG PoolTag, 75 _In_ ULONG ValidPtes, 76 _In_ PPFN_NUMBER Pfns) 77 { 78 BOOLEAN Valid = TRUE; 79 #if defined(_M_IX86) || defined(_M_AMD64) 80 PUCHAR CurrentAddress; 81 ULONGLONG PteValue, ExpectedValue; 82 ULONG i; 83 84 for (i = 0; i < ValidPtes; i++) 85 { 86 CurrentAddress = (PUCHAR)BaseAddress + i * PAGE_SIZE; 87 PteValue = GET_PTE_VALUE(CurrentAddress); 88 Valid = Valid && 89 ok(PTE_IS_VALID(PteValue), 90 "[%lu] PTE for %p is not valid (0x%I64x)\n", 91 i, CurrentAddress, PteValue); 92 93 Valid = Valid && 94 ok(PTE_GET_PFN(PteValue) == Pfns[i], 95 "[%lu] PTE for %p has PFN %Ix, expected %Ix\n", 96 i, CurrentAddress, PTE_GET_PFN(PteValue), Pfns[i]); 97 } 98 for (; i < TotalPtes; i++) 99 { 100 CurrentAddress = (PUCHAR)BaseAddress + i * PAGE_SIZE; 101 PteValue = GET_PTE_VALUE(CurrentAddress); 102 Valid = Valid && 103 ok(PteValue == 0, 104 "[%lu] PTE for %p is nonzero (0x%I64x)\n", 105 i, CurrentAddress, PteValue); 106 } 107 CurrentAddress = (PUCHAR)BaseAddress - 1 * PAGE_SIZE; 108 PteValue = GET_PTE_VALUE(CurrentAddress); 109 Valid = Valid && 110 ok(PteValue == (PoolTag & ~1ULL), 111 "PTE for %p contains 0x%I64x, expected %x\n", 112 CurrentAddress, PteValue, PoolTag & ~1); 113 CurrentAddress = (PUCHAR)BaseAddress - 2 * PAGE_SIZE; 114 PteValue = GET_PTE_VALUE(CurrentAddress); 115 116 if (g_IsReactOS || g_OsVersion >= 0x0600) 117 { 118 /* On ReactOS and on Vista+ the size is stored in 119 * the NextEntry field of a MMPTE_LIST structure */ 120 #ifdef _M_IX86 121 ExpectedValue = (TotalPtes + 2) << 12; 122 #elif defined(_M_AMD64) 123 ExpectedValue = ((ULONG64)TotalPtes + 2) << 32; 124 #endif 125 } 126 else 127 { 128 /* On Windows 2003 the size is shifted by 1 bit only */ 129 ExpectedValue = (TotalPtes + 2) * 2; 130 } 131 Valid = Valid && 132 ok(PteValue == ExpectedValue, 133 "PTE for %p contains 0x%I64x, expected %x\n", 134 CurrentAddress, PteValue, ExpectedValue); 135 #endif 136 137 return Valid; 138 } 139 140 static 141 VOID 142 TestMap( 143 _In_ PVOID Mapping, 144 _In_ ULONG TotalPtes, 145 _In_ ULONG PoolTag) 146 { 147 PMDL Mdl; 148 PHYSICAL_ADDRESS ZeroPhysical; 149 PHYSICAL_ADDRESS MaxPhysical; 150 PVOID BaseAddress; 151 PPFN_NUMBER MdlPages; 152 ULONG i; 153 154 if (skip(pMmAllocatePagesForMdlEx != NULL, "MmAllocatePagesForMdlEx unavailable\n")) 155 { 156 return; 157 } 158 159 ZeroPhysical.QuadPart = 0; 160 MaxPhysical.QuadPart = 0xffffffffffffffffLL; 161 162 /* Create a one-page MDL and map it */ 163 Mdl = pMmAllocatePagesForMdlEx(ZeroPhysical, 164 MaxPhysical, 165 ZeroPhysical, 166 PAGE_SIZE, 167 MmCached, 168 0); 169 if (skip(Mdl != NULL, "No MDL\n")) 170 { 171 return; 172 } 173 174 MdlPages = (PVOID)(Mdl + 1); 175 176 BaseAddress = MmMapLockedPagesWithReservedMapping(Mapping, 177 PoolTag, 178 Mdl, 179 MmCached); 180 ok(BaseAddress != NULL, "MmMapLockedPagesWithReservedMapping failed\n"); 181 if (!skip(BaseAddress != NULL, "Failed to map MDL\n")) 182 { 183 ok_eq_pointer(BaseAddress, Mapping); 184 185 ok_bool_true(ValidateMapping(BaseAddress, TotalPtes, PoolTag, 1, MdlPages), 186 "ValidateMapping returned"); 187 188 KmtStartSeh() 189 *(volatile ULONG *)BaseAddress = 0x01234567; 190 KmtEndSeh(STATUS_SUCCESS); 191 192 MmUnmapReservedMapping(BaseAddress, 193 PoolTag, 194 Mdl); 195 196 ok_bool_true(ValidateMapping(Mapping, TotalPtes, PoolTag, 0, NULL), 197 "ValidateMapping returned"); 198 } 199 200 /* Try again but at an unaligned address */ 201 BaseAddress = MmMapLockedPagesWithReservedMapping((PUCHAR)Mapping + sizeof(ULONG), 202 PoolTag, 203 Mdl, 204 MmCached); 205 ok(BaseAddress != NULL, "MmMapLockedPagesWithReservedMapping failed\n"); 206 if (!skip(BaseAddress != NULL, "Failed to map MDL\n")) 207 { 208 ok_eq_pointer(BaseAddress, (PUCHAR)Mapping + sizeof(ULONG)); 209 210 ok_bool_true(ValidateMapping(BaseAddress, TotalPtes, PoolTag, 1, MdlPages), 211 "ValidateMapping returned"); 212 213 KmtStartSeh() 214 *(volatile ULONG *)BaseAddress = 0x01234567; 215 KmtEndSeh(STATUS_SUCCESS); 216 217 MmUnmapReservedMapping(BaseAddress, 218 PoolTag, 219 Mdl); 220 221 ok_bool_true(ValidateMapping(Mapping, TotalPtes, PoolTag, 0, NULL), 222 "ValidateMapping returned"); 223 } 224 225 MmFreePagesFromMdl(Mdl); 226 227 /* Map all pages */ 228 Mdl = pMmAllocatePagesForMdlEx(ZeroPhysical, 229 MaxPhysical, 230 ZeroPhysical, 231 TotalPtes * PAGE_SIZE, 232 MmCached, 233 0); 234 if (skip(Mdl != NULL, "No MDL\n")) 235 { 236 return; 237 } 238 239 MdlPages = (PVOID)(Mdl + 1); 240 241 BaseAddress = MmMapLockedPagesWithReservedMapping(Mapping, 242 PoolTag, 243 Mdl, 244 MmCached); 245 ok(BaseAddress != NULL, "MmMapLockedPagesWithReservedMapping failed\n"); 246 if (!skip(BaseAddress != NULL, "Failed to map MDL\n")) 247 { 248 ok_eq_pointer(BaseAddress, Mapping); 249 250 ok_bool_true(ValidateMapping(BaseAddress, TotalPtes, PoolTag, TotalPtes, MdlPages), 251 "ValidateMapping returned"); 252 253 for (i = 0; i < TotalPtes; i++) 254 { 255 KmtStartSeh() 256 *((volatile ULONG *)BaseAddress + i * PAGE_SIZE / sizeof(ULONG)) = 0x01234567; 257 KmtEndSeh(STATUS_SUCCESS); 258 } 259 260 MmUnmapReservedMapping(BaseAddress, 261 PoolTag, 262 Mdl); 263 264 ok_bool_true(ValidateMapping(Mapping, TotalPtes, PoolTag, 0, NULL), 265 "ValidateMapping returned"); 266 } 267 268 MmFreePagesFromMdl(Mdl); 269 270 /* Try to map more pages than we reserved */ 271 Mdl = pMmAllocatePagesForMdlEx(ZeroPhysical, 272 MaxPhysical, 273 ZeroPhysical, 274 (TotalPtes + 1) * PAGE_SIZE, 275 MmCached, 276 0); 277 if (skip(Mdl != NULL, "No MDL\n")) 278 { 279 return; 280 } 281 282 BaseAddress = MmMapLockedPagesWithReservedMapping(Mapping, 283 PoolTag, 284 Mdl, 285 MmCached); 286 ok_eq_pointer(BaseAddress, NULL); 287 if (BaseAddress) 288 { 289 MmUnmapReservedMapping(BaseAddress, 290 PoolTag, 291 Mdl); 292 } 293 294 MmFreePagesFromMdl(Mdl); 295 } 296 297 START_TEST(MmReservedMapping) 298 { 299 PVOID Mapping; 300 301 g_IsPae = ExIsProcessorFeaturePresent(PF_PAE_ENABLED); 302 g_OsVersion = SharedUserData->NtMajorVersion << 8 | SharedUserData->NtMinorVersion; 303 g_IsReactOS = *(PULONG)(KI_USER_SHARED_DATA + PAGE_SIZE - sizeof(ULONG)) == 0x8eac705; 304 ok(g_IsReactOS == 1, "Not reactos\n"); 305 306 pMmAllocatePagesForMdlEx = KmtGetSystemRoutineAddress(L"MmAllocatePagesForMdlEx"); 307 308 /* one byte - single page */ 309 Mapping = MmAllocateMappingAddress(1, 'MRmK'); 310 ok(Mapping != NULL, "MmAllocateMappingAddress failed\n"); 311 if (!skip(Mapping != NULL, "No mapping\n")) 312 { 313 ok_bool_true(ValidateMapping(Mapping, 1, 'MRmK', 0, NULL), 314 "ValidateMapping returned"); 315 316 MmFreeMappingAddress(Mapping, 'MRmK'); 317 } 318 319 /* 10 pages */ 320 Mapping = MmAllocateMappingAddress(10 * PAGE_SIZE, 'MRmK' & ~1); 321 ok(Mapping != NULL, "MmAllocateMappingAddress failed\n"); 322 if (!skip(Mapping != NULL, "No mapping\n")) 323 { 324 ok_bool_true(ValidateMapping(Mapping, 10, 'MRmK', 0, NULL), 325 "ValidateMapping returned"); 326 327 /* PAGE_FAULT_IN_NONPAGED_AREA can't be caught with SEH */ 328 if (0) 329 { 330 (void)*(volatile UCHAR *)Mapping; 331 } 332 333 TestMap(Mapping, 10, 'MRmK'); 334 335 MmFreeMappingAddress(Mapping, 'MRmK'); 336 } 337 338 /* PoolTag = 0 */ 339 Mapping = MmAllocateMappingAddress(1, 0); 340 ok(Mapping == NULL, "MmAllocateMappingAddress failed\n"); 341 if (Mapping != NULL) 342 { 343 MmFreeMappingAddress(Mapping, 0); 344 } 345 346 /* PoolTag = 1 */ 347 Mapping = MmAllocateMappingAddress(1, 1); 348 ok(Mapping != NULL, "MmAllocateMappingAddress failed\n"); 349 if (Mapping != NULL) 350 { 351 ok_bool_true(ValidateMapping(Mapping, 1, 1, 0, NULL), 352 "ValidateMapping returned"); 353 354 TestMap(Mapping, 1, 1); 355 356 MmFreeMappingAddress(Mapping, 1); 357 } 358 359 /* Free an unaligned address */ 360 Mapping = MmAllocateMappingAddress(PAGE_SIZE, 'MRmK'); 361 ok(Mapping != NULL, "MmAllocateMappingAddress failed\n"); 362 if (Mapping != NULL) 363 { 364 ok_bool_true(ValidateMapping(Mapping, 1, 'MRmK', 0, NULL), 365 "ValidateMapping returned"); 366 367 TestMap(Mapping, 1, 'MRmK'); 368 369 MmFreeMappingAddress((PUCHAR)Mapping + sizeof(ULONG), 'MRmK'); 370 } 371 } 372