/* Capture the PTE */
TempPte = *PointerPte;
- /* We only support valid PTEs for now */
- ASSERT(TempPte.u.Hard.Valid == 1);
+ /* See if the PTE is valid */
if (TempPte.u.Hard.Valid == 0)
{
- /* Invalid PTEs not supported yet */
+ /* Prototype and paged out PTEs not supported yet */
ASSERT(TempPte.u.Soft.Prototype == 0);
- ASSERT(TempPte.u.Soft.Transition == 0);
+ ASSERT(TempPte.u.Soft.PageFileHigh == 0);
+
+ if (TempPte.u.Soft.Transition)
+ {
+ /* Get the PFN entry */
+ PageFrameIndex = PFN_FROM_PTE(&TempPte);
+ Pfn1 = MiGetPfnEntry(PageFrameIndex);
+
+ DPRINT("Pte %p is transitional!\n", PointerPte);
+
+ /* Destroy the PTE */
+ MI_ERASE_PTE(PointerPte);
+
+ /* Drop the reference on the page table. */
+ MiDecrementShareCount(MiGetPfnEntry(Pfn1->u4.PteFrame), Pfn1->u4.PteFrame);
+
+ ASSERT(Pfn1->u3.e1.PrototypePte == 0);
+
+ /* Make the page free. For prototypes, it will be made free when deleting the section object */
+ if (Pfn1->u2.ShareCount == 0)
+ {
+ NT_ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
+
+ /* And it should be in standby or modified list */
+ ASSERT((Pfn1->u3.e1.PageLocation == ModifiedPageList) || (Pfn1->u3.e1.PageLocation == StandbyPageList));
+
+ /* Unlink it and temporarily mark it as active */
+ MiUnlinkPageFromList(Pfn1);
+ Pfn1->u3.e2.ReferenceCount++;
+ Pfn1->u3.e1.PageLocation = ActiveAndValid;
+
+ /* This will put it back in free list and clean properly up */
+ MI_SET_PFN_DELETED(Pfn1);
+ MiDecrementReferenceCount(Pfn1, PageFrameIndex);
+ }
+ return;
+ }
}
/* Get the PFN entry */
#if (_MI_PAGING_LEVELS == 2)
}
#endif
+ /* Drop the share count on the page table */
+ PointerPde = MiPteToPde(PointerPte);
+ MiDecrementShareCount(MiGetPfnEntry(PointerPde->u.Hard.PageFrameNumber),
+ PointerPde->u.Hard.PageFrameNumber);
+
/* Drop the share count */
MiDecrementShareCount(Pfn1, PageFrameIndex);
(ULONG_PTR)Pfn1->PteAddress);
}
}
+
+ /* Erase it */
+ MI_ERASE_PTE(PointerPte);
}
else
{
(ULONG_PTR)Pfn1->PteAddress);
}
+ /* Erase the PTE */
+ MI_ERASE_PTE(PointerPte);
+
/* There should only be 1 shared reference count */
ASSERT(Pfn1->u2.ShareCount == 1);
//CurrentProcess->NumberOfPrivatePages--;
}
- /* Destroy the PTE and flush the TLB */
- MI_ERASE_PTE(PointerPte);
+ /* Flush the TLB */
KeFlushCurrentTb();
}
{
MMPTE TempPte;
PMMPFN Pfn;
+ PEPROCESS CurrentProcess;
+ PETHREAD CurrentThread;
+ BOOLEAN WsSafe, WsShared;
+ ULONG Protect;
+ KIRQL OldIrql;
PAGED_CODE();
/* Copy this PTE's contents */
ASSERT(TempPte.u.Long);
/* Check for a special prototype format */
- if (TempPte.u.Soft.Valid == 0 &&
- TempPte.u.Soft.Prototype == 1)
+ if ((TempPte.u.Soft.Valid == 0) &&
+ (TempPte.u.Soft.Prototype == 1))
{
- /* Unsupported now */
- UNIMPLEMENTED;
- ASSERT(FALSE);
+ /* Check if the prototype PTE is not yet pointing to a PTE */
+ if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
+ {
+ /* The prototype PTE contains the protection */
+ return MmProtectToValue[TempPte.u.Soft.Protection];
+ }
+
+ /* Get a pointer to the underlying shared PTE */
+ PointerPte = MiProtoPteToPte(&TempPte);
+
+ /* Since the PTE we want to read can be paged out at any time, we need
+ to release the working set lock first, so that it can be paged in */
+ CurrentThread = PsGetCurrentThread();
+ CurrentProcess = PsGetCurrentProcess();
+ MiUnlockProcessWorkingSetForFault(CurrentProcess,
+ CurrentThread,
+ &WsSafe,
+ &WsShared);
+
+ /* Now read the PTE value */
+ TempPte = *PointerPte;
+
+ /* Check if that one is invalid */
+ if (!TempPte.u.Hard.Valid)
+ {
+ /* We get the protection directly from this PTE */
+ Protect = MmProtectToValue[TempPte.u.Soft.Protection];
+ }
+ else
+ {
+ /* The PTE is valid, so we might need to get the protection from
+ the PFN. Lock the PFN database */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Check if the PDE is still valid */
+ if (MiAddressToPte(PointerPte)->u.Hard.Valid == 0)
+ {
+ /* It's not, make it valid */
+ MiMakeSystemAddressValidPfn(PointerPte, OldIrql);
+ }
+
+ /* Now it's safe to read the PTE value again */
+ TempPte = *PointerPte;
+ ASSERT(TempPte.u.Long != 0);
+
+ /* Check again if the PTE is invalid */
+ if (!TempPte.u.Hard.Valid)
+ {
+ /* The PTE is not valid, so we can use it's protection field */
+ Protect = MmProtectToValue[TempPte.u.Soft.Protection];
+ }
+ else
+ {
+ /* The PTE is valid, so we can find the protection in the
+ OriginalPte field of the PFN */
+ Pfn = MI_PFN_ELEMENT(TempPte.u.Hard.PageFrameNumber);
+ Protect = MmProtectToValue[Pfn->OriginalPte.u.Soft.Protection];
+ }
+
+ /* Release the PFN database */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ }
+
+ /* Lock the working set again */
+ MiLockProcessWorkingSetForFault(CurrentProcess,
+ CurrentThread,
+ WsSafe,
+ WsShared);
+
+ return Protect;
}
/* In the easy case of transition or demand zero PTE just return its protection */
}
/* This is software PTE */
- DPRINT1("Prototype PTE: %lx %p\n", TempPte.u.Hard.PageFrameNumber, Pfn);
- DPRINT1("VA: %p\n", MiPteToAddress(&TempPte));
- DPRINT1("Mask: %lx\n", TempPte.u.Soft.Protection);
- DPRINT1("Mask2: %lx\n", Pfn->OriginalPte.u.Soft.Protection);
+ DPRINT("Prototype PTE: %lx %p\n", TempPte.u.Hard.PageFrameNumber, Pfn);
+ DPRINT("VA: %p\n", MiPteToAddress(&TempPte));
+ DPRINT("Mask: %lx\n", TempPte.u.Soft.Protection);
+ DPRINT("Mask2: %lx\n", Pfn->OriginalPte.u.Soft.Protection);
return MmProtectToValue[TempPte.u.Soft.Protection];
}
/* Check for ROS specific memory area */
MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, *BaseAddress);
- if ((MemoryArea) && (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW))
+ if ((MemoryArea) && (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3))
{
/* Evil hack */
return MiRosProtectVirtualMemory(Process,
if ((NewAccessProtection & PAGE_NOACCESS) ||
(NewAccessProtection & PAGE_GUARD))
{
- /* The page should be in the WS and we should make it transition now */
- DPRINT1("Making valid page invalid is not yet supported!\n");
- Status = STATUS_NOT_IMPLEMENTED;
- /* Unlock the working set */
- MiUnlockProcessWorkingSetUnsafe(Process, Thread);
- goto FailPath;
- }
+ KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Mark the PTE as transition and change its protection */
+ PteContents.u.Hard.Valid = 0;
+ PteContents.u.Soft.Transition = 1;
+ PteContents.u.Trans.Protection = ProtectionMask;
+ /* Decrease PFN share count and write the PTE */
+ MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents));
+ // FIXME: remove the page from the WS
+ MI_WRITE_INVALID_PTE(PointerPte, PteContents);
+#ifdef CONFIG_SMP
+ // FIXME: Should invalidate entry in every CPU TLB
+ ASSERT(FALSE);
+#endif
+ KeInvalidateTlbEntry(MiPteToAddress(PointerPte));
- /* Write the protection mask and write it with a TLB flush */
- Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
- MiFlushTbAndCapture(Vad,
- PointerPte,
- ProtectionMask,
- Pfn1,
- TRUE);
+ /* We are done for this PTE */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ }
+ else
+ {
+ /* Write the protection mask and write it with a TLB flush */
+ Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
+ MiFlushTbAndCapture(Vad,
+ PointerPte,
+ ProtectionMask,
+ Pfn1,
+ TRUE);
+ }
}
else
{
/* We don't support these cases yet */
ASSERT(PteContents.u.Soft.Prototype == 0);
- ASSERT(PteContents.u.Soft.Transition == 0);
+ //ASSERT(PteContents.u.Soft.Transition == 0);
/* The PTE is already demand-zero, just update the protection mask */
PteContents.u.Soft.Protection = ProtectionMask;
}
}
+ DPRINT("NtAllocateVirtualMemory: Process 0x%p, Address 0x%p, Zerobits %lu , RegionSize 0x%x, Allocation type 0x%x, Protect 0x%x.\n",
+ Process, PBaseAddress, ZeroBits, PRegionSize, AllocationType, Protect);
+
//
// Check for large page allocations and make sure that the required privilege
// is being held, before attempting to handle them.
//
}
_SEH2_END;
+ DPRINT("Reserved %x bytes at %p.\n", PRegionSize, StartingAddress);
return STATUS_SUCCESS;
}
}
}
+ DPRINT("NtFreeVirtualMemory: Process 0x%p, Adress 0x%p, size 0x%x, FreeType %x.\n",
+ Process, PBaseAddress, PRegionSize, FreeType);
+
//
// Lock the address space
//
ASSERT(Vad->StartingVpn << PAGE_SHIFT == (ULONG_PTR)MemoryArea->StartingAddress);
ASSERT((Vad->EndingVpn + 1) << PAGE_SHIFT == (ULONG_PTR)MemoryArea->EndingAddress);
Vad->EndingVpn = ((ULONG_PTR)StartingAddress - 1) >> PAGE_SHIFT;
- MemoryArea->EndingAddress = (PVOID)(((Vad->EndingVpn + 1) << PAGE_SHIFT) - 1);
+ MemoryArea->EndingAddress = (PVOID)(StartingAddress);
}
else
{