ReactOS 0.4.16-dev-1067-ge98bba2
vadnode.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
#include <mm/ARM3/miarm.h>
#include "miavl.h"
#include <sdk/lib/rtl/avlsupp.c>
Include dependency graph for vadnode.c:

Go to the source code of this file.

Macros

#define NDEBUG
 
#define MODULE_INVOLVED_IN_ARM3
 
#define ASSERT_LOCKED_FOR_READ(Table)
 
#define ASSERT_LOCKED_FOR_WRITE(Table)
 

Functions

PMMVAD NTAPI MiLocateVad (_In_ PMM_AVL_TABLE Table, _In_ PVOID VirtualAddress)
 
PMMVAD NTAPI MiLocateAddress (_In_ PVOID VirtualAddress)
 
TABLE_SEARCH_RESULT NTAPI MiCheckForConflictingNode (IN ULONG_PTR StartVpn, IN ULONG_PTR EndVpn, IN PMM_AVL_TABLE Table, OUT PMMADDRESS_NODE *NodeOrParent)
 
VOID NTAPI MiInsertNode (IN PMM_AVL_TABLE Table, IN PMMADDRESS_NODE NewNode, IN PMMADDRESS_NODE Parent, IN TABLE_SEARCH_RESULT Result)
 
VOID NTAPI MiInsertVad (IN PMMVAD Vad, IN PMM_AVL_TABLE VadRoot)
 
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)
 
VOID NTAPI MiInsertBasedSection (IN PSECTION Section)
 
VOID NTAPI MiRemoveNode (IN PMMADDRESS_NODE Node, IN PMM_AVL_TABLE Table)
 
PMMADDRESS_NODE NTAPI MiGetPreviousNode (IN PMMADDRESS_NODE Node)
 
PMMADDRESS_NODE NTAPI MiGetNextNode (IN PMMADDRESS_NODE Node)
 
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)
 
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)
 
NTSTATUS NTAPI MiFindEmptyAddressRangeDownBasedTree (IN SIZE_T Length, IN ULONG_PTR BoundaryAddress, IN ULONG_PTR Alignment, IN PMM_AVL_TABLE Table, OUT PULONG_PTR Base)
 
NTSTATUS NTAPI MiCheckSecuredVad (IN PMMVAD Vad, IN PVOID Base, IN SIZE_T Size, IN ULONG ProtectionMask)
 

Variables

CHAR MmReadWrite [32]
 
MM_AVL_TABLE MiRosKernelVadRoot
 

Macro Definition Documentation

◆ ASSERT_LOCKED_FOR_READ

#define ASSERT_LOCKED_FOR_READ (   Table)

Definition at line 109 of file vadnode.c.

◆ ASSERT_LOCKED_FOR_WRITE

#define ASSERT_LOCKED_FOR_WRITE (   Table)

Definition at line 110 of file vadnode.c.

◆ MODULE_INVOLVED_IN_ARM3

#define MODULE_INVOLVED_IN_ARM3

Definition at line 16 of file vadnode.c.

◆ NDEBUG

#define NDEBUG

Definition at line 13 of file vadnode.c.

Function Documentation

◆ MiCheckForConflictingNode()

TABLE_SEARCH_RESULT NTAPI MiCheckForConflictingNode ( IN ULONG_PTR  StartVpn,
IN ULONG_PTR  EndVpn,
IN PMM_AVL_TABLE  Table,
OUT PMMADDRESS_NODE NodeOrParent 
)

Definition at line 157 of file vadnode.c.

161{
162 PMMADDRESS_NODE ParentNode, CurrentNode;
163
165
166 /* If the tree is empty, there is no conflict */
167 if (Table->NumberGenericTableElements == 0) return TableEmptyTree;
168
169 /* Start looping from the root node */
170 CurrentNode = RtlRightChildAvl(&Table->BalancedRoot);
171 ASSERT(CurrentNode != NULL);
172 while (CurrentNode)
173 {
174 ParentNode = CurrentNode;
175
176 /* This address comes after */
177 if (StartVpn > CurrentNode->EndingVpn)
178 {
179 /* Keep searching on the right */
180 CurrentNode = RtlRightChildAvl(CurrentNode);
181 }
182 else if (EndVpn < CurrentNode->StartingVpn)
183 {
184 /* This address ends before the node starts, search on the left */
185 CurrentNode = RtlLeftChildAvl(CurrentNode);
186 }
187 else
188 {
189 /* This address is part of this node, return it */
190 *NodeOrParent = ParentNode;
191 return TableFoundNode;
192 }
193 }
194
195 /* There is no more child, save the current node as parent */
196 *NodeOrParent = ParentNode;
197 if (StartVpn > ParentNode->EndingVpn)
198 {
199 return TableInsertAsRight;
200 }
201 else
202 {
203 return TableInsertAsLeft;
204 }
205}
#define NULL
Definition: types.h:112
ASMGENDATA Table[]
Definition: genincdata.c:61
#define RtlRightChildAvl
Definition: miavl.h:45
#define RtlLeftChildAvl
Definition: miavl.h:46
#define ASSERT(a)
Definition: mode.c:44
ULONG_PTR EndingVpn
Definition: mmtypes.h:654
#define ASSERT_LOCKED_FOR_READ(Table)
Definition: vadnode.c:109

Referenced by MiInsertVadEx(), MiMapLockedPagesInUserSpace(), MiProtectVirtualMemory(), MmIsAddressRangeFree(), MmLocateMemoryAreaByRegion(), and NtAllocateVirtualMemory().

◆ MiCheckSecuredVad()

NTSTATUS NTAPI MiCheckSecuredVad ( IN PMMVAD  Vad,
IN PVOID  Base,
IN SIZE_T  Size,
IN ULONG  ProtectionMask 
)

Definition at line 815 of file vadnode.c.

819{
820 ULONG_PTR StartAddress, EndAddress;
821
822 /* Compute start and end address */
823 StartAddress = (ULONG_PTR)Base;
824 EndAddress = StartAddress + Size - 1;
825
826 /* Are we deleting/unmapping, or changing? */
827 if (ProtectionMask < MM_DELETE_CHECK)
828 {
829 /* Changing... are we allowed to do so? */
830 if ((Vad->u.VadFlags.NoChange == 1) &&
831 (Vad->u2.VadFlags2.SecNoChange == 1) &&
832 (Vad->u.VadFlags.Protection != ProtectionMask))
833 {
834 /* Nope, bail out */
835 DPRINT1("Trying to mess with a no-change VAD!\n");
837 }
838 }
839 else
840 {
841 /* This is allowed */
842 ProtectionMask = 0;
843 }
844
845 /* ARM3 doesn't support this yet */
846 ASSERT(Vad->u2.VadFlags2.MultipleSecured == 0);
847
848 /* Is this a one-secured VAD, like a TEB or PEB? */
849 if (Vad->u2.VadFlags2.OneSecured)
850 {
851 /* Is this allocation being described by the VAD? */
852 if ((StartAddress <= ((PMMVAD_LONG)Vad)->u3.Secured.EndVpn) &&
853 (EndAddress >= ((PMMVAD_LONG)Vad)->u3.Secured.StartVpn))
854 {
855 /* Guard page? */
856 if (ProtectionMask & MM_DECOMMIT)
857 {
858 DPRINT1("Not allowed to change protection on guard page!\n");
860 }
861
862 /* ARM3 doesn't have read-only VADs yet */
863 ASSERT(Vad->u2.VadFlags2.ReadOnly == 0);
864
865 /* Check if read-write protections are allowed */
866 if (MmReadWrite[ProtectionMask] < MM_READ_WRITE_ALLOWED)
867 {
868 DPRINT1("Invalid protection mask for RW access!\n");
870 }
871 }
872 }
873
874 /* All good, allow the change */
875 return STATUS_SUCCESS;
876}
#define DPRINT1
Definition: precomp.h:8
#define ULONG_PTR
Definition: config.h:101
#define MM_READ_WRITE_ALLOWED
Definition: miarm.h:267
#define MM_DELETE_CHECK
Definition: miarm.h:270
#define MM_DECOMMIT
Definition: miarm.h:64
static BYTE u3[]
Definition: msg.c:580
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2478
#define STATUS_INVALID_PAGE_PROTECTION
Definition: ntstatus.h:305
#define STATUS_SUCCESS
Definition: shellext.h:65
ULONG ReadOnly
Definition: mmtypes.h:710
MMVAD_FLAGS2 VadFlags2
Definition: mmtypes.h:771
union _MMVAD_LONG::@2715 u2
uint32_t ULONG_PTR
Definition: typedefs.h:65
CHAR MmReadWrite[32]
Definition: vadnode.c:25
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533

Referenced by MiUnmapViewOfSection(), and NtAllocateVirtualMemory().

◆ MiFindEmptyAddressRangeDownBasedTree()

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 at line 711 of file vadnode.c.

716{
717 PMMADDRESS_NODE Node, LowestNode;
718 ULONG_PTR LowVpn, BestVpn;
719
721
722 /* Sanity checks */
724 ASSERT(BoundaryAddress);
725 ASSERT(BoundaryAddress <= ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
726
727 /* Compute page length, make sure the boundary address is valid */
729 if ((BoundaryAddress + 1) < Length) return STATUS_NO_MEMORY;
730
731 /* Check if the table is empty */
732 BestVpn = ROUND_DOWN(BoundaryAddress + 1 - Length, Alignment);
733 if (Table->NumberGenericTableElements == 0)
734 {
735 /* Tree is empty, the candidate address is already the best one */
736 *Base = BestVpn;
737 return STATUS_SUCCESS;
738 }
739
740 /* Go to the right-most node which should be the biggest address */
741 Node = Table->BalancedRoot.RightChild;
743
744 /* Check if we can fit in here */
745 LowVpn = ROUND_UP(Node->EndingVpn + 1, Alignment);
746 if ((LowVpn < BoundaryAddress) && (Length <= (BoundaryAddress - LowVpn)))
747 {
748#if (NTDDI_VERSION >= NTDDI_VISTA)
749 /* Return the address. */
750 *Base = BestVpn;
751#else
752 /* Note: this is a compatibility hack that mimics a bug in the 2k3
753 kernel. It will can waste up to Alignment bytes of memory above
754 the allocation. This bug was fixed in Windows Vista */
755 *Base = ROUND_DOWN(BoundaryAddress - Length, Alignment);
756#endif
757 return STATUS_SUCCESS;
758 }
759
760 /* Now loop the Vad nodes */
761 do
762 {
763 /* Break out if we've reached the last node */
764 LowestNode = MiGetPreviousNode(Node);
765 if (!LowestNode) break;
766
767 /* Check if this node could contain the requested address */
768 LowVpn = ROUND_UP(LowestNode->EndingVpn + 1, Alignment);
769 if ((LowestNode->EndingVpn < BestVpn) &&
770 (LowVpn < Node->StartingVpn) &&
771 (Length <= (Node->StartingVpn - LowVpn)))
772 {
773 /* Check if we need to take BoundaryAddress into account */
774 if (BoundaryAddress < Node->StartingVpn)
775 {
776 /* Return the optimal VPN address */
777 *Base = BestVpn;
778 return STATUS_SUCCESS;
779 }
780 else
781 {
782 /* The upper margin is given by the Node's starting address */
783 *Base = ROUND_DOWN(Node->StartingVpn - Length, Alignment);
784 return STATUS_SUCCESS;
785 }
786 }
787
788 /* Move to the next node */
789 Node = LowestNode;
790 } while (TRUE);
791
792 /* Check if there's enough space before the lowest Vad */
793 if ((Node->StartingVpn > (ULONG_PTR)MI_LOWEST_VAD_ADDRESS) &&
794 ((Node->StartingVpn - (ULONG_PTR)MI_LOWEST_VAD_ADDRESS) >= Length))
795 {
796 /* Check if it fits in perfectly */
797 if (BoundaryAddress < Node->StartingVpn)
798 {
799 /* Return the optimal VPN address */
800 *Base = BestVpn;
801 return STATUS_SUCCESS;
802 }
803
804 /* Return an aligned base address within this node */
805 *Base = ROUND_DOWN(Node->StartingVpn - Length, Alignment);
806 return STATUS_SUCCESS;
807 }
808
809 /* No address space left at all */
810 return STATUS_NO_MEMORY;
811}
#define STATUS_NO_MEMORY
Definition: d3dkmdt.h:51
#define TRUE
Definition: types.h:120
union node Node
Definition: types.h:1255
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
#define ROUND_DOWN(n, align)
Definition: eventvwr.h:33
#define MI_LOWEST_VAD_ADDRESS
Definition: miarm.h:15
MM_AVL_TABLE MmSectionBasedRoot
Definition: section.c:109
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define MM_HIGHEST_VAD_ADDRESS
Definition: mm.h:46
Definition: dlist.c:348
PMMADDRESS_NODE NTAPI MiGetPreviousNode(IN PMMADDRESS_NODE Node)
Definition: vadnode.c:425
#define ROUND_TO_PAGES(Size)

Referenced by MmCreateArm3Section().

◆ MiFindEmptyAddressRangeDownTree()

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 at line 593 of file vadnode.c.

599{
600 PMMADDRESS_NODE Node, OldNode = NULL, Child;
601 ULONG_PTR LowVpn, HighVpn, AlignmentVpn;
602 PFN_NUMBER PageCount;
603
605
606 /* Sanity checks */
607 ASSERT(BoundaryAddress);
608 ASSERT(BoundaryAddress <= ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS));
609 ASSERT((Alignment & (PAGE_SIZE - 1)) == 0);
610
611 /* Calculate page numbers for the length and alignment */
613 PageCount = Length >> PAGE_SHIFT;
614 AlignmentVpn = Alignment / PAGE_SIZE;
615
616 /* Check for kernel mode table (memory areas) */
617 if (Table->Unused == 1)
618 {
619 LowVpn = ALIGN_UP_BY((ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT, AlignmentVpn);
620 }
621 else
622 {
624 }
625
626 /* Check if there is enough space below the boundary */
627 if ((LowVpn + Length) > (BoundaryAddress + 1))
628 {
629 return TableFoundNode;
630 }
631
632 /* Check if the table is empty */
633 if (Table->NumberGenericTableElements == 0)
634 {
635 /* Tree is empty, the candidate address is already the best one */
636 *Base = ALIGN_DOWN_BY(BoundaryAddress + 1 - Length, Alignment);
637 return TableEmptyTree;
638 }
639
640 /* Calculate the initial upper margin */
641 HighVpn = (BoundaryAddress + 1) >> PAGE_SHIFT;
642
643 /* Starting from the root, follow the right children until we found a node
644 that ends above the boundary */
645 Node = RtlRightChildAvl(&Table->BalancedRoot);
646 while ((Node->EndingVpn < HighVpn) &&
648
649 /* Now loop the Vad nodes */
650 while (Node)
651 {
652 /* Calculate the lower margin */
653 LowVpn = ALIGN_UP_BY(Node->EndingVpn + 1, AlignmentVpn);
654
655 /* Check if the current bounds are suitable */
656 if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount))
657 {
658 /* There is enough space to add our node */
659 LowVpn = ALIGN_DOWN_BY(HighVpn - PageCount, AlignmentVpn);
660 *Base = LowVpn << PAGE_SHIFT;
661
662 /* Can we use the current node as parent? */
664 {
665 /* Node has no right child, so use it as parent */
666 *Parent = Node;
667 return TableInsertAsRight;
668 }
669 else
670 {
671 /* Node has a right child. This means we must have already
672 moved one node left from the right-most node we started
673 with, thus we already have an OldNode! */
674 ASSERT(OldNode != NULL);
675
676 /* The node we had before is the most left grandchild of
677 that right child, use it as parent. */
678 ASSERT(RtlLeftChildAvl(OldNode) == NULL);
679 *Parent = OldNode;
680 return TableInsertAsLeft;
681 }
682 }
683
684 /* Update the upper margin if necessary */
685 if (Node->StartingVpn < HighVpn) HighVpn = Node->StartingVpn;
686
687 /* Remember the current node and go to the previous node */
688 OldNode = Node;
690 }
691
692 /* Check if there's enough space before the lowest Vad */
694 if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount))
695 {
696 /* There is enough space to add our address */
697 LowVpn = ALIGN_DOWN_BY(HighVpn - PageCount, Alignment >> PAGE_SHIFT);
698 *Base = LowVpn << PAGE_SHIFT;
699 *Parent = OldNode;
700 return TableInsertAsLeft;
701 }
702
703 /* No address space left at all */
704 *Base = 0;
705 *Parent = NULL;
706 return TableFoundNode;
707}
#define ALIGN_DOWN_BY(size, align)
#define ALIGN_UP_BY(size, align)
ULONG_PTR PFN_NUMBER
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
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define MmSystemRangeStart
Definition: mm.h:32
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFDEVICE Child
Definition: wdffdo.h:536

Referenced by MiInsertVadEx(), and MmFindGap().

◆ MiFindEmptyAddressRangeInTree()

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 at line 496 of file vadnode.c.

501{
502 PMMADDRESS_NODE Node, PreviousNode;
503 ULONG_PTR PageCount, AlignmentVpn, LowVpn, HighestVpn;
504 ASSERT(Length != 0);
505
507
508 /* Calculate page numbers for the length, alignment, and starting address */
509 PageCount = BYTES_TO_PAGES(Length);
510 AlignmentVpn = Alignment >> PAGE_SHIFT;
511 LowVpn = ALIGN_UP_BY((ULONG_PTR)MM_LOWEST_USER_ADDRESS >> PAGE_SHIFT, AlignmentVpn);
512
513 /* Check for kernel mode table (memory areas) */
514 if (Table->Unused == 1)
515 {
516 LowVpn = ALIGN_UP_BY((ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT, AlignmentVpn);
517 }
518
519 /* Check if the table is empty */
520 if (Table->NumberGenericTableElements == 0)
521 {
522 /* Tree is empty, the candidate address is already the best one */
523 *Base = LowVpn << PAGE_SHIFT;
524 return TableEmptyTree;
525 }
526
527 /* Otherwise, follow the leftmost child of the right root node's child */
528 Node = RtlRightChildAvl(&Table->BalancedRoot);
530
531 /* Start a search to find a gap */
532 PreviousNode = NULL;
533 while (Node != NULL)
534 {
535 /* Check if the gap below the current node is suitable */
536 if (Node->StartingVpn >= LowVpn + PageCount)
537 {
538 /* There is enough space to add our node */
539 *Base = LowVpn << PAGE_SHIFT;
540
541 /* Can we use the current node as parent? */
542 if (RtlLeftChildAvl(Node) == NULL)
543 {
544 /* Node has no left child, so use it as parent */
545 *PreviousVad = Node;
546 return TableInsertAsLeft;
547 }
548 else
549 {
550 /* Node has a left child, this means that the previous node is
551 the right-most child of it's left child and can be used as
552 the parent. In case we use the space before the left-most
553 node, it's left child must be NULL. */
554 ASSERT(PreviousNode != NULL);
555 ASSERT(RtlRightChildAvl(PreviousNode) == NULL);
556 *PreviousVad = PreviousNode;
557 return TableInsertAsRight;
558 }
559 }
560
561 /* The next candidate is above the current node */
562 if (Node->EndingVpn >= LowVpn)
563 LowVpn = ALIGN_UP_BY(Node->EndingVpn + 1, AlignmentVpn);
564
565 /* Remember the current node and go to the next node */
566 PreviousNode = Node;
568 }
569
570 /* We're up to the highest VAD, will this allocation fit above it? */
571 HighestVpn = ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) / PAGE_SIZE;
572
573 /* Check for kernel mode table (memory areas) */
574 if (Table->Unused == 1)
575 {
576 HighestVpn = ALIGN_UP_BY((ULONG_PTR)(LONG_PTR)-1 >> PAGE_SHIFT, AlignmentVpn);
577 }
578
579 if (HighestVpn >= LowVpn + PageCount)
580 {
581 /* Yes! Use this VAD to store the allocation */
582 *PreviousVad = PreviousNode;
583 *Base = LowVpn << PAGE_SHIFT;
584 return TableInsertAsRight;
585 }
586
587 /* Nyet, there's no free address space for this allocation, so we'll fail */
588 return TableFoundNode;
589}
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
PMMADDRESS_NODE NTAPI MiGetNextNode(IN PMMADDRESS_NODE Node)
Definition: vadnode.c:461
#define BYTES_TO_PAGES(Size)

Referenced by MiInsertVadEx(), MiMapLockedPagesInUserSpace(), and MmFindGap().

◆ MiGetNextNode()

PMMADDRESS_NODE NTAPI MiGetNextNode ( IN PMMADDRESS_NODE  Node)

Definition at line 461 of file vadnode.c.

462{
464
465 /* Get the right child */
467 {
468 /* Get left-most child */
471 return Node;
472 }
473
475 ASSERT(Parent != NULL);
476 while (Parent != Node)
477 {
478 /* The parent should be a left child, return the real predecessor */
480 {
481 /* Return it */
482 return Parent;
483 }
484
485 /* Keep lopping until we find our parent */
486 Node = Parent;
488 }
489
490 /* Nothing found */
491 return NULL;
492}
#define RtlParentAvl
Definition: miavl.h:44
#define RtlIsLeftChildAvl
Definition: miavl.h:47

Referenced by MiFindEmptyAddressRangeInTree(), and MiQueryMemoryBasicInformation().

◆ MiGetPreviousNode()

PMMADDRESS_NODE NTAPI MiGetPreviousNode ( IN PMMADDRESS_NODE  Node)

Definition at line 425 of file vadnode.c.

426{
428
429 /* Get the left child */
431 {
432 /* Get right-most child */
435 return Node;
436 }
437
439 ASSERT(Parent != NULL);
440 while (Parent != Node)
441 {
442 /* The parent should be a right child, return the real predecessor */
444 {
445 /* Return it unless it's the root */
447 return Parent;
448 }
449
450 /* Keep lopping until we find our parent */
451 Node = Parent;
453 }
454
455 /* Nothing found */
456 return NULL;
457}
#define RtlIsRightChildAvl
Definition: miavl.h:48

Referenced by MiFindEmptyAddressRangeDownBasedTree(), and MiFindEmptyAddressRangeDownTree().

◆ MiInsertBasedSection()

VOID NTAPI MiInsertBasedSection ( IN PSECTION  Section)

Definition at line 386 of file vadnode.c.

387{
390 ASSERT(Section->Address.EndingVpn >= Section->Address.StartingVpn);
391
393
394 /* Find the parent VAD and where this child should be inserted */
395 Result = RtlpFindAvlTableNodeOrParent(&MmSectionBasedRoot, (PVOID)Section->Address.StartingVpn, &Parent);
396 ASSERT(Result != TableFoundNode);
397 ASSERT((Parent != NULL) || (Result == TableEmptyTree));
398 MiInsertNode(&MmSectionBasedRoot, &Section->Address, Parent, Result);
399}
#define RtlpFindAvlTableNodeOrParent
Definition: miavl.h:32
VOID NTAPI MiInsertNode(IN PMM_AVL_TABLE Table, IN PMMADDRESS_NODE NewNode, IN PMMADDRESS_NODE Parent, IN TABLE_SEARCH_RESULT Result)
Definition: vadnode.c:209
#define ASSERT_LOCKED_FOR_WRITE(Table)
Definition: vadnode.c:110
_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
TABLE_SEARCH_RESULT
Definition: rtltypes.h:386

Referenced by MmCreateArm3Section().

◆ MiInsertNode()

VOID NTAPI MiInsertNode ( IN PMM_AVL_TABLE  Table,
IN PMMADDRESS_NODE  NewNode,
IN PMMADDRESS_NODE  Parent,
IN TABLE_SEARCH_RESULT  Result 
)

Definition at line 209 of file vadnode.c.

213{
215
216 /* Insert it into the tree */
218}
#define RtlpInsertAvlTreeNode
Definition: miavl.h:35

Referenced by MiInsertBasedSection(), MiInsertVad(), and MiInsertVadEx().

◆ MiInsertVad()

VOID NTAPI MiInsertVad ( IN PMMVAD  Vad,
IN PMM_AVL_TABLE  VadRoot 
)

Definition at line 222 of file vadnode.c.

224{
227
229
230 /* Validate the VAD and set it as the current hint */
231 ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
232 VadRoot->NodeHint = Vad;
233
234 /* Find the parent VAD and where this child should be inserted */
235 Result = RtlpFindAvlTableNodeOrParent(VadRoot, (PVOID)Vad->StartingVpn, &Parent);
236 ASSERT(Result != TableFoundNode);
237 ASSERT((Parent != NULL) || (Result == TableEmptyTree));
238
239 /* Do the actual insert operation */
240 MiInsertNode(VadRoot, (PVOID)Vad, Parent, Result);
241}

Referenced by MmInsertMemoryArea().

◆ MiInsertVadEx()

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 at line 245 of file vadnode.c.

252{
253 ULONG_PTR StartingAddress, EndingAddress;
254 PEPROCESS CurrentProcess;
255 PETHREAD CurrentThread;
258
259 /* Align the view size to pages */
261
262 /* Get the current process */
263 CurrentProcess = PsGetCurrentProcess();
264
265 /* Acquire the address creation lock and make sure the process is alive */
267 if (CurrentProcess->VmDeleted)
268 {
270 DPRINT1("The process is dying\n");
272 }
273
274 /* Did the caller specify an address? */
275 if (*BaseAddress == 0)
276 {
277 /* Make sure HighestAddress is not too large */
278 HighestAddress = min(HighestAddress, (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS);
279
280 /* Which way should we search? */
281 if ((AllocationType & MEM_TOP_DOWN) || CurrentProcess->VmTopDown)
282 {
283 /* Find an address top-down */
285 HighestAddress,
286 Alignment,
287 &CurrentProcess->VadRoot,
288 &StartingAddress,
289 &Parent);
290 }
291 else
292 {
293 /* Find an address bottom-up */
295 Alignment,
296 &CurrentProcess->VadRoot,
297 &Parent,
298 &StartingAddress);
299 }
300
301 /* Get the ending address, which is the last piece we need for the VAD */
302 EndingAddress = StartingAddress + ViewSize - 1;
303
304 /* Check if we found a suitable location */
305 if ((Result == TableFoundNode) || (EndingAddress > HighestAddress))
306 {
307 DPRINT1("Not enough free space to insert this VAD node!\n");
309 return STATUS_NO_MEMORY;
310 }
311
312 ASSERT(StartingAddress != 0);
313 ASSERT(StartingAddress < (ULONG_PTR)HighestAddress);
314 ASSERT(EndingAddress > StartingAddress);
315 }
316 else
317 {
318 /* Calculate the starting and ending address */
319 StartingAddress = ALIGN_DOWN_BY(*BaseAddress, Alignment);
320 EndingAddress = StartingAddress + ViewSize - 1;
321
322 /* Make sure it doesn't conflict with an existing allocation */
323 Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
324 EndingAddress >> PAGE_SHIFT,
325 &CurrentProcess->VadRoot,
326 &Parent);
327 if (Result == TableFoundNode)
328 {
329 DPRINT("Given address conflicts with existing node\n");
332 }
333 }
334
335 /* Now set the VAD address */
336 Vad->StartingVpn = StartingAddress >> PAGE_SHIFT;
337 Vad->EndingVpn = EndingAddress >> PAGE_SHIFT;
338
339 /* Check if we already need to charge for the pages */
340 if ((Vad->u.VadFlags.PrivateMemory && Vad->u.VadFlags.MemCommit) ||
341 (!Vad->u.VadFlags.PrivateMemory &&
342 (Vad->u.VadFlags.Protection & PAGE_WRITECOPY)))
343 {
344 /* Set the commit charge */
345 Vad->u.VadFlags.CommitCharge = ViewSize / PAGE_SIZE;
346 }
347
348 /* Check if the VAD is to be secured */
349 if (Vad->u2.VadFlags2.OneSecured)
350 {
351 /* This *must* be a long VAD! */
352 ASSERT(Vad->u2.VadFlags2.LongVad);
353
354 /* Yeah this is retarded, I didn't invent it! */
355 ((PMMVAD_LONG)Vad)->u3.Secured.StartVpn = StartingAddress;
356 ((PMMVAD_LONG)Vad)->u3.Secured.EndVpn = EndingAddress;
357 }
358
359 /* Lock the working set */
360 CurrentThread = PsGetCurrentThread();
361 MiLockProcessWorkingSetUnsafe(CurrentProcess, CurrentThread);
362
363 /* Insert the VAD */
364 CurrentProcess->VadRoot.NodeHint = Vad;
365 MiInsertNode(&CurrentProcess->VadRoot, (PVOID)Vad, Parent, Result);
366
367 /* Release the working set */
368 MiUnlockProcessWorkingSetUnsafe(CurrentProcess, CurrentThread);
369
370 /* Update the process' virtual size, and peak virtual size */
371 CurrentProcess->VirtualSize += ViewSize;
372 if (CurrentProcess->VirtualSize > CurrentProcess->PeakVirtualSize)
373 {
374 CurrentProcess->PeakVirtualSize = CurrentProcess->VirtualSize;
375 }
376
377 /* Unlock the address space */
379
380 *BaseAddress = StartingAddress;
381 return STATUS_SUCCESS;
382}
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
VOID FASTCALL KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:53
VOID FASTCALL KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:42
FORCEINLINE VOID MiUnlockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1252
FORCEINLINE VOID MiLockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1182
#define min(a, b)
Definition: monoChain.cc:55
_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
#define MEM_TOP_DOWN
Definition: nt_native.h:1321
#define PAGE_WRITECOPY
Definition: nt_native.h:1305
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:502
#define STATUS_CONFLICTING_ADDRESSES
Definition: ntstatus.h:261
#define DPRINT
Definition: sndvol32.h:73
MM_AVL_TABLE VadRoot
Definition: pstypes.h:1454
EX_PUSH_LOCK AddressCreationLock
Definition: pstypes.h:1291
SIZE_T PeakVirtualSize
Definition: pstypes.h:1273
SIZE_T VirtualSize
Definition: pstypes.h:1274
ULONG VmDeleted
Definition: pstypes.h:1399
ULONG VmTopDown
Definition: pstypes.h:1418
PVOID NodeHint
Definition: mmtypes.h:670
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:593
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:496
TABLE_SEARCH_RESULT NTAPI MiCheckForConflictingNode(IN ULONG_PTR StartVpn, IN ULONG_PTR EndVpn, IN PMM_AVL_TABLE Table, OUT PMMADDRESS_NODE *NodeOrParent)
Definition: vadnode.c:157
#define PsGetCurrentProcess
Definition: psfuncs.h:17

Referenced by MiCreatePebOrTeb(), MiMapViewOfDataSection(), and NtAllocateVirtualMemory().

◆ MiLocateAddress()

PMMVAD NTAPI MiLocateAddress ( _In_ PVOID  VirtualAddress)

Definition at line 149 of file vadnode.c.

150{
153}
PMMVAD NTAPI MiLocateVad(_In_ PMM_AVL_TABLE Table, _In_ PVOID VirtualAddress)
Definition: vadnode.c:116
_Must_inspect_result_ _In_ WDFDMATRANSACTION _In_ PFN_WDF_PROGRAM_DMA _In_ WDF_DMA_DIRECTION _In_ PMDL _In_ PVOID VirtualAddress

◆ MiLocateVad()

PMMVAD NTAPI MiLocateVad ( _In_ PMM_AVL_TABLE  Table,
_In_ PVOID  VirtualAddress 
)

Definition at line 116 of file vadnode.c.

117{
118 PMMVAD FoundVad;
119 ULONG_PTR Vpn;
120 TABLE_SEARCH_RESULT SearchResult;
121
123
124 /* Start with the the hint */
125 FoundVad = (PMMVAD)Table->NodeHint;
126 if (!FoundVad) return NULL;
127
128 /* Check if this VPN is in the hint, if so, use it */
130 if ((Vpn >= FoundVad->StartingVpn) && (Vpn <= FoundVad->EndingVpn)) return FoundVad;
131
132 /* VAD hint didn't work, go look for it */
133 SearchResult = RtlpFindAvlTableNodeOrParent(Table,
134 (PVOID)Vpn,
135 (PMMADDRESS_NODE*)&FoundVad);
136 if (SearchResult != TableFoundNode) return NULL;
137
138 /* We found it, update the hint */
139 ASSERT(FoundVad != NULL);
140 ASSERT((Vpn >= FoundVad->StartingVpn) && (Vpn <= FoundVad->EndingVpn));
141
142 /* We allow this (atomic) update without exclusive lock, because it's a hint only */
143 Table->NodeHint = FoundVad;
144 return FoundVad;
145}
if(dx< 0)
Definition: linetemp.h:194
struct _MMVAD * PMMVAD
ULONG_PTR EndingVpn
Definition: mmtypes.h:730
ULONG_PTR StartingVpn
Definition: mmtypes.h:729

Referenced by MiLocateAddress(), MiUnmapViewOfSection(), and MmAccessFault().

◆ MiRemoveNode()

VOID NTAPI MiRemoveNode ( IN PMMADDRESS_NODE  Node,
IN PMM_AVL_TABLE  Table 
)

Definition at line 403 of file vadnode.c.

405{
407
408 /* Call the AVL code */
410
411 /* Decrease element count */
412 Table->NumberGenericTableElements--;
413
414 /* Check if this node was the hint */
415 if (Table->NodeHint == Node)
416 {
417 /* Get a new hint, unless we're empty now, in which case nothing */
418 if (!Table->NumberGenericTableElements) Table->NodeHint = NULL;
419 else Table->NodeHint = Table->BalancedRoot.RightChild;
420 }
421}
#define RtlpDeleteAvlTreeNode
Definition: miavl.h:36

Referenced by MiDeleteARM3Section(), MiUnmapLockedPagesInUserSpace(), MiUnmapViewOfSection(), MmCleanProcessAddressSpace(), MmDeleteTeb(), MmFreeMemoryArea(), and NtFreeVirtualMemory().

Variable Documentation

◆ MiRosKernelVadRoot

MM_AVL_TABLE MiRosKernelVadRoot
extern

Definition at line 54 of file marea.c.

◆ MmReadWrite