0df248c6592bd49c035900effc982b620fea1587
[reactos.git] / reactos / ntoskrnl / mm / virtual.c
1 /*
2 * COPYRIGHT: See COPYING in the top directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/virtual.c
5 * PURPOSE: implementing the Virtualxxx section of the win32 api
6 * PROGRAMMER: David Welch
7 * UPDATE HISTORY:
8 * 09/4/98: Created
9 * 10/6/98: Corrections from Fatahi (i_fatahi@hotmail.com)
10 * 30/9/98: Implemented ZwxxxVirtualMemory functions
11 */
12
13 /* INCLUDE *****************************************************************/
14
15 #include <internal/mm.h>
16 #include <internal/mmhal.h>
17 #include <internal/ob.h>
18 #include <internal/io.h>
19 #include <internal/ps.h>
20 #include <string.h>
21 #include <internal/string.h>
22
23 #define NDEBUG
24 #include <internal/debug.h>
25
26 /* FUNCTIONS ****************************************************************/
27
28 NTSTATUS MmReleaseMemoryArea(PEPROCESS Process, PMEMORY_AREA Marea)
29 {
30 PVOID i;
31
32 DPRINT("MmReleaseMemoryArea(Process %x, Marea %x)\n",Process,Marea);
33
34 DPRINT("Releasing %x between %x %x\n",
35 Marea, Marea->BaseAddress, Marea->BaseAddress + Marea->Length);
36 for (i = Marea->BaseAddress;
37 i < (Marea->BaseAddress + Marea->Length);
38 i = i+PAGESIZE)
39 {
40 MmDeletePageEntry(Process, i, TRUE);
41 }
42 ExFreePool(Marea);
43
44 return(STATUS_SUCCESS);
45 }
46
47 NTSTATUS MmReleaseMmInfo(PEPROCESS Process)
48 {
49 PLIST_ENTRY CurrentEntry;
50 PMEMORY_AREA Current;
51
52 DbgPrint("MmReleaseMmInfo(Process %x)\n",Process);
53
54 while (!IsListEmpty(&Process->Pcb.MemoryAreaList))
55 {
56 CurrentEntry = RemoveHeadList(&Process->Pcb.MemoryAreaList);
57 Current = CONTAINING_RECORD(CurrentEntry, MEMORY_AREA, Entry);
58
59 MmReleaseMemoryArea(Process, Current);
60 }
61
62 Mmi386ReleaseMmInfo(Process);
63
64 DPRINT("Finished MmReleaseMmInfo()\n");
65 return(STATUS_SUCCESS);
66 }
67
68 BOOLEAN MmIsNonPagedSystemAddressValid(PVOID VirtualAddress)
69 {
70 UNIMPLEMENTED;
71 }
72
73 BOOLEAN MmIsAddressValid(PVOID VirtualAddress)
74 /*
75 * FUNCTION: Checks whether the given address is valid for a read or write
76 * ARGUMENTS:
77 * VirtualAddress = address to check
78 * RETURNS: True if the access would be valid
79 * False if the access would cause a page fault
80 * NOTES: This function checks whether a byte access to the page would
81 * succeed. Is this realistic for RISC processors which don't
82 * allow byte granular access?
83 */
84 {
85 MEMORY_AREA* MemoryArea;
86
87 MemoryArea = MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),
88 VirtualAddress);
89
90 if (MemoryArea == NULL)
91 {
92 return(FALSE);
93 }
94 return(TRUE);
95 }
96
97
98 NTSTATUS
99 STDCALL
100 NtAllocateVirtualMemory (
101 IN HANDLE ProcessHandle,
102 IN OUT PVOID * BaseAddress,
103 IN ULONG ZeroBits,
104 IN OUT PULONG RegionSize,
105 IN ULONG AllocationType,
106 IN ULONG Protect
107 )
108 /*
109 * FUNCTION: Allocates a block of virtual memory in the process address space
110 * ARGUMENTS:
111 * ProcessHandle = The handle of the process which owns the virtual memory
112 * BaseAddress = A pointer to the virtual memory allocated. If you
113 * supply a non zero value the system will try to
114 * allocate the memory at the address supplied. It round
115 * it down to a multiple of the page size.
116 * ZeroBits = (OPTIONAL) You can specify the number of high order bits
117 * that must be zero, ensuring that the memory will be
118 * allocated at a address below a certain value.
119 * RegionSize = The number of bytes to allocate
120 * AllocationType = Indicates the type of virtual memory you like to
121 * allocated, can be one of the values : MEM_COMMIT,
122 * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN
123 * Protect = Indicates the protection type of the pages allocated, can be
124 * a combination of PAGE_READONLY, PAGE_READWRITE,
125 * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
126 * PAGE_NOACCESS
127 * REMARKS:
128 * This function maps to the win32 VirtualAllocEx. Virtual memory is
129 * process based so the protocol starts with a ProcessHandle. I
130 * splitted the functionality of obtaining the actual address and
131 * specifying the start address in two parameters ( BaseAddress and
132 * StartAddress ) The NumberOfBytesAllocated specify the range and the
133 * AllocationType and ProctectionType map to the other two parameters.
134 * RETURNS: Status
135 */
136 {
137 PEPROCESS Process;
138 MEMORY_AREA* MemoryArea;
139 ULONG Type;
140 NTSTATUS Status;
141
142 DPRINT("NtAllocateVirtualMemory(ProcessHandle %x, *BaseAddress %x, "
143 "ZeroBits %d, *RegionSize %x, AllocationType %x, Protect %x)\n",
144 ProcessHandle,*BaseAddress,ZeroBits,*RegionSize,AllocationType,
145 Protect);
146
147 Status = ObReferenceObjectByHandle(ProcessHandle,
148 PROCESS_VM_OPERATION,
149 NULL,
150 UserMode,
151 (PVOID*)(&Process),
152 NULL);
153 if (Status != STATUS_SUCCESS)
154 {
155 DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
156 return(Status);
157 }
158
159 if (AllocationType & MEM_RESERVE)
160 {
161 Type = MEMORY_AREA_RESERVE;
162 }
163 else
164 {
165 Type = MEMORY_AREA_COMMIT;
166 }
167
168 if ((*BaseAddress) != 0)
169 {
170 MemoryArea = MmOpenMemoryAreaByAddress(Process, *BaseAddress);
171
172 if (MemoryArea != NULL)
173 {
174 if (MemoryArea->BaseAddress == (*BaseAddress) &&
175 MemoryArea->Length == *RegionSize)
176 {
177 MemoryArea->Type = Type;
178 MemoryArea->Attributes =Protect;
179 DPRINT("*BaseAddress %x\n",*BaseAddress);
180 ObDereferenceObject(Process);
181 return(STATUS_SUCCESS);
182 }
183
184 MemoryArea = MmSplitMemoryArea(Process,
185 MemoryArea,
186 *BaseAddress,
187 *RegionSize,
188 Type,
189 Protect);
190 DPRINT("*BaseAddress %x\n",*BaseAddress);
191 ObDereferenceObject(Process);
192 return(STATUS_SUCCESS);
193 }
194 }
195
196 //FIXME RegionSize should be passed as pointer
197
198
199 Status = MmCreateMemoryArea(UserMode,
200 Process,
201 Type,
202 BaseAddress,
203 *RegionSize,
204 Protect,
205 &MemoryArea);
206
207 if (Status != STATUS_SUCCESS)
208 {
209 DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
210 ObDereferenceObject(Process);
211 return(Status);
212 }
213
214 DPRINT("*BaseAddress %x\n",*BaseAddress);
215 ObDereferenceObject(Process);
216 return(STATUS_SUCCESS);
217 }
218
219
220 NTSTATUS
221 STDCALL
222 NtFlushVirtualMemory (
223 IN HANDLE ProcessHandle,
224 IN PVOID BaseAddress,
225 IN ULONG NumberOfBytesToFlush,
226 OUT PULONG NumberOfBytesFlushed OPTIONAL
227 )
228 /*
229 * FUNCTION: Flushes virtual memory to file
230 * ARGUMENTS:
231 * ProcessHandle = Points to the process that allocated the virtual
232 * memory
233 * BaseAddress = Points to the memory address
234 * NumberOfBytesToFlush = Limits the range to flush,
235 * NumberOfBytesFlushed = Actual number of bytes flushed
236 * RETURNS: Status
237 */
238 {
239 UNIMPLEMENTED;
240 }
241
242
243 NTSTATUS
244 STDCALL
245 NtFreeVirtualMemory (
246 IN HANDLE ProcessHandle,
247 IN PVOID * BaseAddress,
248 IN PULONG RegionSize,
249 IN ULONG FreeType
250 )
251 /*
252 * FUNCTION: Frees a range of virtual memory
253 * ARGUMENTS:
254 * ProcessHandle = Points to the process that allocated the virtual
255 * memory
256 * BaseAddress = Points to the memory address, rounded down to a
257 * multiple of the pagesize
258 * RegionSize = Limits the range to free, rounded up to a multiple of
259 * the paging size
260 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
261 * RETURNS: Status
262 */
263 {
264 MEMORY_AREA* MemoryArea;
265 NTSTATUS Status;
266 PEPROCESS Process;
267
268 DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *BaseAddress %x, "
269 "*RegionSize %x, FreeType %x)\n",ProcessHandle,*BaseAddress,
270 *RegionSize,FreeType);
271
272
273 Status = ObReferenceObjectByHandle(ProcessHandle,
274 PROCESS_VM_OPERATION,
275 PsProcessType,
276 UserMode,
277 (PVOID*)(&Process),
278 NULL);
279 if (Status != STATUS_SUCCESS)
280 {
281 return(Status);
282 }
283
284 MemoryArea = MmOpenMemoryAreaByAddress(Process,*BaseAddress);
285 if (MemoryArea == NULL)
286 {
287 ObDereferenceObject(Process);
288 return(STATUS_UNSUCCESSFUL);
289 }
290
291 switch (FreeType)
292 {
293 case MEM_RELEASE:
294 if (MemoryArea->BaseAddress != (*BaseAddress))
295 {
296 ObDereferenceObject(Process);
297 return(STATUS_UNSUCCESSFUL);
298 }
299 MmFreeMemoryArea(PsGetCurrentProcess(),
300 BaseAddress,
301 0,
302 TRUE);
303 ObDereferenceObject(Process);
304 return(STATUS_SUCCESS);
305
306 case MEM_DECOMMIT:
307 MmSplitMemoryArea(PsGetCurrentProcess(),
308 MemoryArea,
309 *BaseAddress,
310 *RegionSize,
311 MEMORY_AREA_RESERVE,
312 MemoryArea->Attributes);
313 ObDereferenceObject(Process);
314 return(STATUS_SUCCESS);
315 }
316 ObDereferenceObject(Process);
317 return(STATUS_NOT_IMPLEMENTED);
318 }
319
320
321 NTSTATUS
322 STDCALL
323 NtLockVirtualMemory (
324 HANDLE ProcessHandle,
325 PVOID BaseAddress,
326 ULONG NumberOfBytesToLock,
327 PULONG NumberOfBytesLocked
328 )
329 {
330 UNIMPLEMENTED;
331 }
332
333
334 VOID MmChangeAreaProtection(PEPROCESS Process,
335 PVOID BaseAddress,
336 ULONG Length,
337 ULONG Protect)
338 {
339 ULONG i;
340
341 for (i=0; i<(Length/PAGESIZE); i++)
342 {
343 if (MmIsPagePresent(Process, BaseAddress + (i*PAGESIZE)))
344 {
345 MmSetPageProtect(Process, BaseAddress + (i*PAGESIZE), Protect);
346 }
347 }
348 }
349
350
351 NTSTATUS
352 STDCALL
353 NtProtectVirtualMemory (
354 IN HANDLE ProcessHandle,
355 IN PVOID BaseAddress,
356 IN ULONG NumberOfBytesToProtect,
357 IN ULONG NewAccessProtection,
358 OUT PULONG OldAccessProtection
359 )
360 {
361 PMEMORY_AREA MemoryArea;
362 PEPROCESS Process;
363 NTSTATUS Status;
364
365 Status = ObReferenceObjectByHandle(ProcessHandle,
366 PROCESS_VM_OPERATION,
367 PsProcessType,
368 UserMode,
369 (PVOID*)(&Process),
370 NULL);
371 if (Status != STATUS_SUCCESS)
372 {
373 DPRINT("NtProtectVirtualMemory() = %x\n",Status);
374 return(Status);
375 }
376
377 MemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
378 if (MemoryArea == NULL)
379 {
380 DPRINT("NtProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL);
381 ObDereferenceObject(Process);
382 return(STATUS_UNSUCCESSFUL);
383 }
384
385 *OldAccessProtection = MemoryArea->Attributes;
386
387 if (MemoryArea->BaseAddress == BaseAddress &&
388 MemoryArea->Length == NumberOfBytesToProtect)
389 {
390 MemoryArea->Attributes = NewAccessProtection;
391 }
392 else
393 {
394 MemoryArea = MmSplitMemoryArea(Process,
395 MemoryArea,
396 BaseAddress,
397 NumberOfBytesToProtect,
398 MemoryArea->Type,
399 NewAccessProtection);
400 }
401 MmChangeAreaProtection(Process,BaseAddress,NumberOfBytesToProtect,
402 NewAccessProtection);
403 ObDereferenceObject(Process);
404 return(STATUS_SUCCESS);
405 }
406
407
408 NTSTATUS
409 STDCALL
410 NtQueryVirtualMemory (
411 IN HANDLE ProcessHandle,
412 IN PVOID Address,
413 IN CINT VirtualMemoryInformationClass,
414 OUT PVOID VirtualMemoryInformation,
415 IN ULONG Length,
416 OUT PULONG ResultLength
417 )
418 {
419 UNIMPLEMENTED;
420 }
421
422
423 NTSTATUS
424 STDCALL
425 NtReadVirtualMemory (
426 IN HANDLE ProcessHandle,
427 IN PVOID BaseAddress,
428 OUT PVOID Buffer,
429 IN ULONG NumberOfBytesToRead,
430 OUT PULONG NumberOfBytesRead
431 )
432 {
433 NTSTATUS Status;
434 PMDL Mdl;
435 PVOID SystemAddress;
436 PEPROCESS Process;
437
438 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
439 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
440 Buffer,NumberOfBytesToRead);
441
442 Status = ObReferenceObjectByHandle(ProcessHandle,
443 PROCESS_VM_WRITE,
444 NULL,
445 UserMode,
446 (PVOID*)(&Process),
447 NULL);
448 if (Status != STATUS_SUCCESS)
449 {
450 return(Status);
451 }
452
453 Mdl = MmCreateMdl(NULL,
454 Buffer,
455 NumberOfBytesToRead);
456 MmProbeAndLockPages(Mdl,
457 UserMode,
458 IoWriteAccess);
459
460 KeAttachProcess(Process);
461
462 SystemAddress = MmGetSystemAddressForMdl(Mdl);
463 memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead);
464
465 KeDetachProcess();
466
467 ObDereferenceObject(Process);
468
469 *NumberOfBytesRead = NumberOfBytesToRead;
470 return(STATUS_SUCCESS);
471 }
472
473
474 NTSTATUS
475 STDCALL
476 NtUnlockVirtualMemory (
477 HANDLE ProcessHandle,
478 PVOID BaseAddress,
479 ULONG NumberOfBytesToUnlock,
480 PULONG NumberOfBytesUnlocked OPTIONAL
481 )
482 {
483 UNIMPLEMENTED;
484 }
485
486
487 NTSTATUS
488 STDCALL
489 NtWriteVirtualMemory (
490 IN HANDLE ProcessHandle,
491 IN PVOID BaseAddress,
492 IN PVOID Buffer,
493 IN ULONG NumberOfBytesToWrite,
494 OUT PULONG NumberOfBytesWritten
495 )
496 {
497 NTSTATUS Status;
498 PMDL Mdl;
499 PVOID SystemAddress;
500 PEPROCESS Process;
501
502 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
503 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
504 Buffer,NumberOfBytesToWrite);
505
506 Status = ObReferenceObjectByHandle(ProcessHandle,
507 PROCESS_VM_WRITE,
508 NULL,
509 UserMode,
510 (PVOID*)(&Process),
511 NULL);
512 if (Status != STATUS_SUCCESS)
513 {
514 return(Status);
515 }
516
517 Mdl = MmCreateMdl(NULL,
518 Buffer,
519 NumberOfBytesToWrite);
520 MmProbeAndLockPages(Mdl,
521 UserMode,
522 IoReadAccess);
523
524 KeAttachProcess(Process);
525
526 SystemAddress = MmGetSystemAddressForMdl(Mdl);
527 memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
528
529 KeDetachProcess();
530
531 ObDereferenceObject(Process);
532
533 *NumberOfBytesWritten = NumberOfBytesToWrite;
534 return(STATUS_SUCCESS);
535 }
536