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