reactos/reactos/ntoskrnl/mm/mdl.c
David Welch 126768af64 Lots of changes to the kernel
svn path=/trunk/; revision=527
1999-05-29 00:15:17 +00:00

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);
}