- Added return values to some unimplemented functions.
[reactos.git] / reactos / ntoskrnl / mm / virtual.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: virtual.c,v 1.71 2003/12/14 17:44:02 hbirr Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/virtual.c
23 * PURPOSE: Implementing operations on virtual memory.
24 * PROGRAMMER: David Welch
25 */
26
27 /* INCLUDE *****************************************************************/
28
29 #include <ddk/ntddk.h>
30 #include <internal/mm.h>
31 #include <internal/ob.h>
32 #include <internal/io.h>
33 #include <internal/ps.h>
34 #include <internal/pool.h>
35 #include <internal/safe.h>
36
37 #define NDEBUG
38 #include <internal/debug.h>
39
40 /* FUNCTIONS *****************************************************************/
41
42 NTSTATUS STDCALL
43 NtFlushVirtualMemory(IN HANDLE ProcessHandle,
44 IN PVOID BaseAddress,
45 IN ULONG NumberOfBytesToFlush,
46 OUT PULONG NumberOfBytesFlushed OPTIONAL)
47 /*
48 * FUNCTION: Flushes virtual memory to file
49 * ARGUMENTS:
50 * ProcessHandle = Points to the process that allocated the virtual
51 * memory
52 * BaseAddress = Points to the memory address
53 * NumberOfBytesToFlush = Limits the range to flush,
54 * NumberOfBytesFlushed = Actual number of bytes flushed
55 * RETURNS: Status
56 */
57 {
58 UNIMPLEMENTED;
59 return(STATUS_NOT_IMPLEMENTED);
60 }
61
62 NTSTATUS STDCALL
63 NtLockVirtualMemory(HANDLE ProcessHandle,
64 PVOID BaseAddress,
65 ULONG NumberOfBytesToLock,
66 PULONG NumberOfBytesLocked) // ULONG LockOption?
67 {
68 // AG [08-20-03] : I have *no* idea if this is correct, I just used the
69 // other functions as a template and made a few intelligent guesses...
70
71 NTSTATUS Status;
72 PMDL Mdl;
73 PEPROCESS Process;
74
75 DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
76 "NumberOfBytesToLock %d), NumberOfBytesLocked %x\n",ProcessHandle,BaseAddress,
77 NumberOfBytesToLock, NumberOfBytesLocked);
78
79 Status = ObReferenceObjectByHandle(ProcessHandle,
80 PROCESS_VM_WRITE,
81 NULL,
82 UserMode,
83 (PVOID*)(&Process),
84 NULL);
85 if (Status != STATUS_SUCCESS)
86 {
87 return(Status);
88 }
89
90 Mdl = MmCreateMdl(NULL,
91 BaseAddress,
92 NumberOfBytesToLock);
93 MmProbeAndLockPages(Mdl,
94 UserMode,
95 IoWriteAccess);
96
97 ExFreePool(Mdl); // Are we supposed to do this here?
98
99 ObDereferenceObject(Process);
100
101 *NumberOfBytesLocked = NumberOfBytesToLock;
102 return(STATUS_SUCCESS);
103 }
104
105 NTSTATUS STDCALL
106 NtQueryVirtualMemory (IN HANDLE ProcessHandle,
107 IN PVOID Address,
108 IN CINT VirtualMemoryInformationClass,
109 OUT PVOID VirtualMemoryInformation,
110 IN ULONG Length,
111 OUT PULONG UnsafeResultLength)
112 {
113 NTSTATUS Status;
114 PEPROCESS Process;
115 MEMORY_AREA* MemoryArea;
116 ULONG ResultLength = 0;
117 PMADDRESS_SPACE AddressSpace;
118
119 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
120 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
121 "Length %lu ResultLength %x)\n",ProcessHandle,Address,
122 VirtualMemoryInformationClass,VirtualMemoryInformation,
123 Length,ResultLength);
124
125 Status = ObReferenceObjectByHandle(ProcessHandle,
126 PROCESS_QUERY_INFORMATION,
127 NULL,
128 UserMode,
129 (PVOID*)(&Process),
130 NULL);
131
132 if (!NT_SUCCESS(Status))
133 {
134 DPRINT("NtQueryVirtualMemory() = %x\n",Status);
135 return(Status);
136 }
137
138 AddressSpace = &Process->AddressSpace;
139 MmLockAddressSpace(AddressSpace);
140 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
141 Address);
142 switch(VirtualMemoryInformationClass)
143 {
144 case MemoryBasicInformation:
145 {
146 PMEMORY_BASIC_INFORMATION Info =
147 (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
148
149 if (Length != sizeof(MEMORY_BASIC_INFORMATION))
150 {
151 MmUnlockAddressSpace(AddressSpace);
152 ObDereferenceObject(Process);
153 return(STATUS_INFO_LENGTH_MISMATCH);
154 }
155
156 if (MemoryArea == NULL)
157 {
158 Info->State = MEM_FREE;
159 Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
160 Status = STATUS_SUCCESS;
161 ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
162 }
163 else if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
164 {
165 Status = MmQueryAnonMem(MemoryArea, Address, Info,
166 &ResultLength);
167 }
168 else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
169 {
170 Status = MmQuerySectionView(MemoryArea, Address, Info,
171 &ResultLength);
172 }
173 else
174 {
175 Status = STATUS_UNSUCCESSFUL;
176 ResultLength = 0;
177 }
178 break;
179 }
180
181 default:
182 {
183 Status = STATUS_INVALID_INFO_CLASS;
184 ResultLength = 0;
185 break;
186 }
187 }
188
189 MmUnlockAddressSpace(AddressSpace);
190 ObDereferenceObject(Process);
191 if (UnsafeResultLength != NULL)
192 {
193 MmCopyToCaller(UnsafeResultLength, &ResultLength, sizeof(ULONG));
194 }
195 return(Status);
196 }
197
198 NTSTATUS STDCALL
199 NtProtectVirtualMemory(IN HANDLE ProcessHandle,
200 IN PVOID BaseAddress,
201 IN ULONG NumberOfBytesToProtect,
202 IN ULONG NewAccessProtection,
203 OUT PULONG UnsafeOldAccessProtection)
204 {
205 PMEMORY_AREA MemoryArea;
206 PEPROCESS Process;
207 NTSTATUS Status;
208 PMADDRESS_SPACE AddressSpace;
209 ULONG OldAccessProtection;
210
211 NumberOfBytesToProtect =
212 PAGE_ROUND_UP(BaseAddress + NumberOfBytesToProtect) -
213 PAGE_ROUND_DOWN(BaseAddress);
214 BaseAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
215
216 Status = ObReferenceObjectByHandle(ProcessHandle,
217 PROCESS_VM_OPERATION,
218 PsProcessType,
219 UserMode,
220 (PVOID*)(&Process),
221 NULL);
222 if (Status != STATUS_SUCCESS)
223 {
224 DPRINT("NtProtectVirtualMemory() = %x\n",Status);
225 return(Status);
226 }
227
228 AddressSpace = &Process->AddressSpace;
229
230 MmLockAddressSpace(AddressSpace);
231 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
232 BaseAddress);
233 if (MemoryArea == NULL)
234 {
235 MmUnlockAddressSpace(AddressSpace);
236 ObDereferenceObject(Process);
237 return(STATUS_UNSUCCESSFUL);
238 }
239
240 if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
241 {
242 Status = MmProtectAnonMem(AddressSpace, MemoryArea, BaseAddress,
243 NumberOfBytesToProtect, NewAccessProtection,
244 &OldAccessProtection);
245 }
246 else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
247 {
248 Status = MmProtectSectionView(AddressSpace, MemoryArea, BaseAddress,
249 NumberOfBytesToProtect,
250 NewAccessProtection,
251 &OldAccessProtection);
252 }
253
254 MmUnlockAddressSpace(AddressSpace);
255 ObDereferenceObject(Process);
256
257 MmCopyToCaller(UnsafeOldAccessProtection, &OldAccessProtection,
258 sizeof(ULONG));
259
260 return(Status);
261 }
262
263 NTSTATUS STDCALL
264 NtReadVirtualMemory(IN HANDLE ProcessHandle,
265 IN PVOID BaseAddress,
266 OUT PVOID Buffer,
267 IN ULONG NumberOfBytesToRead,
268 OUT PULONG NumberOfBytesRead)
269 {
270 NTSTATUS Status;
271 PMDL Mdl;
272 PVOID SystemAddress;
273 PEPROCESS Process;
274
275 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
276 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
277 Buffer,NumberOfBytesToRead);
278
279 Status = ObReferenceObjectByHandle(ProcessHandle,
280 PROCESS_VM_WRITE,
281 NULL,
282 UserMode,
283 (PVOID*)(&Process),
284 NULL);
285 if (Status != STATUS_SUCCESS)
286 {
287 return(Status);
288 }
289
290 Mdl = MmCreateMdl(NULL,
291 Buffer,
292 NumberOfBytesToRead);
293 MmProbeAndLockPages(Mdl,
294 UserMode,
295 IoWriteAccess);
296
297 KeAttachProcess(Process);
298
299 SystemAddress = MmGetSystemAddressForMdl(Mdl);
300 memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead);
301
302 KeDetachProcess();
303
304 if (Mdl->MappedSystemVa != NULL)
305 {
306 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
307 }
308 MmUnlockPages(Mdl);
309 ExFreePool(Mdl);
310
311 ObDereferenceObject(Process);
312
313 *NumberOfBytesRead = NumberOfBytesToRead;
314 return(STATUS_SUCCESS);
315 }
316
317 NTSTATUS STDCALL
318 NtUnlockVirtualMemory(HANDLE ProcessHandle,
319 PVOID BaseAddress,
320 ULONG NumberOfBytesToUnlock,
321 PULONG NumberOfBytesUnlocked OPTIONAL)
322 {
323 // AG [08-20-03] : I have *no* idea if this is correct, I just used the
324 // other functions as a template and made a few intelligent guesses...
325
326 NTSTATUS Status;
327 PMDL Mdl;
328 PEPROCESS Process;
329
330 DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
331 "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle,BaseAddress,
332 NumberOfBytesToUnlock, NumberOfBytesUnlocked);
333
334 Status = ObReferenceObjectByHandle(ProcessHandle,
335 PROCESS_VM_WRITE,
336 NULL,
337 UserMode,
338 (PVOID*)(&Process),
339 NULL);
340 if (Status != STATUS_SUCCESS)
341 {
342 return(Status);
343 }
344
345 Mdl = MmCreateMdl(NULL,
346 BaseAddress,
347 NumberOfBytesToUnlock);
348
349 ObDereferenceObject(Process);
350
351 if (Mdl->MappedSystemVa != NULL)
352 {
353 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
354 }
355 MmUnlockPages(Mdl);
356 ExFreePool(Mdl);
357
358 *NumberOfBytesUnlocked = NumberOfBytesToUnlock;
359
360 return(STATUS_SUCCESS);
361 }
362
363
364 NTSTATUS STDCALL
365 NtWriteVirtualMemory(IN HANDLE ProcessHandle,
366 IN PVOID BaseAddress,
367 IN PVOID Buffer,
368 IN ULONG NumberOfBytesToWrite,
369 OUT PULONG NumberOfBytesWritten)
370 {
371 NTSTATUS Status;
372 PMDL Mdl;
373 PVOID SystemAddress;
374 PEPROCESS Process;
375
376 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
377 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
378 Buffer,NumberOfBytesToWrite);
379
380 Status = ObReferenceObjectByHandle(ProcessHandle,
381 PROCESS_VM_WRITE,
382 NULL,
383 UserMode,
384 (PVOID*)(&Process),
385 NULL);
386 if (Status != STATUS_SUCCESS)
387 {
388 return(Status);
389 }
390
391 Mdl = MmCreateMdl(NULL,
392 Buffer,
393 NumberOfBytesToWrite);
394 MmProbeAndLockPages(Mdl,
395 UserMode,
396 IoReadAccess);
397
398 KeAttachProcess(Process);
399
400 SystemAddress = MmGetSystemAddressForMdl(Mdl);
401 memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
402
403 KeDetachProcess();
404
405 ObDereferenceObject(Process);
406
407 if (Mdl->MappedSystemVa != NULL)
408 {
409 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
410 }
411 MmUnlockPages(Mdl);
412 ExFreePool(Mdl);
413
414 *NumberOfBytesWritten = NumberOfBytesToWrite;
415
416 return(STATUS_SUCCESS);
417 }
418
419 /*
420 * @unimplemented
421 */
422 PVOID STDCALL
423 MmSecureVirtualMemory (PVOID Address,
424 SIZE_T Length,
425 ULONG Mode)
426 {
427 /* Only works for user space */
428 if (MmHighestUserAddress < Address)
429 {
430 return NULL;
431 }
432
433 UNIMPLEMENTED;
434
435 return 0;
436 }
437
438
439 /*
440 * @unimplemented
441 */
442 VOID STDCALL
443 MmUnsecureVirtualMemory(PVOID SecureMem)
444 {
445 if (NULL == SecureMem)
446 {
447 return;
448 }
449
450 UNIMPLEMENTED;
451 }
452
453
454 /*
455 * @implemented
456 */
457 VOID STDCALL
458 ProbeForRead (IN PVOID Address,
459 IN ULONG Length,
460 IN ULONG Alignment)
461 {
462 assert (Alignment ==1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
463
464 if (Length == 0)
465 return;
466
467 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
468 {
469 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
470 }
471 else if ((ULONG_PTR)Address + Length < (ULONG_PTR)Address ||
472 (ULONG_PTR)Address + Length > (ULONG_PTR)MmUserProbeAddress)
473 {
474 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
475 }
476 }
477
478
479 /*
480 * @implemented
481 */
482 VOID STDCALL
483 ProbeForWrite (IN PVOID Address,
484 IN ULONG Length,
485 IN ULONG Alignment)
486 {
487 PULONG Ptr;
488 ULONG x;
489 ULONG i;
490
491 assert (Alignment ==1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
492
493 if (Length == 0)
494 return;
495
496 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
497 {
498 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
499 }
500 else if ((ULONG_PTR)Address + Length < (ULONG_PTR)Address ||
501 (ULONG_PTR)Address + Length > (ULONG_PTR)MmUserProbeAddress)
502 {
503 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
504 }
505
506 /* Check for accessible pages */
507 for (i = 0; i < Length; i += PAGE_SIZE)
508 {
509 Ptr = (PULONG)(((ULONG_PTR)Address & ~(PAGE_SIZE - 1)) + i);
510 x = *Ptr;
511 *Ptr = x;
512 }
513 }
514
515 /* EOF */