mirror of
https://github.com/reactos/reactos.git
synced 2024-06-01 02:01:57 +00:00
126768af64
svn path=/trunk/; revision=527
288 lines
7.9 KiB
C
288 lines
7.9 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: ntoskrnl/mm/mdl.c
|
|
* PURPOSE: Manipulates MDLs
|
|
* PROGRAMMER: David Welch (welch@cwcom.net)
|
|
* UPDATE HISTORY:
|
|
* 27/05/98: Created
|
|
*/
|
|
|
|
/* INCLUDES ****************************************************************/
|
|
|
|
#include <ddk/ntddk.h>
|
|
#include <internal/mm.h>
|
|
#include <internal/mmhal.h>
|
|
#include <string.h>
|
|
#include <internal/string.h>
|
|
|
|
#define NDEBUG
|
|
#include <internal/debug.h>
|
|
|
|
/* FUNCTIONS ***************************************************************/
|
|
|
|
|
|
VOID MmUnlockPages(PMDL MemoryDescriptorList)
|
|
/*
|
|
* FUNCTION: Unlocks the physical pages described by a given MDL
|
|
* ARGUMENTS:
|
|
* MemoryDescriptorList = MDL describing the buffer to be unlocked
|
|
* NOTES: The memory described by the specified MDL must have been locked
|
|
* previously by a call to MmProbeAndLockPages. As the pages unlocked, the
|
|
* MDL is updated
|
|
*/
|
|
{
|
|
/* It is harmless to leave this one as a stub */
|
|
}
|
|
|
|
PVOID MmMapLockedPages(PMDL Mdl, KPROCESSOR_MODE AccessMode)
|
|
/*
|
|
* FUNCTION: Maps the physical pages described by a given MDL
|
|
* ARGUMENTS:
|
|
* Mdl = Points to an MDL updated by MmProbeAndLockPages
|
|
* AccessMode = Specifies the access mode in which to map the MDL
|
|
* RETURNS: The base virtual address that maps the locked pages for the
|
|
* range described by the MDL
|
|
*/
|
|
{
|
|
PVOID base = NULL;
|
|
unsigned int i;
|
|
ULONG* mdl_pages=NULL;
|
|
MEMORY_AREA* Result;
|
|
|
|
DPRINT("MmMapLockedPages(Mdl %x, AccessMode %x)\n", Mdl, AccessMode);
|
|
|
|
DPRINT("Mdl->ByteCount %x\n",Mdl->ByteCount);
|
|
DPRINT("PAGE_ROUND_UP(Mdl->ByteCount)/PAGESIZE) %x\n",
|
|
PAGE_ROUND_UP(Mdl->ByteCount)/PAGESIZE);
|
|
|
|
MmCreateMemoryArea(KernelMode,
|
|
NULL,
|
|
MEMORY_AREA_MDL_MAPPING,
|
|
&base,
|
|
Mdl->ByteCount + Mdl->ByteOffset,
|
|
0,
|
|
&Result);
|
|
CHECKPOINT;
|
|
mdl_pages = (ULONG *)(Mdl + 1);
|
|
for (i=0; i<(PAGE_ROUND_UP(Mdl->ByteCount+Mdl->ByteOffset)/PAGESIZE); i++)
|
|
{
|
|
DPRINT("Writing %x with physical address %x\n",
|
|
base+(i*PAGESIZE),mdl_pages[i]);
|
|
MmSetPage(NULL,
|
|
(PVOID)((DWORD)base+(i*PAGESIZE)),
|
|
PAGE_READWRITE,
|
|
mdl_pages[i]);
|
|
}
|
|
DPRINT("base %x\n",base);
|
|
Mdl->MdlFlags = Mdl->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
|
|
return(base + Mdl->ByteOffset);
|
|
}
|
|
|
|
VOID MmUnmapLockedPages(PVOID BaseAddress, PMDL Mdl)
|
|
/*
|
|
* FUNCTION: Releases a mapping set up by a preceding call to MmMapLockedPages
|
|
* ARGUMENTS:
|
|
* BaseAddress = Base virtual address to which the pages were mapped
|
|
* MemoryDescriptorList = MDL describing the mapped pages
|
|
*/
|
|
{
|
|
DPRINT("MmUnmapLockedPages(BaseAddress %x, Mdl %x)\n", Mdl, BaseAddress);
|
|
(void)MmFreeMemoryArea(NULL,
|
|
BaseAddress-Mdl->ByteOffset,
|
|
Mdl->ByteCount,
|
|
FALSE);
|
|
DPRINT("MmUnmapLockedPages() finished\n");
|
|
}
|
|
|
|
VOID MmPrepareMdlForReuse(PMDL Mdl)
|
|
{
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
VOID KeFlushIoBuffers(PMDL Mdl, BOOLEAN ReadOperation, BOOLEAN DmaOperation)
|
|
{
|
|
/* NOP on the x86 */
|
|
/* See ntddk.h from Windows 98 DDK */
|
|
}
|
|
|
|
VOID MmProbeAndLockPages(PMDL Mdl, KPROCESSOR_MODE AccessMode,
|
|
LOCK_OPERATION Operation)
|
|
/*
|
|
* FUNCTION: Probes the specified pages, makes them resident and locks them
|
|
* ARGUMENTS:
|
|
* Mdl = MDL to probe
|
|
* AccessMode = Access at which to probe the buffer
|
|
* Operation = Operation to probe for
|
|
*/
|
|
{
|
|
ULONG* mdl_pages=NULL;
|
|
int i;
|
|
MEMORY_AREA* marea;
|
|
PVOID Address;
|
|
|
|
DPRINT("MmProbeAndLockPages(Mdl %x)\n",Mdl);
|
|
DPRINT("StartVa %x\n",Mdl->StartVa);
|
|
|
|
marea = MmOpenMemoryAreaByAddress(Mdl->Process,
|
|
Mdl->StartVa);
|
|
DPRINT("marea %x\n",marea);
|
|
|
|
|
|
|
|
/*
|
|
* Check the area is valid
|
|
*/
|
|
if (marea==NULL )
|
|
{
|
|
DbgPrint("(%s:%d) Area is invalid\n",__FILE__,__LINE__);
|
|
ExRaiseStatus(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
/*
|
|
* Lock the memory area
|
|
* (We can't allow it to be freed while an I/O operation to it is
|
|
* ongoing)
|
|
*/
|
|
|
|
/*
|
|
* Lock the pages
|
|
*/
|
|
mdl_pages = (ULONG *)(Mdl + 1);
|
|
|
|
for (i=0;i<(PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGESIZE);i++)
|
|
{
|
|
Address = Mdl->StartVa + (i*PAGESIZE);
|
|
mdl_pages[i] = (MmGetPhysicalAddress(Address)).u.LowPart;
|
|
DPRINT("mdl_pages[i] %x\n",mdl_pages[i]);
|
|
}
|
|
}
|
|
|
|
ULONG MmGetMdlByteCount(PMDL Mdl)
|
|
/*
|
|
*
|
|
*/
|
|
{
|
|
return(Mdl->ByteCount);
|
|
}
|
|
|
|
ULONG MmGetMdlByteOffset(PMDL Mdl)
|
|
/*
|
|
* FUNCTION: Returns the byte offset within its page of the buffer described
|
|
* by the given MDL
|
|
* ARGUMENTS:
|
|
* Mdl = the mdl to query
|
|
* RETURNS: The offset in bytes
|
|
*/
|
|
{
|
|
return(Mdl->ByteOffset);
|
|
}
|
|
|
|
ULONG MmSizeOfMdl(PVOID Base, ULONG Length)
|
|
/*
|
|
* FUNCTION: Returns the number of bytes to allocate for an MDL describing
|
|
* the given address range
|
|
* ARGUMENTS:
|
|
* Base = base virtual address
|
|
* Length = number of bytes to map
|
|
*/
|
|
{
|
|
unsigned int len=ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base,Length);
|
|
|
|
DPRINT("MmSizeOfMdl() %x\n",sizeof(MDL)+(len*sizeof(ULONG)));
|
|
return(sizeof(MDL)+(len*sizeof(ULONG)));
|
|
}
|
|
|
|
PVOID MmGetMdlVirtualAddress(PMDL Mdl)
|
|
{
|
|
return(Mdl->StartVa + Mdl->ByteOffset);
|
|
}
|
|
|
|
PVOID MmGetSystemAddressForMdl(PMDL Mdl)
|
|
/*
|
|
* FUNCTION: Returns a nonpaged system-space virtual address for the buffer
|
|
* described by the MDL. It maps the physical pages described by a given
|
|
* MDL into system space, if they are not already mapped to system space.
|
|
* ARGUMENTS:
|
|
* Mdl = Mdl to map
|
|
* RETURNS: The base system-space virtual address that maps the physical
|
|
* pages described by the given MDL.
|
|
*/
|
|
{
|
|
DPRINT("MmGetSystemAddressForMdl(Mdl %x)\n", Mdl);
|
|
|
|
if (!( (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) ||
|
|
(Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) ))
|
|
{
|
|
Mdl->MappedSystemVa = MmMapLockedPages(Mdl,KernelMode);
|
|
}
|
|
DPRINT("Returning %x\n",Mdl->MappedSystemVa);
|
|
return(Mdl->MappedSystemVa);
|
|
}
|
|
|
|
VOID MmBuildMdlForNonPagedPool(PMDL Mdl)
|
|
/*
|
|
* FUNCTION: Fills in the corresponding physical page array of a given
|
|
* MDL for a buffer in nonpaged system space
|
|
* ARGUMENTS:
|
|
* Mdl = Points to an MDL that supplies a virtual address,
|
|
* byte offset and length
|
|
*/
|
|
{
|
|
int va;
|
|
Mdl->MdlFlags = Mdl->MdlFlags | MDL_SOURCE_IS_NONPAGED_POOL;
|
|
for (va=0; va<Mdl->Size; va++)
|
|
{
|
|
((PULONG)(Mdl + 1))[va] =
|
|
(MmGetPhysicalAddress(Mdl->StartVa + (va * PAGESIZE))).u.LowPart;
|
|
}
|
|
Mdl->MappedSystemVa = Mdl->StartVa;
|
|
}
|
|
|
|
VOID MmInitializeMdl(PMDL MemoryDescriptorList, PVOID Base, ULONG Length)
|
|
/*
|
|
* FUNCTION: Initializes the header of an MDL
|
|
* ARGUMENTS:
|
|
* MemoryDescriptorList = Points to the MDL to be initialized
|
|
* BaseVa = Points to the base virtual address of a buffer
|
|
* Length = Specifies the length (in bytes) of a buffer
|
|
*/
|
|
{
|
|
memset(MemoryDescriptorList,0,sizeof(MDL));
|
|
MemoryDescriptorList->StartVa = (PVOID)PAGE_ROUND_DOWN(Base);
|
|
MemoryDescriptorList->ByteOffset = (ULONG)(Base - PAGE_ROUND_DOWN(Base));
|
|
MemoryDescriptorList->MdlFlags = 0;
|
|
MemoryDescriptorList->ByteCount = Length;
|
|
MemoryDescriptorList->Size = sizeof(MDL) +
|
|
(ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base,Length) * sizeof(ULONG));
|
|
MemoryDescriptorList->Process = PsGetCurrentProcess();
|
|
}
|
|
|
|
PMDL MmCreateMdl(PMDL MemoryDescriptorList, PVOID Base, ULONG Length)
|
|
/*
|
|
* FUNCTION: Allocates and initalizes an MDL
|
|
* ARGUMENTS:
|
|
* MemoryDescriptorList = Points to MDL to initalize. If this is
|
|
* NULL then one is allocated
|
|
* Base = Base virtual address of the buffer
|
|
* Length = Length in bytes of the buffer
|
|
* RETURNS: A pointer to initalized MDL
|
|
*/
|
|
{
|
|
if (MemoryDescriptorList == NULL)
|
|
{
|
|
ULONG Size;
|
|
|
|
Size = MmSizeOfMdl(Base,Length);
|
|
MemoryDescriptorList = (PMDL)ExAllocatePool(NonPagedPool,Size);
|
|
if (MemoryDescriptorList==NULL)
|
|
{
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
MmInitializeMdl(MemoryDescriptorList,Base,Length);
|
|
|
|
return(MemoryDescriptorList);
|
|
}
|