ReactOS 0.4.16-dev-1946-g52006dd
virtual.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/virtual.c
5 * PURPOSE: ARM Memory Manager Virtual Memory 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 <mm/ARM3/miarm.h>
17
18#define MI_MAPPED_COPY_PAGES 14
19#define MI_POOL_COPY_BYTES 512
20#define MI_MAX_TRANSFER_SIZE 64 * 1024
21
25 IN OUT PSIZE_T NumberOfBytesToProtect,
26 IN ULONG NewAccessProtection,
27 OUT PULONG OldAccessProtection OPTIONAL);
28
29VOID
32 IN PMMPTE PointerPte,
33 IN ULONG ProtectionMask,
34 IN PMMPFN Pfn1,
35 IN BOOLEAN CaptureDirtyBit);
36
37
38/* PRIVATE FUNCTIONS **********************************************************/
39
43 IN ULONG_PTR EndingAddress,
44 IN PMMVAD Vad,
46{
47 PMMPTE PointerPte, LastPte;
48 PMMPDE PointerPde;
49 BOOLEAN OnPdeBoundary = TRUE;
50#if _MI_PAGING_LEVELS >= 3
51 PMMPPE PointerPpe;
52 BOOLEAN OnPpeBoundary = TRUE;
53#if _MI_PAGING_LEVELS == 4
54 PMMPXE PointerPxe;
55 BOOLEAN OnPxeBoundary = TRUE;
56#endif
57#endif
58
59 /* Make sure this all makes sense */
60 ASSERT(PsGetCurrentThread()->OwnsProcessWorkingSetExclusive || PsGetCurrentThread()->OwnsProcessWorkingSetShared);
61 ASSERT(EndingAddress >= StartingAddress);
62 PointerPte = MiAddressToPte(StartingAddress);
63 LastPte = MiAddressToPte(EndingAddress);
64
65 /*
66 * In case this is a committed VAD, assume the whole range is committed
67 * and count the individually decommitted pages.
68 * In case it is not, assume the range is not committed and count the individually committed pages.
69 */
70 ULONG_PTR CommittedPages = Vad->u.VadFlags.MemCommit ? BYTES_TO_PAGES(EndingAddress - StartingAddress) : 0;
71
72 while (PointerPte <= LastPte)
73 {
74#if _MI_PAGING_LEVELS == 4
75 /* Check if PXE was ever paged in. */
76 if (OnPxeBoundary)
77 {
78 PointerPxe = MiPteToPxe(PointerPte);
79
80 /* Check that this loop is sane */
81 ASSERT(OnPpeBoundary);
82 ASSERT(OnPdeBoundary);
83
84 if (PointerPxe->u.Long == 0)
85 {
86 PointerPxe++;
87 PointerPte = MiPxeToPte(PointerPde);
88 continue;
89 }
90
91 if (PointerPxe->u.Hard.Valid == 0)
93 }
94 ASSERT(PointerPxe->u.Hard.Valid == 1);
95#endif
96
97#if _MI_PAGING_LEVELS >= 3
98 /* Now PPE */
99 if (OnPpeBoundary)
100 {
101 PointerPpe = MiPteToPpe(PointerPte);
102
103 /* Sanity again */
104 ASSERT(OnPdeBoundary);
105
106 if (PointerPpe->u.Long == 0)
107 {
108 PointerPpe++;
109 PointerPte = MiPpeToPte(PointerPpe);
110#if _MI_PAGING_LEVELS == 4
111 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
112#endif
113 continue;
114 }
115
116 if (PointerPpe->u.Hard.Valid == 0)
118 }
119 ASSERT(PointerPpe->u.Hard.Valid == 1);
120#endif
121
122 /* Last level is the PDE */
123 if (OnPdeBoundary)
124 {
125 PointerPde = MiPteToPde(PointerPte);
126 if (PointerPde->u.Long == 0)
127 {
128 PointerPde++;
129 PointerPte = MiPdeToPte(PointerPde);
130#if _MI_PAGING_LEVELS >= 3
131 OnPpeBoundary = MiIsPteOnPpeBoundary(PointerPte);
132#if _MI_PAGING_LEVELS == 4
133 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
134#endif
135#endif
136 continue;
137 }
138
139 if (PointerPde->u.Hard.Valid == 0)
141 }
142 ASSERT(PointerPde->u.Hard.Valid == 1);
143
144 /* Is this PTE demand zero? */
145 if (PointerPte->u.Long != 0)
146 {
147 /* It isn't -- is it a decommited, invalid, or faulted PTE? */
148 if ((PointerPte->u.Hard.Valid == 0) &&
149 (PointerPte->u.Soft.Protection == MM_DECOMMIT) &&
150 ((PointerPte->u.Soft.Prototype == 0) ||
151 (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)))
152 {
153 /* It is, so remove it from the count of committed pages if we have to */
154 if (Vad->u.VadFlags.MemCommit)
155 CommittedPages--;
156 }
157 else if (!Vad->u.VadFlags.MemCommit)
158 {
159 /* It is a valid, non-decommited, non-paged out PTE. Count it in. */
160 CommittedPages++;
161 }
162 }
163
164 /* Move to the next PTE */
165 PointerPte++;
166 /* Manage page tables */
167 OnPdeBoundary = MiIsPteOnPdeBoundary(PointerPte);
168#if _MI_PAGING_LEVELS >= 3
169 OnPpeBoundary = MiIsPteOnPpeBoundary(PointerPte);
170#if _MI_PAGING_LEVELS == 4
171 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
172#endif
173#endif
174 }
175
176 /* Make sure we didn't mess this up */
177 ASSERT(CommittedPages <= BYTES_TO_PAGES(EndingAddress - StartingAddress));
178 return CommittedPages;
179}
180
181ULONG
182NTAPI
183MiMakeSystemAddressValid(IN PVOID PageTableVirtualAddress,
184 IN PEPROCESS CurrentProcess)
185{
187 BOOLEAN WsShared = FALSE, WsSafe = FALSE, LockChange = FALSE;
188 PETHREAD CurrentThread = PsGetCurrentThread();
189
190 /* Must be a non-pool page table, since those are double-mapped already */
191 ASSERT(PageTableVirtualAddress > MM_HIGHEST_USER_ADDRESS);
192 ASSERT((PageTableVirtualAddress < MmPagedPoolStart) ||
193 (PageTableVirtualAddress > MmPagedPoolEnd));
194
195 /* Working set lock or PFN lock should be held */
197
198 /* Check if the page table is valid */
199 while (!MmIsAddressValid(PageTableVirtualAddress))
200 {
201 /* Release the working set lock */
203 CurrentThread,
204 &WsSafe,
205 &WsShared);
206
207 /* Fault it in */
208 Status = MmAccessFault(FALSE, PageTableVirtualAddress, KernelMode, NULL);
209 if (!NT_SUCCESS(Status))
210 {
211 /* This should not fail */
212 KeBugCheckEx(KERNEL_DATA_INPAGE_ERROR,
213 1,
214 Status,
215 (ULONG_PTR)CurrentProcess,
216 (ULONG_PTR)PageTableVirtualAddress);
217 }
218
219 /* Lock the working set again */
220 MiLockProcessWorkingSetForFault(CurrentProcess,
221 CurrentThread,
222 WsSafe,
223 WsShared);
224
225 /* This flag will be useful later when we do better locking */
226 LockChange = TRUE;
227 }
228
229 /* Let caller know what the lock state is */
230 return LockChange;
231}
232
233ULONG
234NTAPI
237{
239 BOOLEAN LockChange = FALSE;
240
241 /* Must be e kernel address */
243
244 /* Check if the page is valid */
246 {
247 /* Release the PFN database */
248 MiReleasePfnLock(OldIrql);
249
250 /* Fault it in */
252 if (!NT_SUCCESS(Status))
253 {
254 /* This should not fail */
255 KeBugCheckEx(KERNEL_DATA_INPAGE_ERROR,
256 3,
257 Status,
258 0,
260 }
261
262 /* This flag will be useful later when we do better locking */
263 LockChange = TRUE;
264
265 /* Lock the PFN database */
266 OldIrql = MiAcquirePfnLock();
267 }
268
269 /* Let caller know what the lock state is */
270 return LockChange;
271}
272
274NTAPI
276 IN PFN_NUMBER PageCount,
277 IN ULONG Flags,
278 OUT PPFN_NUMBER ValidPages)
279{
280 PFN_COUNT ActualPages = 0;
281 PETHREAD CurrentThread = PsGetCurrentThread();
282 PMMPFN Pfn1, Pfn2;
283 PFN_NUMBER PageFrameIndex, PageTableIndex;
286
287 /* Lock the system working set */
288 MiLockWorkingSet(CurrentThread, &MmSystemCacheWs);
289
290 /* Loop all pages */
291 while (PageCount)
292 {
293 /* Make sure there's some data about the page */
294 if (PointerPte->u.Long)
295 {
296 /* Normally this is one possibility -- freeing a valid page */
297 if (PointerPte->u.Hard.Valid)
298 {
299 /* Get the page PFN */
300 PageFrameIndex = PFN_FROM_PTE(PointerPte);
301 Pfn1 = MiGetPfnEntry(PageFrameIndex);
302
303 /* Should not have any working set data yet */
304 ASSERT(Pfn1->u1.WsIndex == 0);
305
306 /* Actual valid, legitimate, pages */
307 if (ValidPages) (*ValidPages)++;
308
309 /* Get the page table entry */
310 PageTableIndex = Pfn1->u4.PteFrame;
311 Pfn2 = MiGetPfnEntry(PageTableIndex);
312
313 /* Lock the PFN database */
314 OldIrql = MiAcquirePfnLock();
315
316 /* Delete it the page */
317 MI_SET_PFN_DELETED(Pfn1);
318 MiDecrementShareCount(Pfn1, PageFrameIndex);
319
320 /* Decrement the page table too */
321 MiDecrementShareCount(Pfn2, PageTableIndex);
322
323 /* Release the PFN database */
324 MiReleasePfnLock(OldIrql);
325
326 /* Destroy the PTE */
327 MI_ERASE_PTE(PointerPte);
328 }
329 else
330 {
331 /* As always, only handle current ARM3 scenarios */
332 ASSERT(PointerPte->u.Soft.Prototype == 0);
333 ASSERT(PointerPte->u.Soft.Transition == 0);
334
335 /*
336 * The only other ARM3 possibility is a demand zero page, which would
337 * mean freeing some of the paged pool pages that haven't even been
338 * touched yet, as part of a larger allocation.
339 *
340 * Right now, we shouldn't expect any page file information in the PTE
341 */
342 ASSERT(PointerPte->u.Soft.PageFileHigh == 0);
343
344 /* Destroy the PTE */
345 MI_ERASE_PTE(PointerPte);
346 }
347
348 /* Actual legitimate pages */
349 ActualPages++;
350 }
351
352 /* Keep going */
353 PointerPte++;
354 PageCount--;
355 }
356
357 /* Release the working set */
358 MiUnlockWorkingSet(CurrentThread, &MmSystemCacheWs);
359
360 /* Flush the entire TLB */
362
363 /* Done */
364 return ActualPages;
365}
366
367VOID
368NTAPI
371 IN PEPROCESS CurrentProcess,
373{
374 PMMPFN Pfn1;
376 PFN_NUMBER PageFrameIndex;
377 PMMPDE PointerPde;
378
379 /* PFN lock must be held */
381
382 /* WorkingSet must be exclusively locked */
384
385 /* This must be current process. */
386 ASSERT(CurrentProcess == PsGetCurrentProcess());
387
388 /* Capture the PTE */
389 TempPte = *PointerPte;
390
391 /* See if the PTE is valid */
392 if (TempPte.u.Hard.Valid == 0)
393 {
394 /* Prototype and paged out PTEs not supported yet */
395 ASSERT(TempPte.u.Soft.Prototype == 0);
396 ASSERT((TempPte.u.Soft.PageFileHigh == 0) || (TempPte.u.Soft.Transition == 1));
397
398 if (TempPte.u.Soft.Transition)
399 {
400 /* Get the PFN entry */
401 PageFrameIndex = PFN_FROM_PTE(&TempPte);
402 Pfn1 = MiGetPfnEntry(PageFrameIndex);
403
404 DPRINT("Pte %p is transitional!\n", PointerPte);
405
406 /* Make sure the saved PTE address is valid */
407 ASSERT((PMMPTE)((ULONG_PTR)Pfn1->PteAddress & ~0x1) == PointerPte);
408
409 /* Destroy the PTE */
410 MI_ERASE_PTE(PointerPte);
411
412 /* Drop the reference on the page table. */
414
415 /* In case of shared page, the prototype PTE must be in transition, not the process one */
416 ASSERT(Pfn1->u3.e1.PrototypePte == 0);
417
418 /* Delete the PFN */
419 MI_SET_PFN_DELETED(Pfn1);
420
421 /* It must be either free (refcount == 0) or being written (refcount == 1) */
422 ASSERT(Pfn1->u3.e2.ReferenceCount == Pfn1->u3.e1.WriteInProgress);
423
424 /* See if we must free it ourselves, or if it will be freed once I/O is over */
425 if (Pfn1->u3.e2.ReferenceCount == 0)
426 {
427 /* And it should be in standby or modified list */
429
430 /* Unlink it and set its reference count to one */
432 Pfn1->u3.e2.ReferenceCount++;
433
434 /* This will put it back in free list and clean properly up */
435 MiDecrementReferenceCount(Pfn1, PageFrameIndex);
436 }
437 return;
438 }
439 }
440
441 /* Get the PFN entry */
442 PageFrameIndex = PFN_FROM_PTE(&TempPte);
443 Pfn1 = MiGetPfnEntry(PageFrameIndex);
444
445 /* Check if this is a valid, prototype PTE */
446 if (Pfn1->u3.e1.PrototypePte == 1)
447 {
448 /* Get the PDE and make sure it's faulted in */
449 PointerPde = MiPteToPde(PointerPte);
450 if (PointerPde->u.Hard.Valid == 0)
451 {
452#if (_MI_PAGING_LEVELS == 2)
453 /* Could be paged pool access from a new process -- synchronize the page directories */
455 {
456#endif
457 /* The PDE must be valid at this point */
458 KeBugCheckEx(MEMORY_MANAGEMENT,
459 0x61940,
460 (ULONG_PTR)PointerPte,
461 PointerPte->u.Long,
463 }
464#if (_MI_PAGING_LEVELS == 2)
465 }
466#endif
467 /* Drop the share count on the page table */
468 PointerPde = MiPteToPde(PointerPte);
470 PointerPde->u.Hard.PageFrameNumber);
471
472 /* Drop the share count */
473 MiDecrementShareCount(Pfn1, PageFrameIndex);
474
475 /* Either a fork, or this is the shared user data page */
476 if ((PointerPte <= MiHighestUserPte) && (PrototypePte != Pfn1->PteAddress))
477 {
478 /* If it's not the shared user page, then crash, since there's no fork() yet */
481 {
482 /* Must be some sort of memory corruption */
483 KeBugCheckEx(MEMORY_MANAGEMENT,
484 0x400,
485 (ULONG_PTR)PointerPte,
487 (ULONG_PTR)Pfn1->PteAddress);
488 }
489 }
490
491 /* Erase it */
492 MI_ERASE_PTE(PointerPte);
493 }
494 else
495 {
496 /* Make sure the saved PTE address is valid */
497 if ((PMMPTE)((ULONG_PTR)Pfn1->PteAddress & ~0x1) != PointerPte)
498 {
499 /* The PFN entry is illegal, or invalid */
500 KeBugCheckEx(MEMORY_MANAGEMENT,
501 0x401,
502 (ULONG_PTR)PointerPte,
503 PointerPte->u.Long,
504 (ULONG_PTR)Pfn1->PteAddress);
505 }
506
507 /* Erase the PTE */
508 MI_ERASE_PTE(PointerPte);
509
510 /* There should only be 1 shared reference count */
511 ASSERT(Pfn1->u2.ShareCount == 1);
512
513 /* Drop the reference on the page table. */
515
516 /* Mark the PFN for deletion and dereference what should be the last ref */
517 MI_SET_PFN_DELETED(Pfn1);
518 MiDecrementShareCount(Pfn1, PageFrameIndex);
519
520 /* We should eventually do this */
521 //CurrentProcess->NumberOfPrivatePages--;
522 }
523
524 /* Flush the TLB */
526}
527
528VOID
529NTAPI
531 _In_ ULONG_PTR Va,
532 _In_ ULONG_PTR EndingAddress,
533 _In_opt_ PMMVAD Vad)
534{
535 PMMPTE PointerPte, PrototypePte, LastPrototypePte;
536 PMMPDE PointerPde;
537#if (_MI_PAGING_LEVELS >= 3)
538 PMMPPE PointerPpe;
539#endif
540#if (_MI_PAGING_LEVELS >= 4)
541 PMMPPE PointerPxe;
542#endif
544 PEPROCESS CurrentProcess;
546 BOOLEAN AddressGap = FALSE;
547 PSUBSECTION Subsection;
548
549 /* We should never get RosMm memory areas here */
550 ASSERT((Vad == NULL) || !MI_IS_MEMORY_AREA_VAD(Vad));
551
552 /* Get the current process */
553 CurrentProcess = PsGetCurrentProcess();
554
555 /* Check if this is a section VAD or a VM VAD */
556 if (!(Vad) || (Vad->u.VadFlags.PrivateMemory) || !(Vad->FirstPrototypePte))
557 {
558 /* Don't worry about prototypes */
559 PrototypePte = LastPrototypePte = NULL;
560 }
561 else
562 {
563 /* Get the prototype PTE */
564 PrototypePte = Vad->FirstPrototypePte;
565 LastPrototypePte = Vad->FirstPrototypePte + 1;
566 }
567
568 /* In all cases, we don't support fork() yet */
569 ASSERT(CurrentProcess->CloneRoot == NULL);
570
571 /* Loop the PTE for each VA (EndingAddress is inclusive!) */
572 while (Va <= EndingAddress)
573 {
574#if (_MI_PAGING_LEVELS >= 4)
575 /* Get the PXE and check if it's valid */
576 PointerPxe = MiAddressToPxe((PVOID)Va);
577 if (!PointerPxe->u.Hard.Valid)
578 {
579 /* Check for unmapped range and skip it */
580 if (!PointerPxe->u.Long)
581 {
582 /* There are gaps in the address space */
583 AddressGap = TRUE;
584
585 /* Update Va and continue looping */
586 Va = (ULONG_PTR)MiPxeToAddress(PointerPxe + 1);
587 continue;
588 }
589
590 /* Make the PXE valid */
591 MiMakeSystemAddressValid(MiPteToAddress(PointerPxe), CurrentProcess);
592 }
593#endif
594#if (_MI_PAGING_LEVELS >= 3)
595 /* Get the PPE and check if it's valid */
596 PointerPpe = MiAddressToPpe((PVOID)Va);
597 if (!PointerPpe->u.Hard.Valid)
598 {
599 /* Check for unmapped range and skip it */
600 if (!PointerPpe->u.Long)
601 {
602 /* There are gaps in the address space */
603 AddressGap = TRUE;
604
605 /* Update Va and continue looping */
606 Va = (ULONG_PTR)MiPpeToAddress(PointerPpe + 1);
607 continue;
608 }
609
610 /* Make the PPE valid */
611 MiMakeSystemAddressValid(MiPteToAddress(PointerPpe), CurrentProcess);
612 }
613#endif
614 /* Skip invalid PDEs */
615 PointerPde = MiAddressToPde((PVOID)Va);
616 if (!PointerPde->u.Long)
617 {
618 /* There are gaps in the address space */
619 AddressGap = TRUE;
620
621 /* Check if all the PDEs are invalid, so there's nothing to free */
622 Va = (ULONG_PTR)MiPdeToAddress(PointerPde + 1);
623 continue;
624 }
625
626 /* Now check if the PDE is mapped in */
627 if (!PointerPde->u.Hard.Valid)
628 {
629 /* It isn't, so map it in */
630 PointerPte = MiPteToAddress(PointerPde);
631 MiMakeSystemAddressValid(PointerPte, CurrentProcess);
632 }
633
634 /* Now we should have a valid PDE, mapped in, and still have some VA */
635 ASSERT(PointerPde->u.Hard.Valid == 1);
636 ASSERT(Va <= EndingAddress);
637
638 /* Check if this is a section VAD with gaps in it */
639 if ((AddressGap) && (LastPrototypePte))
640 {
641 /* We need to skip to the next correct prototype PTE */
643
644 /* And we need the subsection to skip to the next last prototype PTE */
645 Subsection = MiLocateSubsection(Vad, Va >> PAGE_SHIFT);
646 if (Subsection)
647 {
648 /* Found it! */
649 LastPrototypePte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
650 }
651 else
652 {
653 /* No more subsections, we are done with prototype PTEs */
655 }
656 }
657
658 /* Lock the PFN Database while we delete the PTEs */
659 OldIrql = MiAcquirePfnLock();
660 PointerPte = MiAddressToPte(Va);
661 do
662 {
663 /* Making sure the PDE is still valid */
664 ASSERT(PointerPde->u.Hard.Valid == 1);
665
666 /* Capture the PDE and make sure it exists */
667 TempPte = *PointerPte;
668 if (TempPte.u.Long)
669 {
670 /* Check if the PTE is actually mapped in */
672 {
673 /* Are we dealing with section VAD? */
674 if ((LastPrototypePte) && (PrototypePte > LastPrototypePte))
675 {
676 /* We need to skip to the next correct prototype PTE */
678
679 /* And we need the subsection to skip to the next last prototype PTE */
680 Subsection = MiLocateSubsection(Vad, Va >> PAGE_SHIFT);
681 if (Subsection)
682 {
683 /* Found it! */
684 LastPrototypePte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
685 }
686 else
687 {
688 /* No more subsections, we are done with prototype PTEs */
690 }
691 }
692
693 /* Check for prototype PTE */
694 if ((TempPte.u.Hard.Valid == 0) &&
695 (TempPte.u.Soft.Prototype == 1))
696 {
697 /* Just nuke it */
698 MI_ERASE_PTE(PointerPte);
699 }
700 else
701 {
702 /* Delete the PTE proper */
703 MiDeletePte(PointerPte,
704 (PVOID)Va,
705 CurrentProcess,
707 }
708 }
709 else
710 {
711 /* The PTE was never mapped, just nuke it here */
712 MI_ERASE_PTE(PointerPte);
713 }
714
716 {
717 ASSERT(PointerPde->u.Long != 0);
718
719 /* Delete the PDE proper */
720 MiDeletePde(PointerPde, CurrentProcess);
721
722 /* Continue with the next PDE */
723 Va = (ULONG_PTR)MiPdeToAddress(PointerPde + 1);
724
725 /* Use this to detect address gaps */
726 PointerPte++;
727
728 PrototypePte++;
729 break;
730 }
731 }
732
733 /* Update the address and PTE for it */
734 Va += PAGE_SIZE;
735 PointerPte++;
736 PrototypePte++;
737 } while ((Va & (PDE_MAPPED_VA - 1)) && (Va <= EndingAddress));
738
739 /* Release the lock */
740 MiReleasePfnLock(OldIrql);
741
742 if (Va > EndingAddress) return;
743
744 /* Check if we exited the loop regularly */
745 AddressGap = (PointerPte != MiAddressToPte(Va));
746 }
747}
748
749LONG
751 OUT PBOOLEAN HaveBadAddress,
752 OUT PULONG_PTR BadAddress)
753{
754 PEXCEPTION_RECORD ExceptionRecord;
755 PAGED_CODE();
756
757 //
758 // Assume default
759 //
760 *HaveBadAddress = FALSE;
761
762 //
763 // Get the exception record
764 //
765 ExceptionRecord = ExceptionInfo->ExceptionRecord;
766
767 //
768 // Look at the exception code
769 //
770 if ((ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
771 (ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
772 (ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR))
773 {
774 //
775 // We can tell the address if we have more than one parameter
776 //
777 if (ExceptionRecord->NumberParameters > 1)
778 {
779 //
780 // Return the address
781 //
782 *HaveBadAddress = TRUE;
783 *BadAddress = ExceptionRecord->ExceptionInformation[1];
784 }
785 }
786
787 //
788 // Continue executing the next handler
789 //
791}
792
794NTAPI
797 IN PEPROCESS TargetProcess,
801 OUT PSIZE_T ReturnSize)
802{
803 PFN_NUMBER MdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + MI_MAPPED_COPY_PAGES + 1];
804 PMDL Mdl = (PMDL)MdlBuffer;
805 SIZE_T TotalSize, CurrentSize, RemainingSize;
806 volatile BOOLEAN FailedInProbe = FALSE;
807 volatile BOOLEAN PagesLocked = FALSE;
808 PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
809 volatile PVOID MdlAddress = NULL;
811 BOOLEAN HaveBadAddress;
812 ULONG_PTR BadAddress;
814 PAGED_CODE();
815
816 //
817 // Calculate the maximum amount of data to move
818 //
819 TotalSize = MI_MAPPED_COPY_PAGES * PAGE_SIZE;
820 if (BufferSize <= TotalSize) TotalSize = BufferSize;
821 CurrentSize = TotalSize;
822 RemainingSize = BufferSize;
823
824 //
825 // Loop as long as there is still data
826 //
827 while (RemainingSize > 0)
828 {
829 //
830 // Check if this transfer will finish everything off
831 //
832 if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
833
834 //
835 // Attach to the source address space
836 //
837 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
838
839 //
840 // Check state for this pass
841 //
842 ASSERT(MdlAddress == NULL);
843 ASSERT(PagesLocked == FALSE);
844 ASSERT(FailedInProbe == FALSE);
845
846 //
847 // Protect user-mode copy
848 //
850 {
851 //
852 // If this is our first time, probe the buffer
853 //
854 if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
855 {
856 //
857 // Catch a failure here
858 //
859 FailedInProbe = TRUE;
860
861 //
862 // Do the probe
863 //
865
866 //
867 // Passed
868 //
869 FailedInProbe = FALSE;
870 }
871
872 //
873 // Initialize and probe and lock the MDL
874 //
875 MmInitializeMdl(Mdl, CurrentAddress, CurrentSize);
877 PagesLocked = TRUE;
878 }
880 {
882 }
884
885 /* Detach from source process */
887
888 if (Status != STATUS_SUCCESS)
889 {
890 goto Exit;
891 }
892
893 //
894 // Now map the pages
895 //
898 MmCached,
899 NULL,
900 FALSE,
902 if (!MdlAddress)
903 {
905 goto Exit;
906 }
907
908 //
909 // Grab to the target process
910 //
911 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
912
914 {
915 //
916 // Check if this is our first time through
917 //
918 if ((CurrentTargetAddress == TargetAddress) && (PreviousMode != KernelMode))
919 {
920 //
921 // Catch a failure here
922 //
923 FailedInProbe = TRUE;
924
925 //
926 // Do the probe
927 //
929
930 //
931 // Passed
932 //
933 FailedInProbe = FALSE;
934 }
935
936 //
937 // Now do the actual move
938 //
939 RtlCopyMemory(CurrentTargetAddress, MdlAddress, CurrentSize);
940 }
942 &HaveBadAddress,
943 &BadAddress))
944 {
945 *ReturnSize = BufferSize - RemainingSize;
946 //
947 // Check if we failed during the probe
948 //
949 if (FailedInProbe)
950 {
951 //
952 // Exit
953 //
955 }
956 else
957 {
958 //
959 // Othewise we failed during the move.
960 // Check if we know exactly where we stopped copying
961 //
962 if (HaveBadAddress)
963 {
964 //
965 // Return the exact number of bytes copied
966 //
967 *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
968 }
969 //
970 // Return partial copy
971 //
973 }
974 }
975 _SEH2_END;
976
977 /* Detach from target process */
979
980 //
981 // Check for SEH status
982 //
983 if (Status != STATUS_SUCCESS)
984 {
985 goto Exit;
986 }
987
988 //
989 // Unmap and unlock
990 //
991 MmUnmapLockedPages(MdlAddress, Mdl);
992 MdlAddress = NULL;
994 PagesLocked = FALSE;
995
996 //
997 // Update location and size
998 //
999 RemainingSize -= CurrentSize;
1000 CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
1001 CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize);
1002 }
1003
1004Exit:
1005 if (MdlAddress != NULL)
1006 MmUnmapLockedPages(MdlAddress, Mdl);
1007 if (PagesLocked)
1009
1010 //
1011 // All bytes read
1012 //
1013 if (Status == STATUS_SUCCESS)
1014 *ReturnSize = BufferSize;
1015 return Status;
1016}
1017
1019NTAPI
1022 IN PEPROCESS TargetProcess,
1026 OUT PSIZE_T ReturnSize)
1027{
1028 UCHAR StackBuffer[MI_POOL_COPY_BYTES];
1029 SIZE_T TotalSize, CurrentSize, RemainingSize;
1030 volatile BOOLEAN FailedInProbe = FALSE, HavePoolAddress = FALSE;
1031 PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
1032 PVOID PoolAddress;
1034 BOOLEAN HaveBadAddress;
1035 ULONG_PTR BadAddress;
1037 PAGED_CODE();
1038
1039 DPRINT("Copying %Iu bytes from process %p (address %p) to process %p (Address %p)\n",
1040 BufferSize, SourceProcess, SourceAddress, TargetProcess, TargetAddress);
1041
1042 //
1043 // Calculate the maximum amount of data to move
1044 //
1045 TotalSize = MI_MAX_TRANSFER_SIZE;
1046 if (BufferSize <= MI_MAX_TRANSFER_SIZE) TotalSize = BufferSize;
1047 CurrentSize = TotalSize;
1048 RemainingSize = BufferSize;
1049
1050 //
1051 // Check if we can use the stack
1052 //
1054 {
1055 //
1056 // Use it
1057 //
1058 PoolAddress = (PVOID)StackBuffer;
1059 }
1060 else
1061 {
1062 //
1063 // Allocate pool
1064 //
1065 PoolAddress = ExAllocatePoolWithTag(NonPagedPool, TotalSize, 'VmRw');
1066 if (!PoolAddress) ASSERT(FALSE);
1067 HavePoolAddress = TRUE;
1068 }
1069
1070 //
1071 // Loop as long as there is still data
1072 //
1073 while (RemainingSize > 0)
1074 {
1075 //
1076 // Check if this transfer will finish everything off
1077 //
1078 if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
1079
1080 //
1081 // Attach to the source address space
1082 //
1083 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
1084
1085 /* Check that state is sane */
1086 ASSERT(FailedInProbe == FALSE);
1088
1089 //
1090 // Protect user-mode copy
1091 //
1092 _SEH2_TRY
1093 {
1094 //
1095 // If this is our first time, probe the buffer
1096 //
1097 if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
1098 {
1099 //
1100 // Catch a failure here
1101 //
1102 FailedInProbe = TRUE;
1103
1104 //
1105 // Do the probe
1106 //
1108
1109 //
1110 // Passed
1111 //
1112 FailedInProbe = FALSE;
1113 }
1114
1115 //
1116 // Do the copy
1117 //
1118 RtlCopyMemory(PoolAddress, CurrentAddress, CurrentSize);
1119 }
1121 &HaveBadAddress,
1122 &BadAddress))
1123 {
1124 *ReturnSize = BufferSize - RemainingSize;
1125
1126 //
1127 // Check if we failed during the probe
1128 //
1129 if (FailedInProbe)
1130 {
1131 //
1132 // Exit
1133 //
1135 }
1136 else
1137 {
1138 //
1139 // We failed during the move.
1140 // Check if we know exactly where we stopped copying
1141 //
1142 if (HaveBadAddress)
1143 {
1144 //
1145 // Return the exact number of bytes copied
1146 //
1147 *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
1148 }
1149 //
1150 // Return partial copy
1151 //
1153 }
1154 }
1155 _SEH2_END
1156
1157 /* Let go of the source */
1159
1160 if (Status != STATUS_SUCCESS)
1161 {
1162 goto Exit;
1163 }
1164
1165 /* Grab the target process */
1166 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
1167
1168 _SEH2_TRY
1169 {
1170 //
1171 // Check if this is our first time through
1172 //
1173 if ((CurrentTargetAddress == TargetAddress) && (PreviousMode != KernelMode))
1174 {
1175 //
1176 // Catch a failure here
1177 //
1178 FailedInProbe = TRUE;
1179
1180 //
1181 // Do the probe
1182 //
1184
1185 //
1186 // Passed
1187 //
1188 FailedInProbe = FALSE;
1189 }
1190
1191 //
1192 // Now do the actual move
1193 //
1194 RtlCopyMemory(CurrentTargetAddress, PoolAddress, CurrentSize);
1195 }
1197 &HaveBadAddress,
1198 &BadAddress))
1199 {
1200 *ReturnSize = BufferSize - RemainingSize;
1201 //
1202 // Check if we failed during the probe
1203 //
1204 if (FailedInProbe)
1205 {
1206 //
1207 // Exit
1208 //
1210 }
1211 else
1212 {
1213 //
1214 // Otherwise we failed during the move.
1215 // Check if we know exactly where we stopped copying
1216 //
1217 if (HaveBadAddress)
1218 {
1219 //
1220 // Return the exact number of bytes copied
1221 //
1222 *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
1223 }
1224 //
1225 // Return partial copy
1226 //
1228 }
1229 }
1230 _SEH2_END;
1231
1232 //
1233 // Detach from target
1234 //
1236
1237 //
1238 // Check for SEH status
1239 //
1240 if (Status != STATUS_SUCCESS)
1241 {
1242 goto Exit;
1243 }
1244
1245 //
1246 // Update location and size
1247 //
1248 RemainingSize -= CurrentSize;
1249 CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
1250 CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress +
1251 CurrentSize);
1252 }
1253
1254Exit:
1255 //
1256 // Check if we had allocated pool
1257 //
1258 if (HavePoolAddress)
1259 ExFreePoolWithTag(PoolAddress, 'VmRw');
1260
1261 //
1262 // All bytes read
1263 //
1264 if (Status == STATUS_SUCCESS)
1265 *ReturnSize = BufferSize;
1266 return Status;
1267}
1268
1270NTAPI
1273 IN PEPROCESS TargetProcess,
1277 OUT PSIZE_T ReturnSize)
1278{
1280 PEPROCESS Process = SourceProcess;
1281
1282 //
1283 // Don't accept zero-sized buffers
1284 //
1285 if (!BufferSize) return STATUS_SUCCESS;
1286
1287 //
1288 // If we are copying from ourselves, lock the target instead
1289 //
1290 if (SourceProcess == PsGetCurrentProcess()) Process = TargetProcess;
1291
1292 //
1293 // Acquire rundown protection
1294 //
1295 if (!ExAcquireRundownProtection(&Process->RundownProtect))
1296 {
1297 //
1298 // Fail
1299 //
1301 }
1302
1303 //
1304 // See if we should use the pool copy
1305 //
1307 {
1308 //
1309 // Use MDL-copy
1310 //
1311 Status = MiDoMappedCopy(SourceProcess,
1313 TargetProcess,
1315 BufferSize,
1317 ReturnSize);
1318 }
1319 else
1320 {
1321 //
1322 // Do pool copy
1323 //
1324 Status = MiDoPoolCopy(SourceProcess,
1326 TargetProcess,
1328 BufferSize,
1330 ReturnSize);
1331 }
1332
1333 //
1334 // Release the lock
1335 //
1336 ExReleaseRundownProtection(&Process->RundownProtect);
1337 return Status;
1338}
1339
1341NTAPI
1346{
1347 PAGED_CODE();
1348
1350
1351 // Report actual state.
1354
1355 // Pretend success.
1356 return STATUS_SUCCESS; // STATUS_NOT_IMPLEMENTED
1357}
1358
1359ULONG
1360NTAPI
1362{
1363 MMPTE TempPte;
1364 PMMPFN Pfn;
1365 PEPROCESS CurrentProcess;
1366 PETHREAD CurrentThread;
1367 BOOLEAN WsSafe, WsShared;
1368 ULONG Protect;
1369 KIRQL OldIrql;
1370 PAGED_CODE();
1371
1372 /* Copy this PTE's contents */
1373 TempPte = *PointerPte;
1374
1375 /* Assure it's not totally zero */
1376 ASSERT(TempPte.u.Long);
1377
1378 /* Check for a special prototype format */
1379 if ((TempPte.u.Soft.Valid == 0) &&
1380 (TempPte.u.Soft.Prototype == 1))
1381 {
1382 /* Check if the prototype PTE is not yet pointing to a PTE */
1383 if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
1384 {
1385 /* The prototype PTE contains the protection */
1386 return MmProtectToValue[TempPte.u.Soft.Protection];
1387 }
1388
1389 /* Get a pointer to the underlying shared PTE */
1390 PointerPte = MiProtoPteToPte(&TempPte);
1391
1392 /* Since the PTE we want to read can be paged out at any time, we need
1393 to release the working set lock first, so that it can be paged in */
1394 CurrentThread = PsGetCurrentThread();
1395 CurrentProcess = PsGetCurrentProcess();
1396 MiUnlockProcessWorkingSetForFault(CurrentProcess,
1397 CurrentThread,
1398 &WsSafe,
1399 &WsShared);
1400
1401 /* Now read the PTE value */
1402 TempPte = *PointerPte;
1403
1404 /* Check if that one is invalid */
1405 if (!TempPte.u.Hard.Valid)
1406 {
1407 /* We get the protection directly from this PTE */
1408 Protect = MmProtectToValue[TempPte.u.Soft.Protection];
1409 }
1410 else
1411 {
1412 /* The PTE is valid, so we might need to get the protection from
1413 the PFN. Lock the PFN database */
1414 OldIrql = MiAcquirePfnLock();
1415
1416 /* Check if the PDE is still valid */
1417 if (MiAddressToPte(PointerPte)->u.Hard.Valid == 0)
1418 {
1419 /* It's not, make it valid */
1421 }
1422
1423 /* Now it's safe to read the PTE value again */
1424 TempPte = *PointerPte;
1425 ASSERT(TempPte.u.Long != 0);
1426
1427 /* Check again if the PTE is invalid */
1428 if (!TempPte.u.Hard.Valid)
1429 {
1430 /* The PTE is not valid, so we can use it's protection field */
1431 Protect = MmProtectToValue[TempPte.u.Soft.Protection];
1432 }
1433 else
1434 {
1435 /* The PTE is valid, so we can find the protection in the
1436 OriginalPte field of the PFN */
1439 }
1440
1441 /* Release the PFN database */
1442 MiReleasePfnLock(OldIrql);
1443 }
1444
1445 /* Lock the working set again */
1446 MiLockProcessWorkingSetForFault(CurrentProcess,
1447 CurrentThread,
1448 WsSafe,
1449 WsShared);
1450
1451 return Protect;
1452 }
1453
1454 /* In the easy case of transition or demand zero PTE just return its protection */
1455 if (!TempPte.u.Hard.Valid) return MmProtectToValue[TempPte.u.Soft.Protection];
1456
1457 /* If we get here, the PTE is valid, so look up the page in PFN database */
1459 if (!Pfn->u3.e1.PrototypePte)
1460 {
1461 /* Return protection of the original pte */
1462 ASSERT(Pfn->u4.AweAllocation == 0);
1464 }
1465
1466 /* This is software PTE */
1467 DPRINT("Prototype PTE: %lx %p\n", TempPte.u.Hard.PageFrameNumber, Pfn);
1468 DPRINT("VA: %p\n", MiPteToAddress(&TempPte));
1469 DPRINT("Mask: %lx\n", TempPte.u.Soft.Protection);
1470 DPRINT("Mask2: %lx\n", Pfn->OriginalPte.u.Soft.Protection);
1471 return MmProtectToValue[TempPte.u.Soft.Protection];
1472}
1473
1474ULONG
1475NTAPI
1477 IN PMMVAD Vad,
1478 IN PEPROCESS TargetProcess,
1479 OUT PULONG ReturnedProtect,
1480 OUT PVOID *NextVa)
1481{
1482
1483 PMMPTE PointerPte, ProtoPte;
1484 PMMPDE PointerPde;
1485#if (_MI_PAGING_LEVELS >= 3)
1486 PMMPPE PointerPpe;
1487#endif
1488#if (_MI_PAGING_LEVELS >= 4)
1489 PMMPXE PointerPxe;
1490#endif
1491 MMPTE TempPte, TempProtoPte;
1492 BOOLEAN DemandZeroPte = TRUE, ValidPte = FALSE;
1494 ASSERT((Vad->StartingVpn <= ((ULONG_PTR)Va >> PAGE_SHIFT)) &&
1495 (Vad->EndingVpn >= ((ULONG_PTR)Va >> PAGE_SHIFT)));
1496
1497 /* Only normal VADs supported */
1498 ASSERT(Vad->u.VadFlags.VadType == VadNone);
1499
1500 /* Get the PDE and PTE for the address */
1501 PointerPde = MiAddressToPde(Va);
1502 PointerPte = MiAddressToPte(Va);
1503#if (_MI_PAGING_LEVELS >= 3)
1504 PointerPpe = MiAddressToPpe(Va);
1505#endif
1506#if (_MI_PAGING_LEVELS >= 4)
1507 PointerPxe = MiAddressToPxe(Va);
1508#endif
1509
1510 /* Return the next range */
1511 *NextVa = (PVOID)((ULONG_PTR)Va + PAGE_SIZE);
1512
1513 do
1514 {
1515#if (_MI_PAGING_LEVELS >= 4)
1516 /* Does the PXE exist? */
1517 if (PointerPxe->u.Long == 0)
1518 {
1519 /* It does not, next range starts at the next PXE */
1520 *NextVa = MiPxeToAddress(PointerPxe + 1);
1521 break;
1522 }
1523
1524 /* Is the PXE valid? */
1525 if (PointerPxe->u.Hard.Valid == 0)
1526 {
1527 /* Is isn't, fault it in (make the PPE accessible) */
1528 MiMakeSystemAddressValid(PointerPpe, TargetProcess);
1529 }
1530#endif
1531#if (_MI_PAGING_LEVELS >= 3)
1532 /* Does the PPE exist? */
1533 if (PointerPpe->u.Long == 0)
1534 {
1535 /* It does not, next range starts at the next PPE */
1536 *NextVa = MiPpeToAddress(PointerPpe + 1);
1537 break;
1538 }
1539
1540 /* Is the PPE valid? */
1541 if (PointerPpe->u.Hard.Valid == 0)
1542 {
1543 /* Is isn't, fault it in (make the PDE accessible) */
1544 MiMakeSystemAddressValid(PointerPde, TargetProcess);
1545 }
1546#endif
1547
1548 /* Does the PDE exist? */
1549 if (PointerPde->u.Long == 0)
1550 {
1551 /* It does not, next range starts at the next PDE */
1552 *NextVa = MiPdeToAddress(PointerPde + 1);
1553 break;
1554 }
1555
1556 /* Is the PDE valid? */
1557 if (PointerPde->u.Hard.Valid == 0)
1558 {
1559 /* Is isn't, fault it in (make the PTE accessible) */
1560 MiMakeSystemAddressValid(PointerPte, TargetProcess);
1561 }
1562
1563 /* We have a PTE that we can access now! */
1564 ValidPte = TRUE;
1565
1566 } while (FALSE);
1567
1568 /* Is it safe to try reading the PTE? */
1569 if (ValidPte)
1570 {
1571 /* FIXME: watch out for large pages */
1572 ASSERT(PointerPde->u.Hard.LargePage == FALSE);
1573
1574 /* Capture the PTE */
1575 TempPte = *PointerPte;
1576 if (TempPte.u.Long != 0)
1577 {
1578 /* The PTE is valid, so it's not zeroed out */
1580
1581 /* Is it a decommited, invalid, or faulted PTE? */
1582 if ((TempPte.u.Soft.Protection == MM_DECOMMIT) &&
1583 (TempPte.u.Hard.Valid == 0) &&
1584 ((TempPte.u.Soft.Prototype == 0) ||
1585 (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)))
1586 {
1587 /* Otherwise our defaults should hold */
1588 ASSERT(Protect == 0);
1590 }
1591 else
1592 {
1593 /* This means it's committed */
1594 State = MEM_COMMIT;
1595
1596 /* We don't support these */
1597 ASSERT(Vad->u.VadFlags.VadType != VadDevicePhysicalMemory);
1598 ASSERT(Vad->u.VadFlags.VadType != VadRotatePhysical);
1599 ASSERT(Vad->u.VadFlags.VadType != VadAwe);
1600
1601 /* Get protection state of this page */
1602 Protect = MiGetPageProtection(PointerPte);
1603
1604 /* Check if this is an image-backed VAD */
1605 if ((TempPte.u.Soft.Valid == 0) &&
1606 (TempPte.u.Soft.Prototype == 1) &&
1607 (Vad->u.VadFlags.PrivateMemory == 0) &&
1608 (Vad->ControlArea))
1609 {
1610 DPRINT1("Not supported\n");
1611 ASSERT(FALSE);
1612 }
1613 }
1614 }
1615 }
1616
1617 /* Check if this was a demand-zero PTE, since we need to find the state */
1618 if (DemandZeroPte)
1619 {
1620 /* Not yet handled */
1621 ASSERT(Vad->u.VadFlags.VadType != VadDevicePhysicalMemory);
1622 ASSERT(Vad->u.VadFlags.VadType != VadAwe);
1623
1624 /* Check if this is private commited memory, or an section-backed VAD */
1625 if ((Vad->u.VadFlags.PrivateMemory == 0) && (Vad->ControlArea))
1626 {
1627 /* Tell caller about the next range */
1628 *NextVa = (PVOID)((ULONG_PTR)Va + PAGE_SIZE);
1629
1630 /* Get the prototype PTE for this VAD */
1631 ProtoPte = MI_GET_PROTOTYPE_PTE_FOR_VPN(Vad,
1632 (ULONG_PTR)Va >> PAGE_SHIFT);
1633 if (ProtoPte)
1634 {
1635 /* We should unlock the working set, but it's not being held! */
1636
1637 /* Is the prototype PTE actually valid (committed)? */
1638 TempProtoPte = *ProtoPte;
1639 if (TempProtoPte.u.Long)
1640 {
1641 /* Unless this is a memory-mapped file, handle it like private VAD */
1642 State = MEM_COMMIT;
1643 ASSERT(Vad->u.VadFlags.VadType != VadImageMap);
1644 Protect = MmProtectToValue[Vad->u.VadFlags.Protection];
1645 }
1646
1647 /* We should re-lock the working set */
1648 }
1649 }
1650 else if (Vad->u.VadFlags.MemCommit)
1651 {
1652 /* This is committed memory */
1653 State = MEM_COMMIT;
1654
1655 /* Convert the protection */
1656 Protect = MmProtectToValue[Vad->u.VadFlags.Protection];
1657 }
1658 }
1659
1660 /* Return the protection code */
1661 *ReturnedProtect = Protect;
1662 return State;
1663}
1664
1666NTAPI
1669 OUT PVOID MemoryInformation,
1670 IN SIZE_T MemoryInformationLength,
1672{
1673 PEPROCESS TargetProcess;
1675 PMMVAD Vad = NULL;
1676 PVOID Address, NextAddress;
1678 ULONG NewProtect, NewState;
1679 ULONG_PTR BaseVpn;
1680 MEMORY_BASIC_INFORMATION MemoryInfo;
1684
1685 /* Check for illegal addresses in user-space, or the shared memory area */
1688 {
1690
1691 /* Make up an info structure describing this range */
1692 MemoryInfo.BaseAddress = Address;
1693 MemoryInfo.AllocationProtect = PAGE_READONLY;
1694 MemoryInfo.Type = MEM_PRIVATE;
1695
1696 /* Special case for shared data */
1698 {
1700 MemoryInfo.State = MEM_COMMIT;
1701 MemoryInfo.Protect = PAGE_READONLY;
1702 MemoryInfo.RegionSize = PAGE_SIZE;
1703 }
1704 else
1705 {
1707 MemoryInfo.State = MEM_RESERVE;
1708 MemoryInfo.Protect = PAGE_NOACCESS;
1710 }
1711
1712 /* Return the data, NtQueryInformation already probed it*/
1713 if (PreviousMode != KernelMode)
1714 {
1715 _SEH2_TRY
1716 {
1717 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1719 }
1721 {
1723 }
1724 _SEH2_END;
1725 }
1726 else
1727 {
1728 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1730 }
1731
1732 return Status;
1733 }
1734
1735 /* Check if this is for a local or remote process */
1737 {
1738 TargetProcess = PsGetCurrentProcess();
1739 }
1740 else
1741 {
1742 /* Reference the target process */
1747 (PVOID*)&TargetProcess,
1748 NULL);
1749 if (!NT_SUCCESS(Status)) return Status;
1750
1751 /* Attach to it now */
1752 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
1753 }
1754
1755 /* Lock the address space and make sure the process isn't already dead */
1756 MmLockAddressSpace(&TargetProcess->Vm);
1757 if (TargetProcess->VmDeleted)
1758 {
1759 /* Unlock the address space of the process */
1760 MmUnlockAddressSpace(&TargetProcess->Vm);
1761
1762 /* Check if we were attached */
1764 {
1765 /* Detach and dereference the process */
1767 ObDereferenceObject(TargetProcess);
1768 }
1769
1770 /* Bail out */
1771 DPRINT1("Process is dying\n");
1773 }
1774
1775 /* Loop the VADs */
1777 if (TargetProcess->VadRoot.NumberGenericTableElements)
1778 {
1779 /* Scan on the right */
1780 Vad = (PMMVAD)TargetProcess->VadRoot.BalancedRoot.RightChild;
1781 BaseVpn = (ULONG_PTR)BaseAddress >> PAGE_SHIFT;
1782 while (Vad)
1783 {
1784 /* Check if this VAD covers the allocation range */
1785 if ((BaseVpn >= Vad->StartingVpn) &&
1786 (BaseVpn <= Vad->EndingVpn))
1787 {
1788 /* We're done */
1789 Found = TRUE;
1790 break;
1791 }
1792
1793 /* Check if this VAD is too high */
1794 if (BaseVpn < Vad->StartingVpn)
1795 {
1796 /* Stop if there is no left child */
1797 if (!Vad->LeftChild) break;
1798
1799 /* Search on the left next */
1800 Vad = Vad->LeftChild;
1801 }
1802 else
1803 {
1804 /* Then this VAD is too low, keep searching on the right */
1805 ASSERT(BaseVpn > Vad->EndingVpn);
1806
1807 /* Stop if there is no right child */
1808 if (!Vad->RightChild) break;
1809
1810 /* Search on the right next */
1811 Vad = Vad->RightChild;
1812 }
1813 }
1814 }
1815
1816 /* Was a VAD found? */
1817 if (!Found)
1818 {
1820
1821 /* Calculate region size */
1822 if (Vad)
1823 {
1824 if (Vad->StartingVpn >= BaseVpn)
1825 {
1826 /* Region size is the free space till the start of that VAD */
1827 MemoryInfo.RegionSize = (ULONG_PTR)(Vad->StartingVpn << PAGE_SHIFT) - (ULONG_PTR)Address;
1828 }
1829 else
1830 {
1831 /* Get the next VAD */
1833 if (Vad)
1834 {
1835 /* Region size is the free space till the start of that VAD */
1836 MemoryInfo.RegionSize = (ULONG_PTR)(Vad->StartingVpn << PAGE_SHIFT) - (ULONG_PTR)Address;
1837 }
1838 else
1839 {
1840 /* Maximum possible region size with that base address */
1842 }
1843 }
1844 }
1845 else
1846 {
1847 /* Maximum possible region size with that base address */
1849 }
1850
1851 /* Unlock the address space of the process */
1852 MmUnlockAddressSpace(&TargetProcess->Vm);
1853
1854 /* Check if we were attached */
1856 {
1857 /* Detach and dereference the process */
1859 ObDereferenceObject(TargetProcess);
1860 }
1861
1862 /* Build the rest of the initial information block */
1863 MemoryInfo.BaseAddress = Address;
1864 MemoryInfo.AllocationBase = NULL;
1865 MemoryInfo.AllocationProtect = 0;
1866 MemoryInfo.State = MEM_FREE;
1867 MemoryInfo.Protect = PAGE_NOACCESS;
1868 MemoryInfo.Type = 0;
1869
1870 /* Return the data, NtQueryInformation already probed it*/
1871 if (PreviousMode != KernelMode)
1872 {
1873 _SEH2_TRY
1874 {
1875 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1877 }
1879 {
1881 }
1882 _SEH2_END;
1883 }
1884 else
1885 {
1886 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1888 }
1889
1890 return Status;
1891 }
1892
1893 /* Set the correct memory type based on what kind of VAD this is */
1894 if ((Vad->u.VadFlags.PrivateMemory) ||
1896 {
1897 MemoryInfo.Type = MEM_PRIVATE;
1898 }
1899 else if (Vad->u.VadFlags.VadType == VadImageMap)
1900 {
1901 MemoryInfo.Type = MEM_IMAGE;
1902 }
1903 else
1904 {
1905 MemoryInfo.Type = MEM_MAPPED;
1906 }
1907
1908 /* Check if this is a RosMM VAD */
1909 if (MI_IS_ROSMM_VAD(Vad))
1910 {
1913 if (!NT_SUCCESS(Status))
1914 {
1915 DPRINT1("MmQuerySectionView failed. MemoryArea=%p (%p-%p), BaseAddress=%p\n",
1916 Vad, Vad->StartingVpn, Vad->EndingVpn, BaseAddress);
1918 }
1919 }
1920 else
1921 {
1922 /* Build the initial information block */
1924 MemoryInfo.BaseAddress = Address;
1925 MemoryInfo.AllocationBase = (PVOID)(Vad->StartingVpn << PAGE_SHIFT);
1927 MemoryInfo.Type = MEM_PRIVATE;
1928
1929 /* Acquire the working set lock (shared is enough) */
1931
1932 /* Find the largest chunk of memory which has the same state and protection mask */
1933 MemoryInfo.State = MiQueryAddressState(Address,
1934 Vad,
1935 TargetProcess,
1936 &MemoryInfo.Protect,
1937 &NextAddress);
1938 Address = NextAddress;
1939 while (((ULONG_PTR)Address >> PAGE_SHIFT) <= Vad->EndingVpn)
1940 {
1941 /* Keep going unless the state or protection mask changed */
1942 NewState = MiQueryAddressState(Address, Vad, TargetProcess, &NewProtect, &NextAddress);
1943 if ((NewState != MemoryInfo.State) || (NewProtect != MemoryInfo.Protect)) break;
1944 Address = NextAddress;
1945 }
1946
1947 /* Release the working set lock */
1949
1950 /* Check if we went outside of the VAD */
1951 if (((ULONG_PTR)Address >> PAGE_SHIFT) > Vad->EndingVpn)
1952 {
1953 /* Set the end of the VAD as the end address */
1954 Address = (PVOID)((Vad->EndingVpn + 1) << PAGE_SHIFT);
1955 }
1956
1957 /* Now that we know the last VA address, calculate the region size */
1958 MemoryInfo.RegionSize = ((ULONG_PTR)Address - (ULONG_PTR)MemoryInfo.BaseAddress);
1959 }
1960
1961 /* Unlock the address space of the process */
1962 MmUnlockAddressSpace(&TargetProcess->Vm);
1963
1964 /* Check if we were attached */
1966 {
1967 /* Detach and dereference the process */
1969 ObDereferenceObject(TargetProcess);
1970 }
1971
1972 /* Return the data, NtQueryInformation already probed it */
1973 if (PreviousMode != KernelMode)
1974 {
1975 _SEH2_TRY
1976 {
1977 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1979 }
1981 {
1983 }
1984 _SEH2_END;
1985 }
1986 else
1987 {
1988 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1990 }
1991
1992 /* All went well */
1993 DPRINT("Base: %p AllocBase: %p AllocProtect: %lx Protect: %lx "
1994 "State: %lx Type: %lx Size: %lx\n",
1995 MemoryInfo.BaseAddress, MemoryInfo.AllocationBase,
1996 MemoryInfo.AllocationProtect, MemoryInfo.Protect,
1997 MemoryInfo.State, MemoryInfo.Type, MemoryInfo.RegionSize);
1998
1999 return Status;
2000}
2001
2002BOOLEAN
2003NTAPI
2005 IN ULONG_PTR EndingAddress,
2006 IN PMMVAD Vad,
2008{
2009 PMMPTE PointerPte, LastPte;
2010 PMMPDE PointerPde;
2011 BOOLEAN OnPdeBoundary = TRUE;
2012#if _MI_PAGING_LEVELS >= 3
2013 PMMPPE PointerPpe;
2014 BOOLEAN OnPpeBoundary = TRUE;
2015#if _MI_PAGING_LEVELS == 4
2016 PMMPXE PointerPxe;
2017 BOOLEAN OnPxeBoundary = TRUE;
2018#endif
2019#endif
2020
2021 PAGED_CODE();
2022
2023 /* Check that we hols the right locks */
2024 ASSERT(PsGetCurrentThread()->OwnsProcessWorkingSetExclusive || PsGetCurrentThread()->OwnsProcessWorkingSetShared);
2025
2026 /* Get the PTE addresses */
2027 PointerPte = MiAddressToPte(StartingAddress);
2028 LastPte = MiAddressToPte(EndingAddress);
2029
2030 /* Loop all the PTEs */
2031 while (PointerPte <= LastPte)
2032 {
2033#if _MI_PAGING_LEVELS == 4
2034 /* Check for new PXE boundary */
2035 if (OnPxeBoundary)
2036 {
2037 PointerPxe = MiPteToPxe(PointerPte);
2038
2039 /* Check that this loop is sane */
2040 ASSERT(OnPpeBoundary);
2041 ASSERT(OnPdeBoundary);
2042
2043 if (PointerPxe->u.Long != 0)
2044 {
2045 /* Make it valid if needed */
2046 if (PointerPxe->u.Hard.Valid == 0)
2048 }
2049 else
2050 {
2051 /* Is the entire VAD committed? If not, fail */
2052 if (!Vad->u.VadFlags.MemCommit) return FALSE;
2053
2054 PointerPxe++;
2055 PointerPte = MiPxeToPte(PointerPte);
2056 continue;
2057 }
2058 }
2059#endif
2060
2061#if _MI_PAGING_LEVELS >= 3
2062 /* Check for new PPE boundary */
2063 if (OnPpeBoundary)
2064 {
2065 PointerPpe = MiPteToPpe(PointerPte);
2066
2067 /* Check that this loop is sane */
2068 ASSERT(OnPdeBoundary);
2069
2070 if (PointerPpe->u.Long != 0)
2071 {
2072 /* Make it valid if needed */
2073 if (PointerPpe->u.Hard.Valid == 0)
2075 }
2076 else
2077 {
2078 /* Is the entire VAD committed? If not, fail */
2079 if (!Vad->u.VadFlags.MemCommit) return FALSE;
2080
2081 PointerPpe++;
2082 PointerPte = MiPpeToPte(PointerPpe);
2083#if _MI_PAGING_LEVELS == 4
2084 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
2085#endif
2086 continue;
2087 }
2088 }
2089#endif
2090 /* Check if we've hit a new PDE boundary */
2091 if (OnPdeBoundary)
2092 {
2093 /* Is this PDE demand zero? */
2094 PointerPde = MiPteToPde(PointerPte);
2095 if (PointerPde->u.Long != 0)
2096 {
2097 /* It isn't -- is it valid? */
2098 if (PointerPde->u.Hard.Valid == 0)
2099 {
2100 /* Nope, fault it in */
2101 MiMakeSystemAddressValid(PointerPte, Process);
2102 }
2103 }
2104 else
2105 {
2106 /* Is the entire VAD committed? If not, fail */
2107 if (!Vad->u.VadFlags.MemCommit) return FALSE;
2108
2109 /* The PTE was already valid, so move to the next one */
2110 PointerPde++;
2111 PointerPte = MiPdeToPte(PointerPde);
2112#if _MI_PAGING_LEVELS >= 3
2113 OnPpeBoundary = MiIsPteOnPpeBoundary(PointerPte);
2114#if _MI_PAGING_LEVELS == 4
2115 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
2116#endif
2117#endif
2118
2119 /* New loop iteration with our new, on-boundary PTE. */
2120 continue;
2121 }
2122 }
2123
2124 /* Is the PTE demand zero? */
2125 if (PointerPte->u.Long == 0)
2126 {
2127 /* Is the entire VAD committed? If not, fail */
2128 if (!Vad->u.VadFlags.MemCommit) return FALSE;
2129 }
2130 else
2131 {
2132 /* It isn't -- is it a decommited, invalid, or faulted PTE? */
2133 if ((PointerPte->u.Soft.Protection == MM_DECOMMIT) &&
2134 (PointerPte->u.Hard.Valid == 0) &&
2135 ((PointerPte->u.Soft.Prototype == 0) ||
2136 (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)))
2137 {
2138 /* Then part of the range is decommitted, so fail */
2139 return FALSE;
2140 }
2141 }
2142
2143 /* Move to the next PTE */
2144 PointerPte++;
2145 OnPdeBoundary = MiIsPteOnPdeBoundary(PointerPte);
2146#if _MI_PAGING_LEVELS >= 3
2147 OnPpeBoundary = MiIsPteOnPpeBoundary(PointerPte);
2148#if _MI_PAGING_LEVELS == 4
2149 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
2150#endif
2151#endif
2152 }
2153
2154 /* All PTEs seem valid, and no VAD checks failed, the range is okay */
2155 return TRUE;
2156}
2157
2159NTAPI
2162 IN OUT PSIZE_T NumberOfBytesToProtect,
2163 IN ULONG NewAccessProtection,
2164 OUT PULONG OldAccessProtection OPTIONAL)
2165{
2166 PMMVAD Vad;
2168 ULONG_PTR StartingAddress, EndingAddress;
2169 PMMPTE PointerPte, LastPte;
2170 PMMPDE PointerPde;
2171 MMPTE PteContents;
2172 PMMPFN Pfn1;
2173 ULONG ProtectionMask, OldProtect;
2174 BOOLEAN Committed;
2178
2179 /* We must be attached */
2181
2182 /* Calculate base address for the VAD */
2183 StartingAddress = (ULONG_PTR)PAGE_ALIGN((*BaseAddress));
2184 EndingAddress = (((ULONG_PTR)*BaseAddress + *NumberOfBytesToProtect - 1) | (PAGE_SIZE - 1));
2185
2186 /* Calculate the protection mask and make sure it's valid */
2187 ProtectionMask = MiMakeProtectionMask(NewAccessProtection);
2188 if (ProtectionMask == MM_INVALID_PROTECTION)
2189 {
2190 DPRINT1("Invalid protection mask\n");
2192 }
2193
2194 /* Lock the address space and make sure the process isn't already dead */
2197 if (Process->VmDeleted)
2198 {
2199 DPRINT1("Process is dying\n");
2201 goto FailPath;
2202 }
2203
2204 /* Get the VAD for this address range, and make sure it exists */
2205 Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
2206 EndingAddress >> PAGE_SHIFT,
2207 &Process->VadRoot,
2208 (PMMADDRESS_NODE*)&Vad);
2209 if (Result != TableFoundNode)
2210 {
2211 DPRINT("Could not find a VAD for this allocation\n");
2213 goto FailPath;
2214 }
2215
2216 /* Check if this is a ROSMM VAD */
2217 if (MI_IS_ROSMM_VAD(Vad))
2218 {
2219 /* Not too shabby hack */
2221 *NumberOfBytesToProtect = PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) - PAGE_ROUND_DOWN(*BaseAddress);
2224 (PMEMORY_AREA)Vad,
2225 *BaseAddress,
2226 *NumberOfBytesToProtect,
2227 NewAccessProtection,
2228 OldAccessProtection);
2230 return Status;
2231 }
2232
2233 /* Make sure the address is within this VAD's boundaries */
2234 if ((((ULONG_PTR)StartingAddress >> PAGE_SHIFT) < Vad->StartingVpn) ||
2235 (((ULONG_PTR)EndingAddress >> PAGE_SHIFT) > Vad->EndingVpn))
2236 {
2238 goto FailPath;
2239 }
2240
2241 /* These kinds of VADs are not supported atm */
2242 if ((Vad->u.VadFlags.VadType == VadAwe) ||
2244 (Vad->u.VadFlags.VadType == VadLargePages))
2245 {
2246 DPRINT1("Illegal VAD for attempting to set protection\n");
2248 goto FailPath;
2249 }
2250
2251 /* Check for a VAD whose protection can't be changed */
2252 if (Vad->u.VadFlags.NoChange == 1)
2253 {
2254 DPRINT1("Trying to change protection of a NoChange VAD\n");
2256 goto FailPath;
2257 }
2258
2259 /* Is this section, or private memory? */
2260 if (Vad->u.VadFlags.PrivateMemory == 0)
2261 {
2262 /* Not yet supported */
2264 {
2265 DPRINT1("Illegal VAD for attempting to set protection\n");
2267 goto FailPath;
2268 }
2269
2270 /* Rotate VADs are not yet supported */
2271 if (Vad->u.VadFlags.VadType == VadRotatePhysical)
2272 {
2273 DPRINT1("Illegal VAD for attempting to set protection\n");
2275 goto FailPath;
2276 }
2277
2278 /* Not valid on section files */
2279 if (NewAccessProtection & (PAGE_NOCACHE | PAGE_WRITECOMBINE))
2280 {
2281 /* Fail */
2282 DPRINT1("Invalid protection flags for section\n");
2284 goto FailPath;
2285 }
2286
2287 /* Check if data or page file mapping protection PTE is compatible */
2288 if (!Vad->ControlArea->u.Flags.Image)
2289 {
2290 /* Not yet */
2291 DPRINT1("Fixme: Not checking for valid protection\n");
2292 }
2293
2294 /* This is a section, and this is not yet supported */
2295 DPRINT1("Section protection not yet supported\n");
2296 OldProtect = 0;
2297 }
2298 else
2299 {
2300 /* Private memory, check protection flags */
2301 if ((NewAccessProtection & PAGE_WRITECOPY) ||
2302 (NewAccessProtection & PAGE_EXECUTE_WRITECOPY))
2303 {
2304 DPRINT1("Invalid protection flags for private memory\n");
2306 goto FailPath;
2307 }
2308
2309 /* Lock the working set */
2311
2312 /* Check if all pages in this range are committed */
2313 Committed = MiIsEntireRangeCommitted(StartingAddress,
2314 EndingAddress,
2315 Vad,
2316 Process);
2317 if (!Committed)
2318 {
2319 /* Fail */
2320 DPRINT1("The entire range is not committed\n");
2323 goto FailPath;
2324 }
2325
2326 /* Compute starting and ending PTE and PDE addresses */
2327 PointerPde = MiAddressToPde(StartingAddress);
2328 PointerPte = MiAddressToPte(StartingAddress);
2329 LastPte = MiAddressToPte(EndingAddress);
2330
2331 /* Make this PDE valid */
2333
2334 /* Save protection of the first page */
2335 if (PointerPte->u.Long != 0)
2336 {
2337 /* Capture the page protection and make the PDE valid */
2338 OldProtect = MiGetPageProtection(PointerPte);
2340 }
2341 else
2342 {
2343 /* Grab the old protection from the VAD itself */
2344 OldProtect = MmProtectToValue[Vad->u.VadFlags.Protection];
2345 }
2346
2347 /* Loop all the PTEs now */
2348 while (PointerPte <= LastPte)
2349 {
2350 /* Check if we've crossed a PDE boundary and make the new PDE valid too */
2351 if (MiIsPteOnPdeBoundary(PointerPte))
2352 {
2353 PointerPde = MiPteToPde(PointerPte);
2355 }
2356
2357 /* Capture the PTE and check if it was empty */
2358 PteContents = *PointerPte;
2359 if (PteContents.u.Long == 0)
2360 {
2361 /* This used to be a zero PTE and it no longer is, so we must add a
2362 reference to the pagetable. */
2364 }
2365
2366 /* Check what kind of PTE we are dealing with */
2367 if (PteContents.u.Hard.Valid == 1)
2368 {
2369 /* Get the PFN entry */
2370 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents));
2371
2372 /* We don't support this yet */
2373 ASSERT(Pfn1->u3.e1.PrototypePte == 0);
2374
2375 /* Check if the page should not be accessible at all */
2376 if ((NewAccessProtection & PAGE_NOACCESS) ||
2377 (NewAccessProtection & PAGE_GUARD))
2378 {
2379 KIRQL OldIrql = MiAcquirePfnLock();
2380
2381 /* Mark the PTE as transition and change its protection */
2382 PteContents.u.Hard.Valid = 0;
2383 PteContents.u.Soft.Transition = 1;
2384 PteContents.u.Trans.Protection = ProtectionMask;
2385 /* Decrease PFN share count and write the PTE */
2386 MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents));
2387 // FIXME: remove the page from the WS
2388 MI_WRITE_INVALID_PTE(PointerPte, PteContents);
2389#ifdef CONFIG_SMP
2390 // FIXME: Should invalidate entry in every CPU TLB
2392#endif
2394
2395 /* We are done for this PTE */
2396 MiReleasePfnLock(OldIrql);
2397 }
2398 else
2399 {
2400 /* Write the protection mask and write it with a TLB flush */
2401 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
2403 PointerPte,
2404 ProtectionMask,
2405 Pfn1,
2406 TRUE);
2407 }
2408 }
2409 else
2410 {
2411 /* We don't support these cases yet */
2412 ASSERT(PteContents.u.Soft.Prototype == 0);
2413 //ASSERT(PteContents.u.Soft.Transition == 0);
2414
2415 /* The PTE is already demand-zero, just update the protection mask */
2416 PteContents.u.Soft.Protection = ProtectionMask;
2417 MI_WRITE_INVALID_PTE(PointerPte, PteContents);
2418 ASSERT(PointerPte->u.Long != 0);
2419 }
2420
2421 /* Move to the next PTE */
2422 PointerPte++;
2423 }
2424
2425 /* Unlock the working set */
2427 }
2428
2429 /* Unlock the address space */
2431
2432 /* Return parameters and success */
2433 *NumberOfBytesToProtect = EndingAddress - StartingAddress + 1;
2434 *BaseAddress = (PVOID)StartingAddress;
2435 *OldAccessProtection = OldProtect;
2436 return STATUS_SUCCESS;
2437
2438FailPath:
2439 /* Unlock the address space and return the failure code */
2441 return Status;
2442}
2443
2444VOID
2445NTAPI
2447 IN PEPROCESS TargetProcess,
2449{
2450 PMMPTE PointerPte;
2451#if _MI_PAGING_LEVELS >= 3
2452 PMMPPE PointerPpe = MiPdeToPpe(PointerPde);
2453#if _MI_PAGING_LEVELS == 4
2454 PMMPXE PointerPxe = MiPdeToPxe(PointerPde);
2455#endif
2456#endif
2457
2458 //
2459 // Sanity checks. The latter is because we only use this function with the
2460 // PFN lock not held, so it may go away in the future.
2461 //
2464
2465 //
2466 // If everything is already valid, there is nothing to do.
2467 //
2468 if (
2469#if _MI_PAGING_LEVELS == 4
2470 (PointerPxe->u.Hard.Valid) &&
2471#endif
2472#if _MI_PAGING_LEVELS >= 3
2473 (PointerPpe->u.Hard.Valid) &&
2474#endif
2475 (PointerPde->u.Hard.Valid))
2476 {
2477 return;
2478 }
2479
2480 //
2481 // At least something is invalid, so begin by getting the PTE for the PDE itself
2482 // and then lookup each additional level. We must do it in this precise order
2483 // because the pagfault.c code (as well as in Windows) depends that the next
2484 // level up (higher) must be valid when faulting a lower level
2485 //
2486 PointerPte = MiPteToAddress(PointerPde);
2487 do
2488 {
2489 //
2490 // Make sure APCs continued to be disabled
2491 //
2493
2494#if _MI_PAGING_LEVELS == 4
2495 //
2496 // First, make the PXE valid if needed
2497 //
2498 if (!PointerPxe->u.Hard.Valid)
2499 {
2500 MiMakeSystemAddressValid(PointerPpe, TargetProcess);
2501 ASSERT(PointerPxe->u.Hard.Valid == 1);
2502 }
2503#endif
2504
2505#if _MI_PAGING_LEVELS >= 3
2506 //
2507 // Next, the PPE
2508 //
2509 if (!PointerPpe->u.Hard.Valid)
2510 {
2511 MiMakeSystemAddressValid(PointerPde, TargetProcess);
2512 ASSERT(PointerPpe->u.Hard.Valid == 1);
2513 }
2514#endif
2515
2516 //
2517 // And finally, make the PDE itself valid.
2518 //
2519 MiMakeSystemAddressValid(PointerPte, TargetProcess);
2520
2521 /* Do not increment Page table refcount here for the PDE, this must be managed by caller */
2522
2523 //
2524 // This should've worked the first time so the loop is really just for
2525 // show -- ASSERT that we're actually NOT going to be looping.
2526 //
2527 ASSERT(PointerPde->u.Hard.Valid == 1);
2528 } while (
2529#if _MI_PAGING_LEVELS == 4
2530 !PointerPxe->u.Hard.Valid ||
2531#endif
2532#if _MI_PAGING_LEVELS >= 3
2533 !PointerPpe->u.Hard.Valid ||
2534#endif
2535 !PointerPde->u.Hard.Valid);
2536}
2537
2538VOID
2539NTAPI
2541 IN ULONG Count)
2542{
2543 KIRQL OldIrql;
2544 ULONG i;
2545 MMPTE TempPte;
2546 PFN_NUMBER PageFrameIndex;
2547 PMMPFN Pfn1, Pfn2;
2548
2549 //
2550 // Acquire the PFN lock and loop all the PTEs in the list
2551 //
2552 OldIrql = MiAcquirePfnLock();
2553 for (i = 0; i != Count; i++)
2554 {
2555 //
2556 // The PTE must currently be valid
2557 //
2558 TempPte = *ValidPteList[i];
2559 ASSERT(TempPte.u.Hard.Valid == 1);
2560
2561 //
2562 // Get the PFN entry for the page itself, and then for its page table
2563 //
2564 PageFrameIndex = PFN_FROM_PTE(&TempPte);
2565 Pfn1 = MiGetPfnEntry(PageFrameIndex);
2566 Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
2567
2568 //
2569 // Decrement the share count on the page table, and then on the page
2570 // itself
2571 //
2572 MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
2573 MI_SET_PFN_DELETED(Pfn1);
2574 MiDecrementShareCount(Pfn1, PageFrameIndex);
2575
2576 //
2577 // Make the page decommitted
2578 //
2579 MI_WRITE_INVALID_PTE(ValidPteList[i], MmDecommittedPte);
2580 }
2581
2582 //
2583 // All the PTEs have been dereferenced and made invalid, flush the TLB now
2584 // and then release the PFN lock
2585 //
2587 MiReleasePfnLock(OldIrql);
2588}
2589
2590ULONG
2591NTAPI
2592MiDecommitPages(IN PVOID StartingAddress,
2593 IN PMMPTE EndingPte,
2595 IN PMMVAD Vad)
2596{
2597 PMMPTE PointerPte, CommitPte = NULL;
2598 PMMPDE PointerPde;
2599 ULONG CommitReduction = 0;
2600 PMMPTE ValidPteList[256];
2601 ULONG PteCount = 0;
2602 PMMPFN Pfn1;
2603 MMPTE PteContents;
2604 PETHREAD CurrentThread = PsGetCurrentThread();
2605
2606 //
2607 // Get the PTE and PTE for the address, and lock the working set
2608 // If this was a VAD for a MEM_COMMIT allocation, also figure out where the
2609 // commited range ends so that we can do the right accounting.
2610 //
2611 PointerPde = MiAddressToPde(StartingAddress);
2612 PointerPte = MiAddressToPte(StartingAddress);
2613 if (Vad->u.VadFlags.MemCommit) CommitPte = MiAddressToPte(Vad->EndingVpn << PAGE_SHIFT);
2614 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
2615
2616 //
2617 // Make the PDE valid, and now loop through each page's worth of data
2618 //
2620 while (PointerPte <= EndingPte)
2621 {
2622 //
2623 // Check if we've crossed a PDE boundary
2624 //
2625 if (MiIsPteOnPdeBoundary(PointerPte))
2626 {
2627 //
2628 // Get the new PDE and flush the valid PTEs we had built up until
2629 // now. This helps reduce the amount of TLB flushing we have to do.
2630 // Note that Windows does a much better job using timestamps and
2631 // such, and does not flush the entire TLB all the time, but right
2632 // now we have bigger problems to worry about than TLB flushing.
2633 //
2634 PointerPde = MiAddressToPde(StartingAddress);
2635 if (PteCount)
2636 {
2637 MiProcessValidPteList(ValidPteList, PteCount);
2638 PteCount = 0;
2639 }
2640
2641 //
2642 // Make this PDE valid
2643 //
2645 }
2646
2647 //
2648 // Read this PTE. It might be active or still demand-zero.
2649 //
2650 PteContents = *PointerPte;
2651 if (PteContents.u.Long)
2652 {
2653 //
2654 // The PTE is active. It might be valid and in a working set, or
2655 // it might be a prototype PTE or paged out or even in transition.
2656 //
2657 if (PointerPte->u.Long == MmDecommittedPte.u.Long)
2658 {
2659 //
2660 // It's already decommited, so there's nothing for us to do here
2661 //
2662 CommitReduction++;
2663 }
2664 else
2665 {
2666 //
2667 // Remove it from the counters, and check if it was valid or not
2668 //
2669 //Process->NumberOfPrivatePages--;
2670 if (PteContents.u.Hard.Valid)
2671 {
2672 //
2673 // It's valid. At this point make sure that it is not a ROS
2674 // PFN. Also, we don't support ProtoPTEs in this code path.
2675 //
2676 Pfn1 = MiGetPfnEntry(PteContents.u.Hard.PageFrameNumber);
2677 ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE);
2678 ASSERT(Pfn1->u3.e1.PrototypePte == FALSE);
2679
2680 //
2681 // Flush any pending PTEs that we had not yet flushed, if our
2682 // list has gotten too big, then add this PTE to the flush list.
2683 //
2684 if (PteCount == 256)
2685 {
2686 MiProcessValidPteList(ValidPteList, PteCount);
2687 PteCount = 0;
2688 }
2689 ValidPteList[PteCount++] = PointerPte;
2690 }
2691 else
2692 {
2693 //
2694 // We do not support any of these other scenarios at the moment
2695 //
2696 ASSERT(PteContents.u.Soft.Prototype == 0);
2697 ASSERT(PteContents.u.Soft.Transition == 0);
2698 ASSERT(PteContents.u.Soft.PageFileHigh == 0);
2699
2700 //
2701 // So the only other possibility is that it is still a demand
2702 // zero PTE, in which case we undo the accounting we did
2703 // earlier and simply make the page decommitted.
2704 //
2705 //Process->NumberOfPrivatePages++;
2707 }
2708 }
2709 }
2710 else
2711 {
2712 //
2713 // This used to be a zero PTE and it no longer is, so we must add a
2714 // reference to the pagetable.
2715 //
2716 MiIncrementPageTableReferences(StartingAddress);
2717
2718 //
2719 // Next, we account for decommitted PTEs and make the PTE as such
2720 //
2721 if (PointerPte > CommitPte) CommitReduction++;
2723 }
2724
2725 //
2726 // Move to the next PTE and the next address
2727 //
2728 PointerPte++;
2729 StartingAddress = (PVOID)((ULONG_PTR)StartingAddress + PAGE_SIZE);
2730 }
2731
2732 //
2733 // Flush any dangling PTEs from the loop in the last page table, and then
2734 // release the working set and return the commit reduction accounting.
2735 //
2736 if (PteCount) MiProcessValidPteList(ValidPteList, PteCount);
2738 return CommitReduction;
2739}
2740
2741/* PUBLIC FUNCTIONS ***********************************************************/
2742
2743/*
2744 * @unimplemented
2745 */
2746PVOID
2747NTAPI
2749{
2751 return 0;
2752}
2753
2754/*
2755 * @unimplemented
2756 */
2757PVOID
2758NTAPI
2761 IN ULONG Mode)
2762{
2763 static ULONG Warn; if (!Warn++) UNIMPLEMENTED;
2764 return Address;
2765}
2766
2767/*
2768 * @unimplemented
2769 */
2770VOID
2771NTAPI
2773{
2774 static ULONG Warn; if (!Warn++) UNIMPLEMENTED;
2775}
2776
2777/* SYSTEM CALLS ***************************************************************/
2778
2780NTAPI
2784 IN SIZE_T NumberOfBytesToRead,
2785 OUT PSIZE_T NumberOfBytesRead OPTIONAL)
2786{
2790 SIZE_T BytesRead = 0;
2791 PAGED_CODE();
2792
2793 //
2794 // Check if we came from user mode
2795 //
2796 if (PreviousMode != KernelMode)
2797 {
2798 //
2799 // Validate the read addresses
2800 //
2801 if ((((ULONG_PTR)BaseAddress + NumberOfBytesToRead) < (ULONG_PTR)BaseAddress) ||
2802 (((ULONG_PTR)Buffer + NumberOfBytesToRead) < (ULONG_PTR)Buffer) ||
2803 (((ULONG_PTR)BaseAddress + NumberOfBytesToRead) > MmUserProbeAddress) ||
2804 (((ULONG_PTR)Buffer + NumberOfBytesToRead) > MmUserProbeAddress))
2805 {
2806 //
2807 // Don't allow to write into kernel space
2808 //
2810 }
2811
2812 //
2813 // Enter SEH for probe
2814 //
2815 _SEH2_TRY
2816 {
2817 //
2818 // Probe the output value
2819 //
2820 if (NumberOfBytesRead) ProbeForWriteSize_t(NumberOfBytesRead);
2821 }
2823 {
2824 //
2825 // Get exception code
2826 //
2828 }
2829 _SEH2_END;
2830 }
2831
2832 //
2833 // Don't do zero-byte transfers
2834 //
2835 if (NumberOfBytesToRead)
2836 {
2837 //
2838 // Reference the process
2839 //
2844 (PVOID*)(&Process),
2845 NULL);
2846 if (NT_SUCCESS(Status))
2847 {
2848 //
2849 // Do the copy
2850 //
2854 Buffer,
2855 NumberOfBytesToRead,
2857 &BytesRead);
2858
2859 //
2860 // Dereference the process
2861 //
2863 }
2864 }
2865
2866 //
2867 // Check if the caller sent this parameter
2868 //
2869 if (NumberOfBytesRead)
2870 {
2871 //
2872 // Enter SEH to guard write
2873 //
2874 _SEH2_TRY
2875 {
2876 //
2877 // Return the number of bytes read
2878 //
2879 *NumberOfBytesRead = BytesRead;
2880 }
2882 {
2883 }
2884 _SEH2_END;
2885 }
2886
2887 //
2888 // Return status
2889 //
2890 return Status;
2891}
2892
2894NTAPI
2897 IN PVOID Buffer,
2898 IN SIZE_T NumberOfBytesToWrite,
2899 OUT PSIZE_T NumberOfBytesWritten OPTIONAL)
2900{
2904 SIZE_T BytesWritten = 0;
2905 PAGED_CODE();
2906
2907 //
2908 // Check if we came from user mode
2909 //
2910 if (PreviousMode != KernelMode)
2911 {
2912 //
2913 // Validate the read addresses
2914 //
2915 if ((((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) < (ULONG_PTR)BaseAddress) ||
2916 (((ULONG_PTR)Buffer + NumberOfBytesToWrite) < (ULONG_PTR)Buffer) ||
2917 (((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) > MmUserProbeAddress) ||
2918 (((ULONG_PTR)Buffer + NumberOfBytesToWrite) > MmUserProbeAddress))
2919 {
2920 //
2921 // Don't allow to write into kernel space
2922 //
2924 }
2925
2926 //
2927 // Enter SEH for probe
2928 //
2929 _SEH2_TRY
2930 {
2931 //
2932 // Probe the output value
2933 //
2934 if (NumberOfBytesWritten) ProbeForWriteSize_t(NumberOfBytesWritten);
2935 }
2937 {
2938 //
2939 // Get exception code
2940 //
2942 }
2943 _SEH2_END;
2944 }
2945
2946 //
2947 // Don't do zero-byte transfers
2948 //
2949 if (NumberOfBytesToWrite)
2950 {
2951 //
2952 // Reference the process
2953 //
2958 (PVOID*)&Process,
2959 NULL);
2960 if (NT_SUCCESS(Status))
2961 {
2962 //
2963 // Do the copy
2964 //
2966 Buffer,
2967 Process,
2969 NumberOfBytesToWrite,
2971 &BytesWritten);
2972
2973 //
2974 // Dereference the process
2975 //
2977 }
2978 }
2979
2980 //
2981 // Check if the caller sent this parameter
2982 //
2983 if (NumberOfBytesWritten)
2984 {
2985 //
2986 // Enter SEH to guard write
2987 //
2988 _SEH2_TRY
2989 {
2990 //
2991 // Return the number of bytes written
2992 //
2993 *NumberOfBytesWritten = BytesWritten;
2994 }
2996 {
2997 }
2998 _SEH2_END;
2999 }
3000
3001 //
3002 // Return status
3003 //
3004 return Status;
3005}
3006
3008NTAPI
3011 _In_ SIZE_T FlushSize)
3012{
3016 PAGED_CODE();
3017
3018 /* Is a base address given? */
3019 if (BaseAddress != NULL)
3020 {
3021 /* If the requested size is 0, there is nothing to do */
3022 if (FlushSize == 0)
3023 {
3024 return STATUS_SUCCESS;
3025 }
3026
3027 /* Is this a user mode call? */
3029 {
3030 /* Make sure the base address is in user space */
3032 {
3033 DPRINT1("Invalid BaseAddress 0x%p\n", BaseAddress);
3035 }
3036 }
3037 }
3038
3039 /* Is another process requested? */
3041 {
3042 /* Reference the process */
3047 (PVOID*)&Process,
3048 NULL);
3049 if (!NT_SUCCESS(Status))
3050 {
3051 DPRINT1("Failed to reference the process %p\n", ProcessHandle);
3052 return Status;
3053 }
3054
3055 /* Attach to the process */
3057 }
3058
3059 /* Forward to Ke */
3060 KeSweepICache(BaseAddress, FlushSize);
3061
3062 /* Check if we attached */
3064 {
3065 /* Detach from the process and dereference it */
3068 }
3069
3070 /* All done, return to caller */
3071 return STATUS_SUCCESS;
3072}
3073
3075NTAPI
3077 IN OUT PVOID *UnsafeBaseAddress,
3078 IN OUT SIZE_T *UnsafeNumberOfBytesToProtect,
3079 IN ULONG NewAccessProtection,
3080 OUT PULONG UnsafeOldAccessProtection)
3081{
3083 ULONG OldAccessProtection;
3084 ULONG Protection;
3085 PEPROCESS CurrentProcess = PsGetCurrentProcess();
3087 SIZE_T NumberOfBytesToProtect = 0;
3092 PAGED_CODE();
3093
3094 //
3095 // Check for valid protection flags
3096 //
3097 Protection = NewAccessProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
3098 if (Protection != PAGE_NOACCESS &&
3099 Protection != PAGE_READONLY &&
3100 Protection != PAGE_READWRITE &&
3101 Protection != PAGE_WRITECOPY &&
3102 Protection != PAGE_EXECUTE &&
3103 Protection != PAGE_EXECUTE_READ &&
3104 Protection != PAGE_EXECUTE_READWRITE &&
3105 Protection != PAGE_EXECUTE_WRITECOPY)
3106 {
3107 //
3108 // Fail
3109 //
3111 }
3112
3113 //
3114 // Check if we came from user mode
3115 //
3116 if (PreviousMode != KernelMode)
3117 {
3118 //
3119 // Enter SEH for probing
3120 //
3121 _SEH2_TRY
3122 {
3123 //
3124 // Validate all outputs
3125 //
3126 ProbeForWritePointer(UnsafeBaseAddress);
3127 ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect);
3128 ProbeForWriteUlong(UnsafeOldAccessProtection);
3129
3130 //
3131 // Capture them
3132 //
3133 BaseAddress = *UnsafeBaseAddress;
3134 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
3135 }
3137 {
3138 //
3139 // Get exception code
3140 //
3142 }
3143 _SEH2_END;
3144 }
3145 else
3146 {
3147 //
3148 // Capture directly
3149 //
3150 BaseAddress = *UnsafeBaseAddress;
3151 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
3152 }
3153
3154 //
3155 // Catch illegal base address
3156 //
3158
3159 //
3160 // Catch illegal region size
3161 //
3162 if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < NumberOfBytesToProtect)
3163 {
3164 //
3165 // Fail
3166 //
3168 }
3169
3170 //
3171 // 0 is also illegal
3172 //
3173 if (!NumberOfBytesToProtect) return STATUS_INVALID_PARAMETER_3;
3174
3175 //
3176 // Get a reference to the process
3177 //
3182 (PVOID*)(&Process),
3183 NULL);
3184 if (!NT_SUCCESS(Status)) return Status;
3185
3186 //
3187 // Check if we should attach
3188 //
3189 if (CurrentProcess != Process)
3190 {
3191 //
3192 // Do it
3193 //
3195 Attached = TRUE;
3196 }
3197
3198 //
3199 // Do the actual work
3200 //
3202 &BaseAddress,
3203 &NumberOfBytesToProtect,
3204 NewAccessProtection,
3205 &OldAccessProtection);
3206
3207 //
3208 // Detach if needed
3209 //
3211
3212 //
3213 // Release reference
3214 //
3216
3217 //
3218 // Enter SEH to return data
3219 //
3220 _SEH2_TRY
3221 {
3222 //
3223 // Return data to user
3224 //
3225 *UnsafeOldAccessProtection = OldAccessProtection;
3226 *UnsafeBaseAddress = BaseAddress;
3227 *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
3228 }
3230 {
3231 }
3232 _SEH2_END;
3233
3234 //
3235 // Return status
3236 //
3237 return Status;
3238}
3239
3241BOOLEAN
3243 PMMPFN Pfn1,
3245{
3246 // HACK until we have proper WSLIST support
3247 PMMWSLE Wsle = &Pfn1->Wsle;
3248
3249 if ((LockType & MAP_PROCESS) && (Wsle->u1.e1.LockedInWs))
3250 return TRUE;
3251 if ((LockType & MAP_SYSTEM) && (Wsle->u1.e1.LockedInMemory))
3252 return TRUE;
3253
3254 return FALSE;
3255}
3256
3258VOID
3260 PMMPFN Pfn1,
3262{
3263 // HACK until we have proper WSLIST support
3264 PMMWSLE Wsle = &Pfn1->Wsle;
3265
3266 if (!Wsle->u1.e1.LockedInWs &&
3267 !Wsle->u1.e1.LockedInMemory)
3268 {
3270 }
3271
3272 if (LockType & MAP_PROCESS)
3273 Wsle->u1.e1.LockedInWs = 1;
3274 if (LockType & MAP_SYSTEM)
3275 Wsle->u1.e1.LockedInMemory = 1;
3276}
3277
3279VOID
3281 PMMPFN Pfn1,
3283{
3284 // HACK until we have proper WSLIST support
3285 PMMWSLE Wsle = &Pfn1->Wsle;
3286
3287 if (LockType & MAP_PROCESS)
3288 Wsle->u1.e1.LockedInWs = 0;
3289 if (LockType & MAP_SYSTEM)
3290 Wsle->u1.e1.LockedInMemory = 0;
3291
3292 if (!Wsle->u1.e1.LockedInWs &&
3293 !Wsle->u1.e1.LockedInMemory)
3294 {
3296 }
3297}
3298
3299static
3304 _Inout_ PVOID *EndAddress)
3305
3306{
3307 PMMVAD Vad;
3308 PVOID CurrentVa;
3309
3310 /* Get the base address and align the start address */
3311 *EndAddress = (PUCHAR)*BaseAddress + *RegionSize;
3312 *EndAddress = ALIGN_UP_POINTER_BY(*EndAddress, PAGE_SIZE);
3314
3315 /* First loop and check all VADs */
3316 CurrentVa = *BaseAddress;
3317 while (CurrentVa < *EndAddress)
3318 {
3319 /* Get VAD */
3320 Vad = MiLocateAddress(CurrentVa);
3321 if (Vad == NULL)
3322 {
3325 }
3326
3327 /* Check VAD type */
3328 if ((Vad->u.VadFlags.VadType != VadNone) &&
3329 (Vad->u.VadFlags.VadType != VadImageMap) &&
3330 (Vad->u.VadFlags.VadType != VadWriteWatch))
3331 {
3332 *EndAddress = CurrentVa;
3333 *RegionSize = (PUCHAR)*EndAddress - (PUCHAR)*BaseAddress;
3335 }
3336
3337 CurrentVa = (PVOID)((Vad->EndingVpn + 1) << PAGE_SHIFT);
3338 }
3339
3340 *RegionSize = (PUCHAR)*EndAddress - (PUCHAR)*BaseAddress;
3341 return STATUS_SUCCESS;
3342}
3343
3344static
3349 IN ULONG MapType)
3350{
3351 PEPROCESS CurrentProcess;
3353 PVOID CurrentVa, EndAddress;
3354 PMMPTE PointerPte, LastPte;
3355 PMMPDE PointerPde;
3356#if (_MI_PAGING_LEVELS >= 3)
3357 PMMPDE PointerPpe;
3358#endif
3359#if (_MI_PAGING_LEVELS == 4)
3360 PMMPDE PointerPxe;
3361#endif
3362 PMMPFN Pfn1;
3363 NTSTATUS Status, TempStatus;
3364
3365 /* Lock the address space */
3368
3369 /* Make sure we still have an address space */
3370 CurrentProcess = PsGetCurrentProcess();
3371 if (CurrentProcess->VmDeleted)
3372 {
3374 goto Cleanup;
3375 }
3376
3377 /* Check the VADs in the requested range */
3379 if (!NT_SUCCESS(Status))
3380 {
3381 goto Cleanup;
3382 }
3383
3384 /* Enter SEH for probing */
3385 _SEH2_TRY
3386 {
3387 /* Loop all pages and probe them */
3388 CurrentVa = *BaseAddress;
3389 while (CurrentVa < EndAddress)
3390 {
3391 (void)(*(volatile CHAR*)CurrentVa);
3392 CurrentVa = (PUCHAR)CurrentVa + PAGE_SIZE;
3393 }
3394 }
3396 {
3398 goto Cleanup;
3399 }
3400 _SEH2_END;
3401
3402 /* All pages were accessible, since we hold the address space lock, nothing
3403 can be de-committed. Assume success for now. */
3405
3406 /* Get the PTE and PDE */
3407 PointerPte = MiAddressToPte(*BaseAddress);
3408 PointerPde = MiAddressToPde(*BaseAddress);
3409#if (_MI_PAGING_LEVELS >= 3)
3410 PointerPpe = MiAddressToPpe(*BaseAddress);
3411#endif
3412#if (_MI_PAGING_LEVELS == 4)
3413 PointerPxe = MiAddressToPxe(*BaseAddress);
3414#endif
3415
3416 /* Get the last PTE */
3417 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)EndAddress - 1));
3418
3419 /* Lock the process working set */
3421
3422 /* Loop the pages */
3423 do
3424 {
3425 /* Check for a page that is not accessible */
3426 while (
3427#if (_MI_PAGING_LEVELS == 4)
3428 (PointerPxe->u.Hard.Valid == 0) ||
3429#endif
3430#if (_MI_PAGING_LEVELS >= 3)
3431 (PointerPpe->u.Hard.Valid == 0) ||
3432#endif
3433 (PointerPde->u.Hard.Valid == 0) ||
3434 (PointerPte->u.Hard.Valid == 0))
3435 {
3436 /* Release process working set */
3438
3439 /* Access the page */
3440 CurrentVa = MiPteToAddress(PointerPte);
3441
3442 //HACK: Pass a placeholder TrapInformation so the fault handler knows we're unlocked
3443 TempStatus = MmAccessFault(TRUE, CurrentVa, KernelMode, (PVOID)(ULONG_PTR)0xBADBADA3BADBADA3ULL);
3444 if (!NT_SUCCESS(TempStatus))
3445 {
3446 // This should only happen, when remote backing storage is not accessible
3447 ASSERT(FALSE);
3448 Status = TempStatus;
3449 goto Cleanup;
3450 }
3451
3452 /* Lock the process working set */
3454 }
3455
3456 /* Get the PFN */
3457 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3458 ASSERT(Pfn1 != NULL);
3459
3460 /* Check the previous lock status */
3461 if (MI_IS_LOCKED_VA(Pfn1, MapType))
3462 {
3464 }
3465
3466 /* Lock it */
3467 MI_LOCK_VA(Pfn1, MapType);
3468
3469 /* Go to the next PTE */
3470 PointerPte++;
3471
3472 /* Check if we're on a PDE boundary */
3473 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3474#if (_MI_PAGING_LEVELS >= 3)
3475 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3476#endif
3477#if (_MI_PAGING_LEVELS == 4)
3478 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3479#endif
3480 } while (PointerPte <= LastPte);
3481
3482 /* Release process working set */
3484
3485Cleanup:
3486 /* Unlock address space */
3488
3489 return Status;
3490}
3491
3493NTAPI
3496 IN OUT PSIZE_T NumberOfBytesToLock,
3497 IN ULONG MapType)
3498{
3500 PEPROCESS CurrentProcess = PsGetCurrentProcess();
3505 PVOID CapturedBaseAddress;
3506 SIZE_T CapturedBytesToLock;
3507 PAGED_CODE();
3508
3509 //
3510 // Validate flags
3511 //
3512 if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)))
3513 {
3514 //
3515 // Invalid set of flags
3516 //
3518 }
3519
3520 //
3521 // At least one flag must be specified
3522 //
3523 if (!(MapType & (MAP_PROCESS | MAP_SYSTEM)))
3524 {
3525 //
3526 // No flag given
3527 //
3529 }
3530
3531 //
3532 // Enter SEH for probing
3533 //
3534 _SEH2_TRY
3535 {
3536 //
3537 // Validate output data
3538 //
3540 ProbeForWriteSize_t(NumberOfBytesToLock);
3541
3542 //
3543 // Capture it
3544 //
3545 CapturedBaseAddress = *BaseAddress;
3546 CapturedBytesToLock = *NumberOfBytesToLock;
3547 }
3549 {
3550 //
3551 // Get exception code
3552 //
3554 }
3555 _SEH2_END;
3556
3557 //
3558 // Catch illegal base address
3559 //
3560 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
3561
3562 //
3563 // Catch illegal region size
3564 //
3565 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToLock)
3566 {
3567 //
3568 // Fail
3569 //
3571 }
3572
3573 //
3574 // 0 is also illegal
3575 //
3576 if (!CapturedBytesToLock) return STATUS_INVALID_PARAMETER;
3577
3578 //
3579 // Get a reference to the process
3580 //
3585 (PVOID*)(&Process),
3586 NULL);
3587 if (!NT_SUCCESS(Status)) return Status;
3588
3589 //
3590 // Check if this is is system-mapped
3591 //
3592 if (MapType & MAP_SYSTEM)
3593 {
3594 //
3595 // Check for required privilege
3596 //
3598 {
3599 //
3600 // Fail: Don't have it
3601 //
3604 }
3605 }
3606
3607 //
3608 // Check if we should attach
3609 //
3610 if (CurrentProcess != Process)
3611 {
3612 //
3613 // Do it
3614 //
3616 Attached = TRUE;
3617 }
3618
3619 //
3620 // Call the internal function
3621 //
3622 Status = MiLockVirtualMemory(&CapturedBaseAddress,
3623 &CapturedBytesToLock,
3624 MapType);
3625
3626 //
3627 // Detach if needed
3628 //
3630
3631 //
3632 // Release reference
3633 //
3635
3636 //
3637 // Enter SEH to return data
3638 //
3639 _SEH2_TRY
3640 {
3641 //
3642 // Return data to user
3643 //
3644 *BaseAddress = CapturedBaseAddress;
3645 *NumberOfBytesToLock = CapturedBytesToLock;
3646 }
3648 {
3649 //
3650 // Get exception code
3651 //
3653 }
3654 _SEH2_END;
3655
3656 //
3657 // Return status
3658 //
3659 return Status;
3660}
3661
3662
3663static
3668 IN ULONG MapType)
3669{
3670 PEPROCESS CurrentProcess;
3672 PVOID EndAddress;
3673 PMMPTE PointerPte, LastPte;
3674 PMMPDE PointerPde;
3675#if (_MI_PAGING_LEVELS >= 3)
3676 PMMPDE PointerPpe;
3677#endif
3678#if (_MI_PAGING_LEVELS == 4)
3679 PMMPDE PointerPxe;
3680#endif
3681 PMMPFN Pfn1;
3683
3684 /* Lock the address space */
3687
3688 /* Make sure we still have an address space */
3689 CurrentProcess = PsGetCurrentProcess();
3690 if (CurrentProcess->VmDeleted)
3691 {
3693 goto Cleanup;
3694 }
3695
3696 /* Check the VADs in the requested range */
3698
3699 /* Note: only bail out, if we hit an area without a VAD. If we hit an
3700 incompatible VAD we continue, like Windows does */
3702 {
3704 goto Cleanup;
3705 }
3706
3707 /* Get the PTE and PDE */
3708 PointerPte = MiAddressToPte(*BaseAddress);
3709 PointerPde = MiAddressToPde(*BaseAddress);
3710#if (_MI_PAGING_LEVELS >= 3)
3711 PointerPpe = MiAddressToPpe(*BaseAddress);
3712#endif
3713#if (_MI_PAGING_LEVELS == 4)
3714 PointerPxe = MiAddressToPxe(*BaseAddress);
3715#endif
3716
3717 /* Get the last PTE */
3718 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)EndAddress - 1));
3719
3720 /* Lock the process working set */
3722
3723 /* Loop the pages */
3724 do
3725 {
3726 /* Check for a page that is not present */
3727 if (
3728#if (_MI_PAGING_LEVELS == 4)
3729 (PointerPxe->u.Hard.Valid == 0) ||
3730#endif
3731#if (_MI_PAGING_LEVELS >= 3)
3732 (PointerPpe->u.Hard.Valid == 0) ||
3733#endif
3734 (PointerPde->u.Hard.Valid == 0) ||
3735 (PointerPte->u.Hard.Valid == 0))
3736 {
3737 /* Remember it, but keep going */
3739 }
3740 else
3741 {
3742 /* Get the PFN */
3743 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3744 ASSERT(Pfn1 != NULL);
3745
3746 /* Check if all of the requested locks are present */
3747 if (((MapType & MAP_SYSTEM) && !MI_IS_LOCKED_VA(Pfn1, MAP_SYSTEM)) ||
3748 ((MapType & MAP_PROCESS) && !MI_IS_LOCKED_VA(Pfn1, MAP_PROCESS)))
3749 {
3750 /* Remember it, but keep going */
3752
3753 /* Check if no lock is present */
3755 {
3756 DPRINT1("FIXME: Should remove the page from WS\n");
3757 }
3758 }
3759 }
3760
3761 /* Go to the next PTE */
3762 PointerPte++;
3763
3764 /* Check if we're on a PDE boundary */
3765 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3766#if (_MI_PAGING_LEVELS >= 3)
3767 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3768#endif
3769#if (_MI_PAGING_LEVELS == 4)
3770 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3771#endif
3772 } while (PointerPte <= LastPte);
3773
3774 /* Check if we hit a page that was not locked */
3776 {
3777 goto CleanupWithWsLock;
3778 }
3779
3780 /* All pages in the region were locked, so unlock them all */
3781
3782 /* Get the PTE and PDE */
3783 PointerPte = MiAddressToPte(*BaseAddress);
3784 PointerPde = MiAddressToPde(*BaseAddress);
3785#if (_MI_PAGING_LEVELS >= 3)
3786 PointerPpe = MiAddressToPpe(*BaseAddress);
3787#endif
3788#if (_MI_PAGING_LEVELS == 4)
3789 PointerPxe = MiAddressToPxe(*BaseAddress);
3790#endif
3791
3792 /* Loop the pages */
3793 do
3794 {
3795 /* Unlock it */
3796 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3797 MI_UNLOCK_VA(Pfn1, MapType);
3798
3799 /* Go to the next PTE */
3800 PointerPte++;
3801
3802 /* Check if we're on a PDE boundary */
3803 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3804#if (_MI_PAGING_LEVELS >= 3)
3805 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3806#endif
3807#if (_MI_PAGING_LEVELS == 4)
3808 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3809#endif
3810 } while (PointerPte <= LastPte);
3811
3812 /* Everything is done */
3814
3815CleanupWithWsLock:
3816
3817 /* Release process working set */
3819
3820Cleanup:
3821 /* Unlock address space */
3823
3824 return Status;
3825}
3826
3827
3829NTAPI
3832 IN OUT PSIZE_T NumberOfBytesToUnlock,
3833 IN ULONG MapType)
3834{
3836 PEPROCESS CurrentProcess = PsGetCurrentProcess();
3841 PVOID CapturedBaseAddress;
3842 SIZE_T CapturedBytesToUnlock;
3843 PAGED_CODE();
3844
3845 //
3846 // Validate flags
3847 //
3848 if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)))
3849 {
3850 //
3851 // Invalid set of flags
3852 //
3854 }
3855
3856 //
3857 // At least one flag must be specified
3858 //
3859 if (!(MapType & (MAP_PROCESS | MAP_SYSTEM)))
3860 {
3861 //
3862 // No flag given
3863 //
3865 }
3866
3867 //
3868 // Enter SEH for probing
3869 //
3870 _SEH2_TRY
3871 {
3872 //
3873 // Validate output data
3874 //
3876 ProbeForWriteSize_t(NumberOfBytesToUnlock);
3877
3878 //
3879 // Capture it
3880 //
3881 CapturedBaseAddress = *BaseAddress;
3882 CapturedBytesToUnlock = *NumberOfBytesToUnlock;
3883 }
3885 {
3886 //
3887 // Get exception code
3888 //
3890 }
3891 _SEH2_END;
3892
3893 //
3894 // Catch illegal base address
3895 //
3896 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
3897
3898 //
3899 // Catch illegal region size
3900 //
3901 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToUnlock)
3902 {
3903 //
3904 // Fail
3905 //
3907 }
3908
3909 //
3910 // 0 is also illegal
3911 //
3912 if (!CapturedBytesToUnlock) return STATUS_INVALID_PARAMETER;
3913
3914 //
3915 // Get a reference to the process
3916 //
3921 (PVOID*)(&Process),
3922 NULL);
3923 if (!NT_SUCCESS(Status)) return Status;
3924
3925 //
3926 // Check if this is is system-mapped
3927 //
3928 if (MapType & MAP_SYSTEM)
3929 {
3930 //
3931 // Check for required privilege
3932 //
3934 {
3935 //
3936 // Fail: Don't have it
3937 //
3940 }
3941 }
3942
3943 //
3944 // Check if we should attach
3945 //
3946 if (CurrentProcess != Process)
3947 {
3948 //
3949 // Do it
3950 //
3952 Attached = TRUE;
3953 }
3954
3955 //
3956 // Call the internal function
3957 //
3958 Status = MiUnlockVirtualMemory(&CapturedBaseAddress,
3959 &CapturedBytesToUnlock,
3960 MapType);
3961
3962 //
3963 // Detach if needed
3964 //
3966
3967 //
3968 // Release reference
3969 //
3971
3972 //
3973 // Enter SEH to return data
3974 //
3975 _SEH2_TRY
3976 {
3977 //
3978 // Return data to user
3979 //
3980 *BaseAddress = CapturedBaseAddress;
3981 *NumberOfBytesToUnlock = CapturedBytesToUnlock;
3982 }
3984 {
3985 //
3986 // Get exception code
3987 //
3989 }
3990 _SEH2_END;
3991
3992 //
3993 // Return status
3994 //
3995 return STATUS_SUCCESS;
3996}
3997
3999NTAPI
4002 IN OUT PSIZE_T NumberOfBytesToFlush,
4004{
4008 PVOID CapturedBaseAddress;
4009 SIZE_T CapturedBytesToFlush;
4010 IO_STATUS_BLOCK LocalStatusBlock;
4011 PAGED_CODE();
4012
4013 //
4014 // Check if we came from user mode
4015 //
4016 if (PreviousMode != KernelMode)
4017 {
4018 //
4019 // Enter SEH for probing
4020 //
4021 _SEH2_TRY
4022 {
4023 //
4024 // Validate all outputs
4025 //
4027 ProbeForWriteSize_t(NumberOfBytesToFlush);
4029
4030 //
4031 // Capture them
4032 //
4033 CapturedBaseAddress = *BaseAddress;
4034 CapturedBytesToFlush = *NumberOfBytesToFlush;
4035 }
4037 {
4038 //
4039 // Get exception code
4040 //
4042 }
4043 _SEH2_END;
4044 }
4045 else
4046 {
4047 //
4048 // Capture directly
4049 //
4050 CapturedBaseAddress = *BaseAddress;
4051 CapturedBytesToFlush = *NumberOfBytesToFlush;
4052 }
4053
4054 //
4055 // Catch illegal base address
4056 //
4057 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
4058
4059 //
4060 // Catch illegal region size
4061 //
4062 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToFlush)
4063 {
4064 //
4065 // Fail
4066 //
4068 }
4069
4070 //
4071 // Get a reference to the process
4072 //
4077 (PVOID*)(&Process),
4078 NULL);
4079 if (!NT_SUCCESS(Status)) return Status;
4080
4081 //
4082 // Do it
4083 //
4085 &CapturedBaseAddress,
4086 &CapturedBytesToFlush,
4087 &LocalStatusBlock);
4088
4089 //
4090 // Release reference
4091 //
4093
4094 //
4095 // Enter SEH to return data
4096 //
4097 _SEH2_TRY
4098 {
4099 //
4100 // Return data to user
4101 //
4102 *BaseAddress = PAGE_ALIGN(CapturedBaseAddress);
4103 *NumberOfBytesToFlush = 0;
4104 *IoStatusBlock = LocalStatusBlock;
4105 }
4107 {
4108 }
4109 _SEH2_END;
4110
4111 //
4112 // Return status
4113 //
4114 return Status;
4115}
4116
4117/*
4118 * @unimplemented
4119 */
4121NTAPI
4123 IN ULONG Flags,
4126 IN PVOID *UserAddressArray,
4127 OUT PULONG_PTR EntriesInUserAddressArray,
4128 OUT PULONG Granularity)
4129{
4132 PVOID EndAddress;
4134 ULONG_PTR CapturedEntryCount;
4135 PAGED_CODE();
4136
4137 //
4138 // Check if we came from user mode
4139 //
4140 if (PreviousMode != KernelMode)
4141 {
4142 //
4143 // Enter SEH for probing
4144 //
4145 _SEH2_TRY
4146 {
4147 //
4148 // Catch illegal base address
4149 //
4151
4152 //
4153 // Catch illegal region size
4154 //
4156 {
4157 //
4158 // Fail
4159 //
4161 }
4162
4163 //
4164 // Validate all data
4165 //
4166 ProbeForWriteSize_t(EntriesInUserAddressArray);
4167 ProbeForWriteUlong(Granularity);
4168
4169 //
4170 // Capture them
4171 //
4172 CapturedEntryCount = *EntriesInUserAddressArray;
4173
4174 //
4175 // Must have a count
4176 //
4177 if (CapturedEntryCount == 0) _SEH2_YIELD(return STATUS_INVALID_PARAMETER_5);
4178
4179 //
4180 // Can't be larger than the maximum
4181 //
4182 if (CapturedEntryCount > (MAXULONG_PTR / sizeof(ULONG_PTR)))
4183 {
4184 //
4185 // Fail
4186 //
4188 }
4189
4190 //
4191 // Probe the actual array
4192 //
4193 ProbeForWrite(UserAddressArray,
4194 CapturedEntryCount * sizeof(PVOID),
4195 sizeof(PVOID));
4196 }
4198 {
4199 //
4200 // Get exception code
4201 //
4203 }
4204 _SEH2_END;
4205 }
4206 else
4207 {
4208 //
4209 // Capture directly
4210 //
4211 CapturedEntryCount = *EntriesInUserAddressArray;
4212 ASSERT(CapturedEntryCount != 0);
4213 }
4214
4215 //
4216 // Check if this is a local request
4217 //
4219 {
4220 //
4221 // No need to reference the process
4222 //
4224 }
4225 else
4226 {
4227 //
4228 // Reference the target
4229 //
4234 (PVOID *)&Process,
4235 NULL);
4236 if (!NT_SUCCESS(Status)) return Status;
4237 }
4238
4239 //
4240 // Compute the last address and validate it
4241 //
4242 EndAddress = (PVOID)((ULONG_PTR)BaseAddress + RegionSize - 1);
4243 if (BaseAddress > EndAddress)
4244 {
4245 //
4246 // Fail
4247 //
4250 }
4251
4252 //
4253 // Oops :(
4254 //
4256
4257 //
4258 // Dereference if needed
4259 //
4261
4262 //
4263 // Enter SEH to return data
4264 //
4265 _SEH2_TRY
4266 {
4267 //
4268 // Return data to user
4269 //
4270 *EntriesInUserAddressArray = 0;
4271 *Granularity = PAGE_SIZE;
4272 }
4274 {
4275 //
4276 // Get exception code
4277 //
4279 }
4280 _SEH2_END;
4281
4282 //
4283 // Return success
4284 //
4285 return STATUS_SUCCESS;
4286}
4287
4288/*
4289 * @unimplemented
4290 */
4292NTAPI
4296{
4297 PVOID EndAddress;
4302
4303 //
4304 // Catch illegal base address
4305 //
4307
4308 //
4309 // Catch illegal region size
4310 //
4312 {
4313 //
4314 // Fail
4315 //
4317 }
4318
4319 //
4320 // Check if this is a local request
4321 //
4323 {
4324 //
4325 // No need to reference the process
4326 //
4328 }
4329 else
4330 {
4331 //
4332 // Reference the target
4333 //
4338 (PVOID *)&Process,
4339 NULL);
4340 if (!NT_SUCCESS(Status)) return Status;
4341 }
4342
4343 //
4344 // Compute the last address and validate it
4345 //
4346 EndAddress = (PVOID)((ULONG_PTR)BaseAddress + RegionSize - 1);
4347 if (BaseAddress > EndAddress)
4348 {
4349 //
4350 // Fail
4351 //
4354 }
4355
4356 //
4357 // Oops :(
4358 //
4360
4361 //
4362 // Dereference if needed
4363 //
4365
4366 //
4367 // Return success
4368 //
4369 return STATUS_SUCCESS;
4370}
4371
4373NTAPI
4376 IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
4377 OUT PVOID MemoryInformation,
4378 IN SIZE_T MemoryInformationLength,
4380{
4383
4384 DPRINT("Querying class %d about address: %p\n", MemoryInformationClass, BaseAddress);
4385
4386 /* Bail out if the address is invalid */
4388
4389 /* Probe return buffer */
4391 if (PreviousMode != KernelMode)
4392 {
4393 _SEH2_TRY
4394 {
4395 ProbeForWrite(MemoryInformation,
4396 MemoryInformationLength,
4397 sizeof(ULONG_PTR));
4398
4400 }
4402 {
4404 }
4405 _SEH2_END;
4406
4407 if (!NT_SUCCESS(Status))
4408 {
4409 return Status;
4410 }
4411 }
4412
4413 switch(MemoryInformationClass)
4414 {
4416 /* Validate the size information of the class */
4417 if (MemoryInformationLength < sizeof(MEMORY_BASIC_INFORMATION))
4418 {
4419 /* The size is invalid */
4421 }
4424 MemoryInformation,
4425 MemoryInformationLength,
4426 ReturnLength);
4427 break;
4428
4429 case MemorySectionName:
4430 /* Validate the size information of the class */
4431 if (MemoryInformationLength < sizeof(MEMORY_SECTION_NAME))
4432 {
4433 /* The size is invalid */
4435 }
4438 MemoryInformation,
4439 MemoryInformationLength,
4440 ReturnLength);
4441 break;
4444 default:
4445 DPRINT1("Unhandled memory information class %d\n", MemoryInformationClass);
4446 break;
4447 }
4448
4449 return Status;
4450}
4451
4452/*
4453 * @implemented
4454 */
4456NTAPI
4458 IN OUT PVOID* UBaseAddress,
4460 IN OUT PSIZE_T URegionSize,
4463{
4465 PMMVAD Vad = NULL, FoundVad;
4468 PVOID PBaseAddress;
4469 ULONG_PTR PRegionSize, StartingAddress, EndingAddress;
4470 ULONG_PTR HighestAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS;
4471 PEPROCESS CurrentProcess = PsGetCurrentProcess();
4473 PETHREAD CurrentThread = PsGetCurrentThread();
4475 ULONG ProtectionMask, QuotaCharge = 0, QuotaFree = 0;
4476 BOOLEAN Attached = FALSE, ChangeProtection = FALSE, QuotaCharged = FALSE;
4477 MMPTE TempPte;
4478 PMMPTE PointerPte, LastPte;
4479 PMMPDE PointerPde;
4481 PAGED_CODE();
4482
4483 /* Check for valid Zero bits */
4485 {
4486 DPRINT1("Too many zero bits\n");
4488 }
4489
4490 /* Check for valid Allocation Types */
4493 {
4494 DPRINT1("Invalid Allocation Type\n");
4496 }
4497
4498 /* Check for at least one of these Allocation Types to be set */
4500 {
4501 DPRINT1("No memory allocation base type\n");
4503 }
4504
4505 /* MEM_RESET is an exclusive flag, make sure that is valid too */
4507 {
4508 DPRINT1("Invalid use of MEM_RESET\n");
4510 }
4511
4512 /* Check if large pages are being used */
4514 {
4515 /* Large page allocations MUST be committed */
4516 if (!(AllocationType & MEM_COMMIT))
4517 {
4518 DPRINT1("Must supply MEM_COMMIT with MEM_LARGE_PAGES\n");
4520 }
4521
4522 /* These flags are not allowed with large page allocations */
4524 {
4525 DPRINT1("Using illegal flags with MEM_LARGE_PAGES\n");
4527 }
4528 }
4529
4530 /* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
4532 {
4533 DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
4535 }
4536
4537 /* Check for valid MEM_PHYSICAL usage */
4539 {
4540 /* MEM_PHYSICAL can only be used if MEM_RESERVE is also used */
4541 if (!(AllocationType & MEM_RESERVE))
4542 {
4543 DPRINT1("MEM_PHYSICAL used without MEM_RESERVE\n");
4545 }
4546
4547 /* Only these flags are allowed with MEM_PHYSIAL */
4549 {
4550 DPRINT1("Using illegal flags with MEM_PHYSICAL\n");
4552 }
4553
4554 /* Then make sure PAGE_READWRITE is used */
4555 if (Protect != PAGE_READWRITE)
4556 {
4557 DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n");
4559 }
4560 }
4561
4562 /* Calculate the protection mask and make sure it's valid */
4563 ProtectionMask = MiMakeProtectionMask(Protect);
4564 if (ProtectionMask == MM_INVALID_PROTECTION)
4565 {
4566 DPRINT1("Invalid protection mask\n");
4568 }
4569
4570 /* Enter SEH */
4571 _SEH2_TRY
4572 {
4573 /* Check for user-mode parameters */
4574 if (PreviousMode != KernelMode)
4575 {
4576 /* Make sure they are writable */
4577 ProbeForWritePointer(UBaseAddress);
4578 ProbeForWriteSize_t(URegionSize);
4579 }
4580
4581 /* Capture their values */
4582 PBaseAddress = *UBaseAddress;
4583 PRegionSize = *URegionSize;
4584 }
4586 {
4587 /* Return the exception code */
4589 }
4590 _SEH2_END;
4591
4592 /* Make sure the allocation isn't past the VAD area */
4593 if (PBaseAddress > MM_HIGHEST_VAD_ADDRESS)
4594 {
4595 DPRINT1("Virtual allocation base above User Space\n");
4597 }
4598
4599 /* Make sure the allocation wouldn't overflow past the VAD area */
4600 if ((((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) - (ULONG_PTR)PBaseAddress) < PRegionSize)
4601 {
4602 DPRINT1("Region size would overflow into kernel-memory\n");
4604 }
4605
4606 /* Make sure there's a size specified */
4607 if (!PRegionSize)
4608 {
4609 DPRINT1("Region size is invalid (zero)\n");
4611 }
4612
4613 //
4614 // If this is for the current process, just use PsGetCurrentProcess
4615 //
4617 {
4618 Process = CurrentProcess;
4619 }
4620 else
4621 {
4622 //
4623 // Otherwise, reference the process with VM rights and attach to it if
4624 // this isn't the current process. We must attach because we'll be touching
4625 // PTEs and PDEs that belong to user-mode memory, and also touching the
4626 // Working Set which is stored in Hyperspace.
4627 //
4632 (PVOID*)&Process,
4633 NULL);
4634 if (!NT_SUCCESS(Status)) return Status;
4635 if (CurrentProcess != Process)
4636 {
4638 Attached = TRUE;
4639 }
4640 }
4641
4642 DPRINT("NtAllocateVirtualMemory: Process 0x%p, Address 0x%p, Zerobits %lu , RegionSize 0x%x, Allocation type 0x%x, Protect 0x%x.\n",
4643 Process, PBaseAddress, ZeroBits, PRegionSize, AllocationType, Protect);
4644
4645 //
4646 // Check for large page allocations and make sure that the required privilege
4647 // is being held, before attempting to handle them.
4648 //
4651 {
4652 /* Fail without it */
4653 DPRINT1("Privilege not held for MEM_LARGE_PAGES\n");
4655 goto FailPathNoLock;
4656 }
4657
4658 //
4659 // Fail on the things we don't yet support
4660 //
4662 {
4663 DPRINT1("MEM_LARGE_PAGES not supported\n");
4665 goto FailPathNoLock;
4666 }
4668 {
4669 DPRINT1("MEM_PHYSICAL not supported\n");
4671 goto FailPathNoLock;
4672 }
4674 {
4675 DPRINT1("MEM_WRITE_WATCH not supported\n");
4677 goto FailPathNoLock;
4678 }
4679
4680 //
4681 // Check if the caller is reserving memory, or committing memory and letting
4682 // us pick the base address
4683 //
4684 if (!(PBaseAddress) || (AllocationType & MEM_RESERVE))
4685 {
4686 //
4687 // Do not allow COPY_ON_WRITE through this API
4688 //
4690 {
4691 DPRINT1("Copy on write not allowed through this path\n");
4693 goto FailPathNoLock;
4694 }
4695
4696 //
4697 // Does the caller have an address in mind, or is this a blind commit?
4698 //
4699 if (!PBaseAddress)
4700 {
4701 //
4702 // This is a blind commit, all we need is the region size
4703 //
4704 PRegionSize = ROUND_TO_PAGES(PRegionSize);
4705 EndingAddress = 0;
4706 StartingAddress = 0;
4707
4708 //
4709 // Check if ZeroBits were specified
4710 //
4711 if (ZeroBits != 0)
4712 {
4713 //
4714 // Calculate the highest address and check if it's valid
4715 //
4716 HighestAddress = MAXULONG_PTR >> ZeroBits;
4717 if (HighestAddress > (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS)
4718 {
4720 goto FailPathNoLock;
4721 }
4722 }
4723 }
4724 else
4725 {
4726 //
4727 // This is a reservation, so compute the starting address on the
4728 // expected 64KB granularity, and see where the ending address will
4729 // fall based on the aligned address and the passed in region size
4730 //
4731 EndingAddress = ((ULONG_PTR)PBaseAddress + PRegionSize - 1) | (PAGE_SIZE - 1);
4732 PRegionSize = EndingAddress + 1 - ROUND_DOWN((ULONG_PTR)PBaseAddress, _64K);
4733 StartingAddress = (ULONG_PTR)PBaseAddress;
4734 }
4735
4736 // Charge quotas for the VAD
4738 if (!NT_SUCCESS(Status))
4739 {
4740 DPRINT1("Quota exceeded.\n");
4741 goto FailPathNoLock;
4742 }
4743
4745
4746 //
4747 // Allocate and initialize the VAD
4748 //
4749 Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'SdaV');
4750 if (Vad == NULL)
4751 {
4752 DPRINT1("Failed to allocate a VAD!\n");
4754 goto FailPathNoLock;
4755 }
4756
4757 RtlZeroMemory(Vad, sizeof(MMVAD_LONG));
4759 Vad->u.VadFlags.Protection = ProtectionMask;
4760 Vad->u.VadFlags.PrivateMemory = 1;
4761 Vad->ControlArea = NULL; // For Memory-Area hack
4762
4763 //
4764 // Insert the VAD
4765 //
4766 Status = MiInsertVadEx(Vad,
4767 &StartingAddress,
4768 PRegionSize,
4769 HighestAddress,
4772 if (!NT_SUCCESS(Status))
4773 {
4774 DPRINT1("Failed to insert the VAD!\n");
4775 ExFreePoolWithTag(Vad, 'SdaV');
4776 goto FailPathNoLock;
4777 }
4778
4779 //
4780 // Detach and dereference the target process if
4781 // it was different from the current process
4782 //
4785
4786 //
4787 // Use SEH to write back the base address and the region size. In the case
4788 // of an exception, we do not return back the exception code, as the memory
4789 // *has* been allocated. The caller would now have to call VirtualQuery
4790 // or do some other similar trick to actually find out where its memory
4791 // allocation ended up
4792 //
4793 _SEH2_TRY
4794 {
4795 *URegionSize = PRegionSize;
4796 *UBaseAddress = (PVOID)StartingAddress;
4797 }
4799 {
4800 //
4801 // Ignore exception!
4802 //
4803 }
4804 _SEH2_END;
4805 DPRINT("Reserved %x bytes at %p.\n", PRegionSize, StartingAddress);
4806 return STATUS_SUCCESS;
4807 }
4808
4809 //
4810 // This is a MEM_COMMIT on top of an existing address which must have been
4811 // MEM_RESERVED already. Compute the start and ending base addresses based
4812 // on the user input, and then compute the actual region size once all the
4813 // alignments have been done.
4814 //
4815 EndingAddress = (((ULONG_PTR)PBaseAddress + PRegionSize - 1) | (PAGE_SIZE - 1));
4816 StartingAddress = (ULONG_PTR)PAGE_ALIGN(PBaseAddress);
4817 PRegionSize = EndingAddress - StartingAddress + 1;
4818
4819 //
4820 // Lock the address space and make sure the process isn't already dead
4821 //
4824 if (Process->VmDeleted)
4825 {
4826 DPRINT1("Process is dying\n");
4828 goto FailPath;
4829 }
4830
4831 //
4832 // Get the VAD for this address range, and make sure it exists
4833 //
4834 Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
4835 EndingAddress >> PAGE_SHIFT,
4836 &Process->VadRoot,
4837 (PMMADDRESS_NODE*)&FoundVad);
4838 if (Result != TableFoundNode)
4839 {
4840 DPRINT1("Could not find a VAD for this allocation\n");
4842 goto FailPath;
4843 }
4844
4846 {
4848 DPRINT("MEM_RESET not supported\n");
4850 goto FailPath;
4851 }
4852
4853 //
4854 // These kinds of VADs are illegal for this Windows function when trying to
4855 // commit an existing range
4856 //
4857 if ((FoundVad->u.VadFlags.VadType == VadAwe) ||
4858 (FoundVad->u.VadFlags.VadType == VadDevicePhysicalMemory) ||
4859 (FoundVad->u.VadFlags.VadType == VadLargePages))
4860 {
4861 DPRINT1("Illegal VAD for attempting a MEM_COMMIT\n");
4863 goto FailPath;
4864 }
4865
4866 //
4867 // Make sure that this address range actually fits within the VAD for it
4868 //
4869 if (((StartingAddress >> PAGE_SHIFT) < FoundVad->StartingVpn) ||
4870 ((EndingAddress >> PAGE_SHIFT) > FoundVad->EndingVpn))
4871 {
4872 DPRINT1("Address range does not fit into the VAD\n");
4874 goto FailPath;
4875 }
4876
4877 //
4878 // Make sure this is an ARM3 section
4879 //
4880 if (MI_IS_ROSMM_VAD(FoundVad))
4881 {
4882 DPRINT1("Illegal commit of non-ARM3 section!\n");
4884 goto FailPath;
4885 }
4886
4887 // Is this a previously reserved section being committed? If so, enter the
4888 // special section path
4889 //
4890 if (FoundVad->u.VadFlags.PrivateMemory == FALSE)
4891 {
4892 //
4893 // You cannot commit large page sections through this API
4894 //
4895 if (FoundVad->u.VadFlags.VadType == VadLargePageSection)
4896 {
4897 DPRINT1("Large page sections cannot be VirtualAlloc'd\n");
4899 goto FailPath;
4900 }
4901
4902 //
4903 // You can only use caching flags on a rotate VAD
4904 //
4906 (FoundVad->u.VadFlags.VadType != VadRotatePhysical))
4907 {
4908 DPRINT1("Cannot use caching flags with anything but rotate VADs\n");
4910 goto FailPath;
4911 }
4912
4913 //
4914 // We should make sure that the section's permissions aren't being
4915 // messed with
4916 //
4917 if (FoundVad->u.VadFlags.NoChange)
4918 {
4919 //
4920 // Make sure it's okay to touch it
4921 // Note: The Windows 2003 kernel has a bug here, passing the
4922 // unaligned base address together with the aligned size,
4923 // potentially covering a region larger than the actual allocation.
4924 // Might be exposed through NtGdiCreateDIBSection w/ section handle
4925 // For now we keep this behavior.
4926 // TODO: analyze possible implications, create test case
4927 //
4928 Status = MiCheckSecuredVad(FoundVad,
4929 PBaseAddress,
4930 PRegionSize,
4931 ProtectionMask);
4932 if (!NT_SUCCESS(Status))
4933 {
4934 DPRINT1("Secured VAD being messed around with\n");
4935 goto FailPath;
4936 }
4937 }
4938
4939 //
4940 // ARM3 does not support file-backed sections, only shared memory
4941 //
4942 ASSERT(FoundVad->ControlArea->FilePointer == NULL);
4943
4944 //
4945 // Rotate VADs cannot be guard pages or inaccessible, nor copy on write
4946 //
4947 if ((FoundVad->u.VadFlags.VadType == VadRotatePhysical) &&
4949 {
4950 DPRINT1("Invalid page protection for rotate VAD\n");
4952 goto FailPath;
4953 }
4954
4955 //
4956 // Compute PTE addresses and the quota charge, then grab the commit lock
4957 //
4958 PointerPte = MI_GET_PROTOTYPE_PTE_FOR_VPN(FoundVad, StartingAddress >> PAGE_SHIFT);
4959 LastPte = MI_GET_PROTOTYPE_PTE_FOR_VPN(FoundVad, EndingAddress >> PAGE_SHIFT);
4960 QuotaCharge = (ULONG)(LastPte - PointerPte + 1);
4962
4963 //
4964 // Get the segment template PTE and start looping each page
4965 //
4966 TempPte = FoundVad->ControlArea->Segment->SegmentPteTemplate;
4967 ASSERT(TempPte.u.Long != 0);
4968 while (PointerPte <= LastPte)
4969 {
4970 //
4971 // For each non-already-committed page, write the invalid template PTE
4972 //
4973 if (PointerPte->u.Long == 0)
4974 {
4975 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
4976 }
4977 else
4978 {
4979 QuotaFree++;
4980 }
4981 PointerPte++;
4982 }
4983
4984 //
4985 // Now do the commit accounting and release the lock
4986 //
4987 ASSERT(QuotaCharge >= QuotaFree);
4988 QuotaCharge -= QuotaFree;
4989 FoundVad->ControlArea->Segment->NumberOfCommittedPages += QuotaCharge;
4991
4992 //
4993 // We are done with committing the section pages
4994 //
4996 goto FailPath;
4997 }
4998
4999 //
5000 // This is a specific ReactOS check because we only use normal VADs
5001 //
5002 ASSERT(FoundVad->u.VadFlags.VadType == VadNone);
5003
5004 //
5005 // While this is an actual Windows check
5006 //
5007 ASSERT(FoundVad->u.VadFlags.VadType != VadRotatePhysical);
5008
5009 //
5010 // Throw out attempts to use copy-on-write through this API path
5011 //
5013 {
5014 DPRINT1("Write copy attempted when not allowed\n");
5016 goto FailPath;
5017 }
5018
5019 //
5020 // Initialize a demand-zero PTE
5021 //
5022 TempPte.u.Long = 0;
5023 TempPte.u.Soft.Protection = ProtectionMask;
5024 ASSERT(TempPte.u.Long != 0);
5025
5026 //
5027 // Get the PTE, PDE and the last PTE for this address range
5028 //
5029 PointerPde = MiAddressToPde(StartingAddress);
5030 PointerPte = MiAddressToPte(StartingAddress);
5031 LastPte = MiAddressToPte(EndingAddress);
5032
5033 //
5034 // Update the commit charge in the VAD as well as in the process, and check
5035 // if this commit charge was now higher than the last recorded peak, in which
5036 // case we also update the peak
5037 //
5038 FoundVad->u.VadFlags.CommitCharge += (1 + LastPte - PointerPte);
5039 Process->CommitCharge += (1 + LastPte - PointerPte);
5040 if (Process->CommitCharge > Process->CommitChargePeak)
5041 {
5042 Process->CommitChargePeak = Process->CommitCharge;
5043 }
5044
5045 //
5046 // Lock the working set while we play with user pages and page tables
5047 //
5048 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5049
5050 //
5051 // Make the current page table valid, and then loop each page within it
5052 //
5054 while (PointerPte <= LastPte)
5055 {
5056 //
5057 // Have we crossed into a new page table?
5058 //
5059 if (MiIsPteOnPdeBoundary(PointerPte))
5060 {
5061 //
5062 // Get the PDE and now make it valid too
5063 //
5064 PointerPde = MiPteToPde(PointerPte);
5066 }
5067
5068 //
5069 // Is this a zero PTE as expected?
5070 //
5071 if (PointerPte->u.Long == 0)
5072 {
5073 //
5074 // First increment the count of pages in the page table for this
5075 // process
5076 //
5078
5079 //
5080 // And now write the invalid demand-zero PTE as requested
5081 //
5082 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
5083 }
5084 else if (PointerPte->u.Long == MmDecommittedPte.u.Long)
5085 {
5086 //
5087 // If the PTE was already decommitted, there is nothing else to do
5088 // but to write the new demand-zero PTE
5089 //
5090 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
5091 }
5092 else if (!(ChangeProtection) && (Protect != MiGetPageProtection(PointerPte)))
5093 {
5094 //
5095 // We don't handle these scenarios yet
5096 //
5097 if (PointerPte->u.Soft.Valid == 0)
5098 {
5099 ASSERT(PointerPte->u.Soft.Prototype == 0);
5100 ASSERT((PointerPte->u.Soft.PageFileHigh == 0) || (PointerPte->u.Soft.Transition == 1));
5101 }
5102
5103 //
5104 // There's a change in protection, remember this for later, but do
5105 // not yet handle it.
5106 //
5107 ChangeProtection = TRUE;
5108 }
5109
5110 //
5111 // Move to the next PTE
5112 //
5113 PointerPte++;
5114 }
5115
5116 //
5117 // Release the working set lock, unlock the address space, and detach from
5118 // the target process if it was not the current process. Also dereference the
5119 // target process if this wasn't the case.
5120 //
5123FailPath:
5125
5126 if (!NT_SUCCESS(Status))
5127 {
5128 if (Vad != NULL)
5129 {
5130 ExFreePoolWithTag(Vad, 'SdaV');
5131 }
5132 }
5133
5134 //
5135 // Check if we need to update the protection
5136 //
5137 if (ChangeProtection)
5138 {
5139 PVOID ProtectBaseAddress = (PVOID)StartingAddress;
5140 SIZE_T ProtectSize = PRegionSize;
5141 ULONG OldProtection;
5142
5143 //
5144 // Change the protection of the region
5145 //
5147 &ProtectBaseAddress,
5148 &ProtectSize,
5149 Protect,
5150 &OldProtection);
5151 }
5152
5153FailPathNoLock:
5156
5157 //
5158 // Only write back results on success
5159 //
5160 if (NT_SUCCESS(Status))
5161 {
5162 //
5163 // Use SEH to write back the base address and the region size. In the case
5164 // of an exception, we strangely do return back the exception code, even
5165 // though the memory *has* been allocated. This mimics Windows behavior and
5166 // there is not much we can do about it.
5167 //
5168 _SEH2_TRY
5169 {
5170 *URegionSize = PRegionSize;
5171 *UBaseAddress = (PVOID)StartingAddress;
5172 }
5174 {
5176 }
5177 _SEH2_END;
5178 }
5179 else if (QuotaCharged)
5180 {
5182 }
5183
5184 return Status;
5185}
5186
5187/*
5188 * @implemented
5189 */
5191NTAPI
5193 IN PVOID* UBaseAddress,
5194 IN PSIZE_T URegionSize,
5196{
5197 SIZE_T PRegionSize;
5198 PVOID PBaseAddress;
5199 LONG_PTR AlreadyDecommitted, CommitReduction = 0;
5200 LONG_PTR FirstCommit;
5201 ULONG_PTR StartingAddress, EndingAddress;
5202 PMMVAD Vad;
5203 PMMVAD NewVad;
5207 PETHREAD CurrentThread = PsGetCurrentThread();
5208 PEPROCESS CurrentProcess = PsGetCurrentProcess();
5212 PAGED_CODE();
5213
5214 //
5215 // Only two flags are supported, exclusively.
5216 //
5218 {
5219 DPRINT1("Invalid FreeType (0x%08lx)\n", FreeType);
5221 }
5222
5223 //
5224 // Enter SEH for probe and capture. On failure, return back to the caller
5225 // with an exception violation.
5226 //
5227 _SEH2_TRY
5228 {
5229 //
5230 // Check for user-mode parameters and make sure that they are writeable
5231 //
5232 if (PreviousMode != KernelMode)
5233 {
5234 ProbeForWritePointer(UBaseAddress);
5235 ProbeForWriteUlong(URegionSize);
5236 }
5237
5238 //
5239 // Capture the current values
5240 //
5241 PBaseAddress = *UBaseAddress;
5242 PRegionSize = *URegionSize;
5243 }
5245 {
5247 }
5248 _SEH2_END;
5249
5250 //
5251 // Make sure the allocation isn't past the user area
5252 //
5253 if (PBaseAddress >= MM_HIGHEST_USER_ADDRESS)
5254 {
5255 DPRINT1("Virtual free base above User Space\n");
5257 }
5258
5259 //
5260 // Make sure the allocation wouldn't overflow past the user area
5261 //
5262 if (((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)PBaseAddress) < PRegionSize)
5263 {
5264 DPRINT1("Region size would overflow into kernel-memory\n");
5266 }
5267
5268 //
5269 // If this is for the current process, just use PsGetCurrentProcess
5270 //
5272 {
5273 Process = CurrentProcess;
5274 }
5275 else
5276 {
5277 //
5278 // Otherwise, reference the process with VM rights and attach to it if
5279 // this isn't the current process. We must attach because we'll be touching
5280 // PTEs and PDEs that belong to user-mode memory, and also touching the
5281 // Working Set which is stored in Hyperspace.
5282 //
5287 (PVOID*)&Process,
5288 NULL);
5289 if (!NT_SUCCESS(Status)) return Status;
5290 if (CurrentProcess != Process)
5291 {
5293 Attached = TRUE;
5294 }
5295 }
5296
5297 DPRINT("NtFreeVirtualMemory: Process 0x%p, Address 0x%p, Size 0x%Ix, FreeType 0x%08lx\n",
5298 Process, PBaseAddress, PRegionSize, FreeType);
5299
5300 //
5301 // Lock the address space
5302 //
5305
5306 //
5307 // If the address space is being deleted, fail the de-allocation since it's
5308 // too late to do anything about it
5309 //
5310 if (Process->VmDeleted)
5311 {
5312 DPRINT1("Process is dead\n");
5314 goto FailPath;
5315 }
5316
5317 //
5318 // Compute start and end addresses, and locate the VAD
5319 //
5320 StartingAddress = (ULONG_PTR)PAGE_ALIGN(PBaseAddress);
5321 EndingAddress = ((ULONG_PTR)PBaseAddress + PRegionSize - 1) | (PAGE_SIZE - 1);
5322 Vad = MiLocateAddress((PVOID)StartingAddress);
5323 if (!Vad)
5324 {
5325 DPRINT1("Unable to find VAD for address 0x%p\n", StartingAddress);
5327 goto FailPath;
5328 }
5329
5330 //
5331 // If the range exceeds the VAD's ending VPN, fail this request
5332 //
5333 if (Vad->EndingVpn < (EndingAddress >> PAGE_SHIFT))
5334 {
5335 DPRINT1("Address 0x%p is beyond the VAD\n", EndingAddress);
5337 goto FailPath;
5338 }
5339
5340 //
5341 // Only private memory (except rotate VADs) can be freed through here */
5342 //
5343 if ((!(Vad->u.VadFlags.PrivateMemory) &&
5344 (Vad->u.VadFlags.VadType != VadRotatePhysical)) ||
5346 {
5347 DPRINT("Attempt to free section memory\n");
5349 goto FailPath;
5350 }
5351
5352 //
5353 // ARM3 does not yet handle protected VM
5354 //
5355 ASSERT(Vad->u.VadFlags.NoChange == 0);
5356
5357 //
5358 // Now we can try the operation. First check if this is a RELEASE or a DECOMMIT
5359 //
5360 if (FreeType & MEM_RELEASE)
5361 {
5362 //
5363 // ARM3 only supports this VAD in this path
5364 //
5365 ASSERT(Vad->u.VadFlags.VadType == VadNone);
5366
5367 //
5368 // Is the caller trying to remove the whole VAD, or remove only a portion
5369 // of it? If no region size is specified, then the assumption is that the
5370 // whole VAD is to be destroyed
5371 //
5372 if (!PRegionSize)
5373 {
5374 //
5375 // The caller must specify the base address identically to the range
5376 // that is stored in the VAD.
5377 //
5378 if (((ULONG_PTR)PBaseAddress >> PAGE_SHIFT) != Vad->StartingVpn)
5379 {
5380 DPRINT1("Address 0x%p does not match the VAD\n", PBaseAddress);
5382 goto FailPath;
5383 }
5384
5385 //
5386 // Now compute the actual start/end addresses based on the VAD
5387 //
5388 StartingAddress = Vad->StartingVpn << PAGE_SHIFT;
5389 EndingAddress = (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1);
5390
5391 //
5392 // Finally lock the working set and remove the VAD from the VAD tree
5393 //
5394 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5395 ASSERT(Process->VadRoot.NumberGenericTableElements >= 1);
5396 MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot);
5398 }
5399 else
5400 {
5401 //
5402 // This means the caller wants to release a specific region within
5403 // the range. We have to find out which range this is -- the following
5404 // possibilities exist plus their union (CASE D):
5405 //
5406 // STARTING ADDRESS ENDING ADDRESS
5407 // [<========][========================================][=========>]
5408 // CASE A CASE B CASE C
5409 //
5410 //
5411 // First, check for case A or D
5412 //
5413 if ((StartingAddress >> PAGE_SHIFT) == Vad->StartingVpn)
5414 {
5415 //
5416 // Check for case D
5417 //
5418 if ((EndingAddress >> PAGE_SHIFT) == Vad->EndingVpn)
5419 {
5420 //
5421 // Case D (freeing the entire region)
5422 //
5423 // This is the easiest one to handle -- it is identical to
5424 // the code path above when the caller sets a zero region size
5425 // and the whole VAD is destroyed
5426 //
5427 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5428 ASSERT(Process->VadRoot.NumberGenericTableElements >= 1);
5429 MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot);
5431 }
5432 else
5433 {
5434 //
5435 // Case A (freeing a part at the beginning)
5436 //
5437 // This case is pretty easy too -- we compute a bunch of
5438 // pages to decommit, and then push the VAD's starting address
5439 // a bit further down, then decrement the commit charge
5440 //
5441 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5442 CommitReduction = MiCalculatePageCommitment(StartingAddress,
5443 EndingAddress,
5444 Vad,
5445 Process);
5446 Vad->u.VadFlags.CommitCharge -= CommitReduction;
5447 Vad->StartingVpn = (EndingAddress + 1) >> PAGE_SHIFT;
5448
5449 //
5450 // After analyzing the VAD, set it to NULL so that we don't
5451 // free it in the exit path
5452 //
5453 Vad = NULL;
5454 }
5455 }
5456 else
5457 {
5458 //
5459 // This is case B or case C. First check for case C
5460 //
5461 if ((EndingAddress >> PAGE_SHIFT) == Vad->EndingVpn)
5462 {
5463 //
5464 // Case C (freeing a part at the end)
5465 //
5466 // This is pretty easy and similar to case A. We compute the
5467 // amount of pages to decommit, update the VAD's commit charge
5468 // and then change the ending address of the VAD to be a bit
5469 // smaller.
5470 //
5471 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5472 CommitReduction = MiCalculatePageCommitment(StartingAddress,
5473 EndingAddress,
5474 Vad,
5475 Process);
5476 Vad->u.VadFlags.CommitCharge -= CommitReduction;
5477 Vad->EndingVpn = (StartingAddress - 1) >> PAGE_SHIFT;
5478 }
5479 else
5480 {
5481 //
5482 // Case B (freeing a part in the middle)
5483 //
5484 // This is the hardest one. Because we are removing a chunk
5485 // of memory from the very middle of the VAD, we must actually
5486 // split the VAD into two new VADs and compute the commit
5487 // charges for each of them, and reinsert new charges.
5488 //
5489 NewVad = ExAllocatePoolZero(NonPagedPool, sizeof(MMVAD_LONG), 'SdaV');
5490 if (NewVad == NULL)
5491 {
5492 DPRINT1("Failed to allocate a VAD!\n");
5494 goto FailPath;
5495 }
5496
5497 // Charge quota for the new VAD
5499
5500 if (!NT_SUCCESS(Status))
5501 {
5502 DPRINT1("Ran out of process quota whilst creating new VAD!\n");
5503 ExFreePoolWithTag(NewVad, 'SdaV');
5505 goto FailPath;
5506 }
5507
5508 //
5509 // This new VAD describes the second chunk, so we keep the end
5510 // address of the original and adjust the start to point past
5511 // the released region.
5512 // The commit charge will be calculated below.
5513 //
5514 NewVad->StartingVpn = (EndingAddress + 1) >> PAGE_SHIFT;
5515 NewVad->EndingVpn = Vad->EndingVpn;
5516 NewVad->u.LongFlags = Vad->u.LongFlags;
5517 NewVad->u.VadFlags.CommitCharge = 0;
5518 ASSERT(NewVad->EndingVpn >= NewVad->StartingVpn);
5519
5520 //
5521 // Get the commit charge for the released region
5522 //
5523 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5524 CommitReduction = MiCalculatePageCommitment(StartingAddress,
5525 EndingAddress,
5526 Vad,
5527 Process);
5528
5529 //
5530 // Adjust the end of the original VAD (first chunk).
5531 //
5532 Vad->EndingVpn = (StartingAddress - 1) >> PAGE_SHIFT;
5533
5534 //
5535 // Now the addresses for both VADs are consistent,
5536 // so insert the new one.
5537 // ReactOS: This will take care of creating a second MEMORY_AREA.
5538 //
5539 MiInsertVad(NewVad, &Process->VadRoot);
5540
5541 //
5542 // Calculate the commit charge for the first split.
5543 // The second chunk's size is the original size, minus the
5544 // released region's size, minus this first chunk.
5545 //
5546 FirstCommit = MiCalculatePageCommitment(Vad->StartingVpn << PAGE_SHIFT,
5547 StartingAddress - 1,
5548 Vad,
5549 Process);
5550 NewVad->u.VadFlags.CommitCharge = Vad->u.VadFlags.CommitCharge - CommitReduction - FirstCommit;
5551 Vad->u.VadFlags.CommitCharge = FirstCommit;
5552 }
5553
5554 //
5555 // After analyzing the VAD, set it to NULL so that we don't
5556 // free it in the exit path
5557 //
5558 Vad = NULL;
5559 }
5560 }
5561
5562 //
5563 // Now we have a range of pages to dereference, so call the right API
5564 // to do that and then release the working set, since we're done messing
5565 // around with process pages.
5566 //
5567 MiDeleteVirtualAddresses(StartingAddress, EndingAddress, NULL);
5570
5571FinalPath:
5572 //
5573 // Update the process counters
5574 //
5575 PRegionSize = EndingAddress - StartingAddress + 1;
5576 Process->CommitCharge -= CommitReduction;
5577 if (FreeType & MEM_RELEASE) Process->VirtualSize -= PRegionSize;
5578
5579 //
5580 // Unlock the address space and free the VAD in failure cases. Next,
5581 // detach from the target process so we can write the region size and the
5582 // base address to the correct source process, and dereference the target
5583 // process.
5584 //
5586 if (Vad) ExFreePool(Vad);
5589
5590 //
5591 // Use SEH to safely return the region size and the base address of the
5592 // deallocation. If we get an access violation, don't return a failure code
5593 // as the deallocation *has* happened. The caller will just have to figure
5594 // out another way to find out where it is (such as VirtualQuery).
5595 //
5596 _SEH2_TRY
5597 {
5598 *URegionSize = PRegionSize;
5599 *UBaseAddress = (PVOID)StartingAddress;
5600 }
5602 {
5603 }
5604 _SEH2_END;
5605 return Status;
5606 }
5607
5608 //
5609 // This is the decommit path. You cannot decommit from the following VADs in
5610 // Windows, so fail the vall
5611 //
5612 if ((Vad->u.VadFlags.VadType == VadAwe) ||
5613 (Vad->u.VadFlags.VadType == VadLargePages) ||
5615 {
5616 DPRINT1("Trying to decommit from invalid VAD\n");
5618 goto FailPath;
5619 }
5620
5621 //
5622 // If the caller did not specify a region size, first make sure that this
5623 // region is actually committed. If it is, then compute the ending address
5624 // based on the VAD.
5625 //
5626 if (!PRegionSize)
5627 {
5628 if (((ULONG_PTR)PBaseAddress >> PAGE_SHIFT) != Vad->StartingVpn)
5629 {
5630 DPRINT1("Decomitting non-committed memory\n");
5632 goto FailPath;
5633 }
5634 EndingAddress = (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1);
5635 }
5636
5637 //
5638 // Decommit the PTEs for the range plus the actual backing pages for the
5639 // range, then reduce that amount from the commit charge in the VAD
5640 //
5641 AlreadyDecommitted = MiDecommitPages((PVOID)StartingAddress,
5642 MiAddressToPte(EndingAddress),
5643 Process,
5644 Vad);
5645 CommitReduction = MiAddressToPte(EndingAddress) -
5646 MiAddressToPte(StartingAddress) +
5647 1 -
5648 AlreadyDecommitted;
5649
5650 ASSERT(CommitReduction >= 0);
5651 ASSERT(Vad->u.VadFlags.CommitCharge >= CommitReduction);
5652 Vad->u.VadFlags.CommitCharge -= CommitReduction;
5653
5654 //
5655 // We are done, go to the exit path without freeing the VAD as it remains
5656 // valid since we have not released the allocation.
5657 //
5658 Vad = NULL;
5660 goto FinalPath;
5661
5662 //
5663 // In the failure path, we detach and dereference the target process, and
5664 // return whatever failure code was sent.
5665 //
5666FailPath:
5670 return Status;
5671}
5672
5673
5675NTAPI
5677{
5679 MMPDE TempPde;
5680 MMPTE TempPte;
5681
5682 /* Check if the PXE/PPE/PDE is valid */
5683 if (
5684#if (_MI_PAGING_LEVELS == 4)
5685 (MiAddressToPxe(Address)->u.Hard.Valid) &&
5686#endif
5687#if (_MI_PAGING_LEVELS >= 3)
5688 (MiAddressToPpe(Address)->u.Hard.Valid) &&
5689#endif
5690 (MiAddressToPde(Address)->u.Hard.Valid))
5691 {
5692 /* Check for large pages */
5694 if (TempPde.u.Hard.LargePage)
5695 {
5696 /* Physical address is base page + large page offset */
5699 return PhysicalAddress;
5700 }
5701
5702 /* Check if the PTE is valid */
5704 if (TempPte.u.Hard.Valid)
5705 {
5706 /* Physical address is base page + page offset */
5709 return PhysicalAddress;
5710 }
5711 }
5712
5714 DPRINT1("MM:MmGetPhysicalAddressFailed base address was %p\n", Address);
5716 return PhysicalAddress;
5717}
5718
5719
5720/* EOF */
#define PAGED_CODE()
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
_In_ PVOID _In_ ULONG _Out_ PVOID _In_ ULONG _Inout_ PULONG ReturnLength
_In_ PVOID _In_ ULONG _Out_ PVOID _In_ ULONG _Inout_ PULONG _In_ KPROCESSOR_MODE PreviousMode
ULONG_PTR PFN_NUMBER
unsigned char BOOLEAN
Type
Definition: Type.h:7
HARDWARE_PTE_ARMV6 TempPte
Definition: winldr.c:76
HARDWARE_PDE_ARMV6 TempPde
Definition: winldr.c:78
#define MM_HIGHEST_USER_ADDRESS
Definition: armddk.h:17
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define MAXULONG_PTR
Definition: basetsd.h:97
#define UNIMPLEMENTED
Definition: ntoskrnl.c:15
return Found
Definition: dirsup.c:1270
_In_ WDFREQUEST _In_ MEDIA_LOCK_TYPE LockType
Definition: cdrom.h:1335
Definition: bufpool.h:45
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42
#define BufferSize
Definition: mmc.h:75
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define PAGE_READONLY
Definition: compat.h:138
static const WCHAR Cleanup[]
Definition: register.c:80
#define ULONG_PTR
Definition: config.h:101
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define NonPagedPool
Definition: env_spec_w32.h:307
#define ROUND_DOWN(n, align)
Definition: eventvwr.h:33
#define ExReleaseRundownProtection
Definition: ex.h:139
#define ExGetPreviousMode
Definition: ex.h:143
#define ExAcquireRundownProtection
Definition: ex.h:138
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
#define STATUS_ACCESS_VIOLATION
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
#define KeRosDumpStackFrames(Frames, Count)
Definition: gdidebug.h:11
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
VOID FASTCALL KeReleaseGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:75
VOID FASTCALL KeAcquireGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:64
_In_ ULONG Mode
Definition: hubbusif.h:303
#define USER_SHARED_DATA
Definition: pstypes.h:51
#define PROCESS_VM_READ
Definition: pstypes.h:162
#define PROCESS_QUERY_INFORMATION
Definition: pstypes.h:167
#define PROCESS_VM_WRITE
Definition: pstypes.h:163
#define PROCESS_VM_OPERATION
Definition: pstypes.h:161
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
if(dx< 0)
Definition: linetemp.h:194
PMMVAD NTAPI MiLocateAddress(IN PVOID VirtualAddress)
PMMPTE MiHighestUserPte
Definition: mminit.c:233
#define MI_IS_ROS_PFN(x)
Definition: miarm.h:1106
NTSTATUS NTAPI MiQueryMemorySectionName(IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
Definition: section.c:1754
FORCEINLINE PMMPTE MI_GET_PROTOTYPE_PTE_FOR_VPN(IN PMMVAD Vad, IN ULONG_PTR Vpn)
Definition: miarm.h:1560
FORCEINLINE BOOLEAN MM_ANY_WS_LOCK_HELD_EXCLUSIVE(_In_ PETHREAD Thread)
Definition: miarm.h:1068
FORCEINLINE VOID MiLockProcessWorkingSetShared(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1149
FORCEINLINE VOID MiDeletePde(_In_ PMMPDE PointerPde, _In_ PEPROCESS CurrentProcess)
Definition: miarm.h:2535
PVOID MmPagedPoolStart
Definition: miarm.h:578
FORCEINLINE VOID MiLockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1268
VOID NTAPI MiRemoveNode(IN PMMADDRESS_NODE Node, IN PMM_AVL_TABLE Table)
Definition: vadnode.c:403
FORCEINLINE VOID MiUnlockProcessWorkingSetForFault(IN PEPROCESS Process, IN PETHREAD Thread, OUT PBOOLEAN Safe, OUT PBOOLEAN Shared)
Definition: miarm.h:1471
FORCEINLINE VOID MiLockProcessWorkingSetForFault(IN PEPROCESS Process, IN PETHREAD Thread, IN BOOLEAN Safe, IN BOOLEAN Shared)
Definition: miarm.h:1504
#define MI_SET_PFN_DELETED(x)
Definition: miarm.h:208
#define _64K
Definition: miarm.h:23
FORCEINLINE VOID MiUnlockProcessWorkingSetShared(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1218
FORCEINLINE VOID MI_ERASE_PTE(IN PMMPTE PointerPte)
Definition: miarm.h:1009
FORCEINLINE USHORT MiDecrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:2501
#define MM_DECOMMIT
Definition: miarm.h:64
#define MM_INVALID_PROTECTION
Definition: miarm.h:67
VOID NTAPI MiDecrementShareCount(IN PMMPFN Pfn1, IN PFN_NUMBER PageFrameIndex)
Definition: pfnlist.c:1141
FORCEINLINE VOID MiUnlockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1197
FORCEINLINE VOID MiUnlockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1242
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:996
FORCEINLINE VOID MiUnlockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1354
FORCEINLINE VOID MiDereferencePfnAndDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1618
VOID NTAPI MiUnlinkPageFromList(IN PMMPFN Pfn)
Definition: pfnlist.c:265
FORCEINLINE VOID MiReferenceProbedPageAndBumpLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1690
PSUBSECTION NTAPI MiLocateSubsection(IN PMMVAD Vad, IN ULONG_PTR Vpn)
Definition: section.c:556
NTSTATUS NTAPI MiInsertVadEx(_Inout_ PMMVAD Vad, _In_ ULONG_PTR *BaseAddress, _In_ SIZE_T ViewSize, _In_ ULONG_PTR HighestAddress, _In_ ULONG_PTR Alignment, _In_ ULONG AllocationType)
Definition: vadnode.c:245
KGUARDED_MUTEX MmSectionCommitMutex
Definition: section.c:108
NTSTATUS NTAPI MiCheckSecuredVad(IN PMMVAD Vad, IN PVOID Base, IN SIZE_T Size, IN ULONG ProtectionMask)
Definition: vadnode.c:815
NTSTATUS FASTCALL MiCheckPdeForPagedPool(IN PVOID Address)
Definition: pagfault.c:479
VOID NTAPI MiDecrementReferenceCount(IN PMMPFN Pfn1, IN PFN_NUMBER PageFrameIndex)
Definition: pfnlist.c:1236
#define MI_PTE_LOOKUP_NEEDED
Definition: miarm.h:245
TABLE_SEARCH_RESULT NTAPI MiCheckForConflictingNode(IN ULONG_PTR StartVpn, IN ULONG_PTR EndVpn, IN PMM_AVL_TABLE Table, OUT PMMADDRESS_NODE *NodeOrParent)
Definition: vadnode.c:157
ULONG NTAPI MiMakeProtectionMask(IN ULONG Protect)
Definition: section.c:140
FORCEINLINE USHORT MiIncrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:2475
PMMADDRESS_NODE NTAPI MiGetNextNode(IN PMMADDRESS_NODE Node)
Definition: vadnode.c:461
VOID NTAPI MiInsertVad(_Inout_ PMMVAD Vad, _Inout_ PMM_AVL_TABLE VadRoot)
FORCEINLINE PMMPFN MI_PFN_ELEMENT(IN PFN_NUMBER Pfn)
Definition: miarm.h:1577
FORCEINLINE VOID MiLockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1127
FORCEINLINE VOID MiLockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1172
#define PCHAR
Definition: match.c:90
VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation)
Definition: mdlsup.c:931
VOID NTAPI MmUnlockPages(IN PMDL Mdl)
Definition: mdlsup.c:1435
PVOID NTAPI MmMapLockedPagesSpecifyCache(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN MEMORY_CACHING_TYPE CacheType, IN PVOID BaseAddress, IN ULONG BugCheckOnFailure, IN ULONG Priority)
Definition: mdlsup.c:660
VOID NTAPI MmUnmapLockedPages(IN PVOID BaseAddress, IN PMDL Mdl)
Definition: mdlsup.c:837
BOOLEAN NTAPI MmIsAddressValid(IN PVOID VirtualAddress)
Definition: mmsup.c:174
#define MiAddressToPte(x)
Definition: mmx86.c:19
#define MiAddressToPde(x)
Definition: mmx86.c:20
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
unsigned __int64 ULONG64
Definition: imports.h:198
@ HighPagePriority
Definition: imports.h:55
FORCEINLINE PVOID ExAllocatePoolZero(ULONG PoolType, SIZE_T NumberOfBytes, ULONG Tag)
Definition: precomp.h:45
static const OBJECT_ATTRIBUTES const LARGE_INTEGER ULONG
Definition: virtual.c:34
static PVOID
Definition: virtual.c:33
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
#define MM_SHARED_USER_DATA_VA
Definition: mmtypes.h:48
#define KeGetPreviousMode()
Definition: ketypes.h:1115
#define KernelMode
Definition: asm.h:38
_In_ HANDLE ProcessHandle
Definition: mmfuncs.h:403
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR ZeroBits
Definition: mmfuncs.h:405
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR _In_ SIZE_T _Inout_opt_ PLARGE_INTEGER _Inout_ PSIZE_T _In_ SECTION_INHERIT _In_ ULONG AllocationType
Definition: mmfuncs.h:410
__kernel_entry _Inout_ _Inout_ PSIZE_T RegionSize
Definition: mmfuncs.h:172
__kernel_entry _Inout_ _Inout_ PSIZE_T _In_ ULONG FreeType
Definition: mmfuncs.h:174
struct _MEMORY_BASIC_INFORMATION * PMEMORY_BASIC_INFORMATION
@ MemoryBasicInformation
Definition: mmtypes.h:183
@ MemorySectionName
Definition: mmtypes.h:185
@ MemoryWorkingSetList
Definition: mmtypes.h:184
@ MemoryBasicVlmInformation
Definition: mmtypes.h:186
#define MEM_PHYSICAL
Definition: mmtypes.h:87
#define PAGE_ROUND_UP(x)
Definition: mmtypes.h:38
@ VadAwe
Definition: mmtypes.h:207
@ VadLargePageSection
Definition: mmtypes.h:211
@ VadWriteWatch
Definition: mmtypes.h:208
@ VadLargePages
Definition: mmtypes.h:209
@ VadRotatePhysical
Definition: mmtypes.h:210
@ VadDevicePhysicalMemory
Definition: mmtypes.h:205
@ VadImageMap
Definition: mmtypes.h:206
@ VadNone
Definition: mmtypes.h:204
#define MEM_IMAGE
Definition: mmtypes.h:89
enum _MEMORY_INFORMATION_CLASS MEMORY_INFORMATION_CLASS
struct _MMVAD * PMMVAD
struct _MEMORY_BASIC_INFORMATION MEMORY_BASIC_INFORMATION
#define MAP_PROCESS
Definition: mmtypes.h:67
#define MEM_WRITE_WATCH
Definition: mmtypes.h:86
#define MAP_SYSTEM
Definition: mmtypes.h:68
@ ModifiedPageList
Definition: mmtypes.h:156
@ StandbyPageList
Definition: mmtypes.h:155
#define PAGE_ROUND_DOWN(x)
Definition: mmtypes.h:36
#define _Inout_
Definition: no_sal2.h:162
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
int Count
Definition: noreturn.cpp:7
#define MEM_TOP_DOWN
Definition: nt_native.h:1324
#define PAGE_WRITECOPY
Definition: nt_native.h:1308
#define MEM_FREE
Definition: nt_native.h:1320
#define PAGE_NOCACHE
Definition: nt_native.h:1314
#define MEM_DECOMMIT
Definition: nt_native.h:1318
#define PAGE_READWRITE
Definition: nt_native.h:1307
#define PAGE_EXECUTE_READ
Definition: nt_native.h:1310
#define MEM_RESET
Definition: nt_native.h:1323
#define MEM_PRIVATE
Definition: nt_native.h:1321
#define PAGE_EXECUTE
Definition: nt_native.h:1309
#define NtCurrentProcess()
Definition: nt_native.h:1660
#define MEM_MAPPED
Definition: nt_native.h:1322
#define PAGE_EXECUTE_WRITECOPY
Definition: nt_native.h:1312
#define MEM_RESERVE
Definition: nt_native.h:1317
#define MEM_LARGE_PAGES
Definition: nt_native.h:1325
#define MEM_RELEASE
Definition: nt_native.h:1319
#define MEM_COMMIT
Definition: nt_native.h:1316
#define PAGE_NOACCESS
Definition: nt_native.h:1305
#define PAGE_EXECUTE_READWRITE
Definition: nt_native.h:1311
#define PAGE_GUARD
Definition: nt_native.h:1313
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
FORCEINLINE VOID KeInvalidateTlbEntry(IN PVOID Address)
Definition: ke.h:266
FORCEINLINE VOID KeSweepICache(IN PVOID BaseAddress, IN SIZE_T FlushSize)
Definition: ke.h:282
FORCEINLINE PMMPXE MiPdeToPxe(PMMPDE PointerPde)
Definition: mm.h:300
#define MI_MAX_ZERO_BITS
Definition: mm.h:83
FORCEINLINE PVOID MiPpeToAddress(PMMPTE PointerPpe)
Definition: mm.h:226
FORCEINLINE PMMPDE MiPdeToPpe(PMMPDE PointerPde)
Definition: mm.h:292
FORCEINLINE PMMPPE MiPteToPpe(PMMPTE PointerPte)
Definition: mm.h:276
FORCEINLINE PMMPTE MiPxeToPte(PMMPXE PointerPxe)
Definition: mm.h:260
#define MiIsPteOnPpeBoundary(PointerPte)
Definition: mm.h:308
FORCEINLINE PMMPTE MiPpeToPte(PMMPPE PointerPpe)
Definition: mm.h:252
#define MM_HIGHEST_VAD_ADDRESS
Definition: mm.h:46
#define _MI_PAGING_LEVELS
Definition: mm.h:6
FORCEINLINE PMMPTE MiAddressToPpe(PVOID Address)
Definition: mm.h:161
#define MiProtoPteToPte(x)
Definition: mm.h:316
FORCEINLINE PMMPTE MiAddressToPxe(PVOID Address)
Definition: mm.h:171
#define MiIsPteOnPdeBoundary(PointerPte)
Definition: mm.h:306
FORCEINLINE BOOLEAN MI_IS_MAPPED_PTE(PMMPTE PointerPte)
Definition: mm.h:356
#define MiIsPteOnPxeBoundary(PointerPte)
Definition: mm.h:310
#define PDE_MAPPED_VA
Definition: mm.h:39
#define PFN_FROM_PTE(v)
Definition: mm.h:92
FORCEINLINE PMMPXE MiPteToPxe(PMMPTE PointerPte)
Definition: mm.h:284
FORCEINLINE PVOID MiPxeToAddress(PMMPTE PointerPxe)
Definition: mm.h:235
#define MiPdeToAddress(_Pde)
Definition: mm.h:117
#define MiPteToPde(_Pte)
Definition: mm.h:121
#define PTE_PER_PAGE
Definition: mm.h:20
#define MiPteToAddress(_Pte)
Definition: mm.h:116
#define MiPdeToPte(_Pde)
Definition: mm.h:120
VOID NTAPI KeFlushCurrentTb(VOID)
Definition: cpu.c:535
FORCEINLINE PMMSUPPORT MmGetCurrentAddressSpace(VOID)
Definition: mm.h:1722
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:1045
#define MM_NOIRQL
Definition: mm.h:70
FORCEINLINE VOID MmLockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1694
#define MM_VIRTMEM_GRANULARITY
Definition: mm.h:102
#define MI_ASSERT_PFN_LOCK_HELD()
Definition: mm.h:1041
NTSTATUS NTAPI MmQuerySectionView(PMEMORY_AREA MemoryArea, PVOID Address, PMEMORY_BASIC_INFORMATION Info, PSIZE_T ResultLength)
Definition: section.c:2131
NTSTATUS NTAPI MmProtectSectionView(PMMSUPPORT AddressSpace, PMEMORY_AREA MemoryArea, PVOID BaseAddress, SIZE_T Length, ULONG Protect, PULONG OldProtect)
Definition: section.c:2087
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1707
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1768
#define MI_IS_MEMORY_AREA_VAD(Vad)
Definition: mm.h:270
#define MI_IS_ROSMM_VAD(Vad)
Definition: mm.h:272
#define MEMORY_AREA_SECTION_VIEW
Definition: mm.h:93
NTSTATUS NTAPI MmAccessFault(IN ULONG FaultCode, IN PVOID Address, IN KPROCESSOR_MODE Mode, IN PVOID TrapInformation)
Definition: mmfault.c:220
const LUID SeLockMemoryPrivilege
Definition: priv.c:23
VOID NTAPI KeFlushEntireTb(IN BOOLEAN Invalid, IN BOOLEAN AllProcessors)
Definition: cpu.c:661
BOOLEAN NTAPI KeAreAllApcsDisabled(VOID)
Definition: apc.c:985
CCHAR KeNumberProcessors
Definition: processor.c:19
ULONG MmUserProbeAddress
Definition: init.c:50
MMSUPPORT MmSystemCacheWs
Definition: init.c:55
PVOID MmPagedPoolEnd
Definition: init.c:26
LONG MiGetExceptionInfo(IN PEXCEPTION_POINTERS ExceptionInfo, OUT PBOOLEAN HaveBadAddress, OUT PULONG_PTR BadAddress)
Definition: virtual.c:750
NTSTATUS NTAPI NtResetWriteWatch(IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN SIZE_T RegionSize)
Definition: virtual.c:4293
static NTSTATUS MiLockVirtualMemory(IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
Definition: virtual.c:3346
NTSTATUS NTAPI NtGetWriteWatch(IN HANDLE ProcessHandle, IN ULONG Flags, IN PVOID BaseAddress, IN SIZE_T RegionSize, IN PVOID *UserAddressArray, OUT PULONG_PTR EntriesInUserAddressArray, OUT PULONG Granularity)
Definition: virtual.c:4122
NTSTATUS NTAPI NtFreeVirtualMemory(IN HANDLE ProcessHandle, IN PVOID *UBaseAddress, IN PSIZE_T URegionSize, IN ULONG FreeType)
Definition: virtual.c:5192
NTSTATUS NTAPI MmFlushVirtualMemory(IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, OUT PIO_STATUS_BLOCK IoStatusBlock)
Definition: virtual.c:1342
NTSTATUS NTAPI NtWriteVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN PVOID Buffer, IN SIZE_T NumberOfBytesToWrite, OUT PSIZE_T NumberOfBytesWritten OPTIONAL)
Definition: virtual.c:2895
#define MI_MAPPED_COPY_PAGES
Definition: virtual.c:18
VOID NTAPI MiProcessValidPteList(IN PMMPTE *ValidPteList, IN ULONG Count)
Definition: virtual.c:2540
PVOID NTAPI MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress)
Definition: virtual.c:2748
NTSTATUS NTAPI MmCopyVirtualMemory(IN PEPROCESS SourceProcess, IN PVOID SourceAddress, IN PEPROCESS TargetProcess, OUT PVOID TargetAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T ReturnSize)
Definition: virtual.c:1271
ULONG NTAPI MiGetPageProtection(IN PMMPTE PointerPte)
Definition: virtual.c:1361
NTSTATUS NTAPI NtProtectVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID *UnsafeBaseAddress, IN OUT SIZE_T *UnsafeNumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG UnsafeOldAccessProtection)
Definition: virtual.c:3076
VOID NTAPI MiFlushTbAndCapture(IN PMMVAD FoundVad, IN PMMPTE PointerPte, IN ULONG ProtectionMask, IN PMMPFN Pfn1, IN BOOLEAN CaptureDirtyBit)
Definition: section.c:1821
NTSTATUS NTAPI NtReadVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID Buffer, IN SIZE_T NumberOfBytesToRead, OUT PSIZE_T NumberOfBytesRead OPTIONAL)
Definition: virtual.c:2781
VOID NTAPI MiDeletePte(IN PMMPTE PointerPte, IN PVOID VirtualAddress, IN PEPROCESS CurrentProcess, IN PMMPTE PrototypePte)
Definition: virtual.c:369
NTSTATUS NTAPI NtQueryVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN MEMORY_INFORMATION_CLASS MemoryInformationClass, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
Definition: virtual.c:4374
ULONG NTAPI MiMakeSystemAddressValidPfn(IN PVOID VirtualAddress, IN KIRQL OldIrql)
Definition: virtual.c:235
ULONG NTAPI MiCalculatePageCommitment(IN ULONG_PTR StartingAddress, IN ULONG_PTR EndingAddress, IN PMMVAD Vad, IN PEPROCESS Process)
Definition: virtual.c:42
NTSTATUS NTAPI NtLockVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToLock, IN ULONG MapType)
Definition: virtual.c:3494
FORCEINLINE VOID MI_LOCK_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3259
NTSTATUS NTAPI MiDoPoolCopy(IN PEPROCESS SourceProcess, IN PVOID SourceAddress, IN PEPROCESS TargetProcess, OUT PVOID TargetAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T ReturnSize)
Definition: virtual.c:1020
PHYSICAL_ADDRESS NTAPI MmGetPhysicalAddress(PVOID Address)
Definition: virtual.c:5676
static NTSTATUS MiUnlockVirtualMemory(IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
Definition: virtual.c:3665
VOID NTAPI MmUnsecureVirtualMemory(IN PVOID SecureMem)
Definition: virtual.c:2772
FORCEINLINE VOID MI_UNLOCK_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3280
NTSTATUS NTAPI NtFlushVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToFlush, OUT PIO_STATUS_BLOCK IoStatusBlock)
Definition: virtual.c:4000
NTSTATUS NTAPI MiDoMappedCopy(IN PEPROCESS SourceProcess, IN PVOID SourceAddress, IN PEPROCESS TargetProcess, OUT PVOID TargetAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T ReturnSize)
Definition: virtual.c:795
NTSTATUS NTAPI MiProtectVirtualMemory(IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection OPTIONAL)
Definition: virtual.c:2160
VOID NTAPI MiMakePdeExistAndMakeValid(IN PMMPDE PointerPde, IN PEPROCESS TargetProcess, IN KIRQL OldIrql)
Definition: virtual.c:2446
ULONG NTAPI MiMakeSystemAddressValid(IN PVOID PageTableVirtualAddress, IN PEPROCESS CurrentProcess)
Definition: virtual.c:183
#define MI_MAX_TRANSFER_SIZE
Definition: virtual.c:20
ULONG NTAPI MiDecommitPages(IN PVOID StartingAddress, IN PMMPTE EndingPte, IN PEPROCESS Process, IN PMMVAD Vad)
Definition: virtual.c:2592
VOID NTAPI MiDeleteVirtualAddresses(_In_ ULONG_PTR Va, _In_ ULONG_PTR EndingAddress, _In_opt_ PMMVAD Vad)
Definition: virtual.c:530
PVOID NTAPI MmSecureVirtualMemory(IN PVOID Address, IN SIZE_T Length, IN ULONG Mode)
Definition: virtual.c:2759
static NTSTATUS MiCheckVadsForLockOperation(_Inout_ PVOID *BaseAddress, _Inout_ PSIZE_T RegionSize, _Inout_ PVOID *EndAddress)
Definition: virtual.c:3301
NTSTATUS NTAPI NtUnlockVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToUnlock, IN ULONG MapType)
Definition: virtual.c:3830
FORCEINLINE BOOLEAN MI_IS_LOCKED_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3242
NTSTATUS NTAPI MiQueryMemoryBasicInformation(IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
Definition: virtual.c:1667
ULONG NTAPI MiQueryAddressState(IN PVOID Va, IN PMMVAD Vad, IN PEPROCESS TargetProcess, OUT PULONG ReturnedProtect, OUT PVOID *NextVa)
Definition: virtual.c:1476
BOOLEAN NTAPI MiIsEntireRangeCommitted(IN ULONG_PTR StartingAddress, IN ULONG_PTR EndingAddress, IN PMMVAD Vad, IN PEPROCESS Process)
Definition: virtual.c:2004
PFN_COUNT NTAPI MiDeleteSystemPageableVm(IN PMMPTE PointerPte, IN PFN_NUMBER PageCount, IN ULONG Flags, OUT PPFN_NUMBER ValidPages)
Definition: virtual.c:275
NTSTATUS NTAPI NtAllocateVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID *UBaseAddress, IN ULONG_PTR ZeroBits, IN OUT PSIZE_T URegionSize, IN ULONG AllocationType, IN ULONG Protect)
Definition: virtual.c:4457
NTSTATUS NTAPI NtFlushInstructionCache(_In_ HANDLE ProcessHandle, _In_opt_ PVOID BaseAddress, _In_ SIZE_T FlushSize)
Definition: virtual.c:3009
#define MI_POOL_COPY_BYTES
Definition: virtual.c:19
MMPTE MmDecommittedPte
Definition: init.c:44
MMPTE PrototypePte
Definition: init.c:40
MMPTE DemandZeroPte
Definition: init.c:37
const ULONG MmProtectToValue[32]
Definition: page.c:71
POBJECT_TYPE PsProcessType
Definition: process.c:20
BOOLEAN NTAPI SeSinglePrivilegeCheck(_In_ LUID PrivilegeValue, _In_ KPROCESSOR_MODE PreviousMode)
Checks if a single privilege is present in the context of the calling thread.
Definition: priv.c:744
#define STATUS_QUOTA_EXCEEDED
Definition: ntstatus.h:398
#define STATUS_UNABLE_TO_DELETE_SECTION
Definition: ntstatus.h:357
#define STATUS_WAS_LOCKED
Definition: ntstatus.h:214
#define STATUS_UNABLE_TO_FREE_VM
Definition: ntstatus.h:356
#define STATUS_MEMORY_NOT_ALLOCATED
Definition: ntstatus.h:490
#define STATUS_INCOMPATIBLE_FILE_MAP
Definition: ntstatus.h:407
#define STATUS_INVALID_PARAMETER_4
Definition: ntstatus.h:572
#define STATUS_ALREADY_COMMITTED
Definition: ntstatus.h:363
#define STATUS_INVALID_PARAMETER_2
Definition: ntstatus.h:570
#define STATUS_FREE_VM_NOT_AT_BASE
Definition: ntstatus.h:489
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:596
#define STATUS_INVALID_PARAMETER_6
Definition: ntstatus.h:574
#define STATUS_NOT_LOCKED
Definition: ntstatus.h:372
#define STATUS_IN_PAGE_ERROR
Definition: ntstatus.h:336
#define STATUS_CONFLICTING_ADDRESSES
Definition: ntstatus.h:354
#define STATUS_INVALID_PAGE_PROTECTION
Definition: ntstatus.h:399
#define STATUS_GUARD_PAGE_VIOLATION
Definition: ntstatus.h:262
#define STATUS_NOT_COMMITTED
Definition: ntstatus.h:375
#define STATUS_INVALID_PARAMETER_3
Definition: ntstatus.h:571
#define STATUS_INVALID_PARAMETER_5
Definition: ntstatus.h:573
#define STATUS_PARTIAL_COPY
Definition: ntstatus.h:273
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
long LONG
Definition: pedump.c:60
static WCHAR Address[46]
Definition: ping.c:68
VOID NTAPI KeStackAttachProcess(IN PKPROCESS Process, OUT PRKAPC_STATE ApcState)
Definition: procobj.c:704
VOID NTAPI KeUnstackDetachProcess(IN PRKAPC_STATE ApcState)
Definition: procobj.c:756
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:181
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:82
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:180
#define _SEH2_END
Definition: pseh2_64.h:171
#define _SEH2_TRY
Definition: pseh2_64.h:71
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:184
NTSTATUS NTAPI PsChargeProcessNonPagedPoolQuota(_In_ PEPROCESS Process, _In_ SIZE_T Amount)
Charges the non paged pool quota of a given process.
Definition: quota.c:811
VOID NTAPI PsReturnProcessNonPagedPoolQuota(_In_ PEPROCESS Process, _In_ SIZE_T Amount)
Returns the non paged quota pool that the process was taking up.
Definition: quota.c:938
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:108
PVOID MmHighestUserAddress
Definition: rtlcompat.c:29
@ Warn
Definition: video.h:589
#define ProbeForWritePointer(Ptr)
Definition: probe.h:42
#define ProbeForWriteSize_t(Ptr)
Definition: probe.h:45
#define ProbeForWriteUlong(Ptr)
Definition: probe.h:36
#define ProbeForWriteIoStatusBlock(Ptr)
Definition: probe.h:52
ULONG * PPFN_NUMBER
Definition: ke.h:9
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:73
static void Exit(void)
Definition: sock.c:1330
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
union _CONTROL_AREA::@2796 u
MMSECTION_FLAGS Flags
Definition: mmtypes.h:531
MM_AVL_TABLE VadRoot
Definition: pstypes.h:1542
MMSUPPORT Vm
Definition: pstypes.h:1445
PVOID CloneRoot
Definition: pstypes.h:1388
ULONG VmDeleted
Definition: pstypes.h:1487
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: compat.h:210
DWORD ExceptionCode
Definition: compat.h:208
DWORD NumberParameters
Definition: compat.h:212
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]
Definition: compat.h:213
ULONG PageFrameNumber
Definition: mmtypes.h:74
ULONG PageFrameNumber
Definition: mmtypes.h:109
struct _MMADDRESS_NODE * RightChild
Definition: mmtypes.h:652
USHORT PrototypePte
Definition: mm.h:372
USHORT PageLocation
Definition: mm.h:374
USHORT WriteInProgress
Definition: mm.h:371
Definition: mm.h:389
union _MMPFN::@1934 u4
MMPTE OriginalPte
Definition: mm.h:425
MMWSLE Wsle
Definition: mm.h:452
PMMPTE PteAddress
Definition: mm.h:401
struct _MMPFN::@1931::@1937 e2
ULONG WsIndex
Definition: mm.h:393
union _MMPFN::@1930 u2
MMPFNENTRY e1
Definition: mm.h:412
ULONG_PTR ShareCount
Definition: mm.h:405
union _MMPFN::@1929 u1
union _MMPFN::@1931 u3
ULONG_PTR AweAllocation
Definition: mm.h:439
ULONG_PTR PteFrame
Definition: mm.h:436
ULONG64 LargePage
Definition: mmtypes.h:165
ULONG64 Valid
Definition: mmtypes.h:150
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
ULONG64 Valid
Definition: mmtypes.h:86
ULONG64 Transition
Definition: mmtypes.h:90
ULONG64 Protection
Definition: mmtypes.h:88
ULONG64 Prototype
Definition: mmtypes.h:89
ULONG64 PageFileHigh
Definition: mmtypes.h:93
ULONG64 Protection
Definition: mmtypes.h:103
MMPTE_TRANSITION Trans
Definition: mmtypes.h:220
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
union _MMPTE::@2514 u
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
ULONG_PTR Long
Definition: mmtypes.h:215
ULONG_PTR NoChange
Definition: mmtypes.h:693
ULONG_PTR MemCommit
Definition: mmtypes.h:695
ULONG_PTR Protection
Definition: mmtypes.h:696
ULONG_PTR CommitCharge
Definition: mmtypes.h:691
ULONG_PTR VadType
Definition: mmtypes.h:694
ULONG_PTR PrivateMemory
Definition: mmtypes.h:698
struct _MMVAD * RightChild
Definition: mmtypes.h:728
struct _MMVAD * LeftChild
Definition: mmtypes.h:727
ULONG_PTR EndingVpn
Definition: mmtypes.h:730
PCONTROL_AREA ControlArea
Definition: mmtypes.h:736
ULONG_PTR StartingVpn
Definition: mmtypes.h:729
MMVAD_FLAGS VadFlags
Definition: mmtypes.h:734
union _MMVAD::@2803 u
ULONG_PTR LongFlags
Definition: mmtypes.h:733
ULONG_PTR LockedInMemory
Definition: mmtypes.h:829
ULONG_PTR LockedInWs
Definition: mmtypes.h:828
MMWSLENTRY e1
Definition: mmtypes.h:858
union _MMWSLE::@2813 u1
ULONG_PTR NumberGenericTableElements
Definition: mmtypes.h:668
MMADDRESS_NODE BalancedRoot
Definition: mmtypes.h:662
ULONG PtesInSubsection
Definition: mmtypes.h:583
PMMPTE SubsectionBase
Definition: mmtypes.h:581
ULONG_PTR * PSIZE_T
Definition: typedefs.h:80
uint32_t * PULONG_PTR
Definition: typedefs.h:65
uint32_t * PULONG
Definition: typedefs.h:59
unsigned char * PBOOLEAN
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
char * PCHAR
Definition: typedefs.h:51
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define ALIGN_UP_POINTER_BY(ptr, align)
Definition: umtypes.h:85
#define ALIGN_DOWN_POINTER_BY(ptr, align)
Definition: umtypes.h:82
LONGLONG QuadPart
Definition: typedefs.h:114
PVOID PMDL
Definition: usb.h:39
static BOOL Attached
Definition: vidbios.c:3905
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG _Out_ PULONG ResultLength
Definition: wdfdevice.h:3782
_Must_inspect_result_ _In_ WDFDMATRANSACTION _In_ PFN_WDF_PROGRAM_DMA _In_ WDF_DMA_DIRECTION _In_ PMDL _In_ PVOID VirtualAddress
_In_ WDFDEVICE _In_ PVOID _In_opt_ PMDL Mdl
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesWritten
Definition: wdfiotarget.h:960
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesRead
Definition: wdfiotarget.h:870
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254
#define FORCEINLINE
Definition: wdftypes.h:67
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_Out_ PBOOLEAN QuotaCharged
Definition: exfuncs.h:1153
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG AddressSpace
Definition: iofuncs.h:2274
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS PhysicalAddress
Definition: iotypes.h:1098
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _Inout_ PLARGE_INTEGER _Outptr_ PVOID * TargetAddress
Definition: iotypes.h:1037
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS SourceAddress
Definition: iotypes.h:1127
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
@ IoReadAccess
Definition: ketypes.h:915
KAPC_STATE
Definition: ketypes.h:1711
#define ROUND_TO_PAGES(Size)
#define MmInitializeMdl(_MemoryDescriptorList, _BaseVa, _Length)
#define BYTES_TO_PAGES(Size)
#define PAGE_ALIGN(Va)
_Must_inspect_result_ _In_ ULONG NewProtect
Definition: mmfuncs.h:682
MDL
Definition: mmtypes.h:117
@ MmCached
Definition: mmtypes.h:130
#define PAGE_WRITECOMBINE
Definition: mmtypes.h:78
ULONG PFN_COUNT
Definition: mmtypes.h:102
#define ObDereferenceObject
Definition: obfuncs.h:203
#define PsGetCurrentProcess
Definition: psfuncs.h:17
TABLE_SEARCH_RESULT
Definition: rtltypes.h:386
unsigned char UCHAR
Definition: xmlstorage.h:181
char CHAR
Definition: xmlstorage.h:175
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR _In_ SIZE_T _Inout_opt_ PLARGE_INTEGER _Inout_ PSIZE_T _In_ SECTION_INHERIT _In_ ULONG _In_ ULONG Protect
Definition: zwfuncs.h:221