ReactOS 0.4.15-dev-7788-g1ad9096
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 EndingAddress,
532 IN PMMVAD Vad)
533{
534 PMMPTE PointerPte, PrototypePte, LastPrototypePte;
535 PMMPDE PointerPde;
536#if (_MI_PAGING_LEVELS >= 3)
537 PMMPPE PointerPpe;
538#endif
539#if (_MI_PAGING_LEVELS >= 4)
540 PMMPPE PointerPxe;
541#endif
543 PEPROCESS CurrentProcess;
545 BOOLEAN AddressGap = FALSE;
546 PSUBSECTION Subsection;
547
548 /* Get out if this is a fake VAD, RosMm will free the marea pages */
549 if ((Vad) && (Vad->u.VadFlags.Spare == 1)) return;
550
551 /* Get the current process */
552 CurrentProcess = PsGetCurrentProcess();
553
554 /* Check if this is a section VAD or a VM VAD */
555 if (!(Vad) || (Vad->u.VadFlags.PrivateMemory) || !(Vad->FirstPrototypePte))
556 {
557 /* Don't worry about prototypes */
558 PrototypePte = LastPrototypePte = NULL;
559 }
560 else
561 {
562 /* Get the prototype PTE */
563 PrototypePte = Vad->FirstPrototypePte;
564 LastPrototypePte = Vad->FirstPrototypePte + 1;
565 }
566
567 /* In all cases, we don't support fork() yet */
568 ASSERT(CurrentProcess->CloneRoot == NULL);
569
570 /* Loop the PTE for each VA (EndingAddress is inclusive!) */
571 while (Va <= EndingAddress)
572 {
573#if (_MI_PAGING_LEVELS >= 4)
574 /* Get the PXE and check if it's valid */
575 PointerPxe = MiAddressToPxe((PVOID)Va);
576 if (!PointerPxe->u.Hard.Valid)
577 {
578 /* Check for unmapped range and skip it */
579 if (!PointerPxe->u.Long)
580 {
581 /* There are gaps in the address space */
582 AddressGap = TRUE;
583
584 /* Update Va and continue looping */
585 Va = (ULONG_PTR)MiPxeToAddress(PointerPxe + 1);
586 continue;
587 }
588
589 /* Make the PXE valid */
590 MiMakeSystemAddressValid(MiPteToAddress(PointerPxe), CurrentProcess);
591 }
592#endif
593#if (_MI_PAGING_LEVELS >= 3)
594 /* Get the PPE and check if it's valid */
595 PointerPpe = MiAddressToPpe((PVOID)Va);
596 if (!PointerPpe->u.Hard.Valid)
597 {
598 /* Check for unmapped range and skip it */
599 if (!PointerPpe->u.Long)
600 {
601 /* There are gaps in the address space */
602 AddressGap = TRUE;
603
604 /* Update Va and continue looping */
605 Va = (ULONG_PTR)MiPpeToAddress(PointerPpe + 1);
606 continue;
607 }
608
609 /* Make the PPE valid */
610 MiMakeSystemAddressValid(MiPteToAddress(PointerPpe), CurrentProcess);
611 }
612#endif
613 /* Skip invalid PDEs */
614 PointerPde = MiAddressToPde((PVOID)Va);
615 if (!PointerPde->u.Long)
616 {
617 /* There are gaps in the address space */
618 AddressGap = TRUE;
619
620 /* Check if all the PDEs are invalid, so there's nothing to free */
621 Va = (ULONG_PTR)MiPdeToAddress(PointerPde + 1);
622 continue;
623 }
624
625 /* Now check if the PDE is mapped in */
626 if (!PointerPde->u.Hard.Valid)
627 {
628 /* It isn't, so map it in */
629 PointerPte = MiPteToAddress(PointerPde);
630 MiMakeSystemAddressValid(PointerPte, CurrentProcess);
631 }
632
633 /* Now we should have a valid PDE, mapped in, and still have some VA */
634 ASSERT(PointerPde->u.Hard.Valid == 1);
635 ASSERT(Va <= EndingAddress);
636
637 /* Check if this is a section VAD with gaps in it */
638 if ((AddressGap) && (LastPrototypePte))
639 {
640 /* We need to skip to the next correct prototype PTE */
642
643 /* And we need the subsection to skip to the next last prototype PTE */
644 Subsection = MiLocateSubsection(Vad, Va >> PAGE_SHIFT);
645 if (Subsection)
646 {
647 /* Found it! */
648 LastPrototypePte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
649 }
650 else
651 {
652 /* No more subsections, we are done with prototype PTEs */
654 }
655 }
656
657 /* Lock the PFN Database while we delete the PTEs */
658 OldIrql = MiAcquirePfnLock();
659 PointerPte = MiAddressToPte(Va);
660 do
661 {
662 /* Making sure the PDE is still valid */
663 ASSERT(PointerPde->u.Hard.Valid == 1);
664
665 /* Capture the PDE and make sure it exists */
666 TempPte = *PointerPte;
667 if (TempPte.u.Long)
668 {
669 /* Check if the PTE is actually mapped in */
671 {
672 /* Are we dealing with section VAD? */
673 if ((LastPrototypePte) && (PrototypePte > LastPrototypePte))
674 {
675 /* We need to skip to the next correct prototype PTE */
677
678 /* And we need the subsection to skip to the next last prototype PTE */
679 Subsection = MiLocateSubsection(Vad, Va >> PAGE_SHIFT);
680 if (Subsection)
681 {
682 /* Found it! */
683 LastPrototypePte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
684 }
685 else
686 {
687 /* No more subsections, we are done with prototype PTEs */
689 }
690 }
691
692 /* Check for prototype PTE */
693 if ((TempPte.u.Hard.Valid == 0) &&
694 (TempPte.u.Soft.Prototype == 1))
695 {
696 /* Just nuke it */
697 MI_ERASE_PTE(PointerPte);
698 }
699 else
700 {
701 /* Delete the PTE proper */
702 MiDeletePte(PointerPte,
703 (PVOID)Va,
704 CurrentProcess,
706 }
707 }
708 else
709 {
710 /* The PTE was never mapped, just nuke it here */
711 MI_ERASE_PTE(PointerPte);
712 }
713
715 {
716 ASSERT(PointerPde->u.Long != 0);
717
718 /* Delete the PDE proper */
719 MiDeletePde(PointerPde, CurrentProcess);
720
721 /* Continue with the next PDE */
722 Va = (ULONG_PTR)MiPdeToAddress(PointerPde + 1);
723
724 /* Use this to detect address gaps */
725 PointerPte++;
726 break;
727 }
728 }
729
730 /* Update the address and PTE for it */
731 Va += PAGE_SIZE;
732 PointerPte++;
733 PrototypePte++;
734 } while ((Va & (PDE_MAPPED_VA - 1)) && (Va <= EndingAddress));
735
736 /* Release the lock */
737 MiReleasePfnLock(OldIrql);
738
739 if (Va > EndingAddress) return;
740
741 /* Check if we exited the loop regularly */
742 AddressGap = (PointerPte != MiAddressToPte(Va));
743 }
744}
745
746LONG
748 OUT PBOOLEAN HaveBadAddress,
749 OUT PULONG_PTR BadAddress)
750{
751 PEXCEPTION_RECORD ExceptionRecord;
752 PAGED_CODE();
753
754 //
755 // Assume default
756 //
757 *HaveBadAddress = FALSE;
758
759 //
760 // Get the exception record
761 //
762 ExceptionRecord = ExceptionInfo->ExceptionRecord;
763
764 //
765 // Look at the exception code
766 //
767 if ((ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
768 (ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
769 (ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR))
770 {
771 //
772 // We can tell the address if we have more than one parameter
773 //
774 if (ExceptionRecord->NumberParameters > 1)
775 {
776 //
777 // Return the address
778 //
779 *HaveBadAddress = TRUE;
780 *BadAddress = ExceptionRecord->ExceptionInformation[1];
781 }
782 }
783
784 //
785 // Continue executing the next handler
786 //
788}
789
791NTAPI
794 IN PEPROCESS TargetProcess,
798 OUT PSIZE_T ReturnSize)
799{
800 PFN_NUMBER MdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + MI_MAPPED_COPY_PAGES + 1];
801 PMDL Mdl = (PMDL)MdlBuffer;
802 SIZE_T TotalSize, CurrentSize, RemainingSize;
803 volatile BOOLEAN FailedInProbe = FALSE;
804 volatile BOOLEAN PagesLocked = FALSE;
805 PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
806 volatile PVOID MdlAddress = NULL;
808 BOOLEAN HaveBadAddress;
809 ULONG_PTR BadAddress;
811 PAGED_CODE();
812
813 //
814 // Calculate the maximum amount of data to move
815 //
816 TotalSize = MI_MAPPED_COPY_PAGES * PAGE_SIZE;
817 if (BufferSize <= TotalSize) TotalSize = BufferSize;
818 CurrentSize = TotalSize;
819 RemainingSize = BufferSize;
820
821 //
822 // Loop as long as there is still data
823 //
824 while (RemainingSize > 0)
825 {
826 //
827 // Check if this transfer will finish everything off
828 //
829 if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
830
831 //
832 // Attach to the source address space
833 //
834 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
835
836 //
837 // Check state for this pass
838 //
839 ASSERT(MdlAddress == NULL);
840 ASSERT(PagesLocked == FALSE);
841 ASSERT(FailedInProbe == FALSE);
842
843 //
844 // Protect user-mode copy
845 //
847 {
848 //
849 // If this is our first time, probe the buffer
850 //
851 if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
852 {
853 //
854 // Catch a failure here
855 //
856 FailedInProbe = TRUE;
857
858 //
859 // Do the probe
860 //
862
863 //
864 // Passed
865 //
866 FailedInProbe = FALSE;
867 }
868
869 //
870 // Initialize and probe and lock the MDL
871 //
872 MmInitializeMdl(Mdl, CurrentAddress, CurrentSize);
874 PagesLocked = TRUE;
875 }
877 {
879 }
881
882 /* Detach from source process */
884
885 if (Status != STATUS_SUCCESS)
886 {
887 goto Exit;
888 }
889
890 //
891 // Now map the pages
892 //
895 MmCached,
896 NULL,
897 FALSE,
899 if (!MdlAddress)
900 {
902 goto Exit;
903 }
904
905 //
906 // Grab to the target process
907 //
908 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
909
911 {
912 //
913 // Check if this is our first time through
914 //
915 if ((CurrentTargetAddress == TargetAddress) && (PreviousMode != KernelMode))
916 {
917 //
918 // Catch a failure here
919 //
920 FailedInProbe = TRUE;
921
922 //
923 // Do the probe
924 //
926
927 //
928 // Passed
929 //
930 FailedInProbe = FALSE;
931 }
932
933 //
934 // Now do the actual move
935 //
936 RtlCopyMemory(CurrentTargetAddress, MdlAddress, CurrentSize);
937 }
939 &HaveBadAddress,
940 &BadAddress))
941 {
942 *ReturnSize = BufferSize - RemainingSize;
943 //
944 // Check if we failed during the probe
945 //
946 if (FailedInProbe)
947 {
948 //
949 // Exit
950 //
952 }
953 else
954 {
955 //
956 // Othewise we failed during the move.
957 // Check if we know exactly where we stopped copying
958 //
959 if (HaveBadAddress)
960 {
961 //
962 // Return the exact number of bytes copied
963 //
964 *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
965 }
966 //
967 // Return partial copy
968 //
970 }
971 }
972 _SEH2_END;
973
974 /* Detach from target process */
976
977 //
978 // Check for SEH status
979 //
980 if (Status != STATUS_SUCCESS)
981 {
982 goto Exit;
983 }
984
985 //
986 // Unmap and unlock
987 //
988 MmUnmapLockedPages(MdlAddress, Mdl);
989 MdlAddress = NULL;
991 PagesLocked = FALSE;
992
993 //
994 // Update location and size
995 //
996 RemainingSize -= CurrentSize;
997 CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
998 CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize);
999 }
1000
1001Exit:
1002 if (MdlAddress != NULL)
1003 MmUnmapLockedPages(MdlAddress, Mdl);
1004 if (PagesLocked)
1006
1007 //
1008 // All bytes read
1009 //
1010 if (Status == STATUS_SUCCESS)
1011 *ReturnSize = BufferSize;
1012 return Status;
1013}
1014
1016NTAPI
1019 IN PEPROCESS TargetProcess,
1023 OUT PSIZE_T ReturnSize)
1024{
1025 UCHAR StackBuffer[MI_POOL_COPY_BYTES];
1026 SIZE_T TotalSize, CurrentSize, RemainingSize;
1027 volatile BOOLEAN FailedInProbe = FALSE, HavePoolAddress = FALSE;
1028 PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
1029 PVOID PoolAddress;
1031 BOOLEAN HaveBadAddress;
1032 ULONG_PTR BadAddress;
1034 PAGED_CODE();
1035
1036 DPRINT("Copying %Iu bytes from process %p (address %p) to process %p (Address %p)\n",
1037 BufferSize, SourceProcess, SourceAddress, TargetProcess, TargetAddress);
1038
1039 //
1040 // Calculate the maximum amount of data to move
1041 //
1042 TotalSize = MI_MAX_TRANSFER_SIZE;
1043 if (BufferSize <= MI_MAX_TRANSFER_SIZE) TotalSize = BufferSize;
1044 CurrentSize = TotalSize;
1045 RemainingSize = BufferSize;
1046
1047 //
1048 // Check if we can use the stack
1049 //
1051 {
1052 //
1053 // Use it
1054 //
1055 PoolAddress = (PVOID)StackBuffer;
1056 }
1057 else
1058 {
1059 //
1060 // Allocate pool
1061 //
1062 PoolAddress = ExAllocatePoolWithTag(NonPagedPool, TotalSize, 'VmRw');
1063 if (!PoolAddress) ASSERT(FALSE);
1064 HavePoolAddress = TRUE;
1065 }
1066
1067 //
1068 // Loop as long as there is still data
1069 //
1070 while (RemainingSize > 0)
1071 {
1072 //
1073 // Check if this transfer will finish everything off
1074 //
1075 if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
1076
1077 //
1078 // Attach to the source address space
1079 //
1080 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
1081
1082 /* Check that state is sane */
1083 ASSERT(FailedInProbe == FALSE);
1085
1086 //
1087 // Protect user-mode copy
1088 //
1089 _SEH2_TRY
1090 {
1091 //
1092 // If this is our first time, probe the buffer
1093 //
1094 if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
1095 {
1096 //
1097 // Catch a failure here
1098 //
1099 FailedInProbe = TRUE;
1100
1101 //
1102 // Do the probe
1103 //
1105
1106 //
1107 // Passed
1108 //
1109 FailedInProbe = FALSE;
1110 }
1111
1112 //
1113 // Do the copy
1114 //
1115 RtlCopyMemory(PoolAddress, CurrentAddress, CurrentSize);
1116 }
1118 &HaveBadAddress,
1119 &BadAddress))
1120 {
1121 *ReturnSize = BufferSize - RemainingSize;
1122
1123 //
1124 // Check if we failed during the probe
1125 //
1126 if (FailedInProbe)
1127 {
1128 //
1129 // Exit
1130 //
1132 }
1133 else
1134 {
1135 //
1136 // We failed during the move.
1137 // Check if we know exactly where we stopped copying
1138 //
1139 if (HaveBadAddress)
1140 {
1141 //
1142 // Return the exact number of bytes copied
1143 //
1144 *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
1145 }
1146 //
1147 // Return partial copy
1148 //
1150 }
1151 }
1152 _SEH2_END
1153
1154 /* Let go of the source */
1156
1157 if (Status != STATUS_SUCCESS)
1158 {
1159 goto Exit;
1160 }
1161
1162 /* Grab the target process */
1163 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
1164
1165 _SEH2_TRY
1166 {
1167 //
1168 // Check if this is our first time through
1169 //
1170 if ((CurrentTargetAddress == TargetAddress) && (PreviousMode != KernelMode))
1171 {
1172 //
1173 // Catch a failure here
1174 //
1175 FailedInProbe = TRUE;
1176
1177 //
1178 // Do the probe
1179 //
1181
1182 //
1183 // Passed
1184 //
1185 FailedInProbe = FALSE;
1186 }
1187
1188 //
1189 // Now do the actual move
1190 //
1191 RtlCopyMemory(CurrentTargetAddress, PoolAddress, CurrentSize);
1192 }
1194 &HaveBadAddress,
1195 &BadAddress))
1196 {
1197 *ReturnSize = BufferSize - RemainingSize;
1198 //
1199 // Check if we failed during the probe
1200 //
1201 if (FailedInProbe)
1202 {
1203 //
1204 // Exit
1205 //
1207 }
1208 else
1209 {
1210 //
1211 // Otherwise we failed during the move.
1212 // Check if we know exactly where we stopped copying
1213 //
1214 if (HaveBadAddress)
1215 {
1216 //
1217 // Return the exact number of bytes copied
1218 //
1219 *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
1220 }
1221 //
1222 // Return partial copy
1223 //
1225 }
1226 }
1227 _SEH2_END;
1228
1229 //
1230 // Detach from target
1231 //
1233
1234 //
1235 // Check for SEH status
1236 //
1237 if (Status != STATUS_SUCCESS)
1238 {
1239 goto Exit;
1240 }
1241
1242 //
1243 // Update location and size
1244 //
1245 RemainingSize -= CurrentSize;
1246 CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
1247 CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress +
1248 CurrentSize);
1249 }
1250
1251Exit:
1252 //
1253 // Check if we had allocated pool
1254 //
1255 if (HavePoolAddress)
1256 ExFreePoolWithTag(PoolAddress, 'VmRw');
1257
1258 //
1259 // All bytes read
1260 //
1261 if (Status == STATUS_SUCCESS)
1262 *ReturnSize = BufferSize;
1263 return Status;
1264}
1265
1267NTAPI
1270 IN PEPROCESS TargetProcess,
1274 OUT PSIZE_T ReturnSize)
1275{
1277 PEPROCESS Process = SourceProcess;
1278
1279 //
1280 // Don't accept zero-sized buffers
1281 //
1282 if (!BufferSize) return STATUS_SUCCESS;
1283
1284 //
1285 // If we are copying from ourselves, lock the target instead
1286 //
1287 if (SourceProcess == PsGetCurrentProcess()) Process = TargetProcess;
1288
1289 //
1290 // Acquire rundown protection
1291 //
1292 if (!ExAcquireRundownProtection(&Process->RundownProtect))
1293 {
1294 //
1295 // Fail
1296 //
1298 }
1299
1300 //
1301 // See if we should use the pool copy
1302 //
1304 {
1305 //
1306 // Use MDL-copy
1307 //
1308 Status = MiDoMappedCopy(SourceProcess,
1310 TargetProcess,
1312 BufferSize,
1314 ReturnSize);
1315 }
1316 else
1317 {
1318 //
1319 // Do pool copy
1320 //
1321 Status = MiDoPoolCopy(SourceProcess,
1323 TargetProcess,
1325 BufferSize,
1327 ReturnSize);
1328 }
1329
1330 //
1331 // Release the lock
1332 //
1333 ExReleaseRundownProtection(&Process->RundownProtect);
1334 return Status;
1335}
1336
1338NTAPI
1343{
1344 PAGED_CODE();
1345
1347
1349}
1350
1351ULONG
1352NTAPI
1354{
1355 MMPTE TempPte;
1356 PMMPFN Pfn;
1357 PEPROCESS CurrentProcess;
1358 PETHREAD CurrentThread;
1359 BOOLEAN WsSafe, WsShared;
1360 ULONG Protect;
1361 KIRQL OldIrql;
1362 PAGED_CODE();
1363
1364 /* Copy this PTE's contents */
1365 TempPte = *PointerPte;
1366
1367 /* Assure it's not totally zero */
1368 ASSERT(TempPte.u.Long);
1369
1370 /* Check for a special prototype format */
1371 if ((TempPte.u.Soft.Valid == 0) &&
1372 (TempPte.u.Soft.Prototype == 1))
1373 {
1374 /* Check if the prototype PTE is not yet pointing to a PTE */
1375 if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
1376 {
1377 /* The prototype PTE contains the protection */
1378 return MmProtectToValue[TempPte.u.Soft.Protection];
1379 }
1380
1381 /* Get a pointer to the underlying shared PTE */
1382 PointerPte = MiProtoPteToPte(&TempPte);
1383
1384 /* Since the PTE we want to read can be paged out at any time, we need
1385 to release the working set lock first, so that it can be paged in */
1386 CurrentThread = PsGetCurrentThread();
1387 CurrentProcess = PsGetCurrentProcess();
1388 MiUnlockProcessWorkingSetForFault(CurrentProcess,
1389 CurrentThread,
1390 &WsSafe,
1391 &WsShared);
1392
1393 /* Now read the PTE value */
1394 TempPte = *PointerPte;
1395
1396 /* Check if that one is invalid */
1397 if (!TempPte.u.Hard.Valid)
1398 {
1399 /* We get the protection directly from this PTE */
1400 Protect = MmProtectToValue[TempPte.u.Soft.Protection];
1401 }
1402 else
1403 {
1404 /* The PTE is valid, so we might need to get the protection from
1405 the PFN. Lock the PFN database */
1406 OldIrql = MiAcquirePfnLock();
1407
1408 /* Check if the PDE is still valid */
1409 if (MiAddressToPte(PointerPte)->u.Hard.Valid == 0)
1410 {
1411 /* It's not, make it valid */
1413 }
1414
1415 /* Now it's safe to read the PTE value again */
1416 TempPte = *PointerPte;
1417 ASSERT(TempPte.u.Long != 0);
1418
1419 /* Check again if the PTE is invalid */
1420 if (!TempPte.u.Hard.Valid)
1421 {
1422 /* The PTE is not valid, so we can use it's protection field */
1423 Protect = MmProtectToValue[TempPte.u.Soft.Protection];
1424 }
1425 else
1426 {
1427 /* The PTE is valid, so we can find the protection in the
1428 OriginalPte field of the PFN */
1431 }
1432
1433 /* Release the PFN database */
1434 MiReleasePfnLock(OldIrql);
1435 }
1436
1437 /* Lock the working set again */
1438 MiLockProcessWorkingSetForFault(CurrentProcess,
1439 CurrentThread,
1440 WsSafe,
1441 WsShared);
1442
1443 return Protect;
1444 }
1445
1446 /* In the easy case of transition or demand zero PTE just return its protection */
1447 if (!TempPte.u.Hard.Valid) return MmProtectToValue[TempPte.u.Soft.Protection];
1448
1449 /* If we get here, the PTE is valid, so look up the page in PFN database */
1451 if (!Pfn->u3.e1.PrototypePte)
1452 {
1453 /* Return protection of the original pte */
1454 ASSERT(Pfn->u4.AweAllocation == 0);
1456 }
1457
1458 /* This is software PTE */
1459 DPRINT("Prototype PTE: %lx %p\n", TempPte.u.Hard.PageFrameNumber, Pfn);
1460 DPRINT("VA: %p\n", MiPteToAddress(&TempPte));
1461 DPRINT("Mask: %lx\n", TempPte.u.Soft.Protection);
1462 DPRINT("Mask2: %lx\n", Pfn->OriginalPte.u.Soft.Protection);
1463 return MmProtectToValue[TempPte.u.Soft.Protection];
1464}
1465
1466ULONG
1467NTAPI
1469 IN PMMVAD Vad,
1470 IN PEPROCESS TargetProcess,
1471 OUT PULONG ReturnedProtect,
1472 OUT PVOID *NextVa)
1473{
1474
1475 PMMPTE PointerPte, ProtoPte;
1476 PMMPDE PointerPde;
1477#if (_MI_PAGING_LEVELS >= 3)
1478 PMMPPE PointerPpe;
1479#endif
1480#if (_MI_PAGING_LEVELS >= 4)
1481 PMMPXE PointerPxe;
1482#endif
1483 MMPTE TempPte, TempProtoPte;
1484 BOOLEAN DemandZeroPte = TRUE, ValidPte = FALSE;
1486 ASSERT((Vad->StartingVpn <= ((ULONG_PTR)Va >> PAGE_SHIFT)) &&
1487 (Vad->EndingVpn >= ((ULONG_PTR)Va >> PAGE_SHIFT)));
1488
1489 /* Only normal VADs supported */
1490 ASSERT(Vad->u.VadFlags.VadType == VadNone);
1491
1492 /* Get the PDE and PTE for the address */
1493 PointerPde = MiAddressToPde(Va);
1494 PointerPte = MiAddressToPte(Va);
1495#if (_MI_PAGING_LEVELS >= 3)
1496 PointerPpe = MiAddressToPpe(Va);
1497#endif
1498#if (_MI_PAGING_LEVELS >= 4)
1499 PointerPxe = MiAddressToPxe(Va);
1500#endif
1501
1502 /* Return the next range */
1503 *NextVa = (PVOID)((ULONG_PTR)Va + PAGE_SIZE);
1504
1505 do
1506 {
1507#if (_MI_PAGING_LEVELS >= 4)
1508 /* Does the PXE exist? */
1509 if (PointerPxe->u.Long == 0)
1510 {
1511 /* It does not, next range starts at the next PXE */
1512 *NextVa = MiPxeToAddress(PointerPxe + 1);
1513 break;
1514 }
1515
1516 /* Is the PXE valid? */
1517 if (PointerPxe->u.Hard.Valid == 0)
1518 {
1519 /* Is isn't, fault it in (make the PPE accessible) */
1520 MiMakeSystemAddressValid(PointerPpe, TargetProcess);
1521 }
1522#endif
1523#if (_MI_PAGING_LEVELS >= 3)
1524 /* Does the PPE exist? */
1525 if (PointerPpe->u.Long == 0)
1526 {
1527 /* It does not, next range starts at the next PPE */
1528 *NextVa = MiPpeToAddress(PointerPpe + 1);
1529 break;
1530 }
1531
1532 /* Is the PPE valid? */
1533 if (PointerPpe->u.Hard.Valid == 0)
1534 {
1535 /* Is isn't, fault it in (make the PDE accessible) */
1536 MiMakeSystemAddressValid(PointerPde, TargetProcess);
1537 }
1538#endif
1539
1540 /* Does the PDE exist? */
1541 if (PointerPde->u.Long == 0)
1542 {
1543 /* It does not, next range starts at the next PDE */
1544 *NextVa = MiPdeToAddress(PointerPde + 1);
1545 break;
1546 }
1547
1548 /* Is the PDE valid? */
1549 if (PointerPde->u.Hard.Valid == 0)
1550 {
1551 /* Is isn't, fault it in (make the PTE accessible) */
1552 MiMakeSystemAddressValid(PointerPte, TargetProcess);
1553 }
1554
1555 /* We have a PTE that we can access now! */
1556 ValidPte = TRUE;
1557
1558 } while (FALSE);
1559
1560 /* Is it safe to try reading the PTE? */
1561 if (ValidPte)
1562 {
1563 /* FIXME: watch out for large pages */
1564 ASSERT(PointerPde->u.Hard.LargePage == FALSE);
1565
1566 /* Capture the PTE */
1567 TempPte = *PointerPte;
1568 if (TempPte.u.Long != 0)
1569 {
1570 /* The PTE is valid, so it's not zeroed out */
1572
1573 /* Is it a decommited, invalid, or faulted PTE? */
1574 if ((TempPte.u.Soft.Protection == MM_DECOMMIT) &&
1575 (TempPte.u.Hard.Valid == 0) &&
1576 ((TempPte.u.Soft.Prototype == 0) ||
1577 (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)))
1578 {
1579 /* Otherwise our defaults should hold */
1580 ASSERT(Protect == 0);
1582 }
1583 else
1584 {
1585 /* This means it's committed */
1586 State = MEM_COMMIT;
1587
1588 /* We don't support these */
1589 ASSERT(Vad->u.VadFlags.VadType != VadDevicePhysicalMemory);
1590 ASSERT(Vad->u.VadFlags.VadType != VadRotatePhysical);
1591 ASSERT(Vad->u.VadFlags.VadType != VadAwe);
1592
1593 /* Get protection state of this page */
1594 Protect = MiGetPageProtection(PointerPte);
1595
1596 /* Check if this is an image-backed VAD */
1597 if ((TempPte.u.Soft.Valid == 0) &&
1598 (TempPte.u.Soft.Prototype == 1) &&
1599 (Vad->u.VadFlags.PrivateMemory == 0) &&
1600 (Vad->ControlArea))
1601 {
1602 DPRINT1("Not supported\n");
1603 ASSERT(FALSE);
1604 }
1605 }
1606 }
1607 }
1608
1609 /* Check if this was a demand-zero PTE, since we need to find the state */
1610 if (DemandZeroPte)
1611 {
1612 /* Not yet handled */
1613 ASSERT(Vad->u.VadFlags.VadType != VadDevicePhysicalMemory);
1614 ASSERT(Vad->u.VadFlags.VadType != VadAwe);
1615
1616 /* Check if this is private commited memory, or an section-backed VAD */
1617 if ((Vad->u.VadFlags.PrivateMemory == 0) && (Vad->ControlArea))
1618 {
1619 /* Tell caller about the next range */
1620 *NextVa = (PVOID)((ULONG_PTR)Va + PAGE_SIZE);
1621
1622 /* Get the prototype PTE for this VAD */
1623 ProtoPte = MI_GET_PROTOTYPE_PTE_FOR_VPN(Vad,
1624 (ULONG_PTR)Va >> PAGE_SHIFT);
1625 if (ProtoPte)
1626 {
1627 /* We should unlock the working set, but it's not being held! */
1628
1629 /* Is the prototype PTE actually valid (committed)? */
1630 TempProtoPte = *ProtoPte;
1631 if (TempProtoPte.u.Long)
1632 {
1633 /* Unless this is a memory-mapped file, handle it like private VAD */
1634 State = MEM_COMMIT;
1635 ASSERT(Vad->u.VadFlags.VadType != VadImageMap);
1636 Protect = MmProtectToValue[Vad->u.VadFlags.Protection];
1637 }
1638
1639 /* We should re-lock the working set */
1640 }
1641 }
1642 else if (Vad->u.VadFlags.MemCommit)
1643 {
1644 /* This is committed memory */
1645 State = MEM_COMMIT;
1646
1647 /* Convert the protection */
1648 Protect = MmProtectToValue[Vad->u.VadFlags.Protection];
1649 }
1650 }
1651
1652 /* Return the protection code */
1653 *ReturnedProtect = Protect;
1654 return State;
1655}
1656
1658NTAPI
1661 OUT PVOID MemoryInformation,
1662 IN SIZE_T MemoryInformationLength,
1664{
1665 PEPROCESS TargetProcess;
1667 PMMVAD Vad = NULL;
1668 PVOID Address, NextAddress;
1670 ULONG NewProtect, NewState;
1671 ULONG_PTR BaseVpn;
1672 MEMORY_BASIC_INFORMATION MemoryInfo;
1677
1678 /* Check for illegal addresses in user-space, or the shared memory area */
1681 {
1683
1684 /* Make up an info structure describing this range */
1685 MemoryInfo.BaseAddress = Address;
1686 MemoryInfo.AllocationProtect = PAGE_READONLY;
1687 MemoryInfo.Type = MEM_PRIVATE;
1688
1689 /* Special case for shared data */
1691 {
1693 MemoryInfo.State = MEM_COMMIT;
1694 MemoryInfo.Protect = PAGE_READONLY;
1695 MemoryInfo.RegionSize = PAGE_SIZE;
1696 }
1697 else
1698 {
1700 MemoryInfo.State = MEM_RESERVE;
1701 MemoryInfo.Protect = PAGE_NOACCESS;
1703 }
1704
1705 /* Return the data, NtQueryInformation already probed it*/
1706 if (PreviousMode != KernelMode)
1707 {
1708 _SEH2_TRY
1709 {
1710 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1712 }
1714 {
1716 }
1717 _SEH2_END;
1718 }
1719 else
1720 {
1721 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1723 }
1724
1725 return Status;
1726 }
1727
1728 /* Check if this is for a local or remote process */
1730 {
1731 TargetProcess = PsGetCurrentProcess();
1732 }
1733 else
1734 {
1735 /* Reference the target process */
1740 (PVOID*)&TargetProcess,
1741 NULL);
1742 if (!NT_SUCCESS(Status)) return Status;
1743
1744 /* Attach to it now */
1745 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
1746 }
1747
1748 /* Lock the address space and make sure the process isn't already dead */
1749 MmLockAddressSpace(&TargetProcess->Vm);
1750 if (TargetProcess->VmDeleted)
1751 {
1752 /* Unlock the address space of the process */
1753 MmUnlockAddressSpace(&TargetProcess->Vm);
1754
1755 /* Check if we were attached */
1757 {
1758 /* Detach and dereference the process */
1760 ObDereferenceObject(TargetProcess);
1761 }
1762
1763 /* Bail out */
1764 DPRINT1("Process is dying\n");
1766 }
1767
1768 /* Loop the VADs */
1770 if (TargetProcess->VadRoot.NumberGenericTableElements)
1771 {
1772 /* Scan on the right */
1773 Vad = (PMMVAD)TargetProcess->VadRoot.BalancedRoot.RightChild;
1774 BaseVpn = (ULONG_PTR)BaseAddress >> PAGE_SHIFT;
1775 while (Vad)
1776 {
1777 /* Check if this VAD covers the allocation range */
1778 if ((BaseVpn >= Vad->StartingVpn) &&
1779 (BaseVpn <= Vad->EndingVpn))
1780 {
1781 /* We're done */
1782 Found = TRUE;
1783 break;
1784 }
1785
1786 /* Check if this VAD is too high */
1787 if (BaseVpn < Vad->StartingVpn)
1788 {
1789 /* Stop if there is no left child */
1790 if (!Vad->LeftChild) break;
1791
1792 /* Search on the left next */
1793 Vad = Vad->LeftChild;
1794 }
1795 else
1796 {
1797 /* Then this VAD is too low, keep searching on the right */
1798 ASSERT(BaseVpn > Vad->EndingVpn);
1799
1800 /* Stop if there is no right child */
1801 if (!Vad->RightChild) break;
1802
1803 /* Search on the right next */
1804 Vad = Vad->RightChild;
1805 }
1806 }
1807 }
1808
1809 /* Was a VAD found? */
1810 if (!Found)
1811 {
1813
1814 /* Calculate region size */
1815 if (Vad)
1816 {
1817 if (Vad->StartingVpn >= BaseVpn)
1818 {
1819 /* Region size is the free space till the start of that VAD */
1820 MemoryInfo.RegionSize = (ULONG_PTR)(Vad->StartingVpn << PAGE_SHIFT) - (ULONG_PTR)Address;
1821 }
1822 else
1823 {
1824 /* Get the next VAD */
1826 if (Vad)
1827 {
1828 /* Region size is the free space till the start of that VAD */
1829 MemoryInfo.RegionSize = (ULONG_PTR)(Vad->StartingVpn << PAGE_SHIFT) - (ULONG_PTR)Address;
1830 }
1831 else
1832 {
1833 /* Maximum possible region size with that base address */
1835 }
1836 }
1837 }
1838 else
1839 {
1840 /* Maximum possible region size with that base address */
1842 }
1843
1844 /* Unlock the address space of the process */
1845 MmUnlockAddressSpace(&TargetProcess->Vm);
1846
1847 /* Check if we were attached */
1849 {
1850 /* Detach and dereference the process */
1852 ObDereferenceObject(TargetProcess);
1853 }
1854
1855 /* Build the rest of the initial information block */
1856 MemoryInfo.BaseAddress = Address;
1857 MemoryInfo.AllocationBase = NULL;
1858 MemoryInfo.AllocationProtect = 0;
1859 MemoryInfo.State = MEM_FREE;
1860 MemoryInfo.Protect = PAGE_NOACCESS;
1861 MemoryInfo.Type = 0;
1862
1863 /* Return the data, NtQueryInformation already probed it*/
1864 if (PreviousMode != KernelMode)
1865 {
1866 _SEH2_TRY
1867 {
1868 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1870 }
1872 {
1874 }
1875 _SEH2_END;
1876 }
1877 else
1878 {
1879 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1881 }
1882
1883 return Status;
1884 }
1885
1886 /* Set the correct memory type based on what kind of VAD this is */
1887 if ((Vad->u.VadFlags.PrivateMemory) ||
1889 {
1890 MemoryInfo.Type = MEM_PRIVATE;
1891 }
1892 else if (Vad->u.VadFlags.VadType == VadImageMap)
1893 {
1894 MemoryInfo.Type = MEM_IMAGE;
1895 }
1896 else
1897 {
1898 MemoryInfo.Type = MEM_MAPPED;
1899 }
1900
1901 /* Find the memory area the specified address belongs to */
1904
1905 /* Determine information dependent on the memory area type */
1907 {
1909 if (!NT_SUCCESS(Status))
1910 {
1911 DPRINT1("MmQuerySectionView failed. MemoryArea=%p (%p-%p), BaseAddress=%p\n",
1914 }
1915 }
1916 else
1917 {
1918 /* Build the initial information block */
1920 MemoryInfo.BaseAddress = Address;
1921 MemoryInfo.AllocationBase = (PVOID)(Vad->StartingVpn << PAGE_SHIFT);
1923 MemoryInfo.Type = MEM_PRIVATE;
1924
1925 /* Acquire the working set lock (shared is enough) */
1927
1928 /* Find the largest chunk of memory which has the same state and protection mask */
1929 MemoryInfo.State = MiQueryAddressState(Address,
1930 Vad,
1931 TargetProcess,
1932 &MemoryInfo.Protect,
1933 &NextAddress);
1934 Address = NextAddress;
1935 while (((ULONG_PTR)Address >> PAGE_SHIFT) <= Vad->EndingVpn)
1936 {
1937 /* Keep going unless the state or protection mask changed */
1938 NewState = MiQueryAddressState(Address, Vad, TargetProcess, &NewProtect, &NextAddress);
1939 if ((NewState != MemoryInfo.State) || (NewProtect != MemoryInfo.Protect)) break;
1940 Address = NextAddress;
1941 }
1942
1943 /* Release the working set lock */
1945
1946 /* Check if we went outside of the VAD */
1947 if (((ULONG_PTR)Address >> PAGE_SHIFT) > Vad->EndingVpn)
1948 {
1949 /* Set the end of the VAD as the end address */
1950 Address = (PVOID)((Vad->EndingVpn + 1) << PAGE_SHIFT);
1951 }
1952
1953 /* Now that we know the last VA address, calculate the region size */
1954 MemoryInfo.RegionSize = ((ULONG_PTR)Address - (ULONG_PTR)MemoryInfo.BaseAddress);
1955 }
1956
1957 /* Unlock the address space of the process */
1958 MmUnlockAddressSpace(&TargetProcess->Vm);
1959
1960 /* Check if we were attached */
1962 {
1963 /* Detach and dereference the process */
1965 ObDereferenceObject(TargetProcess);
1966 }
1967
1968 /* Return the data, NtQueryInformation already probed it */
1969 if (PreviousMode != KernelMode)
1970 {
1971 _SEH2_TRY
1972 {
1973 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1975 }
1977 {
1979 }
1980 _SEH2_END;
1981 }
1982 else
1983 {
1984 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1986 }
1987
1988 /* All went well */
1989 DPRINT("Base: %p AllocBase: %p AllocProtect: %lx Protect: %lx "
1990 "State: %lx Type: %lx Size: %lx\n",
1991 MemoryInfo.BaseAddress, MemoryInfo.AllocationBase,
1992 MemoryInfo.AllocationProtect, MemoryInfo.Protect,
1993 MemoryInfo.State, MemoryInfo.Type, MemoryInfo.RegionSize);
1994
1995 return Status;
1996}
1997
1998BOOLEAN
1999NTAPI
2001 IN ULONG_PTR EndingAddress,
2002 IN PMMVAD Vad,
2004{
2005 PMMPTE PointerPte, LastPte;
2006 PMMPDE PointerPde;
2007 BOOLEAN OnPdeBoundary = TRUE;
2008#if _MI_PAGING_LEVELS >= 3
2009 PMMPPE PointerPpe;
2010 BOOLEAN OnPpeBoundary = TRUE;
2011#if _MI_PAGING_LEVELS == 4
2012 PMMPXE PointerPxe;
2013 BOOLEAN OnPxeBoundary = TRUE;
2014#endif
2015#endif
2016
2017 PAGED_CODE();
2018
2019 /* Check that we hols the right locks */
2020 ASSERT(PsGetCurrentThread()->OwnsProcessWorkingSetExclusive || PsGetCurrentThread()->OwnsProcessWorkingSetShared);
2021
2022 /* Get the PTE addresses */
2023 PointerPte = MiAddressToPte(StartingAddress);
2024 LastPte = MiAddressToPte(EndingAddress);
2025
2026 /* Loop all the PTEs */
2027 while (PointerPte <= LastPte)
2028 {
2029#if _MI_PAGING_LEVELS == 4
2030 /* Check for new PXE boundary */
2031 if (OnPxeBoundary)
2032 {
2033 PointerPxe = MiPteToPxe(PointerPte);
2034
2035 /* Check that this loop is sane */
2036 ASSERT(OnPpeBoundary);
2037 ASSERT(OnPdeBoundary);
2038
2039 if (PointerPxe->u.Long != 0)
2040 {
2041 /* Make it valid if needed */
2042 if (PointerPxe->u.Hard.Valid == 0)
2044 }
2045 else
2046 {
2047 /* Is the entire VAD committed? If not, fail */
2048 if (!Vad->u.VadFlags.MemCommit) return FALSE;
2049
2050 PointerPxe++;
2051 PointerPte = MiPxeToPte(PointerPte);
2052 continue;
2053 }
2054 }
2055#endif
2056
2057#if _MI_PAGING_LEVELS >= 3
2058 /* Check for new PPE boundary */
2059 if (OnPpeBoundary)
2060 {
2061 PointerPpe = MiPteToPpe(PointerPte);
2062
2063 /* Check that this loop is sane */
2064 ASSERT(OnPdeBoundary);
2065
2066 if (PointerPpe->u.Long != 0)
2067 {
2068 /* Make it valid if needed */
2069 if (PointerPpe->u.Hard.Valid == 0)
2071 }
2072 else
2073 {
2074 /* Is the entire VAD committed? If not, fail */
2075 if (!Vad->u.VadFlags.MemCommit) return FALSE;
2076
2077 PointerPpe++;
2078 PointerPte = MiPpeToPte(PointerPpe);
2079#if _MI_PAGING_LEVELS == 4
2080 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
2081#endif
2082 continue;
2083 }
2084 }
2085#endif
2086 /* Check if we've hit a new PDE boundary */
2087 if (OnPdeBoundary)
2088 {
2089 /* Is this PDE demand zero? */
2090 PointerPde = MiPteToPde(PointerPte);
2091 if (PointerPde->u.Long != 0)
2092 {
2093 /* It isn't -- is it valid? */
2094 if (PointerPde->u.Hard.Valid == 0)
2095 {
2096 /* Nope, fault it in */
2097 MiMakeSystemAddressValid(PointerPte, Process);
2098 }
2099 }
2100 else
2101 {
2102 /* Is the entire VAD committed? If not, fail */
2103 if (!Vad->u.VadFlags.MemCommit) return FALSE;
2104
2105 /* The PTE was already valid, so move to the next one */
2106 PointerPde++;
2107 PointerPte = MiPdeToPte(PointerPde);
2108#if _MI_PAGING_LEVELS >= 3
2109 OnPpeBoundary = MiIsPteOnPpeBoundary(PointerPte);
2110#if _MI_PAGING_LEVELS == 4
2111 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
2112#endif
2113#endif
2114
2115 /* New loop iteration with our new, on-boundary PTE. */
2116 continue;
2117 }
2118 }
2119
2120 /* Is the PTE demand zero? */
2121 if (PointerPte->u.Long == 0)
2122 {
2123 /* Is the entire VAD committed? If not, fail */
2124 if (!Vad->u.VadFlags.MemCommit) return FALSE;
2125 }
2126 else
2127 {
2128 /* It isn't -- is it a decommited, invalid, or faulted PTE? */
2129 if ((PointerPte->u.Soft.Protection == MM_DECOMMIT) &&
2130 (PointerPte->u.Hard.Valid == 0) &&
2131 ((PointerPte->u.Soft.Prototype == 0) ||
2132 (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)))
2133 {
2134 /* Then part of the range is decommitted, so fail */
2135 return FALSE;
2136 }
2137 }
2138
2139 /* Move to the next PTE */
2140 PointerPte++;
2141 OnPdeBoundary = MiIsPteOnPdeBoundary(PointerPte);
2142#if _MI_PAGING_LEVELS >= 3
2143 OnPpeBoundary = MiIsPteOnPpeBoundary(PointerPte);
2144#if _MI_PAGING_LEVELS == 4
2145 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
2146#endif
2147#endif
2148 }
2149
2150 /* All PTEs seem valid, and no VAD checks failed, the range is okay */
2151 return TRUE;
2152}
2153
2155NTAPI
2158 IN OUT PSIZE_T NumberOfBytesToProtect,
2159 IN ULONG NewAccessProtection,
2160 OUT PULONG OldAccessProtection OPTIONAL)
2161{
2164 ULONG OldAccessProtection_;
2166
2167 *NumberOfBytesToProtect = PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) - PAGE_ROUND_DOWN(*BaseAddress);
2169
2170 AddressSpace = &Process->Vm;
2174 {
2176 return STATUS_UNSUCCESSFUL;
2177 }
2178
2179 if (OldAccessProtection == NULL) OldAccessProtection = &OldAccessProtection_;
2180
2183 MemoryArea,
2184 *BaseAddress,
2185 *NumberOfBytesToProtect,
2186 NewAccessProtection,
2187 OldAccessProtection);
2188
2190
2191 return Status;
2192}
2193
2195NTAPI
2198 IN OUT PSIZE_T NumberOfBytesToProtect,
2199 IN ULONG NewAccessProtection,
2200 OUT PULONG OldAccessProtection OPTIONAL)
2201{
2203 PMMVAD Vad;
2205 ULONG_PTR StartingAddress, EndingAddress;
2206 PMMPTE PointerPte, LastPte;
2207 PMMPDE PointerPde;
2208 MMPTE PteContents;
2209 PMMPFN Pfn1;
2210 ULONG ProtectionMask, OldProtect;
2211 BOOLEAN Committed;
2215
2216 /* We must be attached */
2218
2219 /* Calculate base address for the VAD */
2220 StartingAddress = (ULONG_PTR)PAGE_ALIGN((*BaseAddress));
2221 EndingAddress = (((ULONG_PTR)*BaseAddress + *NumberOfBytesToProtect - 1) | (PAGE_SIZE - 1));
2222
2223 /* Calculate the protection mask and make sure it's valid */
2224 ProtectionMask = MiMakeProtectionMask(NewAccessProtection);
2225 if (ProtectionMask == MM_INVALID_PROTECTION)
2226 {
2227 DPRINT1("Invalid protection mask\n");
2229 }
2230
2231 /* Lock the address space and make sure the process isn't already dead */
2234 if (Process->VmDeleted)
2235 {
2236 DPRINT1("Process is dying\n");
2238 goto FailPath;
2239 }
2240
2241 /* Check for ROS specific memory area */
2244 {
2245 /* Evil hack */
2249 NumberOfBytesToProtect,
2250 NewAccessProtection,
2251 OldAccessProtection);
2252 }
2253
2254 /* Get the VAD for this address range, and make sure it exists */
2255 Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
2256 EndingAddress >> PAGE_SHIFT,
2257 &Process->VadRoot,
2258 (PMMADDRESS_NODE*)&Vad);
2259 if (Result != TableFoundNode)
2260 {
2261 DPRINT("Could not find a VAD for this allocation\n");
2263 goto FailPath;
2264 }
2265
2266 /* Make sure the address is within this VAD's boundaries */
2267 if ((((ULONG_PTR)StartingAddress >> PAGE_SHIFT) < Vad->StartingVpn) ||
2268 (((ULONG_PTR)EndingAddress >> PAGE_SHIFT) > Vad->EndingVpn))
2269 {
2271 goto FailPath;
2272 }
2273
2274 /* These kinds of VADs are not supported atm */
2275 if ((Vad->u.VadFlags.VadType == VadAwe) ||
2277 (Vad->u.VadFlags.VadType == VadLargePages))
2278 {
2279 DPRINT1("Illegal VAD for attempting to set protection\n");
2281 goto FailPath;
2282 }
2283
2284 /* Check for a VAD whose protection can't be changed */
2285 if (Vad->u.VadFlags.NoChange == 1)
2286 {
2287 DPRINT1("Trying to change protection of a NoChange VAD\n");
2289 goto FailPath;
2290 }
2291
2292 /* Is this section, or private memory? */
2293 if (Vad->u.VadFlags.PrivateMemory == 0)
2294 {
2295 /* Not yet supported */
2297 {
2298 DPRINT1("Illegal VAD for attempting to set protection\n");
2300 goto FailPath;
2301 }
2302
2303 /* Rotate VADs are not yet supported */
2304 if (Vad->u.VadFlags.VadType == VadRotatePhysical)
2305 {
2306 DPRINT1("Illegal VAD for attempting to set protection\n");
2308 goto FailPath;
2309 }
2310
2311 /* Not valid on section files */
2312 if (NewAccessProtection & (PAGE_NOCACHE | PAGE_WRITECOMBINE))
2313 {
2314 /* Fail */
2315 DPRINT1("Invalid protection flags for section\n");
2317 goto FailPath;
2318 }
2319
2320 /* Check if data or page file mapping protection PTE is compatible */
2321 if (!Vad->ControlArea->u.Flags.Image)
2322 {
2323 /* Not yet */
2324 DPRINT1("Fixme: Not checking for valid protection\n");
2325 }
2326
2327 /* This is a section, and this is not yet supported */
2328 DPRINT1("Section protection not yet supported\n");
2329 OldProtect = 0;
2330 }
2331 else
2332 {
2333 /* Private memory, check protection flags */
2334 if ((NewAccessProtection & PAGE_WRITECOPY) ||
2335 (NewAccessProtection & PAGE_EXECUTE_WRITECOPY))
2336 {
2337 DPRINT1("Invalid protection flags for private memory\n");
2339 goto FailPath;
2340 }
2341
2342 /* Lock the working set */
2344
2345 /* Check if all pages in this range are committed */
2346 Committed = MiIsEntireRangeCommitted(StartingAddress,
2347 EndingAddress,
2348 Vad,
2349 Process);
2350 if (!Committed)
2351 {
2352 /* Fail */
2353 DPRINT1("The entire range is not committed\n");
2356 goto FailPath;
2357 }
2358
2359 /* Compute starting and ending PTE and PDE addresses */
2360 PointerPde = MiAddressToPde(StartingAddress);
2361 PointerPte = MiAddressToPte(StartingAddress);
2362 LastPte = MiAddressToPte(EndingAddress);
2363
2364 /* Make this PDE valid */
2366
2367 /* Save protection of the first page */
2368 if (PointerPte->u.Long != 0)
2369 {
2370 /* Capture the page protection and make the PDE valid */
2371 OldProtect = MiGetPageProtection(PointerPte);
2373 }
2374 else
2375 {
2376 /* Grab the old protection from the VAD itself */
2377 OldProtect = MmProtectToValue[Vad->u.VadFlags.Protection];
2378 }
2379
2380 /* Loop all the PTEs now */
2381 while (PointerPte <= LastPte)
2382 {
2383 /* Check if we've crossed a PDE boundary and make the new PDE valid too */
2384 if (MiIsPteOnPdeBoundary(PointerPte))
2385 {
2386 PointerPde = MiPteToPde(PointerPte);
2388 }
2389
2390 /* Capture the PTE and check if it was empty */
2391 PteContents = *PointerPte;
2392 if (PteContents.u.Long == 0)
2393 {
2394 /* This used to be a zero PTE and it no longer is, so we must add a
2395 reference to the pagetable. */
2397 }
2398
2399 /* Check what kind of PTE we are dealing with */
2400 if (PteContents.u.Hard.Valid == 1)
2401 {
2402 /* Get the PFN entry */
2403 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents));
2404
2405 /* We don't support this yet */
2406 ASSERT(Pfn1->u3.e1.PrototypePte == 0);
2407
2408 /* Check if the page should not be accessible at all */
2409 if ((NewAccessProtection & PAGE_NOACCESS) ||
2410 (NewAccessProtection & PAGE_GUARD))
2411 {
2412 KIRQL OldIrql = MiAcquirePfnLock();
2413
2414 /* Mark the PTE as transition and change its protection */
2415 PteContents.u.Hard.Valid = 0;
2416 PteContents.u.Soft.Transition = 1;
2417 PteContents.u.Trans.Protection = ProtectionMask;
2418 /* Decrease PFN share count and write the PTE */
2419 MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents));
2420 // FIXME: remove the page from the WS
2421 MI_WRITE_INVALID_PTE(PointerPte, PteContents);
2422#ifdef CONFIG_SMP
2423 // FIXME: Should invalidate entry in every CPU TLB
2425#endif
2427
2428 /* We are done for this PTE */
2429 MiReleasePfnLock(OldIrql);
2430 }
2431 else
2432 {
2433 /* Write the protection mask and write it with a TLB flush */
2434 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
2436 PointerPte,
2437 ProtectionMask,
2438 Pfn1,
2439 TRUE);
2440 }
2441 }
2442 else
2443 {
2444 /* We don't support these cases yet */
2445 ASSERT(PteContents.u.Soft.Prototype == 0);
2446 //ASSERT(PteContents.u.Soft.Transition == 0);
2447
2448 /* The PTE is already demand-zero, just update the protection mask */
2449 PteContents.u.Soft.Protection = ProtectionMask;
2450 MI_WRITE_INVALID_PTE(PointerPte, PteContents);
2451 ASSERT(PointerPte->u.Long != 0);
2452 }
2453
2454 /* Move to the next PTE */
2455 PointerPte++;
2456 }
2457
2458 /* Unlock the working set */
2460 }
2461
2462 /* Unlock the address space */
2464
2465 /* Return parameters and success */
2466 *NumberOfBytesToProtect = EndingAddress - StartingAddress + 1;
2467 *BaseAddress = (PVOID)StartingAddress;
2468 *OldAccessProtection = OldProtect;
2469 return STATUS_SUCCESS;
2470
2471FailPath:
2472 /* Unlock the address space and return the failure code */
2474 return Status;
2475}
2476
2477VOID
2478NTAPI
2480 IN PEPROCESS TargetProcess,
2482{
2483 PMMPTE PointerPte;
2484#if _MI_PAGING_LEVELS >= 3
2485 PMMPPE PointerPpe = MiPdeToPpe(PointerPde);
2486#if _MI_PAGING_LEVELS == 4
2487 PMMPXE PointerPxe = MiPdeToPxe(PointerPde);
2488#endif
2489#endif
2490
2491 //
2492 // Sanity checks. The latter is because we only use this function with the
2493 // PFN lock not held, so it may go away in the future.
2494 //
2497
2498 //
2499 // If everything is already valid, there is nothing to do.
2500 //
2501 if (
2502#if _MI_PAGING_LEVELS == 4
2503 (PointerPxe->u.Hard.Valid) &&
2504#endif
2505#if _MI_PAGING_LEVELS >= 3
2506 (PointerPpe->u.Hard.Valid) &&
2507#endif
2508 (PointerPde->u.Hard.Valid))
2509 {
2510 return;
2511 }
2512
2513 //
2514 // At least something is invalid, so begin by getting the PTE for the PDE itself
2515 // and then lookup each additional level. We must do it in this precise order
2516 // because the pagfault.c code (as well as in Windows) depends that the next
2517 // level up (higher) must be valid when faulting a lower level
2518 //
2519 PointerPte = MiPteToAddress(PointerPde);
2520 do
2521 {
2522 //
2523 // Make sure APCs continued to be disabled
2524 //
2526
2527#if _MI_PAGING_LEVELS == 4
2528 //
2529 // First, make the PXE valid if needed
2530 //
2531 if (!PointerPxe->u.Hard.Valid)
2532 {
2533 MiMakeSystemAddressValid(PointerPpe, TargetProcess);
2534 ASSERT(PointerPxe->u.Hard.Valid == 1);
2535 }
2536#endif
2537
2538#if _MI_PAGING_LEVELS >= 3
2539 //
2540 // Next, the PPE
2541 //
2542 if (!PointerPpe->u.Hard.Valid)
2543 {
2544 MiMakeSystemAddressValid(PointerPde, TargetProcess);
2545 ASSERT(PointerPpe->u.Hard.Valid == 1);
2546 }
2547#endif
2548
2549 //
2550 // And finally, make the PDE itself valid.
2551 //
2552 MiMakeSystemAddressValid(PointerPte, TargetProcess);
2553
2554 /* Do not increment Page table refcount here for the PDE, this must be managed by caller */
2555
2556 //
2557 // This should've worked the first time so the loop is really just for
2558 // show -- ASSERT that we're actually NOT going to be looping.
2559 //
2560 ASSERT(PointerPde->u.Hard.Valid == 1);
2561 } while (
2562#if _MI_PAGING_LEVELS == 4
2563 !PointerPxe->u.Hard.Valid ||
2564#endif
2565#if _MI_PAGING_LEVELS >= 3
2566 !PointerPpe->u.Hard.Valid ||
2567#endif
2568 !PointerPde->u.Hard.Valid);
2569}
2570
2571VOID
2572NTAPI
2574 IN ULONG Count)
2575{
2576 KIRQL OldIrql;
2577 ULONG i;
2578 MMPTE TempPte;
2579 PFN_NUMBER PageFrameIndex;
2580 PMMPFN Pfn1, Pfn2;
2581
2582 //
2583 // Acquire the PFN lock and loop all the PTEs in the list
2584 //
2585 OldIrql = MiAcquirePfnLock();
2586 for (i = 0; i != Count; i++)
2587 {
2588 //
2589 // The PTE must currently be valid
2590 //
2591 TempPte = *ValidPteList[i];
2592 ASSERT(TempPte.u.Hard.Valid == 1);
2593
2594 //
2595 // Get the PFN entry for the page itself, and then for its page table
2596 //
2597 PageFrameIndex = PFN_FROM_PTE(&TempPte);
2598 Pfn1 = MiGetPfnEntry(PageFrameIndex);
2599 Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
2600
2601 //
2602 // Decrement the share count on the page table, and then on the page
2603 // itself
2604 //
2605 MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
2606 MI_SET_PFN_DELETED(Pfn1);
2607 MiDecrementShareCount(Pfn1, PageFrameIndex);
2608
2609 //
2610 // Make the page decommitted
2611 //
2612 MI_WRITE_INVALID_PTE(ValidPteList[i], MmDecommittedPte);
2613 }
2614
2615 //
2616 // All the PTEs have been dereferenced and made invalid, flush the TLB now
2617 // and then release the PFN lock
2618 //
2620 MiReleasePfnLock(OldIrql);
2621}
2622
2623ULONG
2624NTAPI
2625MiDecommitPages(IN PVOID StartingAddress,
2626 IN PMMPTE EndingPte,
2628 IN PMMVAD Vad)
2629{
2630 PMMPTE PointerPte, CommitPte = NULL;
2631 PMMPDE PointerPde;
2632 ULONG CommitReduction = 0;
2633 PMMPTE ValidPteList[256];
2634 ULONG PteCount = 0;
2635 PMMPFN Pfn1;
2636 MMPTE PteContents;
2637 PETHREAD CurrentThread = PsGetCurrentThread();
2638
2639 //
2640 // Get the PTE and PTE for the address, and lock the working set
2641 // If this was a VAD for a MEM_COMMIT allocation, also figure out where the
2642 // commited range ends so that we can do the right accounting.
2643 //
2644 PointerPde = MiAddressToPde(StartingAddress);
2645 PointerPte = MiAddressToPte(StartingAddress);
2646 if (Vad->u.VadFlags.MemCommit) CommitPte = MiAddressToPte(Vad->EndingVpn << PAGE_SHIFT);
2647 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
2648
2649 //
2650 // Make the PDE valid, and now loop through each page's worth of data
2651 //
2653 while (PointerPte <= EndingPte)
2654 {
2655 //
2656 // Check if we've crossed a PDE boundary
2657 //
2658 if (MiIsPteOnPdeBoundary(PointerPte))
2659 {
2660 //
2661 // Get the new PDE and flush the valid PTEs we had built up until
2662 // now. This helps reduce the amount of TLB flushing we have to do.
2663 // Note that Windows does a much better job using timestamps and
2664 // such, and does not flush the entire TLB all the time, but right
2665 // now we have bigger problems to worry about than TLB flushing.
2666 //
2667 PointerPde = MiAddressToPde(StartingAddress);
2668 if (PteCount)
2669 {
2670 MiProcessValidPteList(ValidPteList, PteCount);
2671 PteCount = 0;
2672 }
2673
2674 //
2675 // Make this PDE valid
2676 //
2678 }
2679
2680 //
2681 // Read this PTE. It might be active or still demand-zero.
2682 //
2683 PteContents = *PointerPte;
2684 if (PteContents.u.Long)
2685 {
2686 //
2687 // The PTE is active. It might be valid and in a working set, or
2688 // it might be a prototype PTE or paged out or even in transition.
2689 //
2690 if (PointerPte->u.Long == MmDecommittedPte.u.Long)
2691 {
2692 //
2693 // It's already decommited, so there's nothing for us to do here
2694 //
2695 CommitReduction++;
2696 }
2697 else
2698 {
2699 //
2700 // Remove it from the counters, and check if it was valid or not
2701 //
2702 //Process->NumberOfPrivatePages--;
2703 if (PteContents.u.Hard.Valid)
2704 {
2705 //
2706 // It's valid. At this point make sure that it is not a ROS
2707 // PFN. Also, we don't support ProtoPTEs in this code path.
2708 //
2709 Pfn1 = MiGetPfnEntry(PteContents.u.Hard.PageFrameNumber);
2710 ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE);
2711 ASSERT(Pfn1->u3.e1.PrototypePte == FALSE);
2712
2713 //
2714 // Flush any pending PTEs that we had not yet flushed, if our
2715 // list has gotten too big, then add this PTE to the flush list.
2716 //
2717 if (PteCount == 256)
2718 {
2719 MiProcessValidPteList(ValidPteList, PteCount);
2720 PteCount = 0;
2721 }
2722 ValidPteList[PteCount++] = PointerPte;
2723 }
2724 else
2725 {
2726 //
2727 // We do not support any of these other scenarios at the moment
2728 //
2729 ASSERT(PteContents.u.Soft.Prototype == 0);
2730 ASSERT(PteContents.u.Soft.Transition == 0);
2731 ASSERT(PteContents.u.Soft.PageFileHigh == 0);
2732
2733 //
2734 // So the only other possibility is that it is still a demand
2735 // zero PTE, in which case we undo the accounting we did
2736 // earlier and simply make the page decommitted.
2737 //
2738 //Process->NumberOfPrivatePages++;
2740 }
2741 }
2742 }
2743 else
2744 {
2745 //
2746 // This used to be a zero PTE and it no longer is, so we must add a
2747 // reference to the pagetable.
2748 //
2749 MiIncrementPageTableReferences(StartingAddress);
2750
2751 //
2752 // Next, we account for decommitted PTEs and make the PTE as such
2753 //
2754 if (PointerPte > CommitPte) CommitReduction++;
2756 }
2757
2758 //
2759 // Move to the next PTE and the next address
2760 //
2761 PointerPte++;
2762 StartingAddress = (PVOID)((ULONG_PTR)StartingAddress + PAGE_SIZE);
2763 }
2764
2765 //
2766 // Flush any dangling PTEs from the loop in the last page table, and then
2767 // release the working set and return the commit reduction accounting.
2768 //
2769 if (PteCount) MiProcessValidPteList(ValidPteList, PteCount);
2771 return CommitReduction;
2772}
2773
2774/* PUBLIC FUNCTIONS ***********************************************************/
2775
2776/*
2777 * @unimplemented
2778 */
2779PVOID
2780NTAPI
2782{
2784 return 0;
2785}
2786
2787/*
2788 * @unimplemented
2789 */
2790PVOID
2791NTAPI
2794 IN ULONG Mode)
2795{
2796 static ULONG Warn; if (!Warn++) UNIMPLEMENTED;
2797 return Address;
2798}
2799
2800/*
2801 * @unimplemented
2802 */
2803VOID
2804NTAPI
2806{
2807 static ULONG Warn; if (!Warn++) UNIMPLEMENTED;
2808}
2809
2810/* SYSTEM CALLS ***************************************************************/
2811
2813NTAPI
2817 IN SIZE_T NumberOfBytesToRead,
2818 OUT PSIZE_T NumberOfBytesRead OPTIONAL)
2819{
2823 SIZE_T BytesRead = 0;
2824 PAGED_CODE();
2825
2826 //
2827 // Check if we came from user mode
2828 //
2829 if (PreviousMode != KernelMode)
2830 {
2831 //
2832 // Validate the read addresses
2833 //
2834 if ((((ULONG_PTR)BaseAddress + NumberOfBytesToRead) < (ULONG_PTR)BaseAddress) ||
2835 (((ULONG_PTR)Buffer + NumberOfBytesToRead) < (ULONG_PTR)Buffer) ||
2836 (((ULONG_PTR)BaseAddress + NumberOfBytesToRead) > MmUserProbeAddress) ||
2837 (((ULONG_PTR)Buffer + NumberOfBytesToRead) > MmUserProbeAddress))
2838 {
2839 //
2840 // Don't allow to write into kernel space
2841 //
2843 }
2844
2845 //
2846 // Enter SEH for probe
2847 //
2848 _SEH2_TRY
2849 {
2850 //
2851 // Probe the output value
2852 //
2853 if (NumberOfBytesRead) ProbeForWriteSize_t(NumberOfBytesRead);
2854 }
2856 {
2857 //
2858 // Get exception code
2859 //
2861 }
2862 _SEH2_END;
2863 }
2864
2865 //
2866 // Don't do zero-byte transfers
2867 //
2868 if (NumberOfBytesToRead)
2869 {
2870 //
2871 // Reference the process
2872 //
2877 (PVOID*)(&Process),
2878 NULL);
2879 if (NT_SUCCESS(Status))
2880 {
2881 //
2882 // Do the copy
2883 //
2887 Buffer,
2888 NumberOfBytesToRead,
2890 &BytesRead);
2891
2892 //
2893 // Dereference the process
2894 //
2896 }
2897 }
2898
2899 //
2900 // Check if the caller sent this parameter
2901 //
2902 if (NumberOfBytesRead)
2903 {
2904 //
2905 // Enter SEH to guard write
2906 //
2907 _SEH2_TRY
2908 {
2909 //
2910 // Return the number of bytes read
2911 //
2912 *NumberOfBytesRead = BytesRead;
2913 }
2915 {
2916 }
2917 _SEH2_END;
2918 }
2919
2920 //
2921 // Return status
2922 //
2923 return Status;
2924}
2925
2927NTAPI
2930 IN PVOID Buffer,
2931 IN SIZE_T NumberOfBytesToWrite,
2932 OUT PSIZE_T NumberOfBytesWritten OPTIONAL)
2933{
2937 SIZE_T BytesWritten = 0;
2938 PAGED_CODE();
2939
2940 //
2941 // Check if we came from user mode
2942 //
2943 if (PreviousMode != KernelMode)
2944 {
2945 //
2946 // Validate the read addresses
2947 //
2948 if ((((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) < (ULONG_PTR)BaseAddress) ||
2949 (((ULONG_PTR)Buffer + NumberOfBytesToWrite) < (ULONG_PTR)Buffer) ||
2950 (((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) > MmUserProbeAddress) ||
2951 (((ULONG_PTR)Buffer + NumberOfBytesToWrite) > MmUserProbeAddress))
2952 {
2953 //
2954 // Don't allow to write into kernel space
2955 //
2957 }
2958
2959 //
2960 // Enter SEH for probe
2961 //
2962 _SEH2_TRY
2963 {
2964 //
2965 // Probe the output value
2966 //
2967 if (NumberOfBytesWritten) ProbeForWriteSize_t(NumberOfBytesWritten);
2968 }
2970 {
2971 //
2972 // Get exception code
2973 //
2975 }
2976 _SEH2_END;
2977 }
2978
2979 //
2980 // Don't do zero-byte transfers
2981 //
2982 if (NumberOfBytesToWrite)
2983 {
2984 //
2985 // Reference the process
2986 //
2991 (PVOID*)&Process,
2992 NULL);
2993 if (NT_SUCCESS(Status))
2994 {
2995 //
2996 // Do the copy
2997 //
2999 Buffer,
3000 Process,
3002 NumberOfBytesToWrite,
3004 &BytesWritten);
3005
3006 //
3007 // Dereference the process
3008 //
3010 }
3011 }
3012
3013 //
3014 // Check if the caller sent this parameter
3015 //
3016 if (NumberOfBytesWritten)
3017 {
3018 //
3019 // Enter SEH to guard write
3020 //
3021 _SEH2_TRY
3022 {
3023 //
3024 // Return the number of bytes written
3025 //
3026 *NumberOfBytesWritten = BytesWritten;
3027 }
3029 {
3030 }
3031 _SEH2_END;
3032 }
3033
3034 //
3035 // Return status
3036 //
3037 return Status;
3038}
3039
3041NTAPI
3044 _In_ SIZE_T FlushSize)
3045{
3049 PAGED_CODE();
3050
3051 /* Is a base address given? */
3052 if (BaseAddress != NULL)
3053 {
3054 /* If the requested size is 0, there is nothing to do */
3055 if (FlushSize == 0)
3056 {
3057 return STATUS_SUCCESS;
3058 }
3059
3060 /* Is this a user mode call? */
3062 {
3063 /* Make sure the base address is in user space */
3065 {
3066 DPRINT1("Invalid BaseAddress 0x%p\n", BaseAddress);
3068 }
3069 }
3070 }
3071
3072 /* Is another process requested? */
3074 {
3075 /* Reference the process */
3080 (PVOID*)&Process,
3081 NULL);
3082 if (!NT_SUCCESS(Status))
3083 {
3084 DPRINT1("Failed to reference the process %p\n", ProcessHandle);
3085 return Status;
3086 }
3087
3088 /* Attach to the process */
3090 }
3091
3092 /* Forward to Ke */
3093 KeSweepICache(BaseAddress, FlushSize);
3094
3095 /* Check if we attached */
3097 {
3098 /* Detach from the process and dereference it */
3101 }
3102
3103 /* All done, return to caller */
3104 return STATUS_SUCCESS;
3105}
3106
3108NTAPI
3110 IN OUT PVOID *UnsafeBaseAddress,
3111 IN OUT SIZE_T *UnsafeNumberOfBytesToProtect,
3112 IN ULONG NewAccessProtection,
3113 OUT PULONG UnsafeOldAccessProtection)
3114{
3116 ULONG OldAccessProtection;
3117 ULONG Protection;
3118 PEPROCESS CurrentProcess = PsGetCurrentProcess();
3120 SIZE_T NumberOfBytesToProtect = 0;
3125 PAGED_CODE();
3126
3127 //
3128 // Check for valid protection flags
3129 //
3130 Protection = NewAccessProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
3131 if (Protection != PAGE_NOACCESS &&
3132 Protection != PAGE_READONLY &&
3133 Protection != PAGE_READWRITE &&
3134 Protection != PAGE_WRITECOPY &&
3135 Protection != PAGE_EXECUTE &&
3136 Protection != PAGE_EXECUTE_READ &&
3137 Protection != PAGE_EXECUTE_READWRITE &&
3138 Protection != PAGE_EXECUTE_WRITECOPY)
3139 {
3140 //
3141 // Fail
3142 //
3144 }
3145
3146 //
3147 // Check if we came from user mode
3148 //
3149 if (PreviousMode != KernelMode)
3150 {
3151 //
3152 // Enter SEH for probing
3153 //
3154 _SEH2_TRY
3155 {
3156 //
3157 // Validate all outputs
3158 //
3159 ProbeForWritePointer(UnsafeBaseAddress);
3160 ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect);
3161 ProbeForWriteUlong(UnsafeOldAccessProtection);
3162
3163 //
3164 // Capture them
3165 //
3166 BaseAddress = *UnsafeBaseAddress;
3167 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
3168 }
3170 {
3171 //
3172 // Get exception code
3173 //
3175 }
3176 _SEH2_END;
3177 }
3178 else
3179 {
3180 //
3181 // Capture directly
3182 //
3183 BaseAddress = *UnsafeBaseAddress;
3184 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
3185 }
3186
3187 //
3188 // Catch illegal base address
3189 //
3191
3192 //
3193 // Catch illegal region size
3194 //
3195 if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < NumberOfBytesToProtect)
3196 {
3197 //
3198 // Fail
3199 //
3201 }
3202
3203 //
3204 // 0 is also illegal
3205 //
3206 if (!NumberOfBytesToProtect) return STATUS_INVALID_PARAMETER_3;
3207
3208 //
3209 // Get a reference to the process
3210 //
3215 (PVOID*)(&Process),
3216 NULL);
3217 if (!NT_SUCCESS(Status)) return Status;
3218
3219 //
3220 // Check if we should attach
3221 //
3222 if (CurrentProcess != Process)
3223 {
3224 //
3225 // Do it
3226 //
3228 Attached = TRUE;
3229 }
3230
3231 //
3232 // Do the actual work
3233 //
3235 &BaseAddress,
3236 &NumberOfBytesToProtect,
3237 NewAccessProtection,
3238 &OldAccessProtection);
3239
3240 //
3241 // Detach if needed
3242 //
3244
3245 //
3246 // Release reference
3247 //
3249
3250 //
3251 // Enter SEH to return data
3252 //
3253 _SEH2_TRY
3254 {
3255 //
3256 // Return data to user
3257 //
3258 *UnsafeOldAccessProtection = OldAccessProtection;
3259 *UnsafeBaseAddress = BaseAddress;
3260 *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
3261 }
3263 {
3264 }
3265 _SEH2_END;
3266
3267 //
3268 // Return status
3269 //
3270 return Status;
3271}
3272
3274BOOLEAN
3276 PMMPFN Pfn1,
3278{
3279 // HACK until we have proper WSLIST support
3280 PMMWSLE Wsle = &Pfn1->Wsle;
3281
3282 if ((LockType & MAP_PROCESS) && (Wsle->u1.e1.LockedInWs))
3283 return TRUE;
3284 if ((LockType & MAP_SYSTEM) && (Wsle->u1.e1.LockedInMemory))
3285 return TRUE;
3286
3287 return FALSE;
3288}
3289
3291VOID
3293 PMMPFN Pfn1,
3295{
3296 // HACK until we have proper WSLIST support
3297 PMMWSLE Wsle = &Pfn1->Wsle;
3298
3299 if (!Wsle->u1.e1.LockedInWs &&
3300 !Wsle->u1.e1.LockedInMemory)
3301 {
3303 }
3304
3305 if (LockType & MAP_PROCESS)
3306 Wsle->u1.e1.LockedInWs = 1;
3307 if (LockType & MAP_SYSTEM)
3308 Wsle->u1.e1.LockedInMemory = 1;
3309}
3310
3312VOID
3314 PMMPFN Pfn1,
3316{
3317 // HACK until we have proper WSLIST support
3318 PMMWSLE Wsle = &Pfn1->Wsle;
3319
3320 if (LockType & MAP_PROCESS)
3321 Wsle->u1.e1.LockedInWs = 0;
3322 if (LockType & MAP_SYSTEM)
3323 Wsle->u1.e1.LockedInMemory = 0;
3324
3325 if (!Wsle->u1.e1.LockedInWs &&
3326 !Wsle->u1.e1.LockedInMemory)
3327 {
3329 }
3330}
3331
3332static
3337 _Inout_ PVOID *EndAddress)
3338
3339{
3340 PMMVAD Vad;
3341 PVOID CurrentVa;
3342
3343 /* Get the base address and align the start address */
3344 *EndAddress = (PUCHAR)*BaseAddress + *RegionSize;
3345 *EndAddress = ALIGN_UP_POINTER_BY(*EndAddress, PAGE_SIZE);
3347
3348 /* First loop and check all VADs */
3349 CurrentVa = *BaseAddress;
3350 while (CurrentVa < *EndAddress)
3351 {
3352 /* Get VAD */
3353 Vad = MiLocateAddress(CurrentVa);
3354 if (Vad == NULL)
3355 {
3358 }
3359
3360 /* Check VAD type */
3361 if ((Vad->u.VadFlags.VadType != VadNone) &&
3362 (Vad->u.VadFlags.VadType != VadImageMap) &&
3363 (Vad->u.VadFlags.VadType != VadWriteWatch))
3364 {
3365 *EndAddress = CurrentVa;
3366 *RegionSize = (PUCHAR)*EndAddress - (PUCHAR)*BaseAddress;
3368 }
3369
3370 CurrentVa = (PVOID)((Vad->EndingVpn + 1) << PAGE_SHIFT);
3371 }
3372
3373 *RegionSize = (PUCHAR)*EndAddress - (PUCHAR)*BaseAddress;
3374 return STATUS_SUCCESS;
3375}
3376
3377static
3382 IN ULONG MapType)
3383{
3384 PEPROCESS CurrentProcess;
3386 PVOID CurrentVa, EndAddress;
3387 PMMPTE PointerPte, LastPte;
3388 PMMPDE PointerPde;
3389#if (_MI_PAGING_LEVELS >= 3)
3390 PMMPDE PointerPpe;
3391#endif
3392#if (_MI_PAGING_LEVELS == 4)
3393 PMMPDE PointerPxe;
3394#endif
3395 PMMPFN Pfn1;
3396 NTSTATUS Status, TempStatus;
3397
3398 /* Lock the address space */
3401
3402 /* Make sure we still have an address space */
3403 CurrentProcess = PsGetCurrentProcess();
3404 if (CurrentProcess->VmDeleted)
3405 {
3407 goto Cleanup;
3408 }
3409
3410 /* Check the VADs in the requested range */
3412 if (!NT_SUCCESS(Status))
3413 {
3414 goto Cleanup;
3415 }
3416
3417 /* Enter SEH for probing */
3418 _SEH2_TRY
3419 {
3420 /* Loop all pages and probe them */
3421 CurrentVa = *BaseAddress;
3422 while (CurrentVa < EndAddress)
3423 {
3424 (void)(*(volatile CHAR*)CurrentVa);
3425 CurrentVa = (PUCHAR)CurrentVa + PAGE_SIZE;
3426 }
3427 }
3429 {
3431 goto Cleanup;
3432 }
3433 _SEH2_END;
3434
3435 /* All pages were accessible, since we hold the address space lock, nothing
3436 can be de-committed. Assume success for now. */
3438
3439 /* Get the PTE and PDE */
3440 PointerPte = MiAddressToPte(*BaseAddress);
3441 PointerPde = MiAddressToPde(*BaseAddress);
3442#if (_MI_PAGING_LEVELS >= 3)
3443 PointerPpe = MiAddressToPpe(*BaseAddress);
3444#endif
3445#if (_MI_PAGING_LEVELS == 4)
3446 PointerPxe = MiAddressToPxe(*BaseAddress);
3447#endif
3448
3449 /* Get the last PTE */
3450 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)EndAddress - 1));
3451
3452 /* Lock the process working set */
3454
3455 /* Loop the pages */
3456 do
3457 {
3458 /* Check for a page that is not accessible */
3459 while (
3460#if (_MI_PAGING_LEVELS == 4)
3461 (PointerPxe->u.Hard.Valid == 0) ||
3462#endif
3463#if (_MI_PAGING_LEVELS >= 3)
3464 (PointerPpe->u.Hard.Valid == 0) ||
3465#endif
3466 (PointerPde->u.Hard.Valid == 0) ||
3467 (PointerPte->u.Hard.Valid == 0))
3468 {
3469 /* Release process working set */
3471
3472 /* Access the page */
3473 CurrentVa = MiPteToAddress(PointerPte);
3474
3475 //HACK: Pass a placeholder TrapInformation so the fault handler knows we're unlocked
3476 TempStatus = MmAccessFault(TRUE, CurrentVa, KernelMode, (PVOID)(ULONG_PTR)0xBADBADA3BADBADA3ULL);
3477 if (!NT_SUCCESS(TempStatus))
3478 {
3479 // This should only happen, when remote backing storage is not accessible
3480 ASSERT(FALSE);
3481 Status = TempStatus;
3482 goto Cleanup;
3483 }
3484
3485 /* Lock the process working set */
3487 }
3488
3489 /* Get the PFN */
3490 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3491 ASSERT(Pfn1 != NULL);
3492
3493 /* Check the previous lock status */
3494 if (MI_IS_LOCKED_VA(Pfn1, MapType))
3495 {
3497 }
3498
3499 /* Lock it */
3500 MI_LOCK_VA(Pfn1, MapType);
3501
3502 /* Go to the next PTE */
3503 PointerPte++;
3504
3505 /* Check if we're on a PDE boundary */
3506 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3507#if (_MI_PAGING_LEVELS >= 3)
3508 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3509#endif
3510#if (_MI_PAGING_LEVELS == 4)
3511 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3512#endif
3513 } while (PointerPte <= LastPte);
3514
3515 /* Release process working set */
3517
3518Cleanup:
3519 /* Unlock address space */
3521
3522 return Status;
3523}
3524
3526NTAPI
3529 IN OUT PSIZE_T NumberOfBytesToLock,
3530 IN ULONG MapType)
3531{
3533 PEPROCESS CurrentProcess = PsGetCurrentProcess();
3538 PVOID CapturedBaseAddress;
3539 SIZE_T CapturedBytesToLock;
3540 PAGED_CODE();
3541
3542 //
3543 // Validate flags
3544 //
3545 if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)))
3546 {
3547 //
3548 // Invalid set of flags
3549 //
3551 }
3552
3553 //
3554 // At least one flag must be specified
3555 //
3556 if (!(MapType & (MAP_PROCESS | MAP_SYSTEM)))
3557 {
3558 //
3559 // No flag given
3560 //
3562 }
3563
3564 //
3565 // Enter SEH for probing
3566 //
3567 _SEH2_TRY
3568 {
3569 //
3570 // Validate output data
3571 //
3573 ProbeForWriteSize_t(NumberOfBytesToLock);
3574
3575 //
3576 // Capture it
3577 //
3578 CapturedBaseAddress = *BaseAddress;
3579 CapturedBytesToLock = *NumberOfBytesToLock;
3580 }
3582 {
3583 //
3584 // Get exception code
3585 //
3587 }
3588 _SEH2_END;
3589
3590 //
3591 // Catch illegal base address
3592 //
3593 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
3594
3595 //
3596 // Catch illegal region size
3597 //
3598 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToLock)
3599 {
3600 //
3601 // Fail
3602 //
3604 }
3605
3606 //
3607 // 0 is also illegal
3608 //
3609 if (!CapturedBytesToLock) return STATUS_INVALID_PARAMETER;
3610
3611 //
3612 // Get a reference to the process
3613 //
3618 (PVOID*)(&Process),
3619 NULL);
3620 if (!NT_SUCCESS(Status)) return Status;
3621
3622 //
3623 // Check if this is is system-mapped
3624 //
3625 if (MapType & MAP_SYSTEM)
3626 {
3627 //
3628 // Check for required privilege
3629 //
3631 {
3632 //
3633 // Fail: Don't have it
3634 //
3637 }
3638 }
3639
3640 //
3641 // Check if we should attach
3642 //
3643 if (CurrentProcess != Process)
3644 {
3645 //
3646 // Do it
3647 //
3649 Attached = TRUE;
3650 }
3651
3652 //
3653 // Call the internal function
3654 //
3655 Status = MiLockVirtualMemory(&CapturedBaseAddress,
3656 &CapturedBytesToLock,
3657 MapType);
3658
3659 //
3660 // Detach if needed
3661 //
3663
3664 //
3665 // Release reference
3666 //
3668
3669 //
3670 // Enter SEH to return data
3671 //
3672 _SEH2_TRY
3673 {
3674 //
3675 // Return data to user
3676 //
3677 *BaseAddress = CapturedBaseAddress;
3678 *NumberOfBytesToLock = CapturedBytesToLock;
3679 }
3681 {
3682 //
3683 // Get exception code
3684 //
3686 }
3687 _SEH2_END;
3688
3689 //
3690 // Return status
3691 //
3692 return Status;
3693}
3694
3695
3696static
3701 IN ULONG MapType)
3702{
3703 PEPROCESS CurrentProcess;
3705 PVOID EndAddress;
3706 PMMPTE PointerPte, LastPte;
3707 PMMPDE PointerPde;
3708#if (_MI_PAGING_LEVELS >= 3)
3709 PMMPDE PointerPpe;
3710#endif
3711#if (_MI_PAGING_LEVELS == 4)
3712 PMMPDE PointerPxe;
3713#endif
3714 PMMPFN Pfn1;
3716
3717 /* Lock the address space */
3720
3721 /* Make sure we still have an address space */
3722 CurrentProcess = PsGetCurrentProcess();
3723 if (CurrentProcess->VmDeleted)
3724 {
3726 goto Cleanup;
3727 }
3728
3729 /* Check the VADs in the requested range */
3731
3732 /* Note: only bail out, if we hit an area without a VAD. If we hit an
3733 incompatible VAD we continue, like Windows does */
3735 {
3737 goto Cleanup;
3738 }
3739
3740 /* Get the PTE and PDE */
3741 PointerPte = MiAddressToPte(*BaseAddress);
3742 PointerPde = MiAddressToPde(*BaseAddress);
3743#if (_MI_PAGING_LEVELS >= 3)
3744 PointerPpe = MiAddressToPpe(*BaseAddress);
3745#endif
3746#if (_MI_PAGING_LEVELS == 4)
3747 PointerPxe = MiAddressToPxe(*BaseAddress);
3748#endif
3749
3750 /* Get the last PTE */
3751 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)EndAddress - 1));
3752
3753 /* Lock the process working set */
3755
3756 /* Loop the pages */
3757 do
3758 {
3759 /* Check for a page that is not present */
3760 if (
3761#if (_MI_PAGING_LEVELS == 4)
3762 (PointerPxe->u.Hard.Valid == 0) ||
3763#endif
3764#if (_MI_PAGING_LEVELS >= 3)
3765 (PointerPpe->u.Hard.Valid == 0) ||
3766#endif
3767 (PointerPde->u.Hard.Valid == 0) ||
3768 (PointerPte->u.Hard.Valid == 0))
3769 {
3770 /* Remember it, but keep going */
3772 }
3773 else
3774 {
3775 /* Get the PFN */
3776 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3777 ASSERT(Pfn1 != NULL);
3778
3779 /* Check if all of the requested locks are present */
3780 if (((MapType & MAP_SYSTEM) && !MI_IS_LOCKED_VA(Pfn1, MAP_SYSTEM)) ||
3781 ((MapType & MAP_PROCESS) && !MI_IS_LOCKED_VA(Pfn1, MAP_PROCESS)))
3782 {
3783 /* Remember it, but keep going */
3785
3786 /* Check if no lock is present */
3788 {
3789 DPRINT1("FIXME: Should remove the page from WS\n");
3790 }
3791 }
3792 }
3793
3794 /* Go to the next PTE */
3795 PointerPte++;
3796
3797 /* Check if we're on a PDE boundary */
3798 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3799#if (_MI_PAGING_LEVELS >= 3)
3800 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3801#endif
3802#if (_MI_PAGING_LEVELS == 4)
3803 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3804#endif
3805 } while (PointerPte <= LastPte);
3806
3807 /* Check if we hit a page that was not locked */
3809 {
3810 goto CleanupWithWsLock;
3811 }
3812
3813 /* All pages in the region were locked, so unlock them all */
3814
3815 /* Get the PTE and PDE */
3816 PointerPte = MiAddressToPte(*BaseAddress);
3817 PointerPde = MiAddressToPde(*BaseAddress);
3818#if (_MI_PAGING_LEVELS >= 3)
3819 PointerPpe = MiAddressToPpe(*BaseAddress);
3820#endif
3821#if (_MI_PAGING_LEVELS == 4)
3822 PointerPxe = MiAddressToPxe(*BaseAddress);
3823#endif
3824
3825 /* Loop the pages */
3826 do
3827 {
3828 /* Unlock it */
3829 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3830 MI_UNLOCK_VA(Pfn1, MapType);
3831
3832 /* Go to the next PTE */
3833 PointerPte++;
3834
3835 /* Check if we're on a PDE boundary */
3836 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3837#if (_MI_PAGING_LEVELS >= 3)
3838 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3839#endif
3840#if (_MI_PAGING_LEVELS == 4)
3841 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3842#endif
3843 } while (PointerPte <= LastPte);
3844
3845 /* Everything is done */
3847
3848CleanupWithWsLock:
3849
3850 /* Release process working set */
3852
3853Cleanup:
3854 /* Unlock address space */
3856
3857 return Status;
3858}
3859
3860
3862NTAPI
3865 IN OUT PSIZE_T NumberOfBytesToUnlock,
3866 IN ULONG MapType)
3867{
3869 PEPROCESS CurrentProcess = PsGetCurrentProcess();
3874 PVOID CapturedBaseAddress;
3875 SIZE_T CapturedBytesToUnlock;
3876 PAGED_CODE();
3877
3878 //
3879 // Validate flags
3880 //
3881 if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)))
3882 {
3883 //
3884 // Invalid set of flags
3885 //
3887 }
3888
3889 //
3890 // At least one flag must be specified
3891 //
3892 if (!(MapType & (MAP_PROCESS | MAP_SYSTEM)))
3893 {
3894 //
3895 // No flag given
3896 //
3898 }
3899
3900 //
3901 // Enter SEH for probing
3902 //
3903 _SEH2_TRY
3904 {
3905 //
3906 // Validate output data
3907 //
3909 ProbeForWriteSize_t(NumberOfBytesToUnlock);
3910
3911 //
3912 // Capture it
3913 //
3914 CapturedBaseAddress = *BaseAddress;
3915 CapturedBytesToUnlock = *NumberOfBytesToUnlock;
3916 }
3918 {
3919 //
3920 // Get exception code
3921 //
3923 }
3924 _SEH2_END;
3925
3926 //
3927 // Catch illegal base address
3928 //
3929 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
3930
3931 //
3932 // Catch illegal region size
3933 //
3934 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToUnlock)
3935 {
3936 //
3937 // Fail
3938 //
3940 }
3941
3942 //
3943 // 0 is also illegal
3944 //
3945 if (!CapturedBytesToUnlock) return STATUS_INVALID_PARAMETER;
3946
3947 //
3948 // Get a reference to the process
3949 //
3954 (PVOID*)(&Process),
3955 NULL);
3956 if (!NT_SUCCESS(Status)) return Status;
3957
3958 //
3959 // Check if this is is system-mapped
3960 //
3961 if (MapType & MAP_SYSTEM)
3962 {
3963 //
3964 // Check for required privilege
3965 //
3967 {
3968 //
3969 // Fail: Don't have it
3970 //
3973 }
3974 }
3975
3976 //
3977 // Check if we should attach
3978 //
3979 if (CurrentProcess != Process)
3980 {
3981 //
3982 // Do it
3983 //
3985 Attached = TRUE;
3986 }
3987
3988 //
3989 // Call the internal function
3990 //
3991 Status = MiUnlockVirtualMemory(&CapturedBaseAddress,
3992 &CapturedBytesToUnlock,
3993 MapType);
3994
3995 //
3996 // Detach if needed
3997 //
3999
4000 //
4001 // Release reference
4002 //
4004
4005 //
4006 // Enter SEH to return data
4007 //
4008 _SEH2_TRY
4009 {
4010 //
4011 // Return data to user
4012 //
4013 *BaseAddress = CapturedBaseAddress;
4014 *NumberOfBytesToUnlock = CapturedBytesToUnlock;
4015 }
4017 {
4018 //
4019 // Get exception code
4020 //
4022 }
4023 _SEH2_END;
4024
4025 //
4026 // Return status
4027 //
4028 return STATUS_SUCCESS;
4029}
4030
4032NTAPI
4035 IN OUT PSIZE_T NumberOfBytesToFlush,
4037{
4041 PVOID CapturedBaseAddress;
4042 SIZE_T CapturedBytesToFlush;
4043 IO_STATUS_BLOCK LocalStatusBlock;
4044 PAGED_CODE();
4045
4046 //
4047 // Check if we came from user mode
4048 //
4049 if (PreviousMode != KernelMode)
4050 {
4051 //
4052 // Enter SEH for probing
4053 //
4054 _SEH2_TRY
4055 {
4056 //
4057 // Validate all outputs
4058 //
4060 ProbeForWriteSize_t(NumberOfBytesToFlush);
4062
4063 //
4064 // Capture them
4065 //
4066 CapturedBaseAddress = *BaseAddress;
4067 CapturedBytesToFlush = *NumberOfBytesToFlush;
4068 }
4070 {
4071 //
4072 // Get exception code
4073 //
4075 }
4076 _SEH2_END;
4077 }
4078 else
4079 {
4080 //
4081 // Capture directly
4082 //
4083 CapturedBaseAddress = *BaseAddress;
4084 CapturedBytesToFlush = *NumberOfBytesToFlush;
4085 }
4086
4087 //
4088 // Catch illegal base address
4089 //
4090 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
4091
4092 //
4093 // Catch illegal region size
4094 //
4095 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToFlush)
4096 {
4097 //
4098 // Fail
4099 //
4101 }
4102
4103 //
4104 // Get a reference to the process
4105 //
4110 (PVOID*)(&Process),
4111 NULL);
4112 if (!NT_SUCCESS(Status)) return Status;
4113
4114 //
4115 // Do it
4116 //
4118 &CapturedBaseAddress,
4119 &CapturedBytesToFlush,
4120 &LocalStatusBlock);
4121
4122 //
4123 // Release reference
4124 //
4126
4127 //
4128 // Enter SEH to return data
4129 //
4130 _SEH2_TRY
4131 {
4132 //
4133 // Return data to user
4134 //
4135 *BaseAddress = PAGE_ALIGN(CapturedBaseAddress);
4136 *NumberOfBytesToFlush = 0;
4137 *IoStatusBlock = LocalStatusBlock;
4138 }
4140 {
4141 }
4142 _SEH2_END;
4143
4144 //
4145 // Return status
4146 //
4147 return Status;
4148}
4149
4150/*
4151 * @unimplemented
4152 */
4154NTAPI
4156 IN ULONG Flags,
4159 IN PVOID *UserAddressArray,
4160 OUT PULONG_PTR EntriesInUserAddressArray,
4161 OUT PULONG Granularity)
4162{
4165 PVOID EndAddress;
4167 ULONG_PTR CapturedEntryCount;
4168 PAGED_CODE();
4169
4170 //
4171 // Check if we came from user mode
4172 //
4173 if (PreviousMode != KernelMode)
4174 {
4175 //
4176 // Enter SEH for probing
4177 //
4178 _SEH2_TRY
4179 {
4180 //
4181 // Catch illegal base address
4182 //
4184
4185 //
4186 // Catch illegal region size
4187 //
4189 {
4190 //
4191 // Fail
4192 //
4194 }
4195
4196 //
4197 // Validate all data
4198 //
4199 ProbeForWriteSize_t(EntriesInUserAddressArray);
4200 ProbeForWriteUlong(Granularity);
4201
4202 //
4203 // Capture them
4204 //
4205 CapturedEntryCount = *EntriesInUserAddressArray;
4206
4207 //
4208 // Must have a count
4209 //
4210 if (CapturedEntryCount == 0) _SEH2_YIELD(return STATUS_INVALID_PARAMETER_5);
4211
4212 //
4213 // Can't be larger than the maximum
4214 //
4215 if (CapturedEntryCount > (MAXULONG_PTR / sizeof(ULONG_PTR)))
4216 {
4217 //
4218 // Fail
4219 //
4221 }
4222
4223 //
4224 // Probe the actual array
4225 //
4226 ProbeForWrite(UserAddressArray,
4227 CapturedEntryCount * sizeof(PVOID),
4228 sizeof(PVOID));
4229 }
4231 {
4232 //
4233 // Get exception code
4234 //
4236 }
4237 _SEH2_END;
4238 }
4239 else
4240 {
4241 //
4242 // Capture directly
4243 //
4244 CapturedEntryCount = *EntriesInUserAddressArray;
4245 ASSERT(CapturedEntryCount != 0);
4246 }
4247
4248 //
4249 // Check if this is a local request
4250 //
4252 {
4253 //
4254 // No need to reference the process
4255 //
4257 }
4258 else
4259 {
4260 //
4261 // Reference the target
4262 //
4267 (PVOID *)&Process,
4268 NULL);
4269 if (!NT_SUCCESS(Status)) return Status;
4270 }
4271
4272 //
4273 // Compute the last address and validate it
4274 //
4275 EndAddress = (PVOID)((ULONG_PTR)BaseAddress + RegionSize - 1);
4276 if (BaseAddress > EndAddress)
4277 {
4278 //
4279 // Fail
4280 //
4283 }
4284
4285 //
4286 // Oops :(
4287 //
4289
4290 //
4291 // Dereference if needed
4292 //
4294
4295 //
4296 // Enter SEH to return data
4297 //
4298 _SEH2_TRY
4299 {
4300 //
4301 // Return data to user
4302 //
4303 *EntriesInUserAddressArray = 0;
4304 *Granularity = PAGE_SIZE;
4305 }
4307 {
4308 //
4309 // Get exception code
4310 //
4312 }
4313 _SEH2_END;
4314
4315 //
4316 // Return success
4317 //
4318 return STATUS_SUCCESS;
4319}
4320
4321/*
4322 * @unimplemented
4323 */
4325NTAPI
4329{
4330 PVOID EndAddress;
4335
4336 //
4337 // Catch illegal base address
4338 //
4340
4341 //
4342 // Catch illegal region size
4343 //
4345 {
4346 //
4347 // Fail
4348 //
4350 }
4351
4352 //
4353 // Check if this is a local request
4354 //
4356 {
4357 //
4358 // No need to reference the process
4359 //
4361 }
4362 else
4363 {
4364 //
4365 // Reference the target
4366 //
4371 (PVOID *)&Process,
4372 NULL);
4373 if (!NT_SUCCESS(Status)) return Status;
4374 }
4375
4376 //
4377 // Compute the last address and validate it
4378 //
4379 EndAddress = (PVOID)((ULONG_PTR)BaseAddress + RegionSize - 1);
4380 if (BaseAddress > EndAddress)
4381 {
4382 //
4383 // Fail
4384 //
4387 }
4388
4389 //
4390 // Oops :(
4391 //
4393
4394 //
4395 // Dereference if needed
4396 //
4398
4399 //
4400 // Return success
4401 //
4402 return STATUS_SUCCESS;
4403}
4404
4406NTAPI
4409 IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
4410 OUT PVOID MemoryInformation,
4411 IN SIZE_T MemoryInformationLength,
4413{
4416
4417 DPRINT("Querying class %d about address: %p\n", MemoryInformationClass, BaseAddress);
4418
4419 /* Bail out if the address is invalid */
4421
4422 /* Probe return buffer */
4424 if (PreviousMode != KernelMode)
4425 {
4426 _SEH2_TRY
4427 {
4428 ProbeForWrite(MemoryInformation,
4429 MemoryInformationLength,
4430 sizeof(ULONG_PTR));
4431
4433 }
4435 {
4437 }
4438 _SEH2_END;
4439
4440 if (!NT_SUCCESS(Status))
4441 {
4442 return Status;
4443 }
4444 }
4445
4446 switch(MemoryInformationClass)
4447 {
4449 /* Validate the size information of the class */
4450 if (MemoryInformationLength < sizeof(MEMORY_BASIC_INFORMATION))
4451 {
4452 /* The size is invalid */
4454 }
4457 MemoryInformation,
4458 MemoryInformationLength,
4459 ReturnLength);
4460 break;
4461
4462 case MemorySectionName:
4463 /* Validate the size information of the class */
4464 if (MemoryInformationLength < sizeof(MEMORY_SECTION_NAME))
4465 {
4466 /* The size is invalid */
4468 }
4471 MemoryInformation,
4472 MemoryInformationLength,
4473 ReturnLength);
4474 break;
4477 default:
4478 DPRINT1("Unhandled memory information class %d\n", MemoryInformationClass);
4479 break;
4480 }
4481
4482 return Status;
4483}
4484
4485/*
4486 * @implemented
4487 */
4489NTAPI
4491 IN OUT PVOID* UBaseAddress,
4493 IN OUT PSIZE_T URegionSize,
4496{
4499 PMMVAD Vad = NULL, FoundVad;
4502 PVOID PBaseAddress;
4503 ULONG_PTR PRegionSize, StartingAddress, EndingAddress;
4504 ULONG_PTR HighestAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS;
4505 PEPROCESS CurrentProcess = PsGetCurrentProcess();
4507 PETHREAD CurrentThread = PsGetCurrentThread();
4509 ULONG ProtectionMask, QuotaCharge = 0, QuotaFree = 0;
4510 BOOLEAN Attached = FALSE, ChangeProtection = FALSE, QuotaCharged = FALSE;
4511 MMPTE TempPte;
4512 PMMPTE PointerPte, LastPte;
4513 PMMPDE PointerPde;
4515 PAGED_CODE();
4516
4517 /* Check for valid Zero bits */
4519 {
4520 DPRINT1("Too many zero bits\n");
4522 }
4523
4524 /* Check for valid Allocation Types */
4527 {
4528 DPRINT1("Invalid Allocation Type\n");
4530 }
4531
4532 /* Check for at least one of these Allocation Types to be set */
4534 {
4535 DPRINT1("No memory allocation base type\n");
4537 }
4538
4539 /* MEM_RESET is an exclusive flag, make sure that is valid too */
4541 {
4542 DPRINT1("Invalid use of MEM_RESET\n");
4544 }
4545
4546 /* Check if large pages are being used */
4548 {
4549 /* Large page allocations MUST be committed */
4550 if (!(AllocationType & MEM_COMMIT))
4551 {
4552 DPRINT1("Must supply MEM_COMMIT with MEM_LARGE_PAGES\n");
4554 }
4555
4556 /* These flags are not allowed with large page allocations */
4558 {
4559 DPRINT1("Using illegal flags with MEM_LARGE_PAGES\n");
4561 }
4562 }
4563
4564 /* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
4566 {
4567 DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
4569 }
4570
4571 /* Check for valid MEM_PHYSICAL usage */
4573 {
4574 /* MEM_PHYSICAL can only be used if MEM_RESERVE is also used */
4575 if (!(AllocationType & MEM_RESERVE))
4576 {
4577 DPRINT1("MEM_PHYSICAL used without MEM_RESERVE\n");
4579 }
4580
4581 /* Only these flags are allowed with MEM_PHYSIAL */
4583 {
4584 DPRINT1("Using illegal flags with MEM_PHYSICAL\n");
4586 }
4587
4588 /* Then make sure PAGE_READWRITE is used */
4589 if (Protect != PAGE_READWRITE)
4590 {
4591 DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n");
4593 }
4594 }
4595
4596 /* Calculate the protection mask and make sure it's valid */
4597 ProtectionMask = MiMakeProtectionMask(Protect);
4598 if (ProtectionMask == MM_INVALID_PROTECTION)
4599 {
4600 DPRINT1("Invalid protection mask\n");
4602 }
4603
4604 /* Enter SEH */
4605 _SEH2_TRY
4606 {
4607 /* Check for user-mode parameters */
4608 if (PreviousMode != KernelMode)
4609 {
4610 /* Make sure they are writable */
4611 ProbeForWritePointer(UBaseAddress);
4612 ProbeForWriteSize_t(URegionSize);
4613 }
4614
4615 /* Capture their values */
4616 PBaseAddress = *UBaseAddress;
4617 PRegionSize = *URegionSize;
4618 }
4620 {
4621 /* Return the exception code */
4623 }
4624 _SEH2_END;
4625
4626 /* Make sure the allocation isn't past the VAD area */
4627 if (PBaseAddress > MM_HIGHEST_VAD_ADDRESS)
4628 {
4629 DPRINT1("Virtual allocation base above User Space\n");
4631 }
4632
4633 /* Make sure the allocation wouldn't overflow past the VAD area */
4634 if ((((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) - (ULONG_PTR)PBaseAddress) < PRegionSize)
4635 {
4636 DPRINT1("Region size would overflow into kernel-memory\n");
4638 }
4639
4640 /* Make sure there's a size specified */
4641 if (!PRegionSize)
4642 {
4643 DPRINT1("Region size is invalid (zero)\n");
4645 }
4646
4647 //
4648 // If this is for the current process, just use PsGetCurrentProcess
4649 //
4651 {
4652 Process = CurrentProcess;
4653 }
4654 else
4655 {
4656 //
4657 // Otherwise, reference the process with VM rights and attach to it if
4658 // this isn't the current process. We must attach because we'll be touching
4659 // PTEs and PDEs that belong to user-mode memory, and also touching the
4660 // Working Set which is stored in Hyperspace.
4661 //
4666 (PVOID*)&Process,
4667 NULL);
4668 if (!NT_SUCCESS(Status)) return Status;
4669 if (CurrentProcess != Process)
4670 {
4672 Attached = TRUE;
4673 }
4674 }
4675
4676 DPRINT("NtAllocateVirtualMemory: Process 0x%p, Address 0x%p, Zerobits %lu , RegionSize 0x%x, Allocation type 0x%x, Protect 0x%x.\n",
4677 Process, PBaseAddress, ZeroBits, PRegionSize, AllocationType, Protect);
4678
4679 //
4680 // Check for large page allocations and make sure that the required privilege
4681 // is being held, before attempting to handle them.
4682 //
4685 {
4686 /* Fail without it */
4687 DPRINT1("Privilege not held for MEM_LARGE_PAGES\n");
4689 goto FailPathNoLock;
4690 }
4691
4692 //
4693 // Fail on the things we don't yet support
4694 //
4696 {
4697 DPRINT1("MEM_LARGE_PAGES not supported\n");
4699 goto FailPathNoLock;
4700 }
4702 {
4703 DPRINT1("MEM_PHYSICAL not supported\n");
4705 goto FailPathNoLock;
4706 }
4708 {
4709 DPRINT1("MEM_WRITE_WATCH not supported\n");
4711 goto FailPathNoLock;
4712 }
4713
4714 //
4715 // Check if the caller is reserving memory, or committing memory and letting
4716 // us pick the base address
4717 //
4718 if (!(PBaseAddress) || (AllocationType & MEM_RESERVE))
4719 {
4720 //
4721 // Do not allow COPY_ON_WRITE through this API
4722 //
4724 {
4725 DPRINT1("Copy on write not allowed through this path\n");
4727 goto FailPathNoLock;
4728 }
4729
4730 //
4731 // Does the caller have an address in mind, or is this a blind commit?
4732 //
4733 if (!PBaseAddress)
4734 {
4735 //
4736 // This is a blind commit, all we need is the region size
4737 //
4738 PRegionSize = ROUND_TO_PAGES(PRegionSize);
4739 EndingAddress = 0;
4740 StartingAddress = 0;
4741
4742 //
4743 // Check if ZeroBits were specified
4744 //
4745 if (ZeroBits != 0)
4746 {
4747 //
4748 // Calculate the highest address and check if it's valid
4749 //
4750 HighestAddress = MAXULONG_PTR >> ZeroBits;
4751 if (HighestAddress > (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS)
4752 {
4754 goto FailPathNoLock;
4755 }
4756 }
4757 }
4758 else
4759 {
4760 //
4761 // This is a reservation, so compute the starting address on the
4762 // expected 64KB granularity, and see where the ending address will
4763 // fall based on the aligned address and the passed in region size
4764 //
4765 EndingAddress = ((ULONG_PTR)PBaseAddress + PRegionSize - 1) | (PAGE_SIZE - 1);
4766 PRegionSize = EndingAddress + 1 - ROUND_DOWN((ULONG_PTR)PBaseAddress, _64K);
4767 StartingAddress = (ULONG_PTR)PBaseAddress;
4768 }
4769
4770 // Charge quotas for the VAD
4772 if (!NT_SUCCESS(Status))
4773 {
4774 DPRINT1("Quota exceeded.\n");
4775 goto FailPathNoLock;
4776 }
4777
4779
4780 //
4781 // Allocate and initialize the VAD
4782 //
4783 Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'SdaV');
4784 if (Vad == NULL)
4785 {
4786 DPRINT1("Failed to allocate a VAD!\n");
4788 goto FailPathNoLock;
4789 }
4790
4791 RtlZeroMemory(Vad, sizeof(MMVAD_LONG));
4793 Vad->u.VadFlags.Protection = ProtectionMask;
4794 Vad->u.VadFlags.PrivateMemory = 1;
4795 Vad->ControlArea = NULL; // For Memory-Area hack
4796
4797 //
4798 // Insert the VAD
4799 //
4800 Status = MiInsertVadEx(Vad,
4801 &StartingAddress,
4802 PRegionSize,
4803 HighestAddress,
4806 if (!NT_SUCCESS(Status))
4807 {
4808 DPRINT1("Failed to insert the VAD!\n");
4809 ExFreePoolWithTag(Vad, 'SdaV');
4810 goto FailPathNoLock;
4811 }
4812
4813 //
4814 // Detach and dereference the target process if
4815 // it was different from the current process
4816 //
4819
4820 //
4821 // Use SEH to write back the base address and the region size. In the case
4822 // of an exception, we do not return back the exception code, as the memory
4823 // *has* been allocated. The caller would now have to call VirtualQuery
4824 // or do some other similar trick to actually find out where its memory
4825 // allocation ended up
4826 //
4827 _SEH2_TRY
4828 {
4829 *URegionSize = PRegionSize;
4830 *UBaseAddress = (PVOID)StartingAddress;
4831 }
4833 {
4834 //
4835 // Ignore exception!
4836 //
4837 }
4838 _SEH2_END;
4839 DPRINT("Reserved %x bytes at %p.\n", PRegionSize, StartingAddress);
4840 return STATUS_SUCCESS;
4841 }
4842
4843 //
4844 // This is a MEM_COMMIT on top of an existing address which must have been
4845 // MEM_RESERVED already. Compute the start and ending base addresses based
4846 // on the user input, and then compute the actual region size once all the
4847 // alignments have been done.
4848 //
4849 EndingAddress = (((ULONG_PTR)PBaseAddress + PRegionSize - 1) | (PAGE_SIZE - 1));
4850 StartingAddress = (ULONG_PTR)PAGE_ALIGN(PBaseAddress);
4851 PRegionSize = EndingAddress - StartingAddress + 1;
4852
4853 //
4854 // Lock the address space and make sure the process isn't already dead
4855 //
4858 if (Process->VmDeleted)
4859 {
4860 DPRINT1("Process is dying\n");
4862 goto FailPath;
4863 }
4864
4865 //
4866 // Get the VAD for this address range, and make sure it exists
4867 //
4868 Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
4869 EndingAddress >> PAGE_SHIFT,
4870 &Process->VadRoot,
4871 (PMMADDRESS_NODE*)&FoundVad);
4872 if (Result != TableFoundNode)
4873 {
4874 DPRINT1("Could not find a VAD for this allocation\n");
4876 goto FailPath;
4877 }
4878
4880 {
4882 DPRINT("MEM_RESET not supported\n");
4884 goto FailPath;
4885 }
4886
4887 //
4888 // These kinds of VADs are illegal for this Windows function when trying to
4889 // commit an existing range
4890 //
4891 if ((FoundVad->u.VadFlags.VadType == VadAwe) ||
4892 (FoundVad->u.VadFlags.VadType == VadDevicePhysicalMemory) ||
4893 (FoundVad->u.VadFlags.VadType == VadLargePages))
4894 {
4895 DPRINT1("Illegal VAD for attempting a MEM_COMMIT\n");
4897 goto FailPath;
4898 }
4899
4900 //
4901 // Make sure that this address range actually fits within the VAD for it
4902 //
4903 if (((StartingAddress >> PAGE_SHIFT) < FoundVad->StartingVpn) ||
4904 ((EndingAddress >> PAGE_SHIFT) > FoundVad->EndingVpn))
4905 {
4906 DPRINT1("Address range does not fit into the VAD\n");
4908 goto FailPath;
4909 }
4910
4911 //
4912 // Make sure this is an ARM3 section
4913 //
4917 {
4918 DPRINT1("Illegal commit of non-ARM3 section!\n");
4920 goto FailPath;
4921 }
4922
4923 // Is this a previously reserved section being committed? If so, enter the
4924 // special section path
4925 //
4926 if (FoundVad->u.VadFlags.PrivateMemory == FALSE)
4927 {
4928 //
4929 // You cannot commit large page sections through this API
4930 //
4931 if (FoundVad->u.VadFlags.VadType == VadLargePageSection)
4932 {
4933 DPRINT1("Large page sections cannot be VirtualAlloc'd\n");
4935 goto FailPath;
4936 }
4937
4938 //
4939 // You can only use caching flags on a rotate VAD
4940 //
4942 (FoundVad->u.VadFlags.VadType != VadRotatePhysical))
4943 {
4944 DPRINT1("Cannot use caching flags with anything but rotate VADs\n");
4946 goto FailPath;
4947 }
4948
4949 //
4950 // We should make sure that the section's permissions aren't being
4951 // messed with
4952 //
4953 if (FoundVad->u.VadFlags.NoChange)
4954 {
4955 //
4956 // Make sure it's okay to touch it
4957 // Note: The Windows 2003 kernel has a bug here, passing the
4958 // unaligned base address together with the aligned size,
4959 // potentially covering a region larger than the actual allocation.
4960 // Might be exposed through NtGdiCreateDIBSection w/ section handle
4961 // For now we keep this behavior.
4962 // TODO: analyze possible implications, create test case
4963 //
4964 Status = MiCheckSecuredVad(FoundVad,
4965 PBaseAddress,
4966 PRegionSize,
4967 ProtectionMask);
4968 if (!NT_SUCCESS(Status))
4969 {
4970 DPRINT1("Secured VAD being messed around with\n");
4971 goto FailPath;
4972 }
4973 }
4974
4975 //
4976 // ARM3 does not support file-backed sections, only shared memory
4977 //
4978 ASSERT(FoundVad->ControlArea->FilePointer == NULL);
4979
4980 //
4981 // Rotate VADs cannot be guard pages or inaccessible, nor copy on write
4982 //
4983 if ((FoundVad->u.VadFlags.VadType == VadRotatePhysical) &&
4985 {
4986 DPRINT1("Invalid page protection for rotate VAD\n");
4988 goto FailPath;
4989 }
4990
4991 //
4992 // Compute PTE addresses and the quota charge, then grab the commit lock
4993 //
4994 PointerPte = MI_GET_PROTOTYPE_PTE_FOR_VPN(FoundVad, StartingAddress >> PAGE_SHIFT);
4995 LastPte = MI_GET_PROTOTYPE_PTE_FOR_VPN(FoundVad, EndingAddress >> PAGE_SHIFT);
4996 QuotaCharge = (ULONG)(LastPte - PointerPte + 1);
4998
4999 //
5000 // Get the segment template PTE and start looping each page
5001 //
5002 TempPte = FoundVad->ControlArea->Segment->SegmentPteTemplate;
5003 ASSERT(TempPte.u.Long != 0);
5004 while (PointerPte <= LastPte)
5005 {
5006 //
5007 // For each non-already-committed page, write the invalid template PTE
5008 //
5009 if (PointerPte->u.Long == 0)
5010 {
5011 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
5012 }
5013 else
5014 {
5015 QuotaFree++;
5016 }
5017 PointerPte++;
5018 }
5019
5020 //
5021 // Now do the commit accounting and release the lock
5022 //
5023 ASSERT(QuotaCharge >= QuotaFree);
5024 QuotaCharge -= QuotaFree;
5025 FoundVad->ControlArea->Segment->NumberOfCommittedPages += QuotaCharge;
5027
5028 //
5029 // We are done with committing the section pages
5030 //
5032 goto FailPath;
5033 }
5034
5035 //
5036 // This is a specific ReactOS check because we only use normal VADs
5037 //
5038 ASSERT(FoundVad->u.VadFlags.VadType == VadNone);
5039
5040 //
5041 // While this is an actual Windows check
5042 //
5043 ASSERT(FoundVad->u.VadFlags.VadType != VadRotatePhysical);
5044
5045 //
5046 // Throw out attempts to use copy-on-write through this API path
5047 //
5049 {
5050 DPRINT1("Write copy attempted when not allowed\n");
5052 goto FailPath;
5053 }
5054
5055 //
5056 // Initialize a demand-zero PTE
5057 //
5058 TempPte.u.Long = 0;
5059 TempPte.u.Soft.Protection = ProtectionMask;
5060 ASSERT(TempPte.u.Long != 0);
5061
5062 //
5063 // Get the PTE, PDE and the last PTE for this address range
5064 //
5065 PointerPde = MiAddressToPde(StartingAddress);
5066 PointerPte = MiAddressToPte(StartingAddress);
5067 LastPte = MiAddressToPte(EndingAddress);
5068
5069 //
5070 // Update the commit charge in the VAD as well as in the process, and check
5071 // if this commit charge was now higher than the last recorded peak, in which
5072 // case we also update the peak
5073 //
5074 FoundVad->u.VadFlags.CommitCharge += (1 + LastPte - PointerPte);
5075 Process->CommitCharge += (1 + LastPte - PointerPte);
5076 if (Process->CommitCharge > Process->CommitChargePeak)
5077 {
5078 Process->CommitChargePeak = Process->CommitCharge;
5079 }
5080
5081 //
5082 // Lock the working set while we play with user pages and page tables
5083 //
5084 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5085
5086 //
5087 // Make the current page table valid, and then loop each page within it
5088 //
5090 while (PointerPte <= LastPte)
5091 {
5092 //
5093 // Have we crossed into a new page table?
5094 //
5095 if (MiIsPteOnPdeBoundary(PointerPte))
5096 {
5097 //
5098 // Get the PDE and now make it valid too
5099 //
5100 PointerPde = MiPteToPde(PointerPte);
5102 }
5103
5104 //
5105 // Is this a zero PTE as expected?
5106 //
5107 if (PointerPte->u.Long == 0)
5108 {
5109 //
5110 // First increment the count of pages in the page table for this
5111 // process
5112 //
5114
5115 //
5116 // And now write the invalid demand-zero PTE as requested
5117 //
5118 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
5119 }
5120 else if (PointerPte->u.Long == MmDecommittedPte.u.Long)
5121 {
5122 //
5123 // If the PTE was already decommitted, there is nothing else to do
5124 // but to write the new demand-zero PTE
5125 //
5126 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
5127 }
5128 else if (!(ChangeProtection) && (Protect != MiGetPageProtection(PointerPte)))
5129 {
5130 //
5131 // We don't handle these scenarios yet
5132 //
5133 if (PointerPte->u.Soft.Valid == 0)
5134 {
5135 ASSERT(PointerPte->u.Soft.Prototype == 0);
5136 ASSERT((PointerPte->u.Soft.PageFileHigh == 0) || (PointerPte->u.Soft.Transition == 1));
5137 }
5138
5139 //
5140 // There's a change in protection, remember this for later, but do
5141 // not yet handle it.
5142 //
5143 ChangeProtection = TRUE;
5144 }
5145
5146 //
5147 // Move to the next PTE
5148 //
5149 PointerPte++;
5150 }
5151
5152 //
5153 // Release the working set lock, unlock the address space, and detach from
5154 // the target process if it was not the current process. Also dereference the
5155 // target process if this wasn't the case.
5156 //
5159FailPath:
5161
5162 if (!NT_SUCCESS(Status))
5163 {
5164 if (Vad != NULL)
5165 {
5166 ExFreePoolWithTag(Vad, 'SdaV');
5167 }
5168 }
5169
5170 //
5171 // Check if we need to update the protection
5172 //
5173 if (ChangeProtection)
5174 {
5175 PVOID ProtectBaseAddress = (PVOID)StartingAddress;
5176 SIZE_T ProtectSize = PRegionSize;
5177 ULONG OldProtection;
5178
5179 //
5180 // Change the protection of the region
5181 //
5183 &ProtectBaseAddress,
5184 &ProtectSize,
5185 Protect,
5186 &OldProtection);
5187 }
5188
5189FailPathNoLock:
5192
5193 //
5194 // Only write back results on success
5195 //
5196 if (NT_SUCCESS(Status))
5197 {
5198 //
5199 // Use SEH to write back the base address and the region size. In the case
5200 // of an exception, we strangely do return back the exception code, even
5201 // though the memory *has* been allocated. This mimics Windows behavior and
5202 // there is not much we can do about it.
5203 //
5204 _SEH2_TRY
5205 {
5206 *URegionSize = PRegionSize;
5207 *UBaseAddress = (PVOID)StartingAddress;
5208 }
5210 {
5212 }
5213 _SEH2_END;
5214 }
5215 else if (QuotaCharged)
5216 {
5218 }
5219
5220 return Status;
5221}
5222
5223/*
5224 * @implemented
5225 */
5227NTAPI
5229 IN PVOID* UBaseAddress,
5230 IN PSIZE_T URegionSize,
5232{
5234 SIZE_T PRegionSize;
5235 PVOID PBaseAddress;
5236 LONG_PTR AlreadyDecommitted, CommitReduction = 0;
5237 LONG_PTR FirstCommit;
5238 ULONG_PTR StartingAddress, EndingAddress;
5239 PMMVAD Vad;
5240 PMMVAD NewVad;
5244 PETHREAD CurrentThread = PsGetCurrentThread();
5245 PEPROCESS CurrentProcess = PsGetCurrentProcess();
5249 PAGED_CODE();
5250
5251 //
5252 // Only two flags are supported, exclusively.
5253 //
5255 {
5256 DPRINT1("Invalid FreeType (0x%08lx)\n", FreeType);
5258 }
5259
5260 //
5261 // Enter SEH for probe and capture. On failure, return back to the caller
5262 // with an exception violation.
5263 //
5264 _SEH2_TRY
5265 {
5266 //
5267 // Check for user-mode parameters and make sure that they are writeable
5268 //
5269 if (PreviousMode != KernelMode)
5270 {
5271 ProbeForWritePointer(UBaseAddress);
5272 ProbeForWriteUlong(URegionSize);
5273 }
5274
5275 //
5276 // Capture the current values
5277 //
5278 PBaseAddress = *UBaseAddress;
5279 PRegionSize = *URegionSize;
5280 }
5282 {
5284 }
5285 _SEH2_END;
5286
5287 //
5288 // Make sure the allocation isn't past the user area
5289 //
5290 if (PBaseAddress >= MM_HIGHEST_USER_ADDRESS)
5291 {
5292 DPRINT1("Virtual free base above User Space\n");
5294 }
5295
5296 //
5297 // Make sure the allocation wouldn't overflow past the user area
5298 //
5299 if (((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)PBaseAddress) < PRegionSize)
5300 {
5301 DPRINT1("Region size would overflow into kernel-memory\n");
5303 }
5304
5305 //
5306 // If this is for the current process, just use PsGetCurrentProcess
5307 //
5309 {
5310 Process = CurrentProcess;
5311 }
5312 else
5313 {
5314 //
5315 // Otherwise, reference the process with VM rights and attach to it if
5316 // this isn't the current process. We must attach because we'll be touching
5317 // PTEs and PDEs that belong to user-mode memory, and also touching the
5318 // Working Set which is stored in Hyperspace.
5319 //
5324 (PVOID*)&Process,
5325 NULL);
5326 if (!NT_SUCCESS(Status)) return Status;
5327 if (CurrentProcess != Process)
5328 {
5330 Attached = TRUE;
5331 }
5332 }
5333
5334 DPRINT("NtFreeVirtualMemory: Process 0x%p, Address 0x%p, Size 0x%Ix, FreeType 0x%08lx\n",
5335 Process, PBaseAddress, PRegionSize, FreeType);
5336
5337 //
5338 // Lock the address space
5339 //
5342
5343 //
5344 // If the address space is being deleted, fail the de-allocation since it's
5345 // too late to do anything about it
5346 //
5347 if (Process->VmDeleted)
5348 {
5349 DPRINT1("Process is dead\n");
5351 goto FailPath;
5352 }
5353
5354 //
5355 // Compute start and end addresses, and locate the VAD
5356 //
5357 StartingAddress = (ULONG_PTR)PAGE_ALIGN(PBaseAddress);
5358 EndingAddress = ((ULONG_PTR)PBaseAddress + PRegionSize - 1) | (PAGE_SIZE - 1);
5359 Vad = MiLocateAddress((PVOID)StartingAddress);
5360 if (!Vad)
5361 {
5362 DPRINT1("Unable to find VAD for address 0x%p\n", StartingAddress);
5364 goto FailPath;
5365 }
5366
5367 //
5368 // If the range exceeds the VAD's ending VPN, fail this request
5369 //
5370 if (Vad->EndingVpn < (EndingAddress >> PAGE_SHIFT))
5371 {
5372 DPRINT1("Address 0x%p is beyond the VAD\n", EndingAddress);
5374 goto FailPath;
5375 }
5376
5377 //
5378 // Only private memory (except rotate VADs) can be freed through here */
5379 //
5380 if ((!(Vad->u.VadFlags.PrivateMemory) &&
5381 (Vad->u.VadFlags.VadType != VadRotatePhysical)) ||
5383 {
5384 DPRINT("Attempt to free section memory\n");
5386 goto FailPath;
5387 }
5388
5389 //
5390 // ARM3 does not yet handle protected VM
5391 //
5392 ASSERT(Vad->u.VadFlags.NoChange == 0);
5393
5394 //
5395 // Finally, make sure there is a ReactOS Mm MEMORY_AREA for this allocation
5396 // and that is is an ARM3 memory area, and not a section view, as we currently
5397 // don't support freeing those though this interface.
5398 //
5402
5403 //
5404 // Now we can try the operation. First check if this is a RELEASE or a DECOMMIT
5405 //
5406 if (FreeType & MEM_RELEASE)
5407 {
5408 //
5409 // ARM3 only supports this VAD in this path
5410 //
5411 ASSERT(Vad->u.VadFlags.VadType == VadNone);
5412
5413 //
5414 // Is the caller trying to remove the whole VAD, or remove only a portion
5415 // of it? If no region size is specified, then the assumption is that the
5416 // whole VAD is to be destroyed
5417 //
5418 if (!PRegionSize)
5419 {
5420 //
5421 // The caller must specify the base address identically to the range
5422 // that is stored in the VAD.
5423 //
5424 if (((ULONG_PTR)PBaseAddress >> PAGE_SHIFT) != Vad->StartingVpn)
5425 {
5426 DPRINT1("Address 0x%p does not match the VAD\n", PBaseAddress);
5428 goto FailPath;
5429 }
5430
5431 //
5432 // Now compute the actual start/end addresses based on the VAD
5433 //
5434 StartingAddress = Vad->StartingVpn << PAGE_SHIFT;
5435 EndingAddress = (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1);
5436
5437 //
5438 // Finally lock the working set and remove the VAD from the VAD tree
5439 //
5440 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5441 ASSERT(Process->VadRoot.NumberGenericTableElements >= 1);
5442 MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot);
5444 }
5445 else
5446 {
5447 //
5448 // This means the caller wants to release a specific region within
5449 // the range. We have to find out which range this is -- the following
5450 // possibilities exist plus their union (CASE D):
5451 //
5452 // STARTING ADDRESS ENDING ADDRESS
5453 // [<========][========================================][=========>]
5454 // CASE A CASE B CASE C
5455 //
5456 //
5457 // First, check for case A or D
5458 //
5459 if ((StartingAddress >> PAGE_SHIFT) == Vad->StartingVpn)
5460 {
5461 //
5462 // Check for case D
5463 //
5464 if ((EndingAddress >> PAGE_SHIFT) == Vad->EndingVpn)
5465 {
5466 //
5467 // Case D (freeing the entire region)
5468 //
5469 // This is the easiest one to handle -- it is identical to
5470 // the code path above when the caller sets a zero region size
5471 // and the whole VAD is destroyed
5472 //
5473 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5474 ASSERT(Process->VadRoot.NumberGenericTableElements >= 1);
5475 MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot);
5477 }
5478 else
5479 {
5480 //
5481 // Case A (freeing a part at the beginning)
5482 //
5483 // This case is pretty easy too -- we compute a bunch of
5484 // pages to decommit, and then push the VAD's starting address
5485 // a bit further down, then decrement the commit charge
5486 //
5487 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5488 CommitReduction = MiCalculatePageCommitment(StartingAddress,
5489 EndingAddress,
5490 Vad,
5491 Process);
5492 Vad->u.VadFlags.CommitCharge -= CommitReduction;
5493 // For ReactOS: shrink the corresponding memory area
5496 Vad->StartingVpn = (EndingAddress + 1) >> PAGE_SHIFT;
5498
5499 //
5500 // After analyzing the VAD, set it to NULL so that we don't
5501 // free it in the exit path
5502 //
5503 Vad = NULL;
5504 }
5505 }
5506 else
5507 {
5508 //
5509 // This is case B or case C. First check for case C
5510 //
5511 if ((EndingAddress >> PAGE_SHIFT) == Vad->EndingVpn)
5512 {
5513 //
5514 // Case C (freeing a part at the end)
5515 //
5516 // This is pretty easy and similar to case A. We compute the
5517 // amount of pages to decommit, update the VAD's commit charge
5518 // and then change the ending address of the VAD to be a bit
5519 // smaller.
5520 //
5521 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5522 CommitReduction = MiCalculatePageCommitment(StartingAddress,
5523 EndingAddress,
5524 Vad,
5525 Process);
5526 Vad->u.VadFlags.CommitCharge -= CommitReduction;
5527 // For ReactOS: shrink the corresponding memory area
5530 Vad->EndingVpn = (StartingAddress - 1) >> PAGE_SHIFT;
5532 }
5533 else
5534 {
5535 //
5536 // Case B (freeing a part in the middle)
5537 //
5538 // This is the hardest one. Because we are removing a chunk
5539 // of memory from the very middle of the VAD, we must actually
5540 // split the VAD into two new VADs and compute the commit
5541 // charges for each of them, and reinsert new charges.
5542 //
5543 NewVad = ExAllocatePoolZero(NonPagedPool, sizeof(MMVAD_LONG), 'SdaV');
5544 if (NewVad == NULL)
5545 {
5546 DPRINT1("Failed to allocate a VAD!\n");
5548 goto FailPath;
5549 }
5550
5551 // Charge quota for the new VAD
5553
5554 if (!NT_SUCCESS(Status))
5555 {
5556 DPRINT1("Ran out of process quota whilst creating new VAD!\n");
5557 ExFreePoolWithTag(NewVad, 'SdaV');
5559 goto FailPath;
5560 }
5561
5562 //
5563 // This new VAD describes the second chunk, so we keep the end
5564 // address of the original and adjust the start to point past
5565 // the released region.
5566 // The commit charge will be calculated below.
5567 //
5568 NewVad->StartingVpn = (EndingAddress + 1) >> PAGE_SHIFT;
5569 NewVad->EndingVpn = Vad->EndingVpn;
5570 NewVad->u.LongFlags = Vad->u.LongFlags;
5571 NewVad->u.VadFlags.CommitCharge = 0;
5572 ASSERT(NewVad->EndingVpn >= NewVad->StartingVpn);
5573
5574 //
5575 // Get the commit charge for the released region
5576 //
5577 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5578 CommitReduction = MiCalculatePageCommitment(StartingAddress,
5579 EndingAddress,
5580 Vad,
5581 Process);
5582
5583 //
5584 // Adjust the end of the original VAD (first chunk).
5585 // For ReactOS: shrink the corresponding memory area
5586 //
5589 Vad->EndingVpn = (StartingAddress - 1) >> PAGE_SHIFT;
5591
5592 //
5593 // Now the addresses for both VADs are consistent,
5594 // so insert the new one.
5595 // ReactOS: This will take care of creating a second MEMORY_AREA.
5596 //
5597 MiInsertVad(NewVad, &Process->VadRoot);
5598
5599 //
5600 // Calculate the commit charge for the first split.
5601 // The second chunk's size is the original size, minus the
5602 // released region's size, minus this first chunk.
5603 //
5604 FirstCommit = MiCalculatePageCommitment(Vad->StartingVpn << PAGE_SHIFT,
5605 StartingAddress - 1,
5606 Vad,
5607 Process);
5608 NewVad->u.VadFlags.CommitCharge = Vad->u.VadFlags.CommitCharge - CommitReduction - FirstCommit;
5609 Vad->u.VadFlags.CommitCharge = FirstCommit;
5610 }
5611
5612 //
5613 // After analyzing the VAD, set it to NULL so that we don't
5614 // free it in the exit path
5615 //
5616 Vad = NULL;
5617 }
5618 }
5619
5620 //
5621 // Now we have a range of pages to dereference, so call the right API
5622 // to do that and then release the working set, since we're done messing
5623 // around with process pages.
5624 //
5625 MiDeleteVirtualAddresses(StartingAddress, EndingAddress, NULL);
5628
5629FinalPath:
5630 //
5631 // Update the process counters
5632 //
5633 PRegionSize = EndingAddress - StartingAddress + 1;
5634 Process->CommitCharge -= CommitReduction;
5635 if (FreeType & MEM_RELEASE) Process->VirtualSize -= PRegionSize;
5636
5637 //
5638 // Unlock the address space and free the VAD in failure cases. Next,
5639 // detach from the target process so we can write the region size and the
5640 // base address to the correct source process, and dereference the target
5641 // process.
5642 //
5644 if (Vad) ExFreePool(Vad);
5647
5648 //
5649 // Use SEH to safely return the region size and the base address of the
5650 // deallocation. If we get an access violation, don't return a failure code
5651 // as the deallocation *has* happened. The caller will just have to figure
5652 // out another way to find out where it is (such as VirtualQuery).
5653 //
5654 _SEH2_TRY
5655 {
5656 *URegionSize = PRegionSize;
5657 *UBaseAddress = (PVOID)StartingAddress;
5658 }
5660 {
5661 }
5662 _SEH2_END;
5663 return Status;
5664 }
5665
5666 //
5667 // This is the decommit path. You cannot decommit from the following VADs in
5668 // Windows, so fail the vall
5669 //
5670 if ((Vad->u.VadFlags.VadType == VadAwe) ||
5671 (Vad->u.VadFlags.VadType == VadLargePages) ||
5673 {
5674 DPRINT1("Trying to decommit from invalid VAD\n");
5676 goto FailPath;
5677 }
5678
5679 //
5680 // If the caller did not specify a region size, first make sure that this
5681 // region is actually committed. If it is, then compute the ending address
5682 // based on the VAD.
5683 //
5684 if (!PRegionSize)
5685 {
5686 if (((ULONG_PTR)PBaseAddress >> PAGE_SHIFT) != Vad->StartingVpn)
5687 {
5688 DPRINT1("Decomitting non-committed memory\n");
5690 goto FailPath;
5691 }
5692 EndingAddress = (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1);
5693 }
5694
5695 //
5696 // Decommit the PTEs for the range plus the actual backing pages for the
5697 // range, then reduce that amount from the commit charge in the VAD
5698 //
5699 AlreadyDecommitted = MiDecommitPages((PVOID)StartingAddress,
5700 MiAddressToPte(EndingAddress),
5701 Process,
5702 Vad);
5703 CommitReduction = MiAddressToPte(EndingAddress) -
5704 MiAddressToPte(StartingAddress) +
5705 1 -
5706 AlreadyDecommitted;
5707
5708 ASSERT(CommitReduction >= 0);
5709 ASSERT(Vad->u.VadFlags.CommitCharge >= CommitReduction);
5710 Vad->u.VadFlags.CommitCharge -= CommitReduction;
5711
5712 //
5713 // We are done, go to the exit path without freeing the VAD as it remains
5714 // valid since we have not released the allocation.
5715 //
5716 Vad = NULL;
5718 goto FinalPath;
5719
5720 //
5721 // In the failure path, we detach and dereference the target process, and
5722 // return whatever failure code was sent.
5723 //
5724FailPath:
5728 return Status;
5729}
5730
5731
5733NTAPI
5735{
5737 MMPDE TempPde;
5738 MMPTE TempPte;
5739
5740 /* Check if the PXE/PPE/PDE is valid */
5741 if (
5742#if (_MI_PAGING_LEVELS == 4)
5743 (MiAddressToPxe(Address)->u.Hard.Valid) &&
5744#endif
5745#if (_MI_PAGING_LEVELS >= 3)
5746 (MiAddressToPpe(Address)->u.Hard.Valid) &&
5747#endif
5748 (MiAddressToPde(Address)->u.Hard.Valid))
5749 {
5750 /* Check for large pages */
5752 if (TempPde.u.Hard.LargePage)
5753 {
5754 /* Physical address is base page + large page offset */
5757 return PhysicalAddress;
5758 }
5759
5760 /* Check if the PTE is valid */
5762 if (TempPte.u.Hard.Valid)
5763 {
5764 /* Physical address is base page + page offset */
5767 return PhysicalAddress;
5768 }
5769 }
5770
5772 DPRINT1("MM:MmGetPhysicalAddressFailed base address was %p\n", Address);
5774 return PhysicalAddress;
5775}
5776
5777
5778/* EOF */
#define PAGED_CODE()
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
unsigned char BOOLEAN
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:103
#define UNIMPLEMENTED
Definition: debug.h:115
return Found
Definition: dirsup.c:1270
_In_ WDFREQUEST _In_ MEDIA_LOCK_TYPE LockType
Definition: cdrom.h:1335
Definition: bufpool.h:45
#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:32
#define PAGE_READONLY
Definition: compat.h:138
static const WCHAR Cleanup[]
Definition: register.c:80
#define ULONG_PTR
Definition: config.h:101
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:43
#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:136
#define ExGetPreviousMode
Definition: ex.h:140
#define ExAcquireRundownProtection
Definition: ex.h:135
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
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
_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 EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define USER_SHARED_DATA
Definition: pstypes.h:51
#define PROCESS_VM_READ
Definition: pstypes.h:161
#define PROCESS_QUERY_INFORMATION
Definition: pstypes.h:166
#define PROCESS_VM_WRITE
Definition: pstypes.h:162
#define PROCESS_VM_OPERATION
Definition: pstypes.h:160
CCHAR KeNumberProcessors
Definition: krnlinit.c:35
if(dx< 0)
Definition: linetemp.h:194
PMMVAD NTAPI MiLocateAddress(IN PVOID VirtualAddress)
Definition: vadnode.c:116
PMMPTE MiHighestUserPte
Definition: mminit.c:233
#define MI_IS_ROS_PFN(x)
Definition: miarm.h:1103
NTSTATUS NTAPI MiQueryMemorySectionName(IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
Definition: section.c:1948
FORCEINLINE PMMPTE MI_GET_PROTOTYPE_PTE_FOR_VPN(IN PMMVAD Vad, IN ULONG_PTR Vpn)
Definition: miarm.h:1557
FORCEINLINE BOOLEAN MM_ANY_WS_LOCK_HELD_EXCLUSIVE(_In_ PETHREAD Thread)
Definition: miarm.h:1065
FORCEINLINE VOID MiLockProcessWorkingSetShared(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1146
FORCEINLINE VOID MiDeletePde(_In_ PMMPDE PointerPde, _In_ PEPROCESS CurrentProcess)
Definition: miarm.h:2541
PVOID MmPagedPoolStart
Definition: miarm.h:574
FORCEINLINE VOID MiLockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1265
VOID NTAPI MiRemoveNode(IN PMMADDRESS_NODE Node, IN PMM_AVL_TABLE Table)
Definition: vadnode.c:440
FORCEINLINE VOID MiUnlockProcessWorkingSetForFault(IN PEPROCESS Process, IN PETHREAD Thread, OUT PBOOLEAN Safe, OUT PBOOLEAN Shared)
Definition: miarm.h:1468
FORCEINLINE VOID MiLockProcessWorkingSetForFault(IN PEPROCESS Process, IN PETHREAD Thread, IN BOOLEAN Safe, IN BOOLEAN Shared)
Definition: miarm.h:1501
#define MI_SET_PFN_DELETED(x)
Definition: miarm.h:194
#define _64K
Definition: miarm.h:23
FORCEINLINE VOID MiUnlockProcessWorkingSetShared(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1215
FORCEINLINE VOID MI_ERASE_PTE(IN PMMPTE PointerPte)
Definition: miarm.h:1006
FORCEINLINE USHORT MiDecrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:2507
#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:1194
FORCEINLINE VOID MiUnlockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1239
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:992
FORCEINLINE VOID MiUnlockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1351
FORCEINLINE VOID MiDereferencePfnAndDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1615
VOID NTAPI MiUnlinkPageFromList(IN PMMPFN Pfn)
Definition: pfnlist.c:265
FORCEINLINE VOID MiReferenceProbedPageAndBumpLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1687
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:282
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:903
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:241
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:150
ULONG NTAPI MiMakeProtectionMask(IN ULONG Protect)
Definition: section.c:140
FORCEINLINE USHORT MiIncrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:2481
PMMADDRESS_NODE NTAPI MiGetNextNode(IN PMMADDRESS_NODE Node)
Definition: vadnode.c:549
VOID NTAPI MiInsertVad(_Inout_ PMMVAD Vad, _Inout_ PMM_AVL_TABLE VadRoot)
FORCEINLINE PMMPFN MI_PFN_ELEMENT(IN PFN_NUMBER Pfn)
Definition: miarm.h:1574
FORCEINLINE VOID MiLockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1124
FORCEINLINE VOID MiLockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1169
#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:57
static const OBJECT_ATTRIBUTES const LARGE_INTEGER ULONG
Definition: virtual.c:34
static PVOID
Definition: virtual.c:33
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define _Inout_
Definition: ms_sal.h:378
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
#define KernelMode
Definition: asm.h:34
#define MM_SHARED_USER_DATA_VA
Definition: mmtypes.h:48
#define KeGetPreviousMode()
Definition: ketypes.h:1115
_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
_In_ PMEMORY_AREA MemoryArea
Definition: newmm.h:207
int Count
Definition: noreturn.cpp:7
#define MEM_TOP_DOWN
Definition: nt_native.h:1321
#define PAGE_WRITECOPY
Definition: nt_native.h:1305
#define MEM_FREE
Definition: nt_native.h:1317
#define PAGE_NOCACHE
Definition: nt_native.h:1311
#define MEM_DECOMMIT
Definition: nt_native.h:1315
#define PAGE_READWRITE
Definition: nt_native.h:1304
#define PAGE_EXECUTE_READ
Definition: nt_native.h:1307
#define MEM_RESET
Definition: nt_native.h:1320
#define MEM_PRIVATE
Definition: nt_native.h:1318
#define PAGE_EXECUTE
Definition: nt_native.h:1306
#define NtCurrentProcess()
Definition: nt_native.h:1657
#define MEM_MAPPED
Definition: nt_native.h:1319
#define PAGE_EXECUTE_WRITECOPY
Definition: nt_native.h:1309
#define MEM_RESERVE
Definition: nt_native.h:1314
#define MEM_LARGE_PAGES
Definition: nt_native.h:1322
#define MEM_RELEASE
Definition: nt_native.h:1316
#define MEM_COMMIT
Definition: nt_native.h:1313
#define PAGE_NOACCESS
Definition: nt_native.h:1302
#define PAGE_EXECUTE_READWRITE
Definition: nt_native.h:1308
#define PAGE_GUARD
Definition: nt_native.h:1310
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
FORCEINLINE VOID KeInvalidateTlbEntry(IN PVOID Address)
Definition: ke.h:264
FORCEINLINE VOID KeSweepICache(IN PVOID BaseAddress, IN SIZE_T FlushSize)
Definition: ke.h:280
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:526
FORCEINLINE PMMSUPPORT MmGetCurrentAddressSpace(VOID)
Definition: mm.h:1719
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:1047
#define MM_NOIRQL
Definition: mm.h:70
FORCEINLINE VOID MmLockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1691
#define MM_VIRTMEM_GRANULARITY
Definition: mm.h:102
#define MI_ASSERT_PFN_LOCK_HELD()
Definition: mm.h:1043
NTSTATUS NTAPI MmQuerySectionView(PMEMORY_AREA MemoryArea, PVOID Address, PMEMORY_BASIC_INFORMATION Info, PSIZE_T ResultLength)
Definition: section.c:2099
NTSTATUS NTAPI MmProtectSectionView(PMMSUPPORT AddressSpace, PMEMORY_AREA MemoryArea, PVOID BaseAddress, SIZE_T Length, ULONG Protect, PULONG OldProtect)
Definition: section.c:2063
PMEMORY_AREA NTAPI MmLocateMemoryAreaByAddress(PMMSUPPORT AddressSpace, PVOID Address)
Definition: marea.c:60
#define MEMORY_AREA_OWNED_BY_ARM3
Definition: mm.h:97
#define MA_GetEndingAddress(_MemoryArea)
Definition: mm.h:245
#define MA_GetStartingAddress(_MemoryArea)
Definition: mm.h:244
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1704
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1765
#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:209
const LUID SeLockMemoryPrivilege
Definition: priv.c:23
VOID NTAPI KeFlushEntireTb(IN BOOLEAN Invalid, IN BOOLEAN AllProcessors)
Definition: cpu.c:617
BOOLEAN NTAPI KeAreAllApcsDisabled(VOID)
Definition: apc.c:985
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:747
NTSTATUS NTAPI NtResetWriteWatch(IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN SIZE_T RegionSize)
Definition: virtual.c:4326
static NTSTATUS MiLockVirtualMemory(IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
Definition: virtual.c:3379
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:4155
VOID NTAPI MiDeleteVirtualAddresses(IN ULONG_PTR Va, IN ULONG_PTR EndingAddress, IN PMMVAD Vad)
Definition: virtual.c:530
NTSTATUS NTAPI NtFreeVirtualMemory(IN HANDLE ProcessHandle, IN PVOID *UBaseAddress, IN PSIZE_T URegionSize, IN ULONG FreeType)
Definition: virtual.c:5228
NTSTATUS NTAPI MmFlushVirtualMemory(IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, OUT PIO_STATUS_BLOCK IoStatusBlock)
Definition: virtual.c:1339
NTSTATUS NTAPI NtWriteVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN PVOID Buffer, IN SIZE_T NumberOfBytesToWrite, OUT PSIZE_T NumberOfBytesWritten OPTIONAL)
Definition: virtual.c:2928
#define MI_MAPPED_COPY_PAGES
Definition: virtual.c:18
VOID NTAPI MiProcessValidPteList(IN PMMPTE *ValidPteList, IN ULONG Count)
Definition: virtual.c:2573
PVOID NTAPI MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress)
Definition: virtual.c:2781
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:1268
ULONG NTAPI MiGetPageProtection(IN PMMPTE PointerPte)
Definition: virtual.c:1353
NTSTATUS NTAPI NtProtectVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID *UnsafeBaseAddress, IN OUT SIZE_T *UnsafeNumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG UnsafeOldAccessProtection)
Definition: virtual.c:3109
VOID NTAPI MiFlushTbAndCapture(IN PMMVAD FoundVad, IN PMMPTE PointerPte, IN ULONG ProtectionMask, IN PMMPFN Pfn1, IN BOOLEAN CaptureDirtyBit)
Definition: section.c:2015
NTSTATUS NTAPI NtReadVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID Buffer, IN SIZE_T NumberOfBytesToRead, OUT PSIZE_T NumberOfBytesRead OPTIONAL)
Definition: virtual.c:2814
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:4407
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:3527
FORCEINLINE VOID MI_LOCK_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3292
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:1017
PHYSICAL_ADDRESS NTAPI MmGetPhysicalAddress(PVOID Address)
Definition: virtual.c:5734
static NTSTATUS MiUnlockVirtualMemory(IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
Definition: virtual.c:3698
VOID NTAPI MmUnsecureVirtualMemory(IN PVOID SecureMem)
Definition: virtual.c:2805
FORCEINLINE VOID MI_UNLOCK_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3313
NTSTATUS NTAPI NtFlushVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToFlush, OUT PIO_STATUS_BLOCK IoStatusBlock)
Definition: virtual.c:4033
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:792
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:2196
VOID NTAPI MiMakePdeExistAndMakeValid(IN PMMPDE PointerPde, IN PEPROCESS TargetProcess, IN KIRQL OldIrql)
Definition: virtual.c:2479
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:2625
PVOID NTAPI MmSecureVirtualMemory(IN PVOID Address, IN SIZE_T Length, IN ULONG Mode)
Definition: virtual.c:2792
static NTSTATUS MiCheckVadsForLockOperation(_Inout_ PVOID *BaseAddress, _Inout_ PSIZE_T RegionSize, _Inout_ PVOID *EndAddress)
Definition: virtual.c:3334
NTSTATUS NTAPI NtUnlockVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToUnlock, IN ULONG MapType)
Definition: virtual.c:3863
FORCEINLINE BOOLEAN MI_IS_LOCKED_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3275
NTSTATUS NTAPI MiQueryMemoryBasicInformation(IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
Definition: virtual.c:1659
ULONG NTAPI MiQueryAddressState(IN PVOID Va, IN PMMVAD Vad, IN PEPROCESS TargetProcess, OUT PULONG ReturnedProtect, OUT PVOID *NextVa)
Definition: virtual.c:1468
BOOLEAN NTAPI MiIsEntireRangeCommitted(IN ULONG_PTR StartingAddress, IN ULONG_PTR EndingAddress, IN PMMVAD Vad, IN PEPROCESS Process)
Definition: virtual.c:2000
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:4490
NTSTATUS NTAPI NtFlushInstructionCache(_In_ HANDLE ProcessHandle, _In_opt_ PVOID BaseAddress, _In_ SIZE_T FlushSize)
Definition: virtual.c:3042
NTSTATUS NTAPI MiRosProtectVirtualMemory(IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection OPTIONAL)
Definition: virtual.c:2156
#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:304
#define STATUS_UNABLE_TO_DELETE_SECTION
Definition: ntstatus.h:264
#define STATUS_WAS_LOCKED
Definition: ntstatus.h:139
#define STATUS_UNABLE_TO_FREE_VM
Definition: ntstatus.h:263
#define STATUS_MEMORY_NOT_ALLOCATED
Definition: ntstatus.h:396
#define STATUS_INCOMPATIBLE_FILE_MAP
Definition: ntstatus.h:313
#define STATUS_INVALID_PARAMETER_4
Definition: ntstatus.h:478
#define STATUS_ALREADY_COMMITTED
Definition: ntstatus.h:270
#define STATUS_INVALID_PARAMETER_2
Definition: ntstatus.h:476
#define STATUS_FREE_VM_NOT_AT_BASE
Definition: ntstatus.h:395
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:502
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:242
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
#define STATUS_INVALID_PARAMETER_6
Definition: ntstatus.h:480
#define STATUS_NOT_LOCKED
Definition: ntstatus.h:279
#define STATUS_IN_PAGE_ERROR
Definition: ntstatus.h:243
#define STATUS_CONFLICTING_ADDRESSES
Definition: ntstatus.h:261
#define STATUS_INVALID_PAGE_PROTECTION
Definition: ntstatus.h:305
#define STATUS_GUARD_PAGE_VIOLATION
Definition: ntstatus.h:182
#define STATUS_NOT_COMMITTED
Definition: ntstatus.h:282
#define STATUS_INVALID_PARAMETER_3
Definition: ntstatus.h:477
#define STATUS_INVALID_PARAMETER_5
Definition: ntstatus.h:479
#define STATUS_PARTIAL_COPY
Definition: ntstatus.h:193
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:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:158
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
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
ULONG PFN_NUMBER
Definition: ke.h:9
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:71
static void Exit(void)
Definition: sock.c:1330
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
MMSECTION_FLAGS Flags
Definition: mmtypes.h:531
union _CONTROL_AREA::@2599 u
MM_AVL_TABLE VadRoot
Definition: pstypes.h:1453
MMSUPPORT Vm
Definition: pstypes.h:1356
PVOID CloneRoot
Definition: pstypes.h:1299
ULONG VmDeleted
Definition: pstypes.h:1398
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
BOOLEAN DeleteInProgress
Definition: mm.h:253
ULONG Type
Definition: mm.h:251
MMVAD VadNode
Definition: mm.h:249
struct _MMADDRESS_NODE * RightChild
Definition: mmtypes.h:652
USHORT PrototypePte
Definition: mm.h:363
USHORT PageLocation
Definition: mm.h:365
USHORT WriteInProgress
Definition: mm.h:362
Definition: mm.h:374
union _MMPFN::@1790 u3
MMPTE OriginalPte
Definition: mm.h:407
MMWSLE Wsle
Definition: mm.h:434
union _MMPFN::@1789 u2
PMMPTE PteAddress
Definition: mm.h:386
ULONG WsIndex
Definition: mm.h:378
MMPFNENTRY e1
Definition: mm.h:397
union _MMPFN::@1793 u4
ULONG_PTR ShareCount
Definition: mm.h:390
union _MMPFN::@1788 u1
struct _MMPFN::@1790::@1796 e2
ULONG_PTR AweAllocation
Definition: mm.h:421
ULONG_PTR PteFrame
Definition: mm.h:418
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
union _MMPTE::@2325 u
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
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::@2606 u
ULONG_PTR LongFlags
Definition: mmtypes.h:733
ULONG_PTR LockedInMemory
Definition: mmtypes.h:829
ULONG_PTR LockedInWs
Definition: mmtypes.h:828
union _MMWSLE::@2616 u1
MMWSLENTRY e1
Definition: mmtypes.h:858
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_UNSUCCESSFUL
Definition: udferr_usr.h:132
#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:3776
_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:863
KAPC_STATE
Definition: ketypes.h:1409
#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:373
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
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