- 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:
ReactOS Portable Systems Group
2009-06-27 03:03:24 +00:00
parent 6e8a0cf662
commit 128aefcd63
4 changed files with 274 additions and 185 deletions
+257
View File
@@ -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 */
+16
View File
@@ -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 */
-184
View File
@@ -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 */
+1 -1
View File
@@ -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>