mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-30 12:23:28 +00:00
- Rewrite MmMapIoSpace and MmUnmapIoSpace to use System PTEs instead.
- Much faster and cleaner (will be even faster when System PTE allocation is optimized).
- Better handling of esoteric caching options, especially relevant for ARM.
- Handled through the MiPlatformCacheAttributes, which should be defined differently for each platform (TODO).
- Handles both I/O (device) and RAM physical memory.
- Correct flushing of CPU caches (not a big deal on x86, but matters on ARM).
svn path=/trunk/; revision=41628
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* PROJECT: ReactOS Kernel
|
||||
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
||||
* FILE: ntoskrnl/mm/ARM3/iosup.c
|
||||
* PURPOSE: ARM Memory Manager I/O Mapping Functionality
|
||||
* PROGRAMMERS: ReactOS Portable Systems Group
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#line 15 "ARM³::IOSUP"
|
||||
#define MODULE_INVOLVED_IN_ARM3
|
||||
#include "../ARM3/miarm.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
//
|
||||
// Each architecture has its own caching attributes for both I/O and Physical
|
||||
// memory mappings.
|
||||
//
|
||||
// This describes the attributes for the x86 architecture. It eventually needs
|
||||
// to go in the appropriate i386 directory.
|
||||
//
|
||||
MI_PFN_CACHE_ATTRIBUTE MiPlatformCacheAttributes[2][MmMaximumCacheType] =
|
||||
{
|
||||
//
|
||||
// RAM
|
||||
//
|
||||
{MiNonCached,MiCached,MiWriteCombined,MiCached,MiNonCached,MiWriteCombined},
|
||||
|
||||
//
|
||||
// Device Memory
|
||||
//
|
||||
{MiNonCached,MiCached,MiWriteCombined,MiCached,MiNonCached,MiWriteCombined},
|
||||
};
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
MmMapIoSpace(IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN ULONG NumberOfBytes,
|
||||
IN MEMORY_CACHING_TYPE CacheType)
|
||||
{
|
||||
|
||||
PFN_TYPE Pfn, PageCount;
|
||||
PMMPTE PointerPte;
|
||||
PVOID BaseAddress;
|
||||
MMPTE TempPte;
|
||||
PMMPFN Pfn1 = NULL;
|
||||
MI_PFN_CACHE_ATTRIBUTE CacheAttribute;
|
||||
BOOLEAN IsIoMapping;
|
||||
|
||||
//
|
||||
// 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);
|
||||
IsIoMapping = (Pfn > MmHighestPhysicalPage) ? TRUE : FALSE;
|
||||
if (!IsIoMapping) Pfn1 = MiGetPfnEntry(Pfn);
|
||||
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 = HyperTemplatePte;
|
||||
switch (CacheAttribute)
|
||||
{
|
||||
case MiNonCached:
|
||||
|
||||
//
|
||||
// Disable the cache
|
||||
//
|
||||
TempPte.u.Hard.CacheDisable = 1;
|
||||
TempPte.u.Hard.WriteThrough = 1;
|
||||
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
|
||||
{
|
||||
//
|
||||
// Start out with nothing
|
||||
//
|
||||
ASSERT(PointerPte->u.Hard.Valid == 0);
|
||||
|
||||
//
|
||||
// Write the PFN
|
||||
//
|
||||
TempPte.u.Hard.PageFrameNumber = Pfn++;
|
||||
*PointerPte++ = TempPte;
|
||||
} while (--PageCount);
|
||||
|
||||
//
|
||||
// We're done!
|
||||
//
|
||||
return BaseAddress;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
VOID
|
||||
NTAPI
|
||||
MmUnmapIoSpace(IN PVOID BaseAddress,
|
||||
IN ULONG NumberOfBytes)
|
||||
{
|
||||
PFN_NUMBER PageCount, Pfn;
|
||||
PMMPTE PointerPte;
|
||||
|
||||
//
|
||||
// Sanity check
|
||||
//
|
||||
ASSERT(NumberOfBytes != 0);
|
||||
|
||||
//
|
||||
// Get the page count
|
||||
//
|
||||
PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseAddress, NumberOfBytes);
|
||||
|
||||
//
|
||||
// Get the PTE and PFN
|
||||
//
|
||||
PointerPte = MiAddressToPte(BaseAddress);
|
||||
Pfn = PFN_FROM_PTE(PointerPte);
|
||||
|
||||
//
|
||||
// Is this an I/O mapping?
|
||||
//
|
||||
if (Pfn > MmHighestPhysicalPage)
|
||||
{
|
||||
//
|
||||
// Destroy the PTE
|
||||
//
|
||||
RtlZeroMemory(PointerPte, PageCount * sizeof(MMPTE));
|
||||
|
||||
//
|
||||
// Blow the TLB
|
||||
//
|
||||
KeFlushEntireTb(TRUE, TRUE);
|
||||
}
|
||||
|
||||
//
|
||||
// Release the PTEs
|
||||
//
|
||||
MiReleaseSystemPtes(PointerPte, PageCount, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
MmMapVideoDisplay(IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN ULONG NumberOfBytes,
|
||||
IN MEMORY_CACHING_TYPE CacheType)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Call the real function
|
||||
//
|
||||
return MmMapIoSpace(PhysicalAddress, NumberOfBytes, CacheType);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
VOID
|
||||
NTAPI
|
||||
MmUnmapVideoDisplay(IN PVOID BaseAddress,
|
||||
IN ULONG NumberOfBytes)
|
||||
{
|
||||
//
|
||||
// Call the real function
|
||||
//
|
||||
MmUnmapIoSpace(BaseAddress, NumberOfBytes);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -20,6 +20,14 @@ typedef enum _MMSYSTEM_PTE_POOL_TYPE
|
||||
MaximumPtePoolTypes
|
||||
} MMSYSTEM_PTE_POOL_TYPE;
|
||||
|
||||
typedef enum _MI_PFN_CACHE_ATTRIBUTE
|
||||
{
|
||||
MiNonCached,
|
||||
MiCached,
|
||||
MiWriteCombined,
|
||||
MiNotMapped
|
||||
} MI_PFN_CACHE_ATTRIBUTE, *PMI_PFN_CACHE_ATTRIBUTE;
|
||||
|
||||
extern MMPTE HyperTemplatePte;
|
||||
|
||||
extern ULONG MmSizeOfNonPagedPoolInBytes;
|
||||
@@ -50,4 +58,12 @@ MiReserveSystemPtes(
|
||||
IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MiReleaseSystemPtes(
|
||||
IN PMMPTE StartingPte,
|
||||
IN ULONG NumberOfPtes,
|
||||
IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
|
||||
);
|
||||
|
||||
/* EOF */
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/mm/iospace.c
|
||||
* PURPOSE: Mapping I/O space
|
||||
*
|
||||
* PROGRAMMERS: David Welch ([email protected])
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
/**********************************************************************
|
||||
* NAME EXPORTED
|
||||
* MmMapIoSpace@16
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Maps a physical memory range into system space.
|
||||
*
|
||||
* ARGUMENTS
|
||||
* PhysicalAddress
|
||||
* First physical address to map;
|
||||
*
|
||||
* NumberOfBytes
|
||||
* Number of bytes to map;
|
||||
*
|
||||
* CacheEnable
|
||||
* Type of memory caching.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* The base virtual address which maps the region.
|
||||
*
|
||||
* NOTE
|
||||
* Description moved here from include/ddk/mmfuncs.h.
|
||||
* Code taken from ntoskrnl/mm/special.c.
|
||||
*
|
||||
* REVISIONS
|
||||
*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID NTAPI
|
||||
MmMapIoSpace (IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN ULONG NumberOfBytes,
|
||||
IN MEMORY_CACHING_TYPE CacheEnable)
|
||||
{
|
||||
PVOID Result;
|
||||
ULONG Offset;
|
||||
MEMORY_AREA* marea;
|
||||
NTSTATUS Status;
|
||||
ULONG i;
|
||||
ULONG Protect;
|
||||
PHYSICAL_ADDRESS BoundaryAddressMultiple;
|
||||
PFN_TYPE Pfn;
|
||||
|
||||
DPRINT("MmMapIoSpace(%lx, %d, %d)\n", PhysicalAddress, NumberOfBytes, CacheEnable);
|
||||
|
||||
if (CacheEnable != MmNonCached &&
|
||||
CacheEnable != MmCached &&
|
||||
CacheEnable != MmWriteCombined)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BoundaryAddressMultiple.QuadPart = 0;
|
||||
Result = NULL;
|
||||
Offset = PhysicalAddress.u.LowPart % PAGE_SIZE;
|
||||
NumberOfBytes += Offset;
|
||||
PhysicalAddress.QuadPart -= Offset;
|
||||
Protect = PAGE_EXECUTE_READWRITE | PAGE_SYSTEM;
|
||||
if (CacheEnable != MmCached)
|
||||
{
|
||||
Protect |= (PAGE_NOCACHE | PAGE_WRITETHROUGH);
|
||||
}
|
||||
|
||||
MmLockAddressSpace(MmGetKernelAddressSpace());
|
||||
Status = MmCreateMemoryArea (MmGetKernelAddressSpace(),
|
||||
MEMORY_AREA_IO_MAPPING,
|
||||
&Result,
|
||||
NumberOfBytes,
|
||||
Protect,
|
||||
&marea,
|
||||
0,
|
||||
FALSE,
|
||||
BoundaryAddressMultiple);
|
||||
MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("MmMapIoSpace failed (%lx)\n", Status);
|
||||
return (NULL);
|
||||
}
|
||||
Pfn = PhysicalAddress.LowPart >> PAGE_SHIFT;
|
||||
for (i = 0; i < PAGE_ROUND_UP(NumberOfBytes); i += PAGE_SIZE, Pfn++)
|
||||
{
|
||||
Status = MmCreateVirtualMappingForKernel((char*)Result + i,
|
||||
Protect,
|
||||
&Pfn,
|
||||
1);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DbgPrint("Unable to create virtual mapping\n");
|
||||
KeBugCheck(MEMORY_MANAGEMENT);
|
||||
}
|
||||
}
|
||||
return (PVOID)((ULONG_PTR)Result + Offset);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* NAME EXPORTED
|
||||
* MmUnmapIoSpace@8
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Unmaps a physical memory range from system space.
|
||||
*
|
||||
* ARGUMENTS
|
||||
* BaseAddress
|
||||
* The base virtual address which maps the region;
|
||||
*
|
||||
* NumberOfBytes
|
||||
* Number of bytes to unmap.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* None.
|
||||
*
|
||||
* NOTE
|
||||
* Code taken from ntoskrnl/mm/special.c.
|
||||
*
|
||||
* REVISIONS
|
||||
*
|
||||
* @implemented
|
||||
*/
|
||||
VOID NTAPI
|
||||
MmUnmapIoSpace (IN PVOID BaseAddress,
|
||||
IN ULONG NumberOfBytes)
|
||||
{
|
||||
LONG Offset;
|
||||
PVOID Address = BaseAddress;
|
||||
|
||||
Offset = (ULONG_PTR)Address % PAGE_SIZE;
|
||||
Address = RVA(Address, - Offset);
|
||||
NumberOfBytes += Offset;
|
||||
|
||||
MmLockAddressSpace(MmGetKernelAddressSpace());
|
||||
MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
|
||||
Address,
|
||||
NULL,
|
||||
NULL);
|
||||
MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* NAME EXPORTED
|
||||
* MmMapVideoDisplay@16
|
||||
*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID NTAPI
|
||||
MmMapVideoDisplay (IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN ULONG NumberOfBytes,
|
||||
IN MEMORY_CACHING_TYPE CacheType)
|
||||
{
|
||||
return MmMapIoSpace (PhysicalAddress, NumberOfBytes, (BOOLEAN)CacheType);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
VOID NTAPI
|
||||
MmUnmapVideoDisplay (IN PVOID BaseAddress,
|
||||
IN ULONG NumberOfBytes)
|
||||
{
|
||||
MmUnmapIoSpace (BaseAddress, NumberOfBytes);
|
||||
}
|
||||
|
||||
|
||||
/* EOF */
|
||||
@@ -362,6 +362,7 @@
|
||||
<directory name="ARM3">
|
||||
<file>hypermap.c</file>
|
||||
<file>init.c</file>
|
||||
<file>iosup.c</file>
|
||||
<file>pool.c</file>
|
||||
<file>syspte.c</file>
|
||||
</directory>
|
||||
@@ -371,7 +372,6 @@
|
||||
<file>dbgpool.c</file>
|
||||
<file>drvlck.c</file>
|
||||
<file>freelist.c</file>
|
||||
<file>iospace.c</file>
|
||||
<file>kmap.c</file>
|
||||
<file>marea.c</file>
|
||||
<file>mdlsup.c</file>
|
||||
|
||||
Reference in New Issue
Block a user