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