2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/mdl.c
5 * PURPOSE: Manipulates MDLs
6 * PROGRAMMER: David Welch (welch@cwcom.net)
11 /* INCLUDES ****************************************************************/
13 #include <ddk/ntddk.h>
14 #include <internal/mm.h>
15 #include <internal/mmhal.h>
17 #include <internal/string.h>
20 #include <internal/debug.h>
22 /* FUNCTIONS ***************************************************************/
25 VOID
MmUnlockPages(PMDL MemoryDescriptorList
)
27 * FUNCTION: Unlocks the physical pages described by a given MDL
29 * MemoryDescriptorList = MDL describing the buffer to be unlocked
30 * NOTES: The memory described by the specified MDL must have been locked
31 * previously by a call to MmProbeAndLockPages. As the pages unlocked, the
35 /* It is harmless to leave this one as a stub */
38 PVOID
MmMapLockedPages(PMDL Mdl
, KPROCESSOR_MODE AccessMode
)
40 * FUNCTION: Maps the physical pages described by a given MDL
42 * Mdl = Points to an MDL updated by MmProbeAndLockPages
43 * AccessMode = Specifies the access mode in which to map the MDL
44 * RETURNS: The base virtual address that maps the locked pages for the
45 * range described by the MDL
50 ULONG
* mdl_pages
=NULL
;
53 DPRINT("Mdl->ByteCount %x\n",Mdl
->ByteCount
);
54 DPRINT("PAGE_ROUND_UP(Mdl->ByteCount)/PAGESIZE) %x\n",
55 PAGE_ROUND_UP(Mdl
->ByteCount
)/PAGESIZE
);
57 MmCreateMemoryArea(KernelMode
,
58 PsGetCurrentProcess(),
59 MEMORY_AREA_MDL_MAPPING
,
61 Mdl
->ByteCount
+ Mdl
->ByteOffset
,
65 mdl_pages
= (ULONG
*)(Mdl
+ 1);
66 for (i
=0; i
<(PAGE_ROUND_UP(Mdl
->ByteCount
+Mdl
->ByteOffset
)/PAGESIZE
); i
++)
68 DPRINT("Writing %x with physical address %x\n",
69 base
+(i
*PAGESIZE
),mdl_pages
[i
]);
71 (PVOID
)((DWORD
)base
+(i
*PAGESIZE
)),
75 DPRINT("base %x\n",base
);
76 Mdl
->MdlFlags
= Mdl
->MdlFlags
| MDL_MAPPED_TO_SYSTEM_VA
;
77 return(base
+ Mdl
->ByteOffset
);
80 VOID
MmUnmapLockedPages(PVOID BaseAddress
, PMDL Mdl
)
82 * FUNCTION: Releases a mapping set up by a preceding call to MmMapLockedPages
84 * BaseAddress = Base virtual address to which the pages were mapped
85 * MemoryDescriptorList = MDL describing the mapped pages
88 (void)MmFreeMemoryArea(PsGetCurrentProcess(),BaseAddress
-Mdl
->ByteOffset
,
89 Mdl
->ByteCount
,FALSE
);
92 VOID
MmPrepareMdlForReuse(PMDL Mdl
)
97 VOID
KeFlushIoBuffers(PMDL Mdl
, BOOLEAN ReadOperation
, BOOLEAN DmaOperation
)
100 /* See ntddk.h from Windows 98 DDK */
103 VOID
MmProbeAndLockPages(PMDL Mdl
, KPROCESSOR_MODE AccessMode
,
104 LOCK_OPERATION Operation
)
106 * FUNCTION: Probes the specified pages, makes them resident and locks them
109 * AccessMode = Access at which to probe the buffer
110 * Operation = Operation to probe for
113 ULONG
* mdl_pages
=NULL
;
118 DPRINT("MmProbeAndLockPages(Mdl %x)\n",Mdl
);
119 DPRINT("StartVa %x\n",Mdl
->StartVa
);
121 marea
= MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),
123 DPRINT("marea %x\n",marea
);
128 * Check the area is valid
132 DbgPrint("(%s:%d) Area is invalid\n",__FILE__
,__LINE__
);
133 ExRaiseStatus(STATUS_INVALID_PARAMETER
);
137 * Lock the memory area
138 * (We can't allow it to be freed while an I/O operation to it is
145 mdl_pages
= (ULONG
*)(Mdl
+ 1);
147 for (i
=0;i
<(PAGE_ROUND_UP(Mdl
->ByteOffset
+Mdl
->ByteCount
)/PAGESIZE
);i
++)
149 Address
= Mdl
->StartVa
+ (i
*PAGESIZE
);
150 mdl_pages
[i
] = (MmGetPhysicalAddress(Address
)).u
.LowPart
;
151 DPRINT("mdl_pages[i] %x\n",mdl_pages
[i
]);
155 ULONG
MmGetMdlByteCount(PMDL Mdl
)
160 return(Mdl
->ByteCount
);
163 ULONG
MmGetMdlByteOffset(PMDL Mdl
)
165 * FUNCTION: Returns the byte offset within its page of the buffer described
168 * Mdl = the mdl to query
169 * RETURNS: The offset in bytes
172 return(Mdl
->ByteOffset
);
175 ULONG
MmSizeOfMdl(PVOID Base
, ULONG Length
)
177 * FUNCTION: Returns the number of bytes to allocate for an MDL describing
178 * the given address range
180 * Base = base virtual address
181 * Length = number of bytes to map
184 unsigned int len
=ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base
,Length
);
186 DPRINT("MmSizeOfMdl() %x\n",sizeof(MDL
)+(len
*sizeof(ULONG
)));
187 return(sizeof(MDL
)+(len
*sizeof(ULONG
)));
190 PVOID
MmGetMdlVirtualAddress(PMDL Mdl
)
192 return(Mdl
->StartVa
+ Mdl
->ByteOffset
);
195 PVOID
MmGetSystemAddressForMdl(PMDL Mdl
)
197 * FUNCTION: Returns a nonpaged system-space virtual address for the buffer
198 * described by the MDL. It maps the physical pages described by a given
199 * MDL into system space, if they are not already mapped to system space.
202 * RETURNS: The base system-space virtual address that maps the physical
203 * pages described by the given MDL.
206 if (!( (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
) ||
207 (Mdl
->MdlFlags
& MDL_SOURCE_IS_NONPAGED_POOL
) ))
209 Mdl
->MappedSystemVa
= MmMapLockedPages(Mdl
,KernelMode
);
211 return(Mdl
->MappedSystemVa
);
214 VOID
MmBuildMdlForNonPagedPool(PMDL Mdl
)
216 * FUNCTION: Fills in the corresponding physical page array of a given
217 * MDL for a buffer in nonpaged system space
219 * Mdl = Points to an MDL that supplies a virtual address,
220 * byte offset and length
224 Mdl
->MdlFlags
= Mdl
->MdlFlags
| MDL_SOURCE_IS_NONPAGED_POOL
;
225 for (va
=0; va
<Mdl
->Size
; va
++)
227 ((PULONG
)(Mdl
+ 1))[va
] =
228 (MmGetPhysicalAddress(Mdl
->StartVa
+ (va
* PAGESIZE
))).u
.LowPart
;
230 Mdl
->MappedSystemVa
= Mdl
->StartVa
;
233 VOID
MmInitializeMdl(PMDL MemoryDescriptorList
, PVOID Base
, ULONG Length
)
235 * FUNCTION: Initializes the header of an MDL
237 * MemoryDescriptorList = Points to the MDL to be initialized
238 * BaseVa = Points to the base virtual address of a buffer
239 * Length = Specifies the length (in bytes) of a buffer
242 memset(MemoryDescriptorList
,0,sizeof(MDL
));
243 MemoryDescriptorList
->StartVa
= (PVOID
)PAGE_ROUND_DOWN(Base
);
244 MemoryDescriptorList
->ByteOffset
= (ULONG
)(Base
- PAGE_ROUND_DOWN(Base
));
245 MemoryDescriptorList
->MdlFlags
= 0;
246 MemoryDescriptorList
->ByteCount
= Length
;
247 MemoryDescriptorList
->Size
= sizeof(MDL
) +
248 (ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base
,Length
) * sizeof(ULONG
));
249 MemoryDescriptorList
->Process
= PsGetCurrentProcess();
252 PMDL
MmCreateMdl(PMDL MemoryDescriptorList
, PVOID Base
, ULONG Length
)
254 * FUNCTION: Allocates and initalizes an MDL
256 * MemoryDescriptorList = Points to MDL to initalize. If this is
257 * NULL then one is allocated
258 * Base = Base virtual address of the buffer
259 * Length = Length in bytes of the buffer
260 * RETURNS: A pointer to initalized MDL
263 if (MemoryDescriptorList
== NULL
)
267 Size
= MmSizeOfMdl(Base
,Length
);
268 MemoryDescriptorList
= (PMDL
)ExAllocatePool(NonPagedPool
,Size
);
269 if (MemoryDescriptorList
==NULL
)
275 MmInitializeMdl(MemoryDescriptorList
,Base
,Length
);
277 return(MemoryDescriptorList
);