Lots of changes to the kernel
[reactos.git] / reactos / ntoskrnl / mm / mdl.c
1 /*
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)
7 * UPDATE HISTORY:
8 * 27/05/98: Created
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <internal/mm.h>
15 #include <internal/mmhal.h>
16 #include <string.h>
17 #include <internal/string.h>
18
19 #define NDEBUG
20 #include <internal/debug.h>
21
22 /* FUNCTIONS ***************************************************************/
23
24
25 VOID MmUnlockPages(PMDL MemoryDescriptorList)
26 /*
27 * FUNCTION: Unlocks the physical pages described by a given MDL
28 * ARGUMENTS:
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
32 * MDL is updated
33 */
34 {
35 /* It is harmless to leave this one as a stub */
36 }
37
38 PVOID MmMapLockedPages(PMDL Mdl, KPROCESSOR_MODE AccessMode)
39 /*
40 * FUNCTION: Maps the physical pages described by a given MDL
41 * ARGUMENTS:
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
46 */
47 {
48 PVOID base = NULL;
49 unsigned int i;
50 ULONG* mdl_pages=NULL;
51 MEMORY_AREA* Result;
52
53 DPRINT("MmMapLockedPages(Mdl %x, AccessMode %x)\n", Mdl, AccessMode);
54
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);
58
59 MmCreateMemoryArea(KernelMode,
60 NULL,
61 MEMORY_AREA_MDL_MAPPING,
62 &base,
63 Mdl->ByteCount + Mdl->ByteOffset,
64 0,
65 &Result);
66 CHECKPOINT;
67 mdl_pages = (ULONG *)(Mdl + 1);
68 for (i=0; i<(PAGE_ROUND_UP(Mdl->ByteCount+Mdl->ByteOffset)/PAGESIZE); i++)
69 {
70 DPRINT("Writing %x with physical address %x\n",
71 base+(i*PAGESIZE),mdl_pages[i]);
72 MmSetPage(NULL,
73 (PVOID)((DWORD)base+(i*PAGESIZE)),
74 PAGE_READWRITE,
75 mdl_pages[i]);
76 }
77 DPRINT("base %x\n",base);
78 Mdl->MdlFlags = Mdl->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
79 return(base + Mdl->ByteOffset);
80 }
81
82 VOID MmUnmapLockedPages(PVOID BaseAddress, PMDL Mdl)
83 /*
84 * FUNCTION: Releases a mapping set up by a preceding call to MmMapLockedPages
85 * ARGUMENTS:
86 * BaseAddress = Base virtual address to which the pages were mapped
87 * MemoryDescriptorList = MDL describing the mapped pages
88 */
89 {
90 DPRINT("MmUnmapLockedPages(BaseAddress %x, Mdl %x)\n", Mdl, BaseAddress);
91 (void)MmFreeMemoryArea(NULL,
92 BaseAddress-Mdl->ByteOffset,
93 Mdl->ByteCount,
94 FALSE);
95 DPRINT("MmUnmapLockedPages() finished\n");
96 }
97
98 VOID MmPrepareMdlForReuse(PMDL Mdl)
99 {
100 UNIMPLEMENTED;
101 }
102
103 VOID KeFlushIoBuffers(PMDL Mdl, BOOLEAN ReadOperation, BOOLEAN DmaOperation)
104 {
105 /* NOP on the x86 */
106 /* See ntddk.h from Windows 98 DDK */
107 }
108
109 VOID MmProbeAndLockPages(PMDL Mdl, KPROCESSOR_MODE AccessMode,
110 LOCK_OPERATION Operation)
111 /*
112 * FUNCTION: Probes the specified pages, makes them resident and locks them
113 * ARGUMENTS:
114 * Mdl = MDL to probe
115 * AccessMode = Access at which to probe the buffer
116 * Operation = Operation to probe for
117 */
118 {
119 ULONG* mdl_pages=NULL;
120 int i;
121 MEMORY_AREA* marea;
122 PVOID Address;
123
124 DPRINT("MmProbeAndLockPages(Mdl %x)\n",Mdl);
125 DPRINT("StartVa %x\n",Mdl->StartVa);
126
127 marea = MmOpenMemoryAreaByAddress(Mdl->Process,
128 Mdl->StartVa);
129 DPRINT("marea %x\n",marea);
130
131
132
133 /*
134 * Check the area is valid
135 */
136 if (marea==NULL )
137 {
138 DbgPrint("(%s:%d) Area is invalid\n",__FILE__,__LINE__);
139 ExRaiseStatus(STATUS_INVALID_PARAMETER);
140 }
141
142 /*
143 * Lock the memory area
144 * (We can't allow it to be freed while an I/O operation to it is
145 * ongoing)
146 */
147
148 /*
149 * Lock the pages
150 */
151 mdl_pages = (ULONG *)(Mdl + 1);
152
153 for (i=0;i<(PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGESIZE);i++)
154 {
155 Address = Mdl->StartVa + (i*PAGESIZE);
156 mdl_pages[i] = (MmGetPhysicalAddress(Address)).u.LowPart;
157 DPRINT("mdl_pages[i] %x\n",mdl_pages[i]);
158 }
159 }
160
161 ULONG MmGetMdlByteCount(PMDL Mdl)
162 /*
163 *
164 */
165 {
166 return(Mdl->ByteCount);
167 }
168
169 ULONG MmGetMdlByteOffset(PMDL Mdl)
170 /*
171 * FUNCTION: Returns the byte offset within its page of the buffer described
172 * by the given MDL
173 * ARGUMENTS:
174 * Mdl = the mdl to query
175 * RETURNS: The offset in bytes
176 */
177 {
178 return(Mdl->ByteOffset);
179 }
180
181 ULONG MmSizeOfMdl(PVOID Base, ULONG Length)
182 /*
183 * FUNCTION: Returns the number of bytes to allocate for an MDL describing
184 * the given address range
185 * ARGUMENTS:
186 * Base = base virtual address
187 * Length = number of bytes to map
188 */
189 {
190 unsigned int len=ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base,Length);
191
192 DPRINT("MmSizeOfMdl() %x\n",sizeof(MDL)+(len*sizeof(ULONG)));
193 return(sizeof(MDL)+(len*sizeof(ULONG)));
194 }
195
196 PVOID MmGetMdlVirtualAddress(PMDL Mdl)
197 {
198 return(Mdl->StartVa + Mdl->ByteOffset);
199 }
200
201 PVOID MmGetSystemAddressForMdl(PMDL Mdl)
202 /*
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.
206 * ARGUMENTS:
207 * Mdl = Mdl to map
208 * RETURNS: The base system-space virtual address that maps the physical
209 * pages described by the given MDL.
210 */
211 {
212 DPRINT("MmGetSystemAddressForMdl(Mdl %x)\n", Mdl);
213
214 if (!( (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) ||
215 (Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) ))
216 {
217 Mdl->MappedSystemVa = MmMapLockedPages(Mdl,KernelMode);
218 }
219 DPRINT("Returning %x\n",Mdl->MappedSystemVa);
220 return(Mdl->MappedSystemVa);
221 }
222
223 VOID MmBuildMdlForNonPagedPool(PMDL Mdl)
224 /*
225 * FUNCTION: Fills in the corresponding physical page array of a given
226 * MDL for a buffer in nonpaged system space
227 * ARGUMENTS:
228 * Mdl = Points to an MDL that supplies a virtual address,
229 * byte offset and length
230 */
231 {
232 int va;
233 Mdl->MdlFlags = Mdl->MdlFlags | MDL_SOURCE_IS_NONPAGED_POOL;
234 for (va=0; va<Mdl->Size; va++)
235 {
236 ((PULONG)(Mdl + 1))[va] =
237 (MmGetPhysicalAddress(Mdl->StartVa + (va * PAGESIZE))).u.LowPart;
238 }
239 Mdl->MappedSystemVa = Mdl->StartVa;
240 }
241
242 VOID MmInitializeMdl(PMDL MemoryDescriptorList, PVOID Base, ULONG Length)
243 /*
244 * FUNCTION: Initializes the header of an MDL
245 * ARGUMENTS:
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
249 */
250 {
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();
259 }
260
261 PMDL MmCreateMdl(PMDL MemoryDescriptorList, PVOID Base, ULONG Length)
262 /*
263 * FUNCTION: Allocates and initalizes an MDL
264 * ARGUMENTS:
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
270 */
271 {
272 if (MemoryDescriptorList == NULL)
273 {
274 ULONG Size;
275
276 Size = MmSizeOfMdl(Base,Length);
277 MemoryDescriptorList = (PMDL)ExAllocatePool(NonPagedPool,Size);
278 if (MemoryDescriptorList==NULL)
279 {
280 return(NULL);
281 }
282 }
283
284 MmInitializeMdl(MemoryDescriptorList,Base,Length);
285
286 return(MemoryDescriptorList);
287 }