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("MmMapLockedPages(Mdl %x, AccessMode %x)\n", Mdl
, AccessMode
);
55 DPRINT("Mdl->ByteCount %x\n",Mdl
->ByteCount
);
56 DPRINT("PAGE_ROUND_UP(Mdl->ByteCount)/PAGESIZE) %x\n",
57 PAGE_ROUND_UP(Mdl
->ByteCount
)/PAGESIZE
);
59 MmCreateMemoryArea(KernelMode
,
61 MEMORY_AREA_MDL_MAPPING
,
63 Mdl
->ByteCount
+ Mdl
->ByteOffset
,
67 mdl_pages
= (ULONG
*)(Mdl
+ 1);
68 for (i
=0; i
<(PAGE_ROUND_UP(Mdl
->ByteCount
+Mdl
->ByteOffset
)/PAGESIZE
); i
++)
70 DPRINT("Writing %x with physical address %x\n",
71 base
+(i
*PAGESIZE
),mdl_pages
[i
]);
73 (PVOID
)((DWORD
)base
+(i
*PAGESIZE
)),
77 DPRINT("base %x\n",base
);
78 Mdl
->MdlFlags
= Mdl
->MdlFlags
| MDL_MAPPED_TO_SYSTEM_VA
;
79 return(base
+ Mdl
->ByteOffset
);
82 VOID
MmUnmapLockedPages(PVOID BaseAddress
, PMDL Mdl
)
84 * FUNCTION: Releases a mapping set up by a preceding call to MmMapLockedPages
86 * BaseAddress = Base virtual address to which the pages were mapped
87 * MemoryDescriptorList = MDL describing the mapped pages
90 DPRINT("MmUnmapLockedPages(BaseAddress %x, Mdl %x)\n", Mdl
, BaseAddress
);
91 (void)MmFreeMemoryArea(NULL
,
92 BaseAddress
-Mdl
->ByteOffset
,
95 DPRINT("MmUnmapLockedPages() finished\n");
98 VOID
MmPrepareMdlForReuse(PMDL Mdl
)
103 VOID
KeFlushIoBuffers(PMDL Mdl
, BOOLEAN ReadOperation
, BOOLEAN DmaOperation
)
106 /* See ntddk.h from Windows 98 DDK */
109 VOID
MmProbeAndLockPages(PMDL Mdl
, KPROCESSOR_MODE AccessMode
,
110 LOCK_OPERATION Operation
)
112 * FUNCTION: Probes the specified pages, makes them resident and locks them
115 * AccessMode = Access at which to probe the buffer
116 * Operation = Operation to probe for
119 ULONG
* mdl_pages
=NULL
;
124 DPRINT("MmProbeAndLockPages(Mdl %x)\n",Mdl
);
125 DPRINT("StartVa %x\n",Mdl
->StartVa
);
127 marea
= MmOpenMemoryAreaByAddress(Mdl
->Process
,
129 DPRINT("marea %x\n",marea
);
134 * Check the area is valid
138 DbgPrint("(%s:%d) Area is invalid\n",__FILE__
,__LINE__
);
139 ExRaiseStatus(STATUS_INVALID_PARAMETER
);
143 * Lock the memory area
144 * (We can't allow it to be freed while an I/O operation to it is
151 mdl_pages
= (ULONG
*)(Mdl
+ 1);
153 for (i
=0;i
<(PAGE_ROUND_UP(Mdl
->ByteOffset
+Mdl
->ByteCount
)/PAGESIZE
);i
++)
155 Address
= Mdl
->StartVa
+ (i
*PAGESIZE
);
156 mdl_pages
[i
] = (MmGetPhysicalAddress(Address
)).u
.LowPart
;
157 DPRINT("mdl_pages[i] %x\n",mdl_pages
[i
]);
161 ULONG
MmGetMdlByteCount(PMDL Mdl
)
166 return(Mdl
->ByteCount
);
169 ULONG
MmGetMdlByteOffset(PMDL Mdl
)
171 * FUNCTION: Returns the byte offset within its page of the buffer described
174 * Mdl = the mdl to query
175 * RETURNS: The offset in bytes
178 return(Mdl
->ByteOffset
);
181 ULONG
MmSizeOfMdl(PVOID Base
, ULONG Length
)
183 * FUNCTION: Returns the number of bytes to allocate for an MDL describing
184 * the given address range
186 * Base = base virtual address
187 * Length = number of bytes to map
190 unsigned int len
=ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base
,Length
);
192 DPRINT("MmSizeOfMdl() %x\n",sizeof(MDL
)+(len
*sizeof(ULONG
)));
193 return(sizeof(MDL
)+(len
*sizeof(ULONG
)));
196 PVOID
MmGetMdlVirtualAddress(PMDL Mdl
)
198 return(Mdl
->StartVa
+ Mdl
->ByteOffset
);
201 PVOID
MmGetSystemAddressForMdl(PMDL Mdl
)
203 * FUNCTION: Returns a nonpaged system-space virtual address for the buffer
204 * described by the MDL. It maps the physical pages described by a given
205 * MDL into system space, if they are not already mapped to system space.
208 * RETURNS: The base system-space virtual address that maps the physical
209 * pages described by the given MDL.
212 DPRINT("MmGetSystemAddressForMdl(Mdl %x)\n", Mdl
);
214 if (!( (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
) ||
215 (Mdl
->MdlFlags
& MDL_SOURCE_IS_NONPAGED_POOL
) ))
217 Mdl
->MappedSystemVa
= MmMapLockedPages(Mdl
,KernelMode
);
219 DPRINT("Returning %x\n",Mdl
->MappedSystemVa
);
220 return(Mdl
->MappedSystemVa
);
223 VOID
MmBuildMdlForNonPagedPool(PMDL Mdl
)
225 * FUNCTION: Fills in the corresponding physical page array of a given
226 * MDL for a buffer in nonpaged system space
228 * Mdl = Points to an MDL that supplies a virtual address,
229 * byte offset and length
233 Mdl
->MdlFlags
= Mdl
->MdlFlags
| MDL_SOURCE_IS_NONPAGED_POOL
;
234 for (va
=0; va
<Mdl
->Size
; va
++)
236 ((PULONG
)(Mdl
+ 1))[va
] =
237 (MmGetPhysicalAddress(Mdl
->StartVa
+ (va
* PAGESIZE
))).u
.LowPart
;
239 Mdl
->MappedSystemVa
= Mdl
->StartVa
;
242 VOID
MmInitializeMdl(PMDL MemoryDescriptorList
, PVOID Base
, ULONG Length
)
244 * FUNCTION: Initializes the header of an MDL
246 * MemoryDescriptorList = Points to the MDL to be initialized
247 * BaseVa = Points to the base virtual address of a buffer
248 * Length = Specifies the length (in bytes) of a buffer
251 memset(MemoryDescriptorList
,0,sizeof(MDL
));
252 MemoryDescriptorList
->StartVa
= (PVOID
)PAGE_ROUND_DOWN(Base
);
253 MemoryDescriptorList
->ByteOffset
= (ULONG
)(Base
- PAGE_ROUND_DOWN(Base
));
254 MemoryDescriptorList
->MdlFlags
= 0;
255 MemoryDescriptorList
->ByteCount
= Length
;
256 MemoryDescriptorList
->Size
= sizeof(MDL
) +
257 (ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base
,Length
) * sizeof(ULONG
));
258 MemoryDescriptorList
->Process
= PsGetCurrentProcess();
261 PMDL
MmCreateMdl(PMDL MemoryDescriptorList
, PVOID Base
, ULONG Length
)
263 * FUNCTION: Allocates and initalizes an MDL
265 * MemoryDescriptorList = Points to MDL to initalize. If this is
266 * NULL then one is allocated
267 * Base = Base virtual address of the buffer
268 * Length = Length in bytes of the buffer
269 * RETURNS: A pointer to initalized MDL
272 if (MemoryDescriptorList
== NULL
)
276 Size
= MmSizeOfMdl(Base
,Length
);
277 MemoryDescriptorList
= (PMDL
)ExAllocatePool(NonPagedPool
,Size
);
278 if (MemoryDescriptorList
==NULL
)
284 MmInitializeMdl(MemoryDescriptorList
,Base
,Length
);
286 return(MemoryDescriptorList
);