#define MODULE_INVOLVED_IN_ARM3
#include "../ARM3/miarm.h"
-extern MM_SYSTEMSIZE MmSystemSize;
+/* GLOBALS ********************************************************************/
+
+ULONG MmProcessColorSeed = 0x12345678;
+PMMWSL MmWorkingSetList;
/* PRIVATE FUNCTIONS **********************************************************/
NTSTATUS Status;
PMEMORY_AREA MemoryArea;
PHYSICAL_ADDRESS BoundaryAddressMultiple;
- PVOID AllocatedBase = (PVOID)MI_LOWEST_VAD_ADDRESS;
+ PVOID AllocatedBase = (PVOID)USER_SHARED_DATA;
BoundaryAddressMultiple.QuadPart = 0;
Status = MmCreateMemoryArea(&Process->Vm,
MEMORY_AREA_OWNED_BY_ARM3,
&AllocatedBase,
((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - 1) -
- (ULONG_PTR)MI_LOWEST_VAD_ADDRESS,
+ (ULONG_PTR)USER_SHARED_DATA,
PAGE_READWRITE,
&MemoryArea,
TRUE,
ULONG RandomCoeff;
ULONG_PTR StartAddress, EndAddress;
LARGE_INTEGER CurrentTime;
+ TABLE_SEARCH_RESULT Result = TableFoundNode;
+ PMMADDRESS_NODE Parent;
/* Allocate a VAD */
Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
StartAddress -= RandomCoeff;
EndAddress = StartAddress + ROUND_TO_PAGES(Size) - 1;
- /* See if this VA range can be obtained */
- if (!MiCheckForConflictingNode(StartAddress >> PAGE_SHIFT,
- EndAddress >> PAGE_SHIFT,
- &Process->VadRoot))
- {
- /* No conflict, use this address */
- *Base = StartAddress;
- goto AfterFound;
- }
+ /* Try to find something below the random upper margin */
+ Result = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
+ EndAddress,
+ PAGE_SIZE,
+ &Process->VadRoot,
+ Base,
+ &Parent);
+ }
+
+ /* Check for success. TableFoundNode means nothing free. */
+ if (Result == TableFoundNode)
+ {
+ /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
+ Result = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
+ (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1,
+ PAGE_SIZE,
+ &Process->VadRoot,
+ Base,
+ &Parent);
+ /* Bail out, if still nothing free was found */
+ if (Result == TableFoundNode) return STATUS_NO_MEMORY;
}
- /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
- Status = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
- (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1,
- PAGE_SIZE,
- &Process->VadRoot,
- Base);
- ASSERT(NT_SUCCESS(Status));
-
-AfterFound:
/* Validate that it came from the VAD ranges */
ASSERT(*Base >= (ULONG_PTR)MI_LOWEST_VAD_ADDRESS);
/* Build the rest of the VAD now */
Vad->StartingVpn = (*Base) >> PAGE_SHIFT;
- Vad->EndingVpn = ((*Base) + Size - 1) >> PAGE_SHIFT;
+ Vad->EndingVpn = ((*Base) + Size - 1) >> PAGE_SHIFT;
Vad->u3.Secured.StartVpn = *Base;
Vad->u3.Secured.EndVpn = (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1);
+ Vad->u1.Parent = NULL;
/* FIXME: Should setup VAD bitmap */
Status = STATUS_SUCCESS;
/* Insert the VAD */
ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
Process->VadRoot.NodeHint = Vad;
- MiInsertNode((PVOID)Vad, &Process->VadRoot);
-
+ Vad->ControlArea = NULL; // For Memory-Area hack
+ Vad->FirstPrototypePte = NULL;
+ DPRINT("VAD: %p\n", Vad);
+ DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base, Process->ImageFileName);
+ MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
+
/* Release the working set */
MiUnlockProcessWorkingSet(Process, Thread);
KeReleaseGuardedMutex(&Process->AddressCreationLock);
/* Return the status */
- DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base, Process->ImageFileName);
return Status;
}
ASSERT((Vad->StartingVpn == ((ULONG_PTR)Teb >> PAGE_SHIFT) &&
(Vad->EndingVpn == (TebEnd >> PAGE_SHIFT))));
ASSERT(Vad->u.VadFlags.NoChange == TRUE);
+ ASSERT(Vad->u2.VadFlags2.OneSecured == TRUE);
ASSERT(Vad->u2.VadFlags2.MultipleSecured == FALSE);
/* Lock the working set */
MiDecrementShareCount(Pfn2, PageTableFrameNumber);
#endif
/* Set the special pending delete marker */
- Pfn1->PteAddress = (PMMPTE)((ULONG_PTR)Pfn1->PteAddress | 1);
+ MI_SET_PFN_DELETED(Pfn1);
/* And now delete the actual stack page */
MiDecrementShareCount(Pfn1, PageFrameNumber);
PointerPte++;
/* Get a page and write the current invalid PTE */
- PageFrameIndex = MiRemoveAnyPage(0);
+ MI_SET_USAGE(MI_USAGE_KERNEL_STACK);
+ MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
+ PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
MI_WRITE_INVALID_PTE(PointerPte, InvalidPte);
/* Initialize the PFN entry for this page */
MI_WRITE_VALID_PTE(PointerPte, TempPte);
}
- // Bug #4835
- (VOID)InterlockedExchangeAddUL(&MiMemoryConsumers[MC_NPPOOL].PagesUsed, StackPages);
-
//
// Release the PFN lock
//
{
PKTHREAD Thread = KeGetCurrentThread();
PMMPTE LimitPte, NewLimitPte, LastPte;
- PFN_NUMBER StackPages;
KIRQL OldIrql;
MMPTE TempPte, InvalidPte;
PFN_NUMBER PageFrameIndex;
// Calculate the number of new pages
//
LimitPte--;
- StackPages = (LimitPte - NewLimitPte + 1);
/* Setup the temporary invalid PTE */
MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
while (LimitPte >= NewLimitPte)
{
/* Get a page and write the current invalid PTE */
- PageFrameIndex = MiRemoveAnyPage(0);
+ MI_SET_USAGE(MI_USAGE_KERNEL_STACK_EXPANSION);
+ MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
+ PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
MI_WRITE_INVALID_PTE(LimitPte, InvalidPte);
/* Initialize the PFN entry for this page */
return Status;
}
+VOID
+NTAPI
+MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess)
+{
+ PMMPFN Pfn1;
+
+ /* Setup some bogus list data */
+ MmWorkingSetList->LastEntry = CurrentProcess->Vm.MinimumWorkingSetSize;
+ MmWorkingSetList->HashTable = NULL;
+ MmWorkingSetList->HashTableSize = 0;
+ MmWorkingSetList->NumberOfImageWaiters = 0;
+ MmWorkingSetList->Wsle = (PVOID)0xDEADBABE;
+ MmWorkingSetList->VadBitMapHint = 1;
+ MmWorkingSetList->HashTableStart = (PVOID)0xBADAB00B;
+ MmWorkingSetList->HighestPermittedHashAddress = (PVOID)0xCAFEBABE;
+ MmWorkingSetList->FirstFree = 1;
+ MmWorkingSetList->FirstDynamic = 2;
+ MmWorkingSetList->NextSlot = 3;
+ MmWorkingSetList->LastInitializedWsle = 4;
+
+ /* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */
+ Pfn1 = MiGetPfnEntry(MiAddressToPte(PDE_BASE)->u.Hard.PageFrameNumber);
+ ASSERT(Pfn1->u4.PteFrame == MiGetPfnEntryIndex(Pfn1));
+ Pfn1->u1.Event = (PKEVENT)CurrentProcess;
+}
+
NTSTATUS
NTAPI
MmInitializeProcessAddressSpace(IN PEPROCESS Process,
PWCHAR Source;
PCHAR Destination;
USHORT Length = 0;
+ MMPTE TempPte;
/* We should have a PDE */
ASSERT(Process->Pcb.DirectoryTableBase[0] != 0);
PointerPde = MiAddressToPde(HYPER_SPACE);
PageFrameNumber = PFN_FROM_PTE(PointerPde);
MiInitializePfn(PageFrameNumber, PointerPde, TRUE);
+
+ /* Setup the PFN for the PTE for the working set */
+ PointerPte = MiAddressToPte(MI_WORKING_SET_LIST);
+ MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, MM_READWRITE, 0);
+ ASSERT(PointerPte->u.Long != 0);
+ PageFrameNumber = PFN_FROM_PTE(PointerPte);
+ MI_WRITE_INVALID_PTE(PointerPte, DemandZeroPte);
+ MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
+ TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
+ MI_WRITE_VALID_PTE(PointerPte, TempPte);
+
+ /* Now initialize the working set list */
+ MiInitializeWorkingSetList(Process);
+
+ /* Sanity check */
+ ASSERT(Process->PhysicalVadRoot == NULL);
/* Release PFN lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
NTSTATUS
NTAPI
+INIT_FUNCTION
MmInitializeHandBuiltProcess(IN PEPROCESS Process,
IN PULONG_PTR DirectoryTableBase)
{
NTSTATUS
NTAPI
+INIT_FUNCTION
MmInitializeHandBuiltProcess2(IN PEPROCESS Process)
{
/* Lock the VAD, ARM3-owned ranges away */
OUT PULONG_PTR DirectoryTableBase)
{
KIRQL OldIrql;
- PFN_NUMBER PdeIndex, HyperIndex;
+ PFN_NUMBER PdeIndex, HyperIndex, WsListIndex;
PMMPTE PointerPte;
MMPTE TempPte, PdePte;
ULONG PdeOffset;
- PMMPTE SystemTable;
+ PMMPTE SystemTable, HyperTable;
+ ULONG Color;
+ PMMPFN Pfn1;
- /* No page colors yet */
- Process->NextPageColor = 0;
+ /* Choose a process color */
+ Process->NextPageColor = RtlRandom(&MmProcessColorSeed);
/* Setup the hyperspace lock */
KeInitializeSpinLock(&Process->HyperSpaceLock);
/* Lock PFN database */
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
- /* Get a page for the PDE */
- PdeIndex = MiRemoveAnyPage(0);
- KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
- MiZeroPhysicalPage(PdeIndex);
- OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ /* Get a zero page for the PDE, if possible */
+ Color = MI_GET_NEXT_PROCESS_COLOR(Process);
+ MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY);
+ PdeIndex = MiRemoveZeroPageSafe(Color);
+ if (!PdeIndex)
+ {
+ /* No zero pages, grab a free one */
+ PdeIndex = MiRemoveAnyPage(Color);
+
+ /* Zero it outside the PFN lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ MiZeroPhysicalPage(PdeIndex);
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ }
+
+ /* Get a zero page for hyperspace, if possible */
+ MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY);
+ Color = MI_GET_NEXT_PROCESS_COLOR(Process);
+ HyperIndex = MiRemoveZeroPageSafe(Color);
+ if (!HyperIndex)
+ {
+ /* No zero pages, grab a free one */
+ HyperIndex = MiRemoveAnyPage(Color);
+
+ /* Zero it outside the PFN lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ MiZeroPhysicalPage(HyperIndex);
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ }
- /* Get a page for hyperspace */
- HyperIndex = MiRemoveAnyPage(0);
- KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
- MiZeroPhysicalPage(HyperIndex);
+ /* Get a zero page for the woring set list, if possible */
+ MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
+ Color = MI_GET_NEXT_PROCESS_COLOR(Process);
+ WsListIndex = MiRemoveZeroPageSafe(Color);
+ if (!WsListIndex)
+ {
+ /* No zero pages, grab a free one */
+ WsListIndex = MiRemoveAnyPage(Color);
+
+ /* Zero it outside the PFN lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ MiZeroPhysicalPage(WsListIndex);
+ }
+ else
+ {
+ /* Release the PFN lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ }
/* Switch to phase 1 initialization */
ASSERT(Process->AddressSpaceInitialized == 0);
Process->AddressSpaceInitialized = 1;
/* Set the base directory pointers */
+ Process->WorkingSetPage = WsListIndex;
DirectoryTableBase[0] = PdeIndex << PAGE_SHIFT;
DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
/* Make sure we don't already have a page directory setup */
ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
+
+ /* Get a PTE to map hyperspace */
+ PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
+ ASSERT(PointerPte != NULL);
+
+ /* Build it */
+ MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
+ PointerPte,
+ MM_READWRITE,
+ HyperIndex);
+
+ /* Set it dirty and map it */
+ PdePte.u.Hard.Dirty = TRUE;
+ MI_WRITE_VALID_PTE(PointerPte, PdePte);
+
+ /* Now get hyperspace's page table */
+ HyperTable = MiPteToAddress(PointerPte);
+
+ /* Now write the PTE/PDE entry for the working set list index itself */
+ TempPte = ValidKernelPte;
+ TempPte.u.Hard.PageFrameNumber = WsListIndex;
+ PdeOffset = MiAddressToPteOffset(MmWorkingSetList);
+ HyperTable[PdeOffset] = TempPte;
+
+ /* Let go of the system PTE */
+ MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
+
+ /* Save the PTE address of the page directory itself */
+ Pfn1 = MiGetPfnEntry(PdeIndex);
+ Pfn1->PteAddress = (PMMPTE)PDE_BASE;
/* Insert us into the Mm process list */
InsertTailList(&MmProcessList, &Process->MmProcessLinks);
/* Copy all the kernel mappings */
PdeOffset = MiGetPdeOffset(MmSystemRangeStart);
-
RtlCopyMemory(&SystemTable[PdeOffset],
MiAddressToPde(MmSystemRangeStart),
PAGE_SIZE - PdeOffset * sizeof(MMPTE));
PMM_AVL_TABLE VadTree;
PETHREAD Thread = PsGetCurrentThread();
+ /* Only support this */
+ ASSERT(Process->AddressSpaceInitialized == 2);
+
/* Lock the process address space from changes */
MmLockAddressSpace(&Process->Vm);
+ /* VM is deleted now */
+ Process->VmDeleted = TRUE;
+
/* Enumerate the VADs */
VadTree = &Process->VadRoot;
- DPRINT("Cleaning up VADs: %d\n", VadTree->NumberGenericTableElements);
while (VadTree->NumberGenericTableElements)
{
/* Grab the current VAD */
/* Remove this VAD from the tree */
ASSERT(VadTree->NumberGenericTableElements >= 1);
- DPRINT("Removing node for VAD: %lx %lx\n", Vad->StartingVpn, Vad->EndingVpn);
MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
- DPRINT("Moving on: %d\n", VadTree->NumberGenericTableElements);
- /* Check if this VAD was the hint */
- if (VadTree->NodeHint == Vad)
+ /* Only regular VADs supported for now */
+ ASSERT(Vad->u.VadFlags.VadType == VadNone);
+
+ /* Check if this is a section VAD */
+ if (!(Vad->u.VadFlags.PrivateMemory) && (Vad->ControlArea))
{
- /* Get a new hint, unless we're empty now, in which case nothing */
- VadTree->NodeHint = VadTree->BalancedRoot.RightChild;
- if (!VadTree->NumberGenericTableElements) VadTree->NodeHint = NULL;
+ /* Remove the view */
+ MiRemoveMappedView(Process, Vad);
}
+ else
+ {
+ /* Delete the addresses */
+ MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT,
+ (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
+ Vad);
- /* Only PEB/TEB VADs supported for now */
- ASSERT(Vad->u.VadFlags.PrivateMemory == 1);
- ASSERT(Vad->u.VadFlags.VadType == VadNone);
+ /* Release the working set */
+ MiUnlockProcessWorkingSet(Process, Thread);
+ }
- /* Release the working set */
- MiUnlockProcessWorkingSet(Process, Thread);
+ /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
+ if (Vad->u.VadFlags.Spare == 1)
+ {
+ /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
+ Vad->u.VadFlags.Spare = 2;
+ continue;
+ }
/* Free the VAD memory */
ExFreePool(Vad);