/* * @implemented */ PVOID NTAPI MmAllocateNonCachedMemory(IN SIZE_T NumberOfBytes) { PFN_COUNT PageCount, MdlPageCount; PFN_NUMBER PageFrameIndex; PHYSICAL_ADDRESS LowAddress, HighAddress, SkipBytes; MI_PFN_CACHE_ATTRIBUTE CacheAttribute; PMDL Mdl; PVOID BaseAddress; PPFN_NUMBER MdlPages; PMMPTE PointerPte; MMPTE TempPte; // // Get the page count // ASSERT(NumberOfBytes != 0); PageCount = (PFN_COUNT)BYTES_TO_PAGES(NumberOfBytes); // // Use the MDL allocator for simplicity, so setup the parameters // LowAddress.QuadPart = 0; HighAddress.QuadPart = -1; SkipBytes.QuadPart = 0; CacheAttribute = MiPlatformCacheAttributes[0][MmNonCached]; // // Now call the MDL allocator // Mdl = MiAllocatePagesForMdl(LowAddress, HighAddress, SkipBytes, NumberOfBytes, CacheAttribute, 0); if (!Mdl) return NULL; // // Get the MDL VA and check how many pages we got (could be partial) // BaseAddress = (PVOID)((ULONG_PTR)Mdl->StartVa + Mdl->ByteOffset); MdlPageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseAddress, Mdl->ByteCount); if (PageCount != MdlPageCount) { // // Unlike MDLs, partial isn't okay for a noncached allocation, so fail // ASSERT(PageCount > MdlPageCount); MmFreePagesFromMdl(Mdl); ExFreePoolWithTag(Mdl, TAG_MDL); return NULL; } // // Allocate system PTEs for the base address // We use an extra page to store the actual MDL pointer for the free later // PointerPte = MiReserveSystemPtes(PageCount + 1, SystemPteSpace); if (!PointerPte) { // // Out of memory... // MmFreePagesFromMdl(Mdl); ExFreePoolWithTag(Mdl, TAG_MDL); return NULL; } // // Store the MDL pointer // *(PMDL*)PointerPte++ = Mdl; // // Okay, now see what range we got // BaseAddress = MiPteToAddress(PointerPte); // // This is our array of pages // MdlPages = (PPFN_NUMBER)(Mdl + 1); // // Setup the template PTE // TempPte = ValidKernelPte; // // Now check what kind of caching we should use // switch (CacheAttribute) { case MiNonCached: // // Disable caching // MI_PAGE_DISABLE_CACHE(&TempPte); MI_PAGE_WRITE_THROUGH(&TempPte); break; case MiWriteCombined: // // Enable write combining // MI_PAGE_DISABLE_CACHE(&TempPte); MI_PAGE_WRITE_COMBINED(&TempPte); break; default: // // Nothing to do // break; } // // Now loop the MDL pages // do { // // Get the PFN // PageFrameIndex = *MdlPages++; // // Set the PFN in the page and write it // TempPte.u.Hard.PageFrameNumber = PageFrameIndex; MI_WRITE_VALID_PTE(PointerPte++, TempPte); } while (--PageCount); // // Return the base address // return BaseAddress; }
/* * @implemented */ PVOID NTAPI MmMapLockedPagesSpecifyCache(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN MEMORY_CACHING_TYPE CacheType, IN PVOID BaseAddress, IN ULONG BugCheckOnFailure, IN MM_PAGE_PRIORITY Priority) { PVOID Base; PPFN_NUMBER MdlPages, LastPage; PFN_COUNT PageCount; BOOLEAN IsIoMapping; MI_PFN_CACHE_ATTRIBUTE CacheAttribute; PMMPTE PointerPte; MMPTE TempPte; // // Sanity check // ASSERT(Mdl->ByteCount != 0); // // Get the base // Base = (PVOID)((ULONG_PTR)Mdl->StartVa + Mdl->ByteOffset); // // Handle kernel case first // if (AccessMode == KernelMode) { // // Get the list of pages and count // MdlPages = (PPFN_NUMBER)(Mdl + 1); PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base, Mdl->ByteCount); LastPage = MdlPages + PageCount; // // Sanity checks // ASSERT((Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL | MDL_PARTIAL_HAS_BEEN_MAPPED)) == 0); ASSERT((Mdl->MdlFlags & (MDL_PAGES_LOCKED | MDL_PARTIAL)) != 0); // // Get the correct cache type // IsIoMapping = (Mdl->MdlFlags & MDL_IO_SPACE) != 0; CacheAttribute = MiPlatformCacheAttributes[IsIoMapping][CacheType]; // // Reserve the PTEs // PointerPte = MiReserveSystemPtes(PageCount, SystemPteSpace); if (!PointerPte) { // // If it can fail, return NULL // if (Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL) return NULL; // // Should we bugcheck? // if (!BugCheckOnFailure) return NULL; // // Yes, crash the system // KeBugCheckEx(NO_MORE_SYSTEM_PTES, 0, PageCount, 0, 0); } // // Get the mapped address // Base = (PVOID)((ULONG_PTR)MiPteToAddress(PointerPte) + Mdl->ByteOffset); // // Get the template // TempPte = ValidKernelPte; switch (CacheAttribute) { case MiNonCached: // // Disable caching // MI_PAGE_DISABLE_CACHE(&TempPte); MI_PAGE_WRITE_THROUGH(&TempPte); break; case MiWriteCombined: // // Enable write combining // MI_PAGE_DISABLE_CACHE(&TempPte); MI_PAGE_WRITE_COMBINED(&TempPte); break; default: // // Nothing to do // break; } // // Loop all PTEs // do { // // We're done here // if (*MdlPages == LIST_HEAD) break; // // Write the PTE // TempPte.u.Hard.PageFrameNumber = *MdlPages; MI_WRITE_VALID_PTE(PointerPte++, TempPte); } while (++MdlPages < LastPage); // // Mark it as mapped // ASSERT((Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) == 0); Mdl->MappedSystemVa = Base; Mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA; // // Check if it was partial // if (Mdl->MdlFlags & MDL_PARTIAL) { // // Write the appropriate flag here too // Mdl->MdlFlags |= MDL_PARTIAL_HAS_BEEN_MAPPED; } // // Return the mapped address // return Base; } UNIMPLEMENTED; return NULL; }
/* * @implemented */ PVOID NTAPI MmMapIoSpace(IN PHYSICAL_ADDRESS PhysicalAddress, IN SIZE_T NumberOfBytes, IN MEMORY_CACHING_TYPE CacheType) { PFN_NUMBER Pfn; PFN_COUNT PageCount; PMMPTE PointerPte; PVOID BaseAddress; MMPTE TempPte; PMMPFN Pfn1 = NULL; MI_PFN_CACHE_ATTRIBUTE CacheAttribute; BOOLEAN IsIoMapping; // // Must be called with a non-zero count // ASSERT(NumberOfBytes != 0); // // Make sure the upper bits are 0 if this system // can't describe more than 4 GB of physical memory. // FIXME: This doesn't respect PAE, but we currently don't // define a PAE build flag since there is no such build. // #if !defined(_M_AMD64) ASSERT(PhysicalAddress.HighPart == 0); #endif // // Normalize and validate the caching attributes // CacheType &= 0xFF; if (CacheType >= MmMaximumCacheType) return NULL; // // Calculate page count // PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(PhysicalAddress.LowPart, NumberOfBytes); // // Compute the PFN and check if it's a known I/O mapping // Also translate the cache attribute // Pfn = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT); Pfn1 = MiGetPfnEntry(Pfn); IsIoMapping = (Pfn1 == NULL) ? TRUE : FALSE; CacheAttribute = MiPlatformCacheAttributes[IsIoMapping][CacheType]; // // Now allocate system PTEs for the mapping, and get the VA // PointerPte = MiReserveSystemPtes(PageCount, SystemPteSpace); if (!PointerPte) return NULL; BaseAddress = MiPteToAddress(PointerPte); // // Check if this is uncached // if (CacheAttribute != MiCached) { // // Flush all caches // KeFlushEntireTb(TRUE, TRUE); KeInvalidateAllCaches(); } // // Now compute the VA offset // BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + BYTE_OFFSET(PhysicalAddress.LowPart)); // // Get the template and configure caching // TempPte = ValidKernelPte; switch (CacheAttribute) { case MiNonCached: // // Disable the cache // MI_PAGE_DISABLE_CACHE(&TempPte); MI_PAGE_WRITE_THROUGH(&TempPte); break; case MiCached: // // Leave defaults // break; case MiWriteCombined: // // We don't support write combining yet // ASSERT(FALSE); break; default: // // Should never happen // ASSERT(FALSE); break; } // // Sanity check and re-flush // Pfn = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT); ASSERT((Pfn1 == MiGetPfnEntry(Pfn)) || (Pfn1 == NULL)); KeFlushEntireTb(TRUE, TRUE); KeInvalidateAllCaches(); // // Do the mapping // do { // // Write the PFN // TempPte.u.Hard.PageFrameNumber = Pfn++; MI_WRITE_VALID_PTE(PointerPte++, TempPte); } while (--PageCount); // // We're done! // return BaseAddress; }