- Update to r53061
[reactos.git] / ntoskrnl / mm / ARM3 / procsup.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/procsup.c
5 * PURPOSE: ARM Memory Manager Process Related Management
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #define MODULE_INVOLVED_IN_ARM3
16 #include "../ARM3/miarm.h"
17
18 /* GLOBALS ********************************************************************/
19
20 ULONG MmProcessColorSeed = 0x12345678;
21 PMMWSL MmWorkingSetList;
22
23 /* PRIVATE FUNCTIONS **********************************************************/
24
25 VOID
26 NTAPI
27 MiRosTakeOverPebTebRanges(IN PEPROCESS Process)
28 {
29 NTSTATUS Status;
30 PMEMORY_AREA MemoryArea;
31 PHYSICAL_ADDRESS BoundaryAddressMultiple;
32 PVOID AllocatedBase = (PVOID)USER_SHARED_DATA;
33 BoundaryAddressMultiple.QuadPart = 0;
34
35 Status = MmCreateMemoryArea(&Process->Vm,
36 MEMORY_AREA_OWNED_BY_ARM3,
37 &AllocatedBase,
38 ((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - 1) -
39 (ULONG_PTR)USER_SHARED_DATA,
40 PAGE_READWRITE,
41 &MemoryArea,
42 TRUE,
43 0,
44 BoundaryAddressMultiple);
45 ASSERT(NT_SUCCESS(Status));
46 }
47
48 NTSTATUS
49 NTAPI
50 MiCreatePebOrTeb(IN PEPROCESS Process,
51 IN ULONG Size,
52 OUT PULONG_PTR Base)
53 {
54 PETHREAD Thread = PsGetCurrentThread();
55 PMMVAD_LONG Vad;
56 NTSTATUS Status;
57 ULONG RandomCoeff;
58 ULONG_PTR StartAddress, EndAddress;
59 LARGE_INTEGER CurrentTime;
60 TABLE_SEARCH_RESULT Result = TableFoundNode;
61 PMMADDRESS_NODE Parent;
62
63 /* Allocate a VAD */
64 Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
65 if (!Vad) return STATUS_NO_MEMORY;
66
67 /* Setup the primary flags with the size, and make it commited, private, RW */
68 Vad->u.LongFlags = 0;
69 Vad->u.VadFlags.CommitCharge = BYTES_TO_PAGES(Size);
70 Vad->u.VadFlags.MemCommit = TRUE;
71 Vad->u.VadFlags.PrivateMemory = TRUE;
72 Vad->u.VadFlags.Protection = MM_READWRITE;
73 Vad->u.VadFlags.NoChange = TRUE;
74
75 /* Setup the secondary flags to make it a secured, writable, long VAD */
76 Vad->u2.LongFlags2 = 0;
77 Vad->u2.VadFlags2.OneSecured = TRUE;
78 Vad->u2.VadFlags2.LongVad = TRUE;
79 Vad->u2.VadFlags2.ReadOnly = FALSE;
80
81 /* Lock the process address space */
82 KeAcquireGuardedMutex(&Process->AddressCreationLock);
83
84 /* Check if this is a PEB creation */
85 if (Size == sizeof(PEB))
86 {
87 /* Start at the highest valid address */
88 StartAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1;
89
90 /* Select the random coefficient */
91 KeQueryTickCount(&CurrentTime);
92 CurrentTime.LowPart &= ((64 * _1KB) >> PAGE_SHIFT) - 1;
93 if (CurrentTime.LowPart <= 1) CurrentTime.LowPart = 2;
94 RandomCoeff = CurrentTime.LowPart << PAGE_SHIFT;
95
96 /* Select the highest valid address minus the random coefficient */
97 StartAddress -= RandomCoeff;
98 EndAddress = StartAddress + ROUND_TO_PAGES(Size) - 1;
99
100 /* Try to find something below the random upper margin */
101 Result = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
102 EndAddress,
103 PAGE_SIZE,
104 &Process->VadRoot,
105 Base,
106 &Parent);
107 }
108
109 /* Check for success. TableFoundNode means nothing free. */
110 if (Result == TableFoundNode)
111 {
112 /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
113 Result = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
114 (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1,
115 PAGE_SIZE,
116 &Process->VadRoot,
117 Base,
118 &Parent);
119 /* Bail out, if still nothing free was found */
120 if (Result == TableFoundNode) return STATUS_NO_MEMORY;
121 }
122
123 /* Validate that it came from the VAD ranges */
124 ASSERT(*Base >= (ULONG_PTR)MI_LOWEST_VAD_ADDRESS);
125
126 /* Build the rest of the VAD now */
127 Vad->StartingVpn = (*Base) >> PAGE_SHIFT;
128 Vad->EndingVpn = ((*Base) + Size - 1) >> PAGE_SHIFT;
129 Vad->u3.Secured.StartVpn = *Base;
130 Vad->u3.Secured.EndVpn = (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1);
131 Vad->u1.Parent = NULL;
132
133 /* FIXME: Should setup VAD bitmap */
134 Status = STATUS_SUCCESS;
135
136 /* Pretend as if we own the working set */
137 MiLockProcessWorkingSet(Process, Thread);
138
139 /* Insert the VAD */
140 ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
141 Process->VadRoot.NodeHint = Vad;
142 Vad->ControlArea = NULL; // For Memory-Area hack
143 Vad->FirstPrototypePte = NULL;
144 DPRINT("VAD: %p\n", Vad);
145 DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base, Process->ImageFileName);
146 MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
147
148 /* Release the working set */
149 MiUnlockProcessWorkingSet(Process, Thread);
150
151 /* Release the address space lock */
152 KeReleaseGuardedMutex(&Process->AddressCreationLock);
153
154 /* Return the status */
155 return Status;
156 }
157
158 VOID
159 NTAPI
160 MmDeleteTeb(IN PEPROCESS Process,
161 IN PTEB Teb)
162 {
163 ULONG_PTR TebEnd;
164 PETHREAD Thread = PsGetCurrentThread();
165 PMMVAD Vad;
166 PMM_AVL_TABLE VadTree = &Process->VadRoot;
167 DPRINT("Deleting TEB: %p in %16s\n", Teb, Process->ImageFileName);
168
169 /* TEB is one page */
170 TebEnd = (ULONG_PTR)Teb + ROUND_TO_PAGES(sizeof(TEB)) - 1;
171
172 /* Attach to the process */
173 KeAttachProcess(&Process->Pcb);
174
175 /* Lock the process address space */
176 KeAcquireGuardedMutex(&Process->AddressCreationLock);
177
178 /* Find the VAD, make sure it's a TEB VAD */
179 Vad = MiLocateAddress(Teb);
180 DPRINT("Removing node for VAD: %lx %lx\n", Vad->StartingVpn, Vad->EndingVpn);
181 ASSERT(Vad != NULL);
182 if (Vad->StartingVpn != ((ULONG_PTR)Teb >> PAGE_SHIFT))
183 {
184 /* Bug in the AVL code? */
185 DPRINT1("Corrupted VAD!\n");
186 }
187 else
188 {
189 /* Sanity checks for a valid TEB VAD */
190 ASSERT((Vad->StartingVpn == ((ULONG_PTR)Teb >> PAGE_SHIFT) &&
191 (Vad->EndingVpn == (TebEnd >> PAGE_SHIFT))));
192 ASSERT(Vad->u.VadFlags.NoChange == TRUE);
193 ASSERT(Vad->u2.VadFlags2.OneSecured == TRUE);
194 ASSERT(Vad->u2.VadFlags2.MultipleSecured == FALSE);
195
196 /* Lock the working set */
197 MiLockProcessWorkingSet(Process, Thread);
198
199 /* Remove this VAD from the tree */
200 ASSERT(VadTree->NumberGenericTableElements >= 1);
201 MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
202
203 /* Release the working set */
204 MiUnlockProcessWorkingSet(Process, Thread);
205
206 /* Remove the VAD */
207 ExFreePool(Vad);
208 }
209
210 /* Release the address space lock */
211 KeReleaseGuardedMutex(&Process->AddressCreationLock);
212
213 /* Detach */
214 KeDetachProcess();
215 }
216
217 VOID
218 NTAPI
219 MmDeleteKernelStack(IN PVOID StackBase,
220 IN BOOLEAN GuiStack)
221 {
222 PMMPTE PointerPte;
223 PFN_NUMBER StackPages, PageFrameNumber;//, PageTableFrameNumber;
224 PMMPFN Pfn1;//, Pfn2;
225 ULONG i;
226 KIRQL OldIrql;
227
228 //
229 // This should be the guard page, so decrement by one
230 //
231 PointerPte = MiAddressToPte(StackBase);
232 PointerPte--;
233
234 //
235 // Calculate pages used
236 //
237 StackPages = BYTES_TO_PAGES(GuiStack ?
238 KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
239
240 /* Acquire the PFN lock */
241 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
242
243 //
244 // Loop them
245 //
246 for (i = 0; i < StackPages; i++)
247 {
248 //
249 // Check if this is a valid PTE
250 //
251 if (PointerPte->u.Hard.Valid == 1)
252 {
253 /* Get the PTE's page */
254 PageFrameNumber = PFN_FROM_PTE(PointerPte);
255 Pfn1 = MiGetPfnEntry(PageFrameNumber);
256 #if 0 // ARM3 might not own the page table, so don't take this risk. Leak it instead!
257 /* Now get the page of the page table mapping it */
258 PageTableFrameNumber = Pfn1->u4.PteFrame;
259 Pfn2 = MiGetPfnEntry(PageTableFrameNumber);
260
261 /* Remove a shared reference, since the page is going away */
262 MiDecrementShareCount(Pfn2, PageTableFrameNumber);
263 #endif
264 /* Set the special pending delete marker */
265 MI_SET_PFN_DELETED(Pfn1);
266
267 /* And now delete the actual stack page */
268 MiDecrementShareCount(Pfn1, PageFrameNumber);
269 }
270
271 //
272 // Next one
273 //
274 PointerPte--;
275 }
276
277 //
278 // We should be at the guard page now
279 //
280 ASSERT(PointerPte->u.Hard.Valid == 0);
281
282 /* Release the PFN lock */
283 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
284
285 //
286 // Release the PTEs
287 //
288 MiReleaseSystemPtes(PointerPte, StackPages + 1, SystemPteSpace);
289 }
290
291 PVOID
292 NTAPI
293 MmCreateKernelStack(IN BOOLEAN GuiStack,
294 IN UCHAR Node)
295 {
296 PFN_NUMBER StackPtes, StackPages;
297 PMMPTE PointerPte, StackPte;
298 PVOID BaseAddress;
299 MMPTE TempPte, InvalidPte;
300 KIRQL OldIrql;
301 PFN_NUMBER PageFrameIndex;
302 ULONG i;
303
304 //
305 // Calculate pages needed
306 //
307 if (GuiStack)
308 {
309 //
310 // We'll allocate 64KB stack, but only commit 12K
311 //
312 StackPtes = BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE);
313 StackPages = BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT);
314
315 }
316 else
317 {
318 //
319 // We'll allocate 12K and that's it
320 //
321 StackPtes = BYTES_TO_PAGES(KERNEL_STACK_SIZE);
322 StackPages = StackPtes;
323 }
324
325 //
326 // Reserve stack pages, plus a guard page
327 //
328 StackPte = MiReserveSystemPtes(StackPtes + 1, SystemPteSpace);
329 if (!StackPte) return NULL;
330
331 //
332 // Get the stack address
333 //
334 BaseAddress = MiPteToAddress(StackPte + StackPtes + 1);
335
336 //
337 // Select the right PTE address where we actually start committing pages
338 //
339 PointerPte = StackPte;
340 if (GuiStack) PointerPte += BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE -
341 KERNEL_LARGE_STACK_COMMIT);
342
343
344 /* Setup the temporary invalid PTE */
345 MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
346
347 /* Setup the template stack PTE */
348 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, PointerPte + 1, MM_READWRITE, 0);
349
350 //
351 // Acquire the PFN DB lock
352 //
353 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
354
355 //
356 // Loop each stack page
357 //
358 for (i = 0; i < StackPages; i++)
359 {
360 //
361 // Next PTE
362 //
363 PointerPte++;
364
365 /* Get a page and write the current invalid PTE */
366 MI_SET_USAGE(MI_USAGE_KERNEL_STACK);
367 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
368 PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
369 MI_WRITE_INVALID_PTE(PointerPte, InvalidPte);
370
371 /* Initialize the PFN entry for this page */
372 MiInitializePfn(PageFrameIndex, PointerPte, 1);
373
374 /* Write the valid PTE */
375 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
376 MI_WRITE_VALID_PTE(PointerPte, TempPte);
377 }
378
379 //
380 // Release the PFN lock
381 //
382 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
383
384 //
385 // Return the stack address
386 //
387 return BaseAddress;
388 }
389
390 NTSTATUS
391 NTAPI
392 MmGrowKernelStackEx(IN PVOID StackPointer,
393 IN ULONG GrowSize)
394 {
395 PKTHREAD Thread = KeGetCurrentThread();
396 PMMPTE LimitPte, NewLimitPte, LastPte;
397 KIRQL OldIrql;
398 MMPTE TempPte, InvalidPte;
399 PFN_NUMBER PageFrameIndex;
400
401 //
402 // Make sure the stack did not overflow
403 //
404 ASSERT(((ULONG_PTR)Thread->StackBase - (ULONG_PTR)Thread->StackLimit) <=
405 (KERNEL_LARGE_STACK_SIZE + PAGE_SIZE));
406
407 //
408 // Get the current stack limit
409 //
410 LimitPte = MiAddressToPte(Thread->StackLimit);
411 ASSERT(LimitPte->u.Hard.Valid == 1);
412
413 //
414 // Get the new one and make sure this isn't a retarded request
415 //
416 NewLimitPte = MiAddressToPte((PVOID)((ULONG_PTR)StackPointer - GrowSize));
417 if (NewLimitPte == LimitPte) return STATUS_SUCCESS;
418
419 //
420 // Now make sure you're not going past the reserved space
421 //
422 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)Thread->StackBase -
423 KERNEL_LARGE_STACK_SIZE));
424 if (NewLimitPte < LastPte)
425 {
426 //
427 // Sorry!
428 //
429 DPRINT1("Thread wants too much stack\n");
430 return STATUS_STACK_OVERFLOW;
431 }
432
433 //
434 // Calculate the number of new pages
435 //
436 LimitPte--;
437
438 /* Setup the temporary invalid PTE */
439 MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
440
441 //
442 // Acquire the PFN DB lock
443 //
444 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
445
446 //
447 // Loop each stack page
448 //
449 while (LimitPte >= NewLimitPte)
450 {
451 /* Get a page and write the current invalid PTE */
452 MI_SET_USAGE(MI_USAGE_KERNEL_STACK_EXPANSION);
453 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
454 PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
455 MI_WRITE_INVALID_PTE(LimitPte, InvalidPte);
456
457 /* Initialize the PFN entry for this page */
458 MiInitializePfn(PageFrameIndex, LimitPte, 1);
459
460 /* Setup the template stack PTE */
461 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, LimitPte, MM_READWRITE, PageFrameIndex);
462
463 /* Write the valid PTE */
464 MI_WRITE_VALID_PTE(LimitPte--, TempPte);
465 }
466
467 //
468 // Release the PFN lock
469 //
470 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
471
472 //
473 // Set the new limit
474 //
475 Thread->StackLimit = (ULONG_PTR)MiPteToAddress(NewLimitPte);
476 return STATUS_SUCCESS;
477 }
478
479 NTSTATUS
480 NTAPI
481 MmGrowKernelStack(IN PVOID StackPointer)
482 {
483 //
484 // Call the extended version
485 //
486 return MmGrowKernelStackEx(StackPointer, KERNEL_LARGE_STACK_COMMIT);
487 }
488
489 NTSTATUS
490 NTAPI
491 MmSetMemoryPriorityProcess(IN PEPROCESS Process,
492 IN UCHAR MemoryPriority)
493 {
494 UCHAR OldPriority;
495
496 //
497 // Check if we have less then 16MB of Physical Memory
498 //
499 if ((MmSystemSize == MmSmallSystem) &&
500 (MmNumberOfPhysicalPages < ((15 * 1024 * 1024) / PAGE_SIZE)))
501 {
502 //
503 // Always use background priority
504 //
505 MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
506 }
507
508 //
509 // Save the old priority and update it
510 //
511 OldPriority = (UCHAR)Process->Vm.Flags.MemoryPriority;
512 Process->Vm.Flags.MemoryPriority = MemoryPriority;
513
514 //
515 // Return the old priority
516 //
517 return OldPriority;
518 }
519
520 LCID
521 NTAPI
522 MmGetSessionLocaleId(VOID)
523 {
524 PEPROCESS Process;
525 PAGED_CODE();
526
527 //
528 // Get the current process
529 //
530 Process = PsGetCurrentProcess();
531
532 //
533 // Check if it's the Session Leader
534 //
535 if (Process->Vm.Flags.SessionLeader)
536 {
537 //
538 // Make sure it has a valid Session
539 //
540 if (Process->Session)
541 {
542 //
543 // Get the Locale ID
544 //
545 #if ROS_HAS_SESSIONS
546 return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
547 #endif
548 }
549 }
550
551 //
552 // Not a session leader, return the default
553 //
554 return PsDefaultThreadLocaleId;
555 }
556
557 NTSTATUS
558 NTAPI
559 MmCreatePeb(IN PEPROCESS Process,
560 IN PINITIAL_PEB InitialPeb,
561 OUT PPEB *BasePeb)
562 {
563 PPEB Peb = NULL;
564 LARGE_INTEGER SectionOffset;
565 SIZE_T ViewSize = 0;
566 PVOID TableBase = NULL;
567 PIMAGE_NT_HEADERS NtHeaders;
568 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
569 NTSTATUS Status;
570 USHORT Characteristics;
571 KAFFINITY ProcessAffinityMask = 0;
572 SectionOffset.QuadPart = (ULONGLONG)0;
573 *BasePeb = NULL;
574
575 //
576 // Attach to Process
577 //
578 KeAttachProcess(&Process->Pcb);
579
580 //
581 // Map NLS Tables
582 //
583 Status = MmMapViewOfSection(ExpNlsSectionPointer,
584 (PEPROCESS)Process,
585 &TableBase,
586 0,
587 0,
588 &SectionOffset,
589 &ViewSize,
590 ViewShare,
591 MEM_TOP_DOWN,
592 PAGE_READONLY);
593 DPRINT1("NLS Tables at: %p\n", TableBase);
594 if (!NT_SUCCESS(Status))
595 {
596 /* Cleanup and exit */
597 KeDetachProcess();
598 return Status;
599 }
600
601 //
602 // Allocate the PEB
603 //
604 Status = MiCreatePebOrTeb(Process, sizeof(PEB), (PULONG_PTR)&Peb);
605 DPRINT1("PEB at: %p\n", Peb);
606 if (!NT_SUCCESS(Status))
607 {
608 /* Cleanup and exit */
609 KeDetachProcess();
610 return Status;
611 }
612
613 //
614 // Use SEH in case we can't load the PEB
615 //
616 _SEH2_TRY
617 {
618 //
619 // Initialize the PEB
620 //
621 RtlZeroMemory(Peb, sizeof(PEB));
622
623 //
624 // Set up data
625 //
626 Peb->ImageBaseAddress = Process->SectionBaseAddress;
627 Peb->InheritedAddressSpace = InitialPeb->InheritedAddressSpace;
628 Peb->Mutant = InitialPeb->Mutant;
629 Peb->ImageUsesLargePages = InitialPeb->ImageUsesLargePages;
630
631 //
632 // NLS
633 //
634 Peb->AnsiCodePageData = (PCHAR)TableBase + ExpAnsiCodePageDataOffset;
635 Peb->OemCodePageData = (PCHAR)TableBase + ExpOemCodePageDataOffset;
636 Peb->UnicodeCaseTableData = (PCHAR)TableBase + ExpUnicodeCaseTableDataOffset;
637
638 //
639 // Default Version Data (could get changed below)
640 //
641 Peb->OSMajorVersion = NtMajorVersion;
642 Peb->OSMinorVersion = NtMinorVersion;
643 Peb->OSBuildNumber = (USHORT)(NtBuildNumber & 0x3FFF);
644 Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */
645 Peb->OSCSDVersion = (USHORT)CmNtCSDVersion;
646
647 //
648 // Heap and Debug Data
649 //
650 Peb->NumberOfProcessors = KeNumberProcessors;
651 Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL);
652 Peb->NtGlobalFlag = NtGlobalFlag;
653 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
654 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
655 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
656 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
657 Peb->CriticalSectionTimeout = MmCriticalSectionTimeout;
658 Peb->MinimumStackCommit = MmMinimumStackCommitInBytes;
659 */
660 Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
661 Peb->ProcessHeaps = (PVOID*)(Peb + 1);
662
663 //
664 // Session ID
665 //
666 if (Process->Session) Peb->SessionId = 0; // MmGetSessionId(Process);
667 }
668 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
669 {
670 //
671 // Fail
672 //
673 KeDetachProcess();
674 _SEH2_YIELD(return _SEH2_GetExceptionCode());
675 }
676 _SEH2_END;
677
678 //
679 // Use SEH in case we can't load the image
680 //
681 _SEH2_TRY
682 {
683 //
684 // Get NT Headers
685 //
686 NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
687 Characteristics = NtHeaders->FileHeader.Characteristics;
688 }
689 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
690 {
691 //
692 // Fail
693 //
694 KeDetachProcess();
695 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
696 }
697 _SEH2_END;
698
699 //
700 // Parse the headers
701 //
702 if (NtHeaders)
703 {
704 //
705 // Use SEH in case we can't load the headers
706 //
707 _SEH2_TRY
708 {
709 //
710 // Get the Image Config Data too
711 //
712 ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
713 TRUE,
714 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
715 (PULONG)&ViewSize);
716 if (ImageConfigData)
717 {
718 //
719 // Probe it
720 //
721 ProbeForRead(ImageConfigData,
722 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
723 sizeof(ULONG));
724 }
725
726 //
727 // Write subsystem data
728 //
729 Peb->ImageSubsystem = NtHeaders->OptionalHeader.Subsystem;
730 Peb->ImageSubsystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
731 Peb->ImageSubsystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
732
733 //
734 // Check for version data
735 //
736 if (NtHeaders->OptionalHeader.Win32VersionValue)
737 {
738 //
739 // Extract values and write them
740 //
741 Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF;
742 Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
743 Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF;
744 Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2;
745
746 /* Process CSD version override */
747 if ((ImageConfigData) && (ImageConfigData->CSDVersion))
748 {
749 /* Take the value from the image configuration directory */
750 Peb->OSCSDVersion = ImageConfigData->CSDVersion;
751 }
752 }
753
754 /* Process optional process affinity mask override */
755 if ((ImageConfigData) && (ImageConfigData->ProcessAffinityMask))
756 {
757 /* Take the value from the image configuration directory */
758 ProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
759 }
760
761 //
762 // Check if this is a UP image
763 if (Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
764 {
765 //
766 // Force it to use CPU 0
767 //
768 /* FIXME: this should use the MmRotatingUniprocessorNumber */
769 Peb->ImageProcessAffinityMask = 0;
770 }
771 else
772 {
773 //
774 // Whatever was configured
775 //
776 Peb->ImageProcessAffinityMask = ProcessAffinityMask;
777 }
778 }
779 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
780 {
781 //
782 // Fail
783 //
784 KeDetachProcess();
785 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
786 }
787 _SEH2_END;
788 }
789
790 //
791 // Detach from the Process
792 //
793 KeDetachProcess();
794 *BasePeb = Peb;
795 return STATUS_SUCCESS;
796 }
797
798 NTSTATUS
799 NTAPI
800 MmCreateTeb(IN PEPROCESS Process,
801 IN PCLIENT_ID ClientId,
802 IN PINITIAL_TEB InitialTeb,
803 OUT PTEB *BaseTeb)
804 {
805 PTEB Teb;
806 NTSTATUS Status = STATUS_SUCCESS;
807 *BaseTeb = NULL;
808
809 //
810 // Attach to Target
811 //
812 KeAttachProcess(&Process->Pcb);
813
814 //
815 // Allocate the TEB
816 //
817 Status = MiCreatePebOrTeb(Process, sizeof(TEB), (PULONG_PTR)&Teb);
818 ASSERT(NT_SUCCESS(Status));
819
820 //
821 // Use SEH in case we can't load the TEB
822 //
823 _SEH2_TRY
824 {
825 //
826 // Initialize the PEB
827 //
828 RtlZeroMemory(Teb, sizeof(TEB));
829
830 //
831 // Set TIB Data
832 //
833 Teb->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
834 Teb->NtTib.Self = (PNT_TIB)Teb;
835
836 //
837 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
838 //
839 Teb->NtTib.Version = 30 << 8;
840
841 //
842 // Set TEB Data
843 //
844 Teb->ClientId = *ClientId;
845 Teb->RealClientId = *ClientId;
846 Teb->ProcessEnvironmentBlock = Process->Peb;
847 Teb->CurrentLocale = PsDefaultThreadLocaleId;
848
849 //
850 // Check if we have a grandparent TEB
851 //
852 if ((InitialTeb->PreviousStackBase == NULL) &&
853 (InitialTeb->PreviousStackLimit == NULL))
854 {
855 //
856 // Use initial TEB values
857 //
858 Teb->NtTib.StackBase = InitialTeb->StackBase;
859 Teb->NtTib.StackLimit = InitialTeb->StackLimit;
860 Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
861 }
862 else
863 {
864 //
865 // Use grandparent TEB values
866 //
867 Teb->NtTib.StackBase = InitialTeb->PreviousStackBase;
868 Teb->NtTib.StackLimit = InitialTeb->PreviousStackLimit;
869 }
870
871 //
872 // Initialize the static unicode string
873 //
874 Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
875 Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
876 }
877 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
878 {
879 //
880 // Get error code
881 //
882 Status = _SEH2_GetExceptionCode();
883 }
884 _SEH2_END;
885
886 //
887 // Return
888 //
889 KeDetachProcess();
890 *BaseTeb = Teb;
891 return Status;
892 }
893
894 VOID
895 NTAPI
896 MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess)
897 {
898 PMMPFN Pfn1;
899
900 /* Setup some bogus list data */
901 MmWorkingSetList->LastEntry = CurrentProcess->Vm.MinimumWorkingSetSize;
902 MmWorkingSetList->HashTable = NULL;
903 MmWorkingSetList->HashTableSize = 0;
904 MmWorkingSetList->NumberOfImageWaiters = 0;
905 MmWorkingSetList->Wsle = (PVOID)0xDEADBABE;
906 MmWorkingSetList->VadBitMapHint = 1;
907 MmWorkingSetList->HashTableStart = (PVOID)0xBADAB00B;
908 MmWorkingSetList->HighestPermittedHashAddress = (PVOID)0xCAFEBABE;
909 MmWorkingSetList->FirstFree = 1;
910 MmWorkingSetList->FirstDynamic = 2;
911 MmWorkingSetList->NextSlot = 3;
912 MmWorkingSetList->LastInitializedWsle = 4;
913
914 /* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */
915 Pfn1 = MiGetPfnEntry(MiAddressToPte(PDE_BASE)->u.Hard.PageFrameNumber);
916 ASSERT(Pfn1->u4.PteFrame == MiGetPfnEntryIndex(Pfn1));
917 Pfn1->u1.Event = (PKEVENT)CurrentProcess;
918 }
919
920 NTSTATUS
921 NTAPI
922 MmInitializeProcessAddressSpace(IN PEPROCESS Process,
923 IN PEPROCESS ProcessClone OPTIONAL,
924 IN PVOID Section OPTIONAL,
925 IN OUT PULONG Flags,
926 IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL)
927 {
928 NTSTATUS Status = STATUS_SUCCESS;
929 SIZE_T ViewSize = 0;
930 PVOID ImageBase = 0;
931 PROS_SECTION_OBJECT SectionObject = Section;
932 PMMPTE PointerPte;
933 KIRQL OldIrql;
934 PMMPDE PointerPde;
935 PFN_NUMBER PageFrameNumber;
936 UNICODE_STRING FileName;
937 PWCHAR Source;
938 PCHAR Destination;
939 USHORT Length = 0;
940 MMPTE TempPte;
941
942 /* We should have a PDE */
943 ASSERT(Process->Pcb.DirectoryTableBase[0] != 0);
944 ASSERT(Process->PdeUpdateNeeded == FALSE);
945
946 /* Attach to the process */
947 KeAttachProcess(&Process->Pcb);
948
949 /* The address space should now been in phase 1 or 0 */
950 ASSERT(Process->AddressSpaceInitialized <= 1);
951 Process->AddressSpaceInitialized = 2;
952
953 /* Initialize the Addresss Space lock */
954 KeInitializeGuardedMutex(&Process->AddressCreationLock);
955 Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
956
957 /* Initialize AVL tree */
958 ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
959 Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
960
961 /* Lock PFN database */
962 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
963
964 /* Setup the PFN for the PDE base of this process */
965 PointerPte = MiAddressToPte(PDE_BASE);
966 PageFrameNumber = PFN_FROM_PTE(PointerPte);
967 MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
968
969 /* Do the same for hyperspace */
970 PointerPde = MiAddressToPde(HYPER_SPACE);
971 PageFrameNumber = PFN_FROM_PTE(PointerPde);
972 MiInitializePfn(PageFrameNumber, (PMMPTE)PointerPde, TRUE);
973
974 /* Setup the PFN for the PTE for the working set */
975 PointerPte = MiAddressToPte(MI_WORKING_SET_LIST);
976 MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, MM_READWRITE, 0);
977 ASSERT(PointerPte->u.Long != 0);
978 PageFrameNumber = PFN_FROM_PTE(PointerPte);
979 MI_WRITE_INVALID_PTE(PointerPte, DemandZeroPte);
980 MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
981 TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
982 MI_WRITE_VALID_PTE(PointerPte, TempPte);
983
984 /* Now initialize the working set list */
985 MiInitializeWorkingSetList(Process);
986
987 /* Sanity check */
988 ASSERT(Process->PhysicalVadRoot == NULL);
989
990 /* Release PFN lock */
991 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
992
993 /* Lock the VAD, ARM3-owned ranges away */
994 MiRosTakeOverPebTebRanges(Process);
995
996 /* Check if there's a Section Object */
997 if (SectionObject)
998 {
999 /* Determine the image file name and save it to EPROCESS */
1000 FileName = SectionObject->FileObject->FileName;
1001 Source = (PWCHAR)((PCHAR)FileName.Buffer + FileName.Length);
1002 if (FileName.Buffer)
1003 {
1004 /* Loop the file name*/
1005 while (Source > FileName.Buffer)
1006 {
1007 /* Make sure this isn't a backslash */
1008 if (*--Source == OBJ_NAME_PATH_SEPARATOR)
1009 {
1010 /* If so, stop it here */
1011 Source++;
1012 break;
1013 }
1014 else
1015 {
1016 /* Otherwise, keep going */
1017 Length++;
1018 }
1019 }
1020 }
1021
1022 /* Copy the to the process and truncate it to 15 characters if necessary */
1023 Destination = Process->ImageFileName;
1024 Length = min(Length, sizeof(Process->ImageFileName) - 1);
1025 while (Length--) *Destination++ = (UCHAR)*Source++;
1026 *Destination = ANSI_NULL;
1027
1028 /* Check if caller wants an audit name */
1029 if (AuditName)
1030 {
1031 /* Setup the audit name */
1032 Status = SeInitializeProcessAuditName(SectionObject->FileObject,
1033 FALSE,
1034 AuditName);
1035 if (!NT_SUCCESS(Status))
1036 {
1037 /* Fail */
1038 KeDetachProcess();
1039 return Status;
1040 }
1041 }
1042
1043 /* Map the section */
1044 Status = MmMapViewOfSection(Section,
1045 Process,
1046 (PVOID*)&ImageBase,
1047 0,
1048 0,
1049 NULL,
1050 &ViewSize,
1051 0,
1052 MEM_COMMIT,
1053 PAGE_READWRITE);
1054
1055 /* Save the pointer */
1056 Process->SectionBaseAddress = ImageBase;
1057 }
1058
1059 /* Be nice and detach */
1060 KeDetachProcess();
1061
1062 /* Return status to caller */
1063 return Status;
1064 }
1065
1066 NTSTATUS
1067 NTAPI
1068 INIT_FUNCTION
1069 MmInitializeHandBuiltProcess(IN PEPROCESS Process,
1070 IN PULONG_PTR DirectoryTableBase)
1071 {
1072 /* Share the directory base with the idle process */
1073 DirectoryTableBase[0] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[0];
1074 DirectoryTableBase[1] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[1];
1075
1076 /* Initialize the Addresss Space */
1077 KeInitializeGuardedMutex(&Process->AddressCreationLock);
1078 KeInitializeSpinLock(&Process->HyperSpaceLock);
1079 Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
1080 ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
1081 Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
1082
1083 /* Done */
1084 Process->HasAddressSpace = TRUE;//??
1085 return STATUS_SUCCESS;
1086 }
1087
1088 NTSTATUS
1089 NTAPI
1090 INIT_FUNCTION
1091 MmInitializeHandBuiltProcess2(IN PEPROCESS Process)
1092 {
1093 /* Lock the VAD, ARM3-owned ranges away */
1094 MiRosTakeOverPebTebRanges(Process);
1095 return STATUS_SUCCESS;
1096 }
1097
1098 #ifdef _M_IX86
1099 /* FIXME: Evaluate ways to make this portable yet arch-specific */
1100 BOOLEAN
1101 NTAPI
1102 MmCreateProcessAddressSpace(IN ULONG MinWs,
1103 IN PEPROCESS Process,
1104 OUT PULONG_PTR DirectoryTableBase)
1105 {
1106 KIRQL OldIrql;
1107 PFN_NUMBER PdeIndex, HyperIndex, WsListIndex;
1108 PMMPTE PointerPte;
1109 MMPTE TempPte, PdePte;
1110 ULONG PdeOffset;
1111 PMMPTE SystemTable, HyperTable;
1112 ULONG Color;
1113 PMMPFN Pfn1;
1114
1115 /* Choose a process color */
1116 Process->NextPageColor = RtlRandom(&MmProcessColorSeed);
1117
1118 /* Setup the hyperspace lock */
1119 KeInitializeSpinLock(&Process->HyperSpaceLock);
1120
1121 /* Lock PFN database */
1122 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1123
1124 /* Get a zero page for the PDE, if possible */
1125 Color = MI_GET_NEXT_PROCESS_COLOR(Process);
1126 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY);
1127 PdeIndex = MiRemoveZeroPageSafe(Color);
1128 if (!PdeIndex)
1129 {
1130 /* No zero pages, grab a free one */
1131 PdeIndex = MiRemoveAnyPage(Color);
1132
1133 /* Zero it outside the PFN lock */
1134 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1135 MiZeroPhysicalPage(PdeIndex);
1136 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1137 }
1138
1139 /* Get a zero page for hyperspace, if possible */
1140 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY);
1141 Color = MI_GET_NEXT_PROCESS_COLOR(Process);
1142 HyperIndex = MiRemoveZeroPageSafe(Color);
1143 if (!HyperIndex)
1144 {
1145 /* No zero pages, grab a free one */
1146 HyperIndex = MiRemoveAnyPage(Color);
1147
1148 /* Zero it outside the PFN lock */
1149 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1150 MiZeroPhysicalPage(HyperIndex);
1151 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1152 }
1153
1154 /* Get a zero page for the woring set list, if possible */
1155 MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
1156 Color = MI_GET_NEXT_PROCESS_COLOR(Process);
1157 WsListIndex = MiRemoveZeroPageSafe(Color);
1158 if (!WsListIndex)
1159 {
1160 /* No zero pages, grab a free one */
1161 WsListIndex = MiRemoveAnyPage(Color);
1162
1163 /* Zero it outside the PFN lock */
1164 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1165 MiZeroPhysicalPage(WsListIndex);
1166 }
1167 else
1168 {
1169 /* Release the PFN lock */
1170 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1171 }
1172
1173 /* Switch to phase 1 initialization */
1174 ASSERT(Process->AddressSpaceInitialized == 0);
1175 Process->AddressSpaceInitialized = 1;
1176
1177 /* Set the base directory pointers */
1178 Process->WorkingSetPage = WsListIndex;
1179 DirectoryTableBase[0] = PdeIndex << PAGE_SHIFT;
1180 DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
1181
1182 /* Make sure we don't already have a page directory setup */
1183 ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
1184
1185 /* Get a PTE to map hyperspace */
1186 PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
1187 ASSERT(PointerPte != NULL);
1188
1189 /* Build it */
1190 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
1191 PointerPte,
1192 MM_READWRITE,
1193 HyperIndex);
1194
1195 /* Set it dirty and map it */
1196 MI_MAKE_DIRTY_PAGE(&PdePte);
1197 MI_WRITE_VALID_PTE(PointerPte, PdePte);
1198
1199 /* Now get hyperspace's page table */
1200 HyperTable = MiPteToAddress(PointerPte);
1201
1202 /* Now write the PTE/PDE entry for the working set list index itself */
1203 TempPte = ValidKernelPte;
1204 TempPte.u.Hard.PageFrameNumber = WsListIndex;
1205 PdeOffset = MiAddressToPteOffset(MmWorkingSetList);
1206 HyperTable[PdeOffset] = TempPte;
1207
1208 /* Let go of the system PTE */
1209 MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
1210
1211 /* Save the PTE address of the page directory itself */
1212 Pfn1 = MiGetPfnEntry(PdeIndex);
1213 Pfn1->PteAddress = (PMMPTE)PDE_BASE;
1214
1215 /* Insert us into the Mm process list */
1216 InsertTailList(&MmProcessList, &Process->MmProcessLinks);
1217
1218 /* Get a PTE to map the page directory */
1219 PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
1220 ASSERT(PointerPte != NULL);
1221
1222 /* Build it */
1223 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
1224 PointerPte,
1225 MM_READWRITE,
1226 PdeIndex);
1227
1228 /* Set it dirty and map it */
1229 MI_MAKE_DIRTY_PAGE(&PdePte);
1230 MI_WRITE_VALID_PTE(PointerPte, PdePte);
1231
1232 /* Now get the page directory (which we'll double map, so call it a page table */
1233 SystemTable = MiPteToAddress(PointerPte);
1234
1235 /* Copy all the kernel mappings */
1236 PdeOffset = MiGetPdeOffset(MmSystemRangeStart);
1237 RtlCopyMemory(&SystemTable[PdeOffset],
1238 MiAddressToPde(MmSystemRangeStart),
1239 PAGE_SIZE - PdeOffset * sizeof(MMPTE));
1240
1241 /* Now write the PTE/PDE entry for hyperspace itself */
1242 TempPte = ValidKernelPte;
1243 TempPte.u.Hard.PageFrameNumber = HyperIndex;
1244 PdeOffset = MiGetPdeOffset(HYPER_SPACE);
1245 SystemTable[PdeOffset] = TempPte;
1246
1247 /* Sanity check */
1248 PdeOffset++;
1249 ASSERT(MiGetPdeOffset(MmHyperSpaceEnd) >= PdeOffset);
1250
1251 /* Now do the x86 trick of making the PDE a page table itself */
1252 PdeOffset = MiGetPdeOffset(PTE_BASE);
1253 TempPte.u.Hard.PageFrameNumber = PdeIndex;
1254 SystemTable[PdeOffset] = TempPte;
1255
1256 /* Let go of the system PTE */
1257 MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
1258 return TRUE;
1259 }
1260 #endif
1261
1262 VOID
1263 NTAPI
1264 MmCleanProcessAddressSpace(IN PEPROCESS Process)
1265 {
1266 PMMVAD Vad;
1267 PMM_AVL_TABLE VadTree;
1268 PETHREAD Thread = PsGetCurrentThread();
1269
1270 /* Only support this */
1271 ASSERT(Process->AddressSpaceInitialized == 2);
1272
1273 /* Lock the process address space from changes */
1274 MmLockAddressSpace(&Process->Vm);
1275
1276 /* VM is deleted now */
1277 Process->VmDeleted = TRUE;
1278
1279 /* Enumerate the VADs */
1280 VadTree = &Process->VadRoot;
1281 while (VadTree->NumberGenericTableElements)
1282 {
1283 /* Grab the current VAD */
1284 Vad = (PMMVAD)VadTree->BalancedRoot.RightChild;
1285
1286 /* Lock the working set */
1287 MiLockProcessWorkingSet(Process, Thread);
1288
1289 /* Remove this VAD from the tree */
1290 ASSERT(VadTree->NumberGenericTableElements >= 1);
1291 MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
1292
1293 /* Only regular VADs supported for now */
1294 ASSERT(Vad->u.VadFlags.VadType == VadNone);
1295
1296 /* Check if this is a section VAD */
1297 if (!(Vad->u.VadFlags.PrivateMemory) && (Vad->ControlArea))
1298 {
1299 /* Remove the view */
1300 MiRemoveMappedView(Process, Vad);
1301 }
1302 else
1303 {
1304 /* Delete the addresses */
1305 MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT,
1306 (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
1307 Vad);
1308
1309 /* Release the working set */
1310 MiUnlockProcessWorkingSet(Process, Thread);
1311 }
1312
1313 /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
1314 if (Vad->u.VadFlags.Spare == 1)
1315 {
1316 /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
1317 Vad->u.VadFlags.Spare = 2;
1318 continue;
1319 }
1320
1321 /* Free the VAD memory */
1322 ExFreePool(Vad);
1323 }
1324
1325 /* Release the address space */
1326 MmUnlockAddressSpace(&Process->Vm);
1327 }
1328
1329 /* SYSTEM CALLS ***************************************************************/
1330
1331 NTSTATUS
1332 NTAPI
1333 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle,
1334 IN OUT PULONG_PTR NumberOfPages,
1335 IN OUT PULONG_PTR UserPfnArray)
1336 {
1337 UNIMPLEMENTED;
1338 return STATUS_NOT_IMPLEMENTED;
1339 }
1340
1341 NTSTATUS
1342 NTAPI
1343 NtMapUserPhysicalPages(IN PVOID VirtualAddresses,
1344 IN ULONG_PTR NumberOfPages,
1345 IN OUT PULONG_PTR UserPfnArray)
1346 {
1347 UNIMPLEMENTED;
1348 return STATUS_NOT_IMPLEMENTED;
1349 }
1350
1351 NTSTATUS
1352 NTAPI
1353 NtMapUserPhysicalPagesScatter(IN PVOID *VirtualAddresses,
1354 IN ULONG_PTR NumberOfPages,
1355 IN OUT PULONG_PTR UserPfnArray)
1356 {
1357 UNIMPLEMENTED;
1358 return STATUS_NOT_IMPLEMENTED;
1359 }
1360
1361 NTSTATUS
1362 NTAPI
1363 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle,
1364 IN OUT PULONG_PTR NumberOfPages,
1365 IN OUT PULONG_PTR UserPfnArray)
1366 {
1367 UNIMPLEMENTED;
1368 return STATUS_NOT_IMPLEMENTED;
1369 }
1370
1371 /* EOF */