[NTOSKRNL/MM/AMD64]

- Implement more of MmCreateProcessAddressSpace
- Acquire pfn lock and use MiRemoveZeroPage in MiGetPteForProcess

svn path=/trunk/; revision=55407
This commit is contained in:
Timo Kreuzer 2012-02-04 12:13:53 +00:00
parent 775cef8b4c
commit afd88373ce

View file

@ -28,7 +28,7 @@ extern MMPTE HyperTemplatePte;
/* GLOBALS *****************************************************************/ /* GLOBALS *****************************************************************/
const const
ULONG ULONG64
MmProtectToPteMask[32] = MmProtectToPteMask[32] =
{ {
// //
@ -151,37 +151,48 @@ MiGetPteForProcess(
Process && Process != PsGetCurrentProcess()) Process && Process != PsGetCurrentProcess())
{ {
UNIMPLEMENTED; UNIMPLEMENTED;
__debugbreak();
return NULL; return NULL;
} }
else if (Create) else if (Create)
{ {
KIRQL OldIrql;
TmplPte.u.Long = 0; TmplPte.u.Long = 0;
TmplPte.u.Flush.Valid = 1; TmplPte.u.Flush.Valid = 1;
TmplPte.u.Flush.Write = 1; TmplPte.u.Flush.Write = 1;
/* All page table levels of user pages are user owned */
TmplPte.u.Flush.Owner = (Address < MmHighestUserAddress) ? 1 : 0;
/* Lock the PFN database */
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
/* Get the PXE */ /* Get the PXE */
Pte = MiAddressToPxe(Address); Pte = MiAddressToPxe(Address);
if (!Pte->u.Hard.Valid) if (!Pte->u.Hard.Valid)
{ {
// TmplPte.u.Hard.PageFrameNumber = MiAllocPage(TRUE); TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(0);
InterlockedExchangePte(Pte, TmplPte); MI_WRITE_VALID_PTE(Pte, TmplPte);
} }
/* Get the PPE */ /* Get the PPE */
Pte = MiAddressToPpe(Address); Pte = MiAddressToPpe(Address);
if (!Pte->u.Hard.Valid) if (!Pte->u.Hard.Valid)
{ {
// TmplPte.u.Hard.PageFrameNumber = MiAllocPage(TRUE); TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(1);
InterlockedExchangePte(Pte, TmplPte); MI_WRITE_VALID_PTE(Pte, TmplPte);
} }
/* Get the PDE */ /* Get the PDE */
Pte = MiAddressToPde(Address); Pte = MiAddressToPde(Address);
if (!Pte->u.Hard.Valid) if (!Pte->u.Hard.Valid)
{ {
// TmplPte.u.Hard.PageFrameNumber = MiAllocPage(TRUE); TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(2);
InterlockedExchangePte(Pte, TmplPte); MI_WRITE_VALID_PTE(Pte, TmplPte);
} }
/* Unlock PFN database */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
} }
else else
{ {
@ -529,6 +540,8 @@ MmCreateVirtualMappingUnsafe(
TmplPte.u.Hard.Valid = 1; TmplPte.u.Hard.Valid = 1;
MiSetPteProtection(&TmplPte, PageProtection); MiSetPteProtection(&TmplPte, PageProtection);
TmplPte.u.Flush.Owner = (Address < MmHighestUserAddress) ? 1 : 0;
//__debugbreak(); //__debugbreak();
for (i = 0; i < PageCount; i++) for (i = 0; i < PageCount; i++)
@ -537,7 +550,7 @@ MmCreateVirtualMappingUnsafe(
Pte = MiGetPteForProcess(Process, Address, TRUE); Pte = MiGetPteForProcess(Process, Address, TRUE);
DPRINT1("MmCreateVirtualMappingUnsafe, Address=%p, TmplPte=%p, Pte=%p\n", DPRINT("MmCreateVirtualMappingUnsafe, Address=%p, TmplPte=%p, Pte=%p\n",
Address, TmplPte.u.Long, Pte); Address, TmplPte.u.Long, Pte);
if (InterlockedExchangePte(Pte, TmplPte)) if (InterlockedExchangePte(Pte, TmplPte))
@ -577,6 +590,44 @@ MmCreateVirtualMapping(PEPROCESS Process,
return MmCreateVirtualMappingUnsafe(Process, Address, Protect, Pages, PageCount); return MmCreateVirtualMappingUnsafe(Process, Address, Protect, Pages, PageCount);
} }
static PMMPTE
MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
{
__debugbreak();
return 0;
}
BOOLEAN MmUnmapPageTable(PMMPTE Pt)
{
ASSERT(FALSE);
return 0;
}
static ULONG64 MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
{
MMPTE Pte, *PointerPte;
PointerPte = MmGetPageTableForProcess(Process, Address, FALSE);
if (PointerPte)
{
Pte = *PointerPte;
MmUnmapPageTable(PointerPte);
return Pte.u.Long;
}
return 0;
}
VOID
NTAPI
MmGetPageFileMapping(
PEPROCESS Process,
PVOID Address,
SWAPENTRY* SwapEntry)
{
ULONG64 Entry = MmGetPageEntryForProcess(Process, Address);
*SwapEntry = Entry >> 1;
}
BOOLEAN BOOLEAN
NTAPI NTAPI
MmCreateProcessAddressSpace(IN ULONG MinWs, MmCreateProcessAddressSpace(IN ULONG MinWs,
@ -584,14 +635,19 @@ MmCreateProcessAddressSpace(IN ULONG MinWs,
OUT PULONG_PTR DirectoryTableBase) OUT PULONG_PTR DirectoryTableBase)
{ {
KIRQL OldIrql; KIRQL OldIrql;
PFN_NUMBER TableBasePfn, HyperPfn; PFN_NUMBER TableBasePfn, HyperPfn, HyperPdPfn, HyperPtPfn, WorkingSetPfn;
PMMPTE PointerPte; PMMPTE SystemPte;
MMPTE TempPte, PdePte; MMPTE TempPte, PdePte;
ULONG TableIndex; ULONG TableIndex;
PMMPTE SystemTable; PMMPTE PageTablePointer;
/* No page colors yet */ /* Make sure we don't already have a page directory setup */
Process->NextPageColor = 0; ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
ASSERT(Process->Pcb.DirectoryTableBase[1] == 0);
ASSERT(Process->WorkingSetPage == 0);
/* Choose a process color */
Process->NextPageColor = (USHORT)RtlRandom(&MmProcessColorSeed);
/* Setup the hyperspace lock */ /* Setup the hyperspace lock */
KeInitializeSpinLock(&Process->HyperSpaceLock); KeInitializeSpinLock(&Process->HyperSpaceLock);
@ -599,67 +655,97 @@ MmCreateProcessAddressSpace(IN ULONG MinWs,
/* Lock PFN database */ /* Lock PFN database */
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
/* Get a page for the table base and for hyperspace */ /* Get a page for the table base and one for hyper space. The PFNs for
TableBasePfn = MiRemoveAnyPage(0); these pages will be initialized in MmInitializeProcessAddressSpace,
HyperPfn = MiRemoveAnyPage(0); when we are already attached to the process. */
TableBasePfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
HyperPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
HyperPdPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
HyperPtPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
WorkingSetPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process));
/* Release PFN lock */ /* Release PFN lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
/* Zero both pages */ /* Zero pages */ /// FIXME:
MiZeroPhysicalPage(TableBasePfn);
MiZeroPhysicalPage(HyperPfn); MiZeroPhysicalPage(HyperPfn);
MiZeroPhysicalPage(WorkingSetPfn);
/* Set the base directory pointers */ /* Set the base directory pointers */
Process->WorkingSetPage = WorkingSetPfn;
DirectoryTableBase[0] = TableBasePfn << PAGE_SHIFT; DirectoryTableBase[0] = TableBasePfn << PAGE_SHIFT;
DirectoryTableBase[1] = HyperPfn << PAGE_SHIFT; DirectoryTableBase[1] = HyperPfn << PAGE_SHIFT;
/* Make sure we don't already have a page directory setup */
ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
/* Insert us into the Mm process list */
InsertTailList(&MmProcessList, &Process->MmProcessLinks);
/* Get a PTE to map the page directory */ /* Get a PTE to map the page directory */
PointerPte = MiReserveSystemPtes(1, SystemPteSpace); SystemPte = MiReserveSystemPtes(1, SystemPteSpace);
ASSERT(PointerPte != NULL); ASSERT(SystemPte != NULL);
/* Build it */ /* Get its address */
MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte, PageTablePointer = MiPteToAddress(SystemPte);
PointerPte,
MM_READWRITE,
TableBasePfn);
/* Set it dirty and map it */ /* Build the PTE for the page directory and map it */
PdePte.u.Hard.Dirty = TRUE; PdePte = ValidKernelPte;
MI_WRITE_VALID_PTE(PointerPte, PdePte); PdePte.u.Hard.PageFrameNumber = TableBasePfn;
*SystemPte = PdePte;
/* Now get the page directory (which we'll double map, so call it a page table */ /// architecture specific
SystemTable = MiPteToAddress(PointerPte); //MiInitializePageDirectoryForProcess(
/* Copy all the kernel mappings */ /* Copy the kernel mappings and zero out the rest */
TableIndex = MiAddressToPxi(MmSystemRangeStart); TableIndex = PXE_PER_PAGE / 2;
RtlZeroMemory(PageTablePointer, TableIndex * sizeof(MMPTE));
RtlCopyMemory(&SystemTable[TableIndex], RtlCopyMemory(PageTablePointer + TableIndex,
MiAddressToPxe(MmSystemRangeStart), MiAddressToPxe(0) + TableIndex,
PAGE_SIZE - TableIndex * sizeof(MMPTE)); PAGE_SIZE - TableIndex * sizeof(MMPTE));
/* Now write the PTE/PDE entry for hyperspace itself */
TempPte = ValidKernelPte;
TempPte.u.Hard.PageFrameNumber = HyperPfn;
TableIndex = MiAddressToPxi((PVOID)HYPER_SPACE);
SystemTable[TableIndex] = TempPte;
/* Sanity check */ /* Sanity check */
ASSERT(MiAddressToPxi(MmHyperSpaceEnd) > TableIndex); ASSERT(MiAddressToPxi(MmHyperSpaceEnd) >= TableIndex);
/* Now do the x86 trick of making the PDE a page table itself */ /* Setup a PTE for the page directory mappings */
TableIndex = MiAddressToPxi((PVOID)PTE_BASE); TempPte = ValidKernelPte;
/* Update the self mapping of the PML4 */
TableIndex = MiAddressToPxi((PVOID)PXE_SELFMAP);
TempPte.u.Hard.PageFrameNumber = TableBasePfn; TempPte.u.Hard.PageFrameNumber = TableBasePfn;
SystemTable[TableIndex] = TempPte; PageTablePointer[TableIndex] = TempPte;
/* Let go of the system PTE */ /* Write the PML4 entry for hyperspace */
MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace); TableIndex = MiAddressToPxi((PVOID)HYPER_SPACE);
TempPte.u.Hard.PageFrameNumber = HyperPfn;
PageTablePointer[TableIndex] = TempPte;
/* Map the hyperspace PDPT to the system PTE */
PdePte.u.Hard.PageFrameNumber = HyperPfn;
*SystemPte = PdePte;
__invlpg(PageTablePointer);
/* Write the hyperspace entry for the first PD */
TempPte.u.Hard.PageFrameNumber = HyperPdPfn;
PageTablePointer[0] = TempPte;
/* Map the hyperspace PD to the system PTE */
PdePte.u.Hard.PageFrameNumber = HyperPdPfn;
*SystemPte = PdePte;
__invlpg(PageTablePointer);
/* Write the hyperspace entry for the first PT */
TempPte.u.Hard.PageFrameNumber = HyperPtPfn;
PageTablePointer[0] = TempPte;
/* Map the hyperspace PT to the system PTE */
PdePte.u.Hard.PageFrameNumber = HyperPtPfn;
*SystemPte = PdePte;
__invlpg(PageTablePointer);
/* Write the hyperspace PTE for the working set list index */
TempPte.u.Hard.PageFrameNumber = WorkingSetPfn;
TableIndex = MiAddressToPti(MmWorkingSetList);
PageTablePointer[TableIndex] = TempPte;
/// end architecture specific
/* Release the system PTE */
MiReleaseSystemPtes(SystemPte, 1, SystemPteSpace);
/* Switch to phase 1 initialization */ /* Switch to phase 1 initialization */
ASSERT(Process->AddressSpaceInitialized == 0); ASSERT(Process->AddressSpaceInitialized == 0);