ReactOS 0.4.15-dev-7906-g1b85a5f
vadnode.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/vadnode.c
5 * PURPOSE: ARM Memory Manager VAD Node Algorithms
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 * Timo Kreuzer (timo.kreuzer@reactos.org)
8 */
9
10/* INCLUDES *******************************************************************/
11
12#include <ntoskrnl.h>
13#define NDEBUG
14#include <debug.h>
15
16#define MODULE_INVOLVED_IN_ARM3
17#include <mm/ARM3/miarm.h>
18
19/* Include Mm version of AVL support */
20#include "miavl.h"
21#include <sdk/lib/rtl/avlsupp.c>
22
23/* GLOBALS ********************************************************************/
24
26{
30
34
38
42};
43
44/* FUNCTIONS ******************************************************************/
45
47
48#if DBG
49
50static
51VOID
52MiDbgAssertIsLockedForRead(_In_ PMM_AVL_TABLE Table)
53{
55 {
56 /* Need to hold MmSectionBasedMutex */
58 }
59 else if (Table == &MiRosKernelVadRoot)
60 {
61 /* Need to hold either the system working-set lock or
62 the idle process' AddressCreationLock */
63 ASSERT(PsGetCurrentThread()->OwnsSystemWorkingSetExclusive ||
64 PsGetCurrentThread()->OwnsSystemWorkingSetShared ||
66 }
67 else
68 {
69 /* Need to hold either the process working-set lock or
70 the current process' AddressCreationLock */
73 (Process->AddressCreationLock.Owner == KeGetCurrentThread()));
74 }
75}
76
77static
78VOID
79MiDbgAssertIsLockedForWrite(_In_ PMM_AVL_TABLE Table)
80{
82 {
83 /* Need to hold MmSectionBasedMutex */
85 }
86 else if (Table == &MiRosKernelVadRoot)
87 {
88 /* Need to hold both the system working-set lock exclusive and
89 the idle process' AddressCreationLock */
90 ASSERT(PsGetCurrentThread()->OwnsSystemWorkingSetExclusive);
92 }
93 else
94 {
95 /* Need to hold both the process working-set lock exclusive and
96 the current process' AddressCreationLock */
99 ASSERT(PsGetCurrentThread()->OwnsProcessWorkingSetExclusive);
100 ASSERT(Process->AddressCreationLock.Owner == KeGetCurrentThread());
101 }
102}
103
104#define ASSERT_LOCKED_FOR_READ(Table) MiDbgAssertIsLockedForRead(Table)
105#define ASSERT_LOCKED_FOR_WRITE(Table) MiDbgAssertIsLockedForWrite(Table)
106
107#else // DBG
108
109#define ASSERT_LOCKED_FOR_READ(Table)
110#define ASSERT_LOCKED_FOR_WRITE(Table)
111
112#endif // DBG
113
114PMMVAD
115NTAPI
117{
118 PMMVAD FoundVad;
119 ULONG_PTR Vpn;
121 TABLE_SEARCH_RESULT SearchResult;
122
124
125 /* Start with the the hint */
126 FoundVad = (PMMVAD)Table->NodeHint;
127 if (!FoundVad) return NULL;
128
129 /* Check if this VPN is in the hint, if so, use it */
131 if ((Vpn >= FoundVad->StartingVpn) && (Vpn <= FoundVad->EndingVpn)) return FoundVad;
132
133 /* VAD hint didn't work, go look for it */
134 SearchResult = RtlpFindAvlTableNodeOrParent(Table,
135 (PVOID)Vpn,
136 (PMMADDRESS_NODE*)&FoundVad);
137 if (SearchResult != TableFoundNode) return NULL;
138
139 /* We found it, update the hint */
140 ASSERT(FoundVad != NULL);
141 ASSERT((Vpn >= FoundVad->StartingVpn) && (Vpn <= FoundVad->EndingVpn));
142
143 /* We allow this (atomic) update without exclusive lock, because it's a hint only */
144 Table->NodeHint = FoundVad;
145 return FoundVad;
146}
147
149NTAPI
151 IN ULONG_PTR EndVpn,
153 OUT PMMADDRESS_NODE *NodeOrParent)
154{
155 PMMADDRESS_NODE ParentNode, CurrentNode;
156
158
159 /* If the tree is empty, there is no conflict */
160 if (Table->NumberGenericTableElements == 0) return TableEmptyTree;
161
162 /* Start looping from the root node */
163 CurrentNode = RtlRightChildAvl(&Table->BalancedRoot);
164 ASSERT(CurrentNode != NULL);
165 while (CurrentNode)
166 {
167 ParentNode = CurrentNode;
168
169 /* This address comes after */
170 if (StartVpn > CurrentNode->EndingVpn)
171 {
172 /* Keep searching on the right */
173 CurrentNode = RtlRightChildAvl(CurrentNode);
174 }
175 else if (EndVpn < CurrentNode->StartingVpn)
176 {
177 /* This address ends before the node starts, search on the left */
178 CurrentNode = RtlLeftChildAvl(CurrentNode);
179 }
180 else
181 {
182 /* This address is part of this node, return it */
183 *NodeOrParent = ParentNode;
184 return TableFoundNode;
185 }
186 }
187
188 /* There is no more child, save the current node as parent */
189 *NodeOrParent = ParentNode;
190 if (StartVpn > ParentNode->EndingVpn)
191 {
192 return TableInsertAsRight;
193 }
194 else
195 {
196 return TableInsertAsLeft;
197 }
198}
199
200VOID
201NTAPI
203 IN PMMADDRESS_NODE NewNode,
206{
207 PMMVAD_LONG Vad;
208
210
211 /* Insert it into the tree */
213
214 /* Now insert an ARM3 MEMORY_AREA for this node, unless the insert was already from the MEMORY_AREA code */
215 Vad = (PMMVAD_LONG)NewNode;
216 if (Vad->u.VadFlags.Spare == 0)
217 {
220 SIZE_T Size;
222 PVOID AllocatedBase = (PVOID)(Vad->StartingVpn << PAGE_SHIFT);
223
224 Size = ((Vad->EndingVpn + 1) - Vad->StartingVpn) << PAGE_SHIFT;
225
226 if (AllocatedBase == NULL)
227 {
228 AllocatedBase = (PVOID)(ULONG_PTR)1;
229 Size -= 1;
230 }
231
234 &AllocatedBase,
235 Size,
237 &MemoryArea,
238 0,
239 PAGE_SIZE);
241
242 /* Check if this is VM VAD */
243 if (Vad->ControlArea == NULL)
244 {
245 /* We store the reactos MEMORY_AREA here */
247 }
248 else
249 {
250 /* This is a section VAD. Store the MAREA here for now */
251 ASSERT(Vad->u4.Banked == (PVOID)(ULONG_PTR)0xDEADBABEDEADBABEULL);
252 Vad->u4.Banked = (PVOID)MemoryArea;
253 }
254 }
255}
256
257VOID
258NTAPI
260 IN PMM_AVL_TABLE VadRoot)
261{
264
266
267 /* Validate the VAD and set it as the current hint */
268 ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
269 VadRoot->NodeHint = Vad;
270
271 /* Find the parent VAD and where this child should be inserted */
272 Result = RtlpFindAvlTableNodeOrParent(VadRoot, (PVOID)Vad->StartingVpn, &Parent);
273 ASSERT(Result != TableFoundNode);
274 ASSERT((Parent != NULL) || (Result == TableEmptyTree));
275
276 /* Do the actual insert operation */
277 MiInsertNode(VadRoot, (PVOID)Vad, Parent, Result);
278}
279
281NTAPI
283 _Inout_ PMMVAD Vad,
286 _In_ ULONG_PTR HighestAddress,
289{
290 ULONG_PTR StartingAddress, EndingAddress;
291 PEPROCESS CurrentProcess;
292 PETHREAD CurrentThread;
295
296 /* Align the view size to pages */
298
299 /* Get the current process */
300 CurrentProcess = PsGetCurrentProcess();
301
302 /* Acquire the address creation lock and make sure the process is alive */
304 if (CurrentProcess->VmDeleted)
305 {
307 DPRINT1("The process is dying\n");
309 }
310
311 /* Did the caller specify an address? */
312 if (*BaseAddress == 0)
313 {
314 /* Make sure HighestAddress is not too large */
315 HighestAddress = min(HighestAddress, (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS);
316
317 /* Which way should we search? */
318 if ((AllocationType & MEM_TOP_DOWN) || CurrentProcess->VmTopDown)
319 {
320 /* Find an address top-down */
322 HighestAddress,
323 Alignment,
324 &CurrentProcess->VadRoot,
325 &StartingAddress,
326 &Parent);
327 }
328 else
329 {
330 /* Find an address bottom-up */
332 Alignment,
333 &CurrentProcess->VadRoot,
334 &Parent,
335 &StartingAddress);
336 }
337
338 /* Get the ending address, which is the last piece we need for the VAD */
339 EndingAddress = StartingAddress + ViewSize - 1;
340
341 /* Check if we found a suitable location */
342 if ((Result == TableFoundNode) || (EndingAddress > HighestAddress))
343 {
344 DPRINT1("Not enough free space to insert this VAD node!\n");
346 return STATUS_NO_MEMORY;
347 }
348
349 ASSERT(StartingAddress != 0);
350 ASSERT(StartingAddress < (ULONG_PTR)HighestAddress);
351 ASSERT(EndingAddress > StartingAddress);
352 }
353 else
354 {
355 /* Calculate the starting and ending address */
356 StartingAddress = ALIGN_DOWN_BY(*BaseAddress, Alignment);
357 EndingAddress = StartingAddress + ViewSize - 1;
358
359 /* Make sure it doesn't conflict with an existing allocation */
360 Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
361 EndingAddress >> PAGE_SHIFT,
362 &CurrentProcess->VadRoot,
363 &Parent);
364 if (Result == TableFoundNode)
365 {
366 DPRINT("Given address conflicts with existing node\n");
369 }
370 }
371
372 /* Now set the VAD address */
373 Vad->StartingVpn = StartingAddress >> PAGE_SHIFT;
374 Vad->EndingVpn = EndingAddress >> PAGE_SHIFT;
375
376 /* Check if we already need to charge for the pages */
377 if ((Vad->u.VadFlags.PrivateMemory && Vad->u.VadFlags.MemCommit) ||
378 (!Vad->u.VadFlags.PrivateMemory &&
379 (Vad->u.VadFlags.Protection & PAGE_WRITECOPY)))
380 {
381 /* Set the commit charge */
382 Vad->u.VadFlags.CommitCharge = ViewSize / PAGE_SIZE;
383 }
384
385 /* Check if the VAD is to be secured */
386 if (Vad->u2.VadFlags2.OneSecured)
387 {
388 /* This *must* be a long VAD! */
389 ASSERT(Vad->u2.VadFlags2.LongVad);
390
391 /* Yeah this is retarded, I didn't invent it! */
392 ((PMMVAD_LONG)Vad)->u3.Secured.StartVpn = StartingAddress;
393 ((PMMVAD_LONG)Vad)->u3.Secured.EndVpn = EndingAddress;
394 }
395
396 /* Lock the working set */
397 CurrentThread = PsGetCurrentThread();
398 MiLockProcessWorkingSetUnsafe(CurrentProcess, CurrentThread);
399
400 /* Insert the VAD */
401 CurrentProcess->VadRoot.NodeHint = Vad;
402 MiInsertNode(&CurrentProcess->VadRoot, (PVOID)Vad, Parent, Result);
403
404 /* Release the working set */
405 MiUnlockProcessWorkingSetUnsafe(CurrentProcess, CurrentThread);
406
407 /* Update the process' virtual size, and peak virtual size */
408 CurrentProcess->VirtualSize += ViewSize;
409 if (CurrentProcess->VirtualSize > CurrentProcess->PeakVirtualSize)
410 {
411 CurrentProcess->PeakVirtualSize = CurrentProcess->VirtualSize;
412 }
413
414 /* Unlock the address space */
416
417 *BaseAddress = StartingAddress;
418 return STATUS_SUCCESS;
419}
420
421VOID
422NTAPI
424{
427 ASSERT(Section->Address.EndingVpn >= Section->Address.StartingVpn);
428
430
431 /* Find the parent VAD and where this child should be inserted */
432 Result = RtlpFindAvlTableNodeOrParent(&MmSectionBasedRoot, (PVOID)Section->Address.StartingVpn, &Parent);
433 ASSERT(Result != TableFoundNode);
434 ASSERT((Parent != NULL) || (Result == TableEmptyTree));
435 MiInsertNode(&MmSectionBasedRoot, &Section->Address, Parent, Result);
436}
437
438VOID
439NTAPI
442{
443 PMMVAD_LONG Vad;
444
446
447 /* Call the AVL code */
449
450 /* Decrease element count */
451 Table->NumberGenericTableElements--;
452
453 /* Check if this node was the hint */
454 if (Table->NodeHint == Node)
455 {
456 /* Get a new hint, unless we're empty now, in which case nothing */
457 if (!Table->NumberGenericTableElements) Table->NodeHint = NULL;
458 else Table->NodeHint = Table->BalancedRoot.RightChild;
459 }
460
461 /* Free the node from ReactOS view as well */
462 Vad = (PMMVAD_LONG)Node;
463 if ((Table != &MmSectionBasedRoot) && (Vad->u.VadFlags.Spare == 0))
464 {
467
468 /* Check if this is VM VAD */
469 if (Vad->ControlArea == NULL)
470 {
471 /* We store the ReactOS MEMORY_AREA here */
473 }
474 else
475 {
476 /* This is a section VAD. We store the ReactOS MEMORY_AREA here */
478 }
479
480 /* Make sure one actually still exists */
481 if (MemoryArea)
482 {
483 /* Make sure we have not already freed it */
484 ASSERT(MemoryArea != (PVOID)(ULONG_PTR)0xDEADBAB1DEADBAB1ULL);
485
486 /* Get the process */
488
489 /* We only create fake memory-areas for ARM3 VADs */
492
493 /* Free it */
495
496 /* Check if this is VM VAD */
497 if (Vad->ControlArea == NULL)
498 {
499 /* Delete the pointer to it */
500 Vad->FirstPrototypePte = (PVOID)(ULONG_PTR)0xDEADBAB1DEADBAB1ULL;
501 }
502 else
503 {
504 /* Delete the pointer to it */
505 Vad->u4.Banked = (PVOID)(ULONG_PTR)0xDEADBAB1DEADBAB1ULL;
506 }
507 }
508 }
509}
510
512NTAPI
514{
516
517 /* Get the left child */
519 {
520 /* Get right-most child */
523 return Node;
524 }
525
527 ASSERT(Parent != NULL);
528 while (Parent != Node)
529 {
530 /* The parent should be a right child, return the real predecessor */
532 {
533 /* Return it unless it's the root */
535 return Parent;
536 }
537
538 /* Keep lopping until we find our parent */
539 Node = Parent;
541 }
542
543 /* Nothing found */
544 return NULL;
545}
546
548NTAPI
550{
552
553 /* Get the right child */
555 {
556 /* Get left-most child */
559 return Node;
560 }
561
563 ASSERT(Parent != NULL);
564 while (Parent != Node)
565 {
566 /* The parent should be a left child, return the real predecessor */
568 {
569 /* Return it */
570 return Parent;
571 }
572
573 /* Keep lopping until we find our parent */
574 Node = Parent;
576 }
577
578 /* Nothing found */
579 return NULL;
580}
581
583NTAPI
587 OUT PMMADDRESS_NODE *PreviousVad,
589{
590 PMMADDRESS_NODE Node, PreviousNode;
591 ULONG_PTR PageCount, AlignmentVpn, LowVpn, HighestVpn;
592 ASSERT(Length != 0);
593
595
596 /* Calculate page numbers for the length, alignment, and starting address */
597 PageCount = BYTES_TO_PAGES(Length);
598 AlignmentVpn = Alignment >> PAGE_SHIFT;
599 LowVpn = ALIGN_UP_BY((ULONG_PTR)MM_LOWEST_USER_ADDRESS >> PAGE_SHIFT, AlignmentVpn);
600
601 /* Check for kernel mode table (memory areas) */
602 if (Table->Unused == 1)
603 {
604 LowVpn = ALIGN_UP_BY((ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT, AlignmentVpn);
605 }
606
607 /* Check if the table is empty */
608 if (Table->NumberGenericTableElements == 0)
609 {
610 /* Tree is empty, the candidate address is already the best one */
611 *Base = LowVpn << PAGE_SHIFT;
612 return TableEmptyTree;
613 }
614
615 /* Otherwise, follow the leftmost child of the right root node's child */
616 Node = RtlRightChildAvl(&Table->BalancedRoot);
618
619 /* Start a search to find a gap */
620 PreviousNode = NULL;
621 while (Node != NULL)
622 {
623 /* Check if the gap below the current node is suitable */
624 if (Node->StartingVpn >= LowVpn + PageCount)
625 {
626 /* There is enough space to add our node */
627 *Base = LowVpn << PAGE_SHIFT;
628
629 /* Can we use the current node as parent? */
630 if (RtlLeftChildAvl(Node) == NULL)
631 {
632 /* Node has no left child, so use it as parent */
633 *PreviousVad = Node;
634 return TableInsertAsLeft;
635 }
636 else
637 {
638 /* Node has a left child, this means that the previous node is
639 the right-most child of it's left child and can be used as
640 the parent. In case we use the space before the left-most
641 node, it's left child must be NULL. */
642 ASSERT(PreviousNode != NULL);
643 ASSERT(RtlRightChildAvl(PreviousNode) == NULL);
644 *PreviousVad = PreviousNode;
645 return TableInsertAsRight;
646 }
647 }
648
649 /* The next candidate is above the current node */
650 if (Node->EndingVpn >= LowVpn)
651 LowVpn = ALIGN_UP_BY(Node->EndingVpn + 1, AlignmentVpn);
652
653 /* Remember the current node and go to the next node */
654 PreviousNode = Node;
656 }
657
658 /* We're up to the highest VAD, will this allocation fit above it? */
659 HighestVpn = ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) / PAGE_SIZE;
660
661 /* Check for kernel mode table (memory areas) */
662 if (Table->Unused == 1)
663 {
664 HighestVpn = ALIGN_UP_BY((ULONG_PTR)(LONG_PTR)-1 >> PAGE_SHIFT, AlignmentVpn);
665 }
666
667 if (HighestVpn >= LowVpn + PageCount)
668 {
669 /* Yes! Use this VAD to store the allocation */
670 *PreviousVad = PreviousNode;
671 *Base = LowVpn << PAGE_SHIFT;
672 return TableInsertAsRight;
673 }
674
675 /* Nyet, there's no free address space for this allocation, so we'll fail */
676 return TableFoundNode;
677}
678
680NTAPI
682 IN ULONG_PTR BoundaryAddress,
687{
688 PMMADDRESS_NODE Node, OldNode = NULL, Child;
689 ULONG_PTR LowVpn, HighVpn, AlignmentVpn;
690 PFN_NUMBER PageCount;
691
693
694 /* Sanity checks */
695 ASSERT(BoundaryAddress);
696 ASSERT(BoundaryAddress <= ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS));
697 ASSERT((Alignment & (PAGE_SIZE - 1)) == 0);
698
699 /* Calculate page numbers for the length and alignment */
701 PageCount = Length >> PAGE_SHIFT;
702 AlignmentVpn = Alignment / PAGE_SIZE;
703
704 /* Check for kernel mode table (memory areas) */
705 if (Table->Unused == 1)
706 {
707 LowVpn = ALIGN_UP_BY((ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT, AlignmentVpn);
708 }
709 else
710 {
712 }
713
714 /* Check if there is enough space below the boundary */
715 if ((LowVpn + Length) > (BoundaryAddress + 1))
716 {
717 return TableFoundNode;
718 }
719
720 /* Check if the table is empty */
721 if (Table->NumberGenericTableElements == 0)
722 {
723 /* Tree is empty, the candidate address is already the best one */
724 *Base = ALIGN_DOWN_BY(BoundaryAddress + 1 - Length, Alignment);
725 return TableEmptyTree;
726 }
727
728 /* Calculate the initial upper margin */
729 HighVpn = (BoundaryAddress + 1) >> PAGE_SHIFT;
730
731 /* Starting from the root, follow the right children until we found a node
732 that ends above the boundary */
733 Node = RtlRightChildAvl(&Table->BalancedRoot);
734 while ((Node->EndingVpn < HighVpn) &&
736
737 /* Now loop the Vad nodes */
738 while (Node)
739 {
740 /* Calculate the lower margin */
741 LowVpn = ALIGN_UP_BY(Node->EndingVpn + 1, AlignmentVpn);
742
743 /* Check if the current bounds are suitable */
744 if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount))
745 {
746 /* There is enough space to add our node */
747 LowVpn = ALIGN_DOWN_BY(HighVpn - PageCount, AlignmentVpn);
748 *Base = LowVpn << PAGE_SHIFT;
749
750 /* Can we use the current node as parent? */
752 {
753 /* Node has no right child, so use it as parent */
754 *Parent = Node;
755 return TableInsertAsRight;
756 }
757 else
758 {
759 /* Node has a right child. This means we must have already
760 moved one node left from the right-most node we started
761 with, thus we already have an OldNode! */
762 ASSERT(OldNode != NULL);
763
764 /* The node we had before is the most left grandchild of
765 that right child, use it as parent. */
766 ASSERT(RtlLeftChildAvl(OldNode) == NULL);
767 *Parent = OldNode;
768 return TableInsertAsLeft;
769 }
770 }
771
772 /* Update the upper margin if necessary */
773 if (Node->StartingVpn < HighVpn) HighVpn = Node->StartingVpn;
774
775 /* Remember the current node and go to the previous node */
776 OldNode = Node;
778 }
779
780 /* Check if there's enough space before the lowest Vad */
782 if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount))
783 {
784 /* There is enough space to add our address */
785 LowVpn = ALIGN_DOWN_BY(HighVpn - PageCount, Alignment >> PAGE_SHIFT);
786 *Base = LowVpn << PAGE_SHIFT;
787 *Parent = OldNode;
788 return TableInsertAsLeft;
789 }
790
791 /* No address space left at all */
792 *Base = 0;
793 *Parent = NULL;
794 return TableFoundNode;
795}
796
798NTAPI
800 IN ULONG_PTR BoundaryAddress,
804{
805 PMMADDRESS_NODE Node, LowestNode;
806 ULONG_PTR LowVpn, BestVpn;
807
809
810 /* Sanity checks */
812 ASSERT(BoundaryAddress);
813 ASSERT(BoundaryAddress <= ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
814
815 /* Compute page length, make sure the boundary address is valid */
817 if ((BoundaryAddress + 1) < Length) return STATUS_NO_MEMORY;
818
819 /* Check if the table is empty */
820 BestVpn = ROUND_DOWN(BoundaryAddress + 1 - Length, Alignment);
821 if (Table->NumberGenericTableElements == 0)
822 {
823 /* Tree is empty, the candidate address is already the best one */
824 *Base = BestVpn;
825 return STATUS_SUCCESS;
826 }
827
828 /* Go to the right-most node which should be the biggest address */
829 Node = Table->BalancedRoot.RightChild;
831
832 /* Check if we can fit in here */
833 LowVpn = ROUND_UP(Node->EndingVpn + 1, Alignment);
834 if ((LowVpn < BoundaryAddress) && (Length <= (BoundaryAddress - LowVpn)))
835 {
836#if (NTDDI_VERSION >= NTDDI_VISTA)
837 /* Return the address. */
838 *Base = BestVpn;
839#else
840 /* Note: this is a compatibility hack that mimics a bug in the 2k3
841 kernel. It will can waste up to Alignment bytes of memory above
842 the allocation. This bug was fixed in Windows Vista */
843 *Base = ROUND_DOWN(BoundaryAddress - Length, Alignment);
844#endif
845 return STATUS_SUCCESS;
846 }
847
848 /* Now loop the Vad nodes */
849 do
850 {
851 /* Break out if we've reached the last node */
852 LowestNode = MiGetPreviousNode(Node);
853 if (!LowestNode) break;
854
855 /* Check if this node could contain the requested address */
856 LowVpn = ROUND_UP(LowestNode->EndingVpn + 1, Alignment);
857 if ((LowestNode->EndingVpn < BestVpn) &&
858 (LowVpn < Node->StartingVpn) &&
859 (Length <= (Node->StartingVpn - LowVpn)))
860 {
861 /* Check if we need to take BoundaryAddress into account */
862 if (BoundaryAddress < Node->StartingVpn)
863 {
864 /* Return the optimal VPN address */
865 *Base = BestVpn;
866 return STATUS_SUCCESS;
867 }
868 else
869 {
870 /* The upper margin is given by the Node's starting address */
871 *Base = ROUND_DOWN(Node->StartingVpn - Length, Alignment);
872 return STATUS_SUCCESS;
873 }
874 }
875
876 /* Move to the next node */
877 Node = LowestNode;
878 } while (TRUE);
879
880 /* Check if there's enough space before the lowest Vad */
881 if ((Node->StartingVpn > (ULONG_PTR)MI_LOWEST_VAD_ADDRESS) &&
882 ((Node->StartingVpn - (ULONG_PTR)MI_LOWEST_VAD_ADDRESS) >= Length))
883 {
884 /* Check if it fits in perfectly */
885 if (BoundaryAddress < Node->StartingVpn)
886 {
887 /* Return the optimal VPN address */
888 *Base = BestVpn;
889 return STATUS_SUCCESS;
890 }
891
892 /* Return an aligned base address within this node */
893 *Base = ROUND_DOWN(Node->StartingVpn - Length, Alignment);
894 return STATUS_SUCCESS;
895 }
896
897 /* No address space left at all */
898 return STATUS_NO_MEMORY;
899}
900
902NTAPI
904 IN PVOID Base,
905 IN SIZE_T Size,
906 IN ULONG ProtectionMask)
907{
908 ULONG_PTR StartAddress, EndAddress;
909
910 /* Compute start and end address */
911 StartAddress = (ULONG_PTR)Base;
912 EndAddress = StartAddress + Size - 1;
913
914 /* Are we deleting/unmapping, or changing? */
915 if (ProtectionMask < MM_DELETE_CHECK)
916 {
917 /* Changing... are we allowed to do so? */
918 if ((Vad->u.VadFlags.NoChange == 1) &&
919 (Vad->u2.VadFlags2.SecNoChange == 1) &&
920 (Vad->u.VadFlags.Protection != ProtectionMask))
921 {
922 /* Nope, bail out */
923 DPRINT1("Trying to mess with a no-change VAD!\n");
925 }
926 }
927 else
928 {
929 /* This is allowed */
930 ProtectionMask = 0;
931 }
932
933 /* ARM3 doesn't support this yet */
934 ASSERT(Vad->u2.VadFlags2.MultipleSecured == 0);
935
936 /* Is this a one-secured VAD, like a TEB or PEB? */
937 if (Vad->u2.VadFlags2.OneSecured)
938 {
939 /* Is this allocation being described by the VAD? */
940 if ((StartAddress <= ((PMMVAD_LONG)Vad)->u3.Secured.EndVpn) &&
941 (EndAddress >= ((PMMVAD_LONG)Vad)->u3.Secured.StartVpn))
942 {
943 /* Guard page? */
944 if (ProtectionMask & MM_DECOMMIT)
945 {
946 DPRINT1("Not allowed to change protection on guard page!\n");
948 }
949
950 /* ARM3 doesn't have read-only VADs yet */
951 ASSERT(Vad->u2.VadFlags2.ReadOnly == 0);
952
953 /* Check if read-write protections are allowed */
954 if (MmReadWrite[ProtectionMask] < MM_READ_WRITE_ALLOWED)
955 {
956 DPRINT1("Invalid protection mask for RW access!\n");
958 }
959 }
960 }
961
962 /* All good, allow the change */
963 return STATUS_SUCCESS;
964}
965
966/* EOF */
967
#define ALIGN_DOWN_BY(size, align)
#define ALIGN_UP_BY(size, align)
ACPI_PHYSICAL_ADDRESS ACPI_SIZE BOOLEAN Warn UINT32 *TableIdx UINT32 ACPI_TABLE_HEADER *OutTableHeader ACPI_TABLE_HEADER **OutTable ACPI_HANDLE UINT32 ACPI_WALK_CALLBACK ACPI_WALK_CALLBACK void void **ReturnValue UINT32 ACPI_BUFFER *RetPathPtr ACPI_OBJECT_HANDLER void *Data ACPI_OBJECT_HANDLER void **Data ACPI_STRING ACPI_OBJECT_LIST ACPI_BUFFER *ReturnObjectBuffer ACPI_DEVICE_INFO **ReturnBuffer ACPI_HANDLE Parent
Definition: acpixf.h:732
#define MM_LOWEST_USER_ADDRESS
Definition: armddk.h:20
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
union node Node
Definition: types.h:1255
#define ULONG_PTR
Definition: config.h:101
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
#define ROUND_DOWN(n, align)
Definition: eventvwr.h:33
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
Status
Definition: gdiplustypes.h:25
ASMGENDATA Table[]
Definition: genincdata.c:61
VOID FASTCALL KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:53
VOID FASTCALL KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:42
#define KeGetCurrentThread
Definition: hal.h:55
if(dx< 0)
Definition: linetemp.h:194
KGUARDED_MUTEX MmSectionBasedMutex
Definition: section.c:110
#define MI_LOWEST_VAD_ADDRESS
Definition: miarm.h:15
#define MM_READ_WRITE_ALLOWED
Definition: miarm.h:253
#define MM_DELETE_CHECK
Definition: miarm.h:256
#define MM_NO_ACCESS_ALLOWED
Definition: miarm.h:255
#define MM_DECOMMIT
Definition: miarm.h:64
FORCEINLINE VOID MiUnlockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1239
#define MM_READ_ONLY_ALLOWED
Definition: miarm.h:254
FORCEINLINE BOOLEAN MI_WS_OWNER(IN PEPROCESS Process)
Definition: miarm.h:1077
MM_AVL_TABLE MmSectionBasedRoot
Definition: section.c:109
FORCEINLINE VOID MiLockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1169
#define RtlpFindAvlTableNodeOrParent
Definition: miavl.h:32
#define RtlIsRightChildAvl
Definition: miavl.h:48
#define RtlpInsertAvlTreeNode
Definition: miavl.h:35
#define RtlRightChildAvl
Definition: miavl.h:45
#define RtlParentAvl
Definition: miavl.h:44
#define RtlLeftChildAvl
Definition: miavl.h:46
#define RtlIsLeftChildAvl
Definition: miavl.h:47
#define RtlpDeleteAvlTreeNode
Definition: miavl.h:36
#define ASSERT(a)
Definition: mode.c:44
static BYTE u3[]
Definition: msg.c:580
#define min(a, b)
Definition: monoChain.cc:55
#define _Inout_
Definition: ms_sal.h:378
#define _In_
Definition: ms_sal.h:308
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
struct _MMPTE * PMMPTE
_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
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR _In_ SIZE_T _Inout_opt_ PLARGE_INTEGER _Inout_ PSIZE_T ViewSize
Definition: mmfuncs.h:408
struct _MMVAD_LONG * PMMVAD_LONG
struct _MMVAD * PMMVAD
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2439
_In_ PMEMORY_AREA MemoryArea
Definition: newmm.h:207
#define MEM_TOP_DOWN
Definition: nt_native.h:1321
#define PAGE_WRITECOPY
Definition: nt_native.h:1305
#define PAGE_READWRITE
Definition: nt_native.h:1304
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define MM_HIGHEST_VAD_ADDRESS
Definition: mm.h:46
#define MmSystemRangeStart
Definition: mm.h:32
NTSTATUS NTAPI MmCreateMemoryArea(PMMSUPPORT AddressSpace, ULONG Type, PVOID *BaseAddress, SIZE_T Length, ULONG Protection, PMEMORY_AREA *Result, ULONG AllocationFlags, ULONG AllocationGranularity)
Definition: marea.c:410
NTSTATUS NTAPI MmFreeMemoryArea(PMMSUPPORT AddressSpace, PMEMORY_AREA MemoryArea, PMM_FREE_PAGE_FUNC FreePage, PVOID FreePageContext)
Definition: marea.c:283
#define MEMORY_AREA_OWNED_BY_ARM3
Definition: mm.h:97
struct _MEMORY_AREA * PMEMORY_AREA
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:502
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
#define STATUS_CONFLICTING_ADDRESSES
Definition: ntstatus.h:261
#define STATUS_INVALID_PAGE_PROTECTION
Definition: ntstatus.h:305
PEPROCESS PsIdleProcess
Definition: psmgr.c:51
ULONG PFN_NUMBER
Definition: ke.h:9
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:71
MM_AVL_TABLE VadRoot
Definition: pstypes.h:1453
EX_PUSH_LOCK AddressCreationLock
Definition: pstypes.h:1290
SIZE_T PeakVirtualSize
Definition: pstypes.h:1272
SIZE_T VirtualSize
Definition: pstypes.h:1273
ULONG VmDeleted
Definition: pstypes.h:1398
ULONG VmTopDown
Definition: pstypes.h:1417
PKTHREAD Owner
Definition: ketypes.h:828
PVOID Vad
Definition: mm.h:255
ULONG Type
Definition: mm.h:251
ULONG_PTR EndingVpn
Definition: mmtypes.h:654
ULONG ReadOnly
Definition: mmtypes.h:710
ULONG_PTR Spare
Definition: mmtypes.h:697
union _MMVAD_LONG::@2614 u
PMMPTE FirstPrototypePte
Definition: mmtypes.h:766
PVOID Banked
Definition: mmtypes.h:780
MMVAD_FLAGS VadFlags
Definition: mmtypes.h:763
union _MMVAD_LONG::@2615 u2
ULONG_PTR EndingVpn
Definition: mmtypes.h:759
union _MMVAD_LONG::@2617 u4
PCONTROL_AREA ControlArea
Definition: mmtypes.h:765
MMVAD_FLAGS2 VadFlags2
Definition: mmtypes.h:771
ULONG_PTR StartingVpn
Definition: mmtypes.h:758
ULONG_PTR EndingVpn
Definition: mmtypes.h:730
ULONG_PTR StartingVpn
Definition: mmtypes.h:729
PVOID NodeHint
Definition: mmtypes.h:670
uint32_t * PULONG_PTR
Definition: typedefs.h:65
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
ULONG_PTR SIZE_T
Definition: typedefs.h:80
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
Definition: dlist.c:348
PMMVAD NTAPI MiLocateAddress(IN PVOID VirtualAddress)
Definition: vadnode.c:116
VOID NTAPI MiInsertBasedSection(IN PSECTION Section)
Definition: vadnode.c:423
VOID NTAPI MiRemoveNode(IN PMMADDRESS_NODE Node, IN PMM_AVL_TABLE Table)
Definition: vadnode.c:440
MM_AVL_TABLE MiRosKernelVadRoot
Definition: marea.c:54
NTSTATUS NTAPI MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length, IN ULONG_PTR BoundaryAddress, IN ULONG_PTR Alignment, IN PMM_AVL_TABLE Table, OUT PULONG_PTR Base)
Definition: vadnode.c:799
VOID NTAPI MiInsertVad(IN PMMVAD Vad, IN PMM_AVL_TABLE VadRoot)
Definition: vadnode.c:259
PMMADDRESS_NODE NTAPI MiGetPreviousNode(IN PMMADDRESS_NODE Node)
Definition: vadnode.c:513
VOID NTAPI MiInsertNode(IN PMM_AVL_TABLE Table, IN PMMADDRESS_NODE NewNode, IN PMMADDRESS_NODE Parent, IN TABLE_SEARCH_RESULT Result)
Definition: vadnode.c:202
#define ASSERT_LOCKED_FOR_READ(Table)
Definition: vadnode.c:109
CHAR MmReadWrite[32]
Definition: vadnode.c:25
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
TABLE_SEARCH_RESULT NTAPI MiFindEmptyAddressRangeDownTree(IN SIZE_T Length, IN ULONG_PTR BoundaryAddress, IN ULONG_PTR Alignment, IN PMM_AVL_TABLE Table, OUT PULONG_PTR Base, OUT PMMADDRESS_NODE *Parent)
Definition: vadnode.c:681
NTSTATUS NTAPI MiCheckSecuredVad(IN PMMVAD Vad, IN PVOID Base, IN SIZE_T Size, IN ULONG ProtectionMask)
Definition: vadnode.c:903
TABLE_SEARCH_RESULT NTAPI MiFindEmptyAddressRangeInTree(IN SIZE_T Length, IN ULONG_PTR Alignment, IN PMM_AVL_TABLE Table, OUT PMMADDRESS_NODE *PreviousVad, OUT PULONG_PTR Base)
Definition: vadnode.c:584
#define ASSERT_LOCKED_FOR_WRITE(Table)
Definition: vadnode.c:110
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
PMMADDRESS_NODE NTAPI MiGetNextNode(IN PMMADDRESS_NODE Node)
Definition: vadnode.c:549
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
_Must_inspect_result_ _In_ WDFDMATRANSACTION _In_ PFN_WDF_PROGRAM_DMA _In_ WDF_DMA_DIRECTION _In_ PMDL _In_ PVOID VirtualAddress
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFDEVICE Child
Definition: wdffdo.h:536
_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
#define ROUND_TO_PAGES(Size)
#define BYTES_TO_PAGES(Size)
#define PsGetCurrentProcess
Definition: psfuncs.h:17
TABLE_SEARCH_RESULT
Definition: rtltypes.h:373
char CHAR
Definition: xmlstorage.h:175