NtGdiGetObject
[reactos.git] / reactos / ntoskrnl / mm / process.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/process.c
5 * PURPOSE: Memory functions related to Processes
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 extern ULONG NtMajorVersion;
17 extern ULONG NtMinorVersion;
18 extern ULONG NtOSCSDVersion;
19 extern ULONG NtGlobalFlag;
20 extern MM_SYSTEMSIZE MmSystemSize;
21
22 #define MM_HIGHEST_VAD_ADDRESS \
23 (PVOID)((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (16 * PAGE_SIZE))
24
25 /* FUNCTIONS *****************************************************************/
26
27 NTSTATUS
28 NTAPI
29 MmSetMemoryPriorityProcess(IN PEPROCESS Process,
30 IN UCHAR MemoryPriority)
31 {
32 UCHAR OldPriority;
33
34 /* Check if we have less then 16MB of Physical Memory */
35 if ((MmSystemSize == MmSmallSystem) &&
36 (MmStats.NrTotalPages < ((15 * 1024 * 1024) / PAGE_SIZE)))
37 {
38 /* Always use background priority */
39 MemoryPriority = 0;
40 }
41
42 /* Save the old priority and update it */
43 OldPriority = Process->Vm.Flags.MemoryPriority;
44 Process->Vm.Flags.MemoryPriority = MemoryPriority;
45
46 /* Return the old priority */
47 return OldPriority;
48 }
49
50 LCID
51 NTAPI
52 MmGetSessionLocaleId(VOID)
53 {
54 PEPROCESS Process;
55 PAGED_CODE();
56
57 /* Get the current process */
58 Process = PsGetCurrentProcess();
59
60 /* Check if it's the Session Leader */
61 if (Process->Vm.Flags.SessionLeader)
62 {
63 /* Make sure it has a valid Session */
64 if (Process->Session)
65 {
66 /* Get the Locale ID */
67 #if ROS_HAS_SESSIONS
68 return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
69 #endif
70 }
71 }
72
73 /* Not a session leader, return the default */
74 return PsDefaultThreadLocaleId;
75 }
76
77 PVOID
78 STDCALL
79 MiCreatePebOrTeb(PEPROCESS Process,
80 PVOID BaseAddress)
81 {
82 NTSTATUS Status;
83 PMADDRESS_SPACE ProcessAddressSpace = (PMADDRESS_SPACE)&Process->VadRoot;
84 PMEMORY_AREA MemoryArea;
85 PHYSICAL_ADDRESS BoundaryAddressMultiple;
86 PVOID AllocatedBase = BaseAddress;
87 BoundaryAddressMultiple.QuadPart = 0;
88
89 /* Acquire the Lock */
90 MmLockAddressSpace(ProcessAddressSpace);
91
92 /*
93 * Create a Peb or Teb.
94 * Loop until it works, decreasing by PAGE_SIZE each time. The logic here
95 * is that a PEB allocation should never fail since the address is free,
96 * while TEB allocation can fail, and we should simply try the address
97 * below. Is there a nicer way of doing this automagically? (ie: findning)
98 * a gap region? -- Alex
99 */
100 do {
101 DPRINT("Trying to allocate: %x\n", AllocatedBase);
102 Status = MmCreateMemoryArea(ProcessAddressSpace,
103 MEMORY_AREA_PEB_OR_TEB,
104 &AllocatedBase,
105 PAGE_SIZE,
106 PAGE_READWRITE,
107 &MemoryArea,
108 TRUE,
109 0,
110 BoundaryAddressMultiple);
111 AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE);
112 } while (Status != STATUS_SUCCESS);
113
114 /* Initialize the Region */
115 MmInitializeRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
116 PAGE_SIZE,
117 MEM_COMMIT,
118 PAGE_READWRITE);
119
120 /* Reserve the pages */
121 MmReserveSwapPages(PAGE_SIZE);
122
123 /* Unlock Address Space */
124 DPRINT("Returning\n");
125 MmUnlockAddressSpace(ProcessAddressSpace);
126 return RVA(AllocatedBase, PAGE_SIZE);
127 }
128
129 VOID
130 MiFreeStackPage(PVOID Context,
131 MEMORY_AREA* MemoryArea,
132 PVOID Address,
133 PFN_TYPE Page,
134 SWAPENTRY SwapEntry,
135 BOOLEAN Dirty)
136 {
137 ASSERT(SwapEntry == 0);
138 if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
139 }
140
141 VOID
142 STDCALL
143 MmDeleteKernelStack(PVOID Stack,
144 BOOLEAN GuiStack)
145 {
146 /* Lock the Address Space */
147 MmLockAddressSpace(MmGetKernelAddressSpace());
148
149 /* Delete the Stack */
150 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
151 Stack,
152 MiFreeStackPage,
153 NULL);
154
155 /* Unlock the Address Space */
156 MmUnlockAddressSpace(MmGetKernelAddressSpace());
157 }
158
159 VOID
160 STDCALL
161 MmDeleteTeb(PEPROCESS Process,
162 PTEB Teb)
163 {
164 PMADDRESS_SPACE ProcessAddressSpace = (PMADDRESS_SPACE)&Process->VadRoot;
165 PMEMORY_AREA MemoryArea;
166
167 /* Lock the Address Space */
168 MmLockAddressSpace(ProcessAddressSpace);
169
170 MemoryArea = MmLocateMemoryAreaByAddress(ProcessAddressSpace, (PVOID)Teb);
171 if (MemoryArea)
172 {
173 /* Delete the Teb */
174 MmFreeVirtualMemory(Process, MemoryArea);
175 }
176
177 /* Unlock the Address Space */
178 MmUnlockAddressSpace(ProcessAddressSpace);
179 }
180
181 PVOID
182 STDCALL
183 MmCreateKernelStack(BOOLEAN GuiStack)
184 {
185 PMEMORY_AREA StackArea;
186 ULONG i;
187 PHYSICAL_ADDRESS BoundaryAddressMultiple;
188 ULONG StackSize = GuiStack ? KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE;
189 PFN_TYPE Page[KERNEL_LARGE_STACK_SIZE / PAGE_SIZE];
190 PVOID KernelStack = NULL;
191 NTSTATUS Status;
192
193 /* Initialize the Boundary Address */
194 BoundaryAddressMultiple.QuadPart = 0;
195
196 /* Lock the Kernel Address Space */
197 MmLockAddressSpace(MmGetKernelAddressSpace());
198
199 /* Create a MAREA for the Kernel Stack */
200 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
201 MEMORY_AREA_KERNEL_STACK,
202 &KernelStack,
203 StackSize,
204 PAGE_READWRITE,
205 &StackArea,
206 FALSE,
207 0,
208 BoundaryAddressMultiple);
209
210 /* Unlock the Address Space */
211 MmUnlockAddressSpace(MmGetKernelAddressSpace());
212
213 /* Check for Success */
214 if (!NT_SUCCESS(Status))
215 {
216 DPRINT1("Failed to create thread stack\n");
217 KEBUGCHECK(0);
218 }
219
220 /*
221 * Mark the Stack in use.
222 * Note: Currently we mark all 60KB in use for a GUI Thread.
223 * We should only do this inside MmGrowKernelStack. TODO!
224 */
225 for (i = 0; i < (StackSize / PAGE_SIZE); i++)
226 {
227 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);
228 }
229
230 /* Create a Virtual Mapping for it */
231 Status = MmCreateVirtualMapping(NULL,
232 KernelStack,
233 PAGE_READWRITE,
234 Page,
235 StackSize / PAGE_SIZE);
236
237 /* Check for success */
238 if (!NT_SUCCESS(Status))
239 {
240 DPRINT1("Could not create Virtual Mapping for Kernel Stack\n");
241 KEBUGCHECK(0);
242 }
243
244 /* Return the stack */
245 return KernelStack;
246 }
247
248 /*
249 * @implemented
250 */
251 NTSTATUS
252 STDCALL
253 MmGrowKernelStack(PVOID StackPointer)
254 {
255 PETHREAD Thread = PsGetCurrentThread();
256
257 /* Make sure we have reserved space for our grow */
258 ASSERT(((PCHAR)Thread->Tcb.StackBase - (PCHAR)Thread->Tcb.StackLimit) <=
259 (KERNEL_LARGE_STACK_SIZE + PAGE_SIZE));
260
261 /*
262 * We'll give you three more pages.
263 * NOTE: See note in MmCreateKernelStack. These pages are already being reserved.
264 * It would be more efficient to only grow them (commit them) here.
265 */
266 Thread->Tcb.StackLimit -= KERNEL_STACK_SIZE;
267
268 /* Return success */
269 return STATUS_SUCCESS;
270 }
271
272 NTSTATUS
273 STDCALL
274 MmCreatePeb(PEPROCESS Process)
275 {
276 PPEB Peb = NULL;
277 LARGE_INTEGER SectionOffset;
278 SIZE_T ViewSize = 0;
279 PVOID TableBase = NULL;
280 PIMAGE_NT_HEADERS NtHeaders;
281 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
282 NTSTATUS Status;
283 KAFFINITY ProcessAffinityMask = 0;
284 SectionOffset.QuadPart = (ULONGLONG)0;
285 DPRINT("MmCreatePeb\n");
286
287 /* Allocate the PEB */
288 Peb = MiCreatePebOrTeb(Process,
289 (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
290 ASSERT(Peb == (PVOID)0x7FFDF000);
291
292 /* Map NLS Tables */
293 DPRINT("Mapping NLS\n");
294 Status = MmMapViewOfSection(ExpNlsSectionPointer,
295 (PEPROCESS)Process,
296 &TableBase,
297 0,
298 0,
299 &SectionOffset,
300 &ViewSize,
301 ViewShare,
302 MEM_TOP_DOWN,
303 PAGE_READONLY);
304 if (!NT_SUCCESS(Status))
305 {
306 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
307 return(Status);
308 }
309 DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize);
310
311 /* Attach to Process */
312 KeAttachProcess(&Process->Pcb);
313
314 /* Initialize the PEB */
315 DPRINT("Allocated: %x\n", Peb);
316 RtlZeroMemory(Peb, sizeof(PEB));
317
318 /* Set up data */
319 DPRINT("Setting up PEB\n");
320 Peb->ImageBaseAddress = Process->SectionBaseAddress;
321 Peb->InheritedAddressSpace = 0;
322 Peb->Mutant = NULL;
323
324 /* NLS */
325 Peb->AnsiCodePageData = (PCHAR)TableBase + ExpAnsiCodePageDataOffset;
326 Peb->OemCodePageData = (PCHAR)TableBase + ExpOemCodePageDataOffset;
327 Peb->UnicodeCaseTableData = (PCHAR)TableBase + ExpUnicodeCaseTableDataOffset;
328
329 /* Default Version Data (could get changed below) */
330 Peb->OSMajorVersion = NtMajorVersion;
331 Peb->OSMinorVersion = NtMinorVersion;
332 Peb->OSBuildNumber = 2195;
333 Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */
334 Peb->OSCSDVersion = NtOSCSDVersion;
335
336 /* Heap and Debug Data */
337 Peb->NumberOfProcessors = KeNumberProcessors;
338 Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE);
339 Peb->NtGlobalFlag = NtGlobalFlag;
340 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
341 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
342 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
343 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;*/
344 Peb->NumberOfHeaps = 0;
345 Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
346 Peb->ProcessHeaps = (PVOID*)Peb + 1;
347
348 /* Image Data */
349 if ((NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress)))
350 {
351 /* Write subsystem data */
352 Peb->ImageSubSystem = NtHeaders->OptionalHeader.Subsystem;
353 Peb->ImageSubSystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
354 Peb->ImageSubSystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
355
356 /* Write Version Data */
357 if (NtHeaders->OptionalHeader.Win32VersionValue)
358 {
359 Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF;
360 Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
361 Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF;
362
363 /* Set the Platform ID */
364 Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2;
365 }
366
367 /* Check if the image is not safe for SMP */
368 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
369 {
370 /* FIXME: Choose one randomly */
371 Peb->ImageProcessAffinityMask = 1;
372 }
373 else
374 {
375 /* Use affinity from Image Header */
376 Peb->ImageProcessAffinityMask = ProcessAffinityMask;
377 }
378
379 _SEH_TRY
380 {
381 /* Get the Image Config Data too */
382 ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
383 TRUE,
384 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
385 &ViewSize);
386
387 ProbeForRead(ImageConfigData,
388 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
389 sizeof(ULONG));
390
391 /* Process the image config data overrides if specfied. */
392 if (ImageConfigData != NULL)
393 {
394 if (ImageConfigData->CSDVersion)
395 {
396 Peb->OSCSDVersion = ImageConfigData->CSDVersion;
397 }
398 if (ImageConfigData->ProcessAffinityMask)
399 {
400 ProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
401 }
402 }
403 }
404 _SEH_HANDLE
405 {
406 Status = _SEH_GetExceptionCode();
407 }
408 _SEH_END;
409 }
410
411 /* Misc data */
412 Peb->SessionId = Process->Session;
413 Process->Peb = Peb;
414
415 /* Detach from the Process */
416 KeDetachProcess();
417
418 DPRINT("MmCreatePeb: Peb created at %p\n", Peb);
419 return Status;
420 }
421
422 PTEB
423 STDCALL
424 MmCreateTeb(PEPROCESS Process,
425 PCLIENT_ID ClientId,
426 PINITIAL_TEB InitialTeb)
427 {
428 PTEB Teb;
429 BOOLEAN Attached = FALSE;
430
431 /* Attach to the process */
432 DPRINT("MmCreateTeb\n");
433 if (Process != PsGetCurrentProcess())
434 {
435 /* Attach to Target */
436 KeAttachProcess(&Process->Pcb);
437 Attached = TRUE;
438 }
439
440 /* Allocate the TEB */
441 Teb = MiCreatePebOrTeb(Process,
442 (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
443
444 /* Initialize the PEB */
445 RtlZeroMemory(Teb, sizeof(TEB));
446
447 /* Set TIB Data */
448 Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF;
449 Teb->Tib.Version = 1;
450 Teb->Tib.Self = (PNT_TIB)Teb;
451
452 /* Set TEB Data */
453 Teb->Cid = *ClientId;
454 Teb->RealClientId = *ClientId;
455 Teb->ProcessEnvironmentBlock = Process->Peb;
456 Teb->CurrentLocale = PsDefaultThreadLocaleId;
457
458 /* Store stack information from InitialTeb */
459 if(InitialTeb != NULL)
460 {
461 Teb->Tib.StackBase = InitialTeb->StackBase;
462 Teb->Tib.StackLimit = InitialTeb->StackLimit;
463 Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
464 }
465
466 /* Return TEB Address */
467 DPRINT("Allocated: %x\n", Teb);
468 if (Attached) KeDetachProcess();
469 return Teb;
470 }
471
472 NTSTATUS
473 STDCALL
474 MmCreateProcessAddressSpace(IN PEPROCESS Process,
475 IN PROS_SECTION_OBJECT Section OPTIONAL,
476 IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL)
477 {
478 NTSTATUS Status;
479 PMADDRESS_SPACE ProcessAddressSpace = (PMADDRESS_SPACE)&Process->VadRoot;
480 PVOID BaseAddress;
481 PMEMORY_AREA MemoryArea;
482 PHYSICAL_ADDRESS BoundaryAddressMultiple;
483 SIZE_T ViewSize = 0;
484 PVOID ImageBase = 0;
485 BoundaryAddressMultiple.QuadPart = 0;
486
487 /* Initialize the Addresss Space */
488 MmInitializeAddressSpace(Process, ProcessAddressSpace);
489
490 /* Acquire the Lock */
491 MmLockAddressSpace(ProcessAddressSpace);
492
493 /* Protect the highest 64KB of the process address space */
494 BaseAddress = (PVOID)MmUserProbeAddress;
495 Status = MmCreateMemoryArea(ProcessAddressSpace,
496 MEMORY_AREA_NO_ACCESS,
497 &BaseAddress,
498 0x10000,
499 PAGE_NOACCESS,
500 &MemoryArea,
501 FALSE,
502 0,
503 BoundaryAddressMultiple);
504 if (!NT_SUCCESS(Status))
505 {
506 DPRINT1("Failed to protect last 64KB\n");
507 goto exit;
508 }
509
510 /* Protect the 60KB above the shared user page */
511 BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE;
512 Status = MmCreateMemoryArea(ProcessAddressSpace,
513 MEMORY_AREA_NO_ACCESS,
514 &BaseAddress,
515 0x10000 - PAGE_SIZE,
516 PAGE_NOACCESS,
517 &MemoryArea,
518 FALSE,
519 0,
520 BoundaryAddressMultiple);
521 if (!NT_SUCCESS(Status))
522 {
523 DPRINT1("Failed to protect the memory above the shared user page\n");
524 goto exit;
525 }
526
527 /* Create the shared data page */
528 BaseAddress = (PVOID)USER_SHARED_DATA;
529 Status = MmCreateMemoryArea(ProcessAddressSpace,
530 MEMORY_AREA_SHARED_DATA,
531 &BaseAddress,
532 PAGE_SIZE,
533 PAGE_EXECUTE_READ,
534 &MemoryArea,
535 FALSE,
536 0,
537 BoundaryAddressMultiple);
538 if (!NT_SUCCESS(Status))
539 {
540 DPRINT1("Failed to create Shared User Data\n");
541 goto exit;
542 }
543
544 /* The process now has an address space */
545 Process->HasAddressSpace = TRUE;
546
547 /* Check if there's a Section Object */
548 if (Section)
549 {
550 UNICODE_STRING FileName;
551 PWCHAR szSrc;
552 PCHAR szDest;
553 USHORT lnFName = 0;
554
555 /* Unlock the Address Space */
556 DPRINT("Unlocking\n");
557 MmUnlockAddressSpace(ProcessAddressSpace);
558
559 DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",
560 Section, Process, &ImageBase);
561 Status = MmMapViewOfSection(Section,
562 (PEPROCESS)Process,
563 (PVOID*)&ImageBase,
564 0,
565 0,
566 NULL,
567 &ViewSize,
568 0,
569 MEM_COMMIT,
570 PAGE_READWRITE);
571 if (!NT_SUCCESS(Status))
572 {
573 DPRINT1("Failed to map process Image\n");
574 return Status;
575 }
576
577 /* Save the pointer */
578 Process->SectionBaseAddress = ImageBase;
579
580 /* Determine the image file name and save it to EPROCESS */
581 DPRINT("Getting Image name\n");
582 FileName = Section->FileObject->FileName;
583 szSrc = (PWCHAR)(FileName.Buffer + FileName.Length);
584 while (szSrc >= FileName.Buffer)
585 {
586 /* Make sure this isn't a backslash */
587 if (*--szSrc == OBJ_NAME_PATH_SEPARATOR)
588 {
589 /* If so, stop it here */
590 szSrc++;
591 break;
592 }
593 else
594 {
595 /* Otherwise, keep going */
596 lnFName++;
597 }
598 }
599
600 /* Copy the to the process and truncate it to 15 characters if necessary */
601 szDest = Process->ImageFileName;
602 lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1);
603 while (lnFName--) *szDest++ = (UCHAR)*szSrc++;
604 *szDest = UNICODE_NULL;
605
606 /* Check if caller wants an audit name */
607 if (AuditName)
608 {
609 /* Setup the audit name */
610 SeInitializeProcessAuditName(Section->FileObject,
611 FALSE,
612 AuditName);
613 }
614
615 /* Return status to caller */
616 return Status;
617 }
618
619 exit:
620 /* Unlock the Address Space */
621 DPRINT("Unlocking\n");
622 MmUnlockAddressSpace(ProcessAddressSpace);
623
624 /* Return status to caller */
625 return Status;
626 }
627
628 VOID
629 NTAPI
630 MmCleanProcessAddressSpace(IN PEPROCESS Process)
631 {
632 /* FIXME: Add part of MmDeleteProcessAddressSpace here */
633 }
634
635 NTSTATUS
636 NTAPI
637 MmDeleteProcessAddressSpace(PEPROCESS Process)
638 {
639 PVOID Address;
640 PMEMORY_AREA MemoryArea;
641
642 DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process,
643 Process->ImageFileName);
644
645 MmLockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
646
647 while ((MemoryArea = ((PMADDRESS_SPACE)&Process->VadRoot)->MemoryAreaRoot) != NULL)
648 {
649 switch (MemoryArea->Type)
650 {
651 case MEMORY_AREA_SECTION_VIEW:
652 Address = (PVOID)MemoryArea->StartingAddress;
653 MmUnlockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
654 MmUnmapViewOfSection(Process, Address);
655 MmLockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
656 break;
657
658 case MEMORY_AREA_VIRTUAL_MEMORY:
659 case MEMORY_AREA_PEB_OR_TEB:
660 MmFreeVirtualMemory(Process, MemoryArea);
661 break;
662
663 case MEMORY_AREA_SHARED_DATA:
664 case MEMORY_AREA_NO_ACCESS:
665 MmFreeMemoryArea((PMADDRESS_SPACE)&Process->VadRoot,
666 MemoryArea,
667 NULL,
668 NULL);
669 break;
670
671 case MEMORY_AREA_MDL_MAPPING:
672 KEBUGCHECK(PROCESS_HAS_LOCKED_PAGES);
673 break;
674
675 default:
676 KEBUGCHECK(0);
677 }
678 }
679
680 Mmi386ReleaseMmInfo(Process);
681
682 MmUnlockAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
683 MmDestroyAddressSpace((PMADDRESS_SPACE)&Process->VadRoot);
684
685 DPRINT("Finished MmReleaseMmInfo()\n");
686 return(STATUS_SUCCESS);
687 }