* Call KeBugcheck in MmDeletePageTable/MmFreePageTable if the

address points to the kernel address space.
* Check if an other process has inserted a kernel page directory
  entry while waiting for a page (MmGetPageEntry/MmGetPageEntry2).
* Check the kernel page directory only for an entry if the
  address points to the kernel address space (MmGetPageEntry1/2,
  MmDeleteVirtualMapping and MmDeletePageFileMapping).
* Disabled MmEnableVirtualMapping/MmDisableVirtualMapping.
  There is no difference between an entry with disabled mapping and
  a swap entry.

svn path=/trunk/; revision=3700
This commit is contained in:
Hartmut Birr 2002-11-05 20:39:03 +00:00
parent a4b5d8a978
commit 3d3d96c5d6

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* $Id: page.c,v 1.45 2002/10/01 19:27:25 chorns Exp $ /* $Id: page.c,v 1.46 2002/11/05 20:39:03 hbirr Exp $
* *
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/i386/page.c * FILE: ntoskrnl/mm/i386/page.c
@ -161,7 +161,7 @@ NTSTATUS MmCopyMmInfo(PEPROCESS Src, PEPROCESS Dest)
} }
DPRINT("Addr %x\n",PAGETABLE_MAP / (4*1024*1024)); DPRINT("Addr %x\n",PAGETABLE_MAP / (4*1024*1024));
PageDirectory[PAGETABLE_MAP / (4*1024*1024)] = PageDirectory[PAGETABLE_MAP / (4*1024*1024)] =
(ULONG)PhysPageDirectory.QuadPart | 0x7; PhysPageDirectory.u.LowPart | PA_PRESENT | PA_READWRITE;
ExUnmapPage(PageDirectory); ExUnmapPage(PageDirectory);
@ -180,7 +180,8 @@ VOID MmDeletePageTable(PEPROCESS Process, PVOID Address)
*(ADDR_TO_PDE(Address)) = 0; *(ADDR_TO_PDE(Address)) = 0;
if (Address >= (PVOID)KERNEL_BASE) if (Address >= (PVOID)KERNEL_BASE)
{ {
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0; KeBugCheck(0);
// MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
} }
FLUSH_TLB; FLUSH_TLB;
if (Process != NULL && Process != CurrentProcess) if (Process != NULL && Process != CurrentProcess)
@ -200,6 +201,7 @@ VOID MmFreePageTable(PEPROCESS Process, PVOID Address)
{ {
KeAttachProcess(Process); KeAttachProcess(Process);
} }
PageTable = (PULONG)PAGE_ROUND_DOWN((PVOID)ADDR_TO_PTE(Address)); PageTable = (PULONG)PAGE_ROUND_DOWN((PVOID)ADDR_TO_PTE(Address));
for (i = 0; i < 1024; i++) for (i = 0; i < 1024; i++)
{ {
@ -212,12 +214,17 @@ VOID MmFreePageTable(PEPROCESS Process, PVOID Address)
} }
npage = *(ADDR_TO_PDE(Address)); npage = *(ADDR_TO_PDE(Address));
*(ADDR_TO_PDE(Address)) = 0; *(ADDR_TO_PDE(Address)) = 0;
FLUSH_TLB;
if (Address >= (PVOID)KERNEL_BASE) if (Address >= (PVOID)KERNEL_BASE)
{ {
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0; // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
KeBugCheck(0);
} }
else
{
MmReleasePageMemoryConsumer(MC_NPPOOL, PTE_TO_PAGE(npage)); MmReleasePageMemoryConsumer(MC_NPPOOL, PTE_TO_PAGE(npage));
FLUSH_TLB; }
if (Process != NULL && Process != CurrentProcess) if (Process != NULL && Process != CurrentProcess)
{ {
KeDetachProcess(); KeDetachProcess();
@ -229,41 +236,66 @@ NTSTATUS MmGetPageEntry2(PVOID PAddress, PULONG* Pte, BOOLEAN MayWait)
* FUNCTION: Get a pointer to the page table entry for a virtual address * FUNCTION: Get a pointer to the page table entry for a virtual address
*/ */
{ {
PULONG Pde; PULONG Pde, kePde;
ULONG Address = (ULONG)PAddress;
PHYSICAL_ADDRESS npage; PHYSICAL_ADDRESS npage;
BOOLEAN Free = FALSE;
NTSTATUS Status;
KIRQL oldIrql;
DPRINT("MmGetPageEntry(Address %x)\n", Address); DPRINT("MmGetPageEntry(Address %x)\n", PAddress);
Pde = ADDR_TO_PDE(Address); Pde = ADDR_TO_PDE(PAddress);
if ((*Pde) == 0) if (*Pde == 0)
{ {
if (Address >= KERNEL_BASE && if (PAddress >= (PVOID)KERNEL_BASE)
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
{ {
(*Pde) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)]; kePde = MmGlobalKernelPageDirectory + ADDR_TO_PDE_OFFSET(PAddress);
oldIrql = KeRaiseIrqlToSynchLevel();
if (*kePde != 0)
{
*Pde = *kePde;
FLUSH_TLB; FLUSH_TLB;
} }
else else
{ {
NTSTATUS Status; KeLowerIrql(oldIrql);
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, MayWait, &npage);
if (!NT_SUCCESS(Status))
{
KeBugCheck(0);
}
oldIrql = KeRaiseIrqlToSynchLevel();
/* An other thread can set this pde entry, we must check again */
if (*kePde == 0)
{
*kePde = npage.u.LowPart | PA_PRESENT | PA_READWRITE;
}
else
{
Free = TRUE;
}
*Pde = *kePde;
FLUSH_TLB;
}
KeLowerIrql(oldIrql);
}
else
{
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, MayWait, &npage); Status = MmRequestPageMemoryConsumer(MC_NPPOOL, MayWait, &npage);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
return(Status); return(Status);
} }
(*Pde) = npage.QuadPart | 0x7; *Pde = npage.u.LowPart | PA_PRESENT | PA_READWRITE | PA_USER;
if (Address >= KERNEL_BASE)
{
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] =
*Pde;
}
memset((PVOID)PAGE_ROUND_DOWN(ADDR_TO_PTE(Address)), 0, PAGE_SIZE);
FLUSH_TLB; FLUSH_TLB;
} }
} }
*Pte = ADDR_TO_PTE(Address); *Pte = (PULONG)ADDR_TO_PTE(PAddress);
return(STATUS_SUCCESS); if (Free)
{
MmReleasePageMemoryConsumer(MC_NPPOOL, npage);
}
return STATUS_SUCCESS;
} }
ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address) ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
@ -288,27 +320,30 @@ ULONG MmGetPageEntry1(PVOID PAddress)
* FUNCTION: Get a pointer to the page table entry for a virtual address * FUNCTION: Get a pointer to the page table entry for a virtual address
*/ */
{ {
PULONG page_tlb; PULONG Pde, kePde;
PULONG page_dir; ULONG Entry = 0;
ULONG Address = (ULONG)PAddress;
DPRINT("MmGetPageEntry(Address %x)\n", Address); DPRINT("MmGetPageEntry(Address %x)\n", PAddress);
page_dir = ADDR_TO_PDE(Address); Pde = ADDR_TO_PDE(PAddress);
if ((*page_dir) == 0 && if (*Pde == 0)
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
{ {
(*page_dir) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)]; if (PAddress >= (PVOID)KERNEL_BASE)
{
kePde = MmGlobalKernelPageDirectory + ADDR_TO_PDE_OFFSET(PAddress);
if (*kePde != 0)
{
*Pde = *kePde;
FLUSH_TLB; FLUSH_TLB;
Entry = *(PULONG)ADDR_TO_PTE(PAddress);
} }
DPRINT("page_dir %x *page_dir %x\n",page_dir,*page_dir); }
if ((*page_dir) == 0) }
else
{ {
return(0); Entry = *(PULONG)ADDR_TO_PTE(PAddress);
} }
page_tlb = ADDR_TO_PTE(Address); return Entry;
DPRINT("page_tlb %x\n",page_tlb);
return(*page_tlb);
} }
ULONG MmGetPageEntryForProcess1(PEPROCESS Process, PVOID Address) ULONG MmGetPageEntryForProcess1(PEPROCESS Process, PVOID Address)
@ -343,7 +378,7 @@ MmGetPhysicalAddressForProcess(PEPROCESS Process,
} }
return(PTE_TO_PAGE(PageEntry)); return(PTE_TO_PAGE(PageEntry));
} }
#if 0
VOID VOID
MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOL* WasDirty, PHYSICAL_ADDRESS* PhysicalAddr) MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOL* WasDirty, PHYSICAL_ADDRESS* PhysicalAddr)
/* /*
@ -413,7 +448,7 @@ MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOL* WasDirty, PHYSIC
PhysicalAddr->u.LowPart = PAGE_MASK(Pte); PhysicalAddr->u.LowPart = PAGE_MASK(Pte);
} }
} }
#endif
VOID VOID
MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOL FreePage, MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOL FreePage,
BOOL* WasDirty, PHYSICAL_ADDRESS* PhysicalAddr) BOOL* WasDirty, PHYSICAL_ADDRESS* PhysicalAddr)
@ -422,7 +457,7 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOL FreePage,
*/ */
{ {
ULONG Pte; ULONG Pte;
PULONG Pde; PULONG Pde, kePde;
PEPROCESS CurrentProcess = PsGetCurrentProcess(); PEPROCESS CurrentProcess = PsGetCurrentProcess();
BOOLEAN WasValid; BOOLEAN WasValid;
@ -440,13 +475,17 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOL FreePage,
* the global page directory. * the global page directory.
*/ */
Pde = ADDR_TO_PDE(Address); Pde = ADDR_TO_PDE(Address);
if ((*Pde) == 0 && if (*Pde == 0 && Address >= (PVOID)KERNEL_BASE)
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
{ {
(*Pde) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)]; kePde = MmGlobalKernelPageDirectory + ADDR_TO_PDE_OFFSET(Address);
if (*kePde != 0)
{
*Pde = *kePde;
FLUSH_TLB; FLUSH_TLB;
} }
if ((*Pde) == 0) }
if (*Pde == 0)
{ {
if (Process != NULL && Process != CurrentProcess) if (Process != NULL && Process != CurrentProcess)
{ {
@ -483,7 +522,7 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOL FreePage,
*/ */
if (Process != NULL && WasValid && if (Process != NULL && WasValid &&
Process->AddressSpace.PageTableRefCountTable != NULL && Process->AddressSpace.PageTableRefCountTable != NULL &&
ADDR_TO_PAGE_TABLE(Address) < 768) Address < (PVOID)KERNEL_BASE)
{ {
PUSHORT Ptrc; PUSHORT Ptrc;
@ -532,7 +571,7 @@ MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
*/ */
{ {
ULONG Pte; ULONG Pte;
PULONG Pde; PULONG Pde, kePde;
PEPROCESS CurrentProcess = PsGetCurrentProcess(); PEPROCESS CurrentProcess = PsGetCurrentProcess();
BOOLEAN WasValid = FALSE; BOOLEAN WasValid = FALSE;
@ -550,13 +589,19 @@ MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
* the global page directory. * the global page directory.
*/ */
Pde = ADDR_TO_PDE(Address); Pde = ADDR_TO_PDE(Address);
if ((*Pde) == 0 && if (*Pde == 0)
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
{ {
(*Pde) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)]; if (Address >= (PVOID)KERNEL_BASE)
{
kePde = MmGlobalKernelPageDirectory + ADDR_TO_PDE_OFFSET(Address);
if (*kePde != 0)
{
*Pde = *kePde;
FLUSH_TLB; FLUSH_TLB;
} }
if ((*Pde) == 0) }
}
if (*Pde == 0)
{ {
if (Process != NULL && Process != CurrentProcess) if (Process != NULL && Process != CurrentProcess)
{ {
@ -572,12 +617,14 @@ MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
Pte = (ULONG)InterlockedExchange((PLONG)ADDR_TO_PTE(Address), 0); Pte = (ULONG)InterlockedExchange((PLONG)ADDR_TO_PTE(Address), 0);
FLUSH_TLB; FLUSH_TLB;
WasValid = PAGE_MASK(Pte) == 0 ? FALSE : TRUE;
/* /*
* Decrement the reference count for this page table. * Decrement the reference count for this page table.
*/ */
if (Process != NULL && WasValid && if (Process != NULL && WasValid &&
Process->AddressSpace.PageTableRefCountTable != NULL && Process->AddressSpace.PageTableRefCountTable != NULL &&
ADDR_TO_PAGE_TABLE(Address) < 768) Address < (PVOID)KERNEL_BASE)
{ {
PUSHORT Ptrc; PUSHORT Ptrc;
@ -607,61 +654,73 @@ MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
BOOLEAN BOOLEAN
Mmi386MakeKernelPageTableGlobal(PVOID PAddress) Mmi386MakeKernelPageTableGlobal(PVOID PAddress)
{ {
PULONG page_dir; PULONG kePde, Pde;
ULONG Address = (ULONG)PAddress;
page_dir = ADDR_TO_PDE(Address); Pde = ADDR_TO_PDE(PAddress);
if ((*page_dir) == 0 && if (*Pde == 0)
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
{ {
(*page_dir) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)]; kePde = MmGlobalKernelPageDirectory + ADDR_TO_PDE_OFFSET(PAddress);
if (*kePde != 0)
{
*Pde = *kePde;
FLUSH_TLB; FLUSH_TLB;
return(TRUE); return(TRUE);
} }
}
return(FALSE); return(FALSE);
} }
BOOLEAN MmIsPageTablePresent(PVOID PAddress) BOOLEAN MmIsPageTablePresent(PVOID PAddress)
{ {
PULONG page_dir; PULONG Pde, kePde;
ULONG Address = (ULONG)PAddress;
page_dir = ADDR_TO_PDE(Address); Pde = ADDR_TO_PDE(PAddress);
if ((*page_dir) == 0 && if (*Pde == 0)
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
{ {
(*page_dir) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)]; kePde = MmGlobalKernelPageDirectory + ADDR_TO_PDE_OFFSET(PAddress);
if (*kePde != 0)
{
*Pde = *kePde;
FLUSH_TLB; FLUSH_TLB;
return TRUE;
} }
return((*page_dir) == 0); }
return FALSE;
} }
NTSTATUS MmCreatePageTable(PVOID PAddress) NTSTATUS MmCreatePageTable(PVOID PAddress)
{ {
PULONG page_dir; PULONG Pde, kePde;
ULONG Address = (ULONG)PAddress;
PHYSICAL_ADDRESS npage; PHYSICAL_ADDRESS npage;
DPRINT("MmGetPageEntry(Address %x)\n", Address);
page_dir = ADDR_TO_PDE(Address);
DPRINT("page_dir %x *page_dir %x\n",page_dir,*page_dir);
if ((*page_dir) == 0 &&
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
{
(*page_dir) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)];
FLUSH_TLB;
}
if ((*page_dir) == 0)
{
NTSTATUS Status; NTSTATUS Status;
DPRINT("MmGetPageEntry(Address %x)\n", PAddress);
Pde = ADDR_TO_PDE(PAddress);
DPRINT("page_dir %x *page_dir %x\n", Pde, *Pde);
if (*Pde == 0 && PAddress >= (PVOID)KERNEL_BASE)
{
kePde = MmGlobalKernelPageDirectory + ADDR_TO_PDE_OFFSET(PAddress);
if (*kePde != 0)
{
*Pde = *kePde;
FLUSH_TLB;
return STATUS_SUCCESS;
}
/* Should we create a kernel page table? */
DPRINT1("!!!!!!!!!!!!!!!!!!\n");
return STATUS_UNSUCCESSFUL;
}
if (*Pde == 0)
{
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &npage); Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &npage);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
return(Status); return(Status);
} }
(*page_dir) = npage.QuadPart | 0x7; MiZeroPage(npage);
memset((PVOID)PAGE_ROUND_DOWN(ADDR_TO_PTE(Address)), 0, PAGE_SIZE); *Pde = npage.u.LowPart | PA_PRESENT | PA_READWRITE | PA_USER;
FLUSH_TLB; FLUSH_TLB;
} }
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
@ -672,36 +731,69 @@ PULONG MmGetPageEntry(PVOID PAddress)
* FUNCTION: Get a pointer to the page table entry for a virtual address * FUNCTION: Get a pointer to the page table entry for a virtual address
*/ */
{ {
PULONG page_tlb; PULONG Pde, kePde;
PULONG page_dir;
ULONG Address = (ULONG)PAddress;
PHYSICAL_ADDRESS npage; PHYSICAL_ADDRESS npage;
KIRQL oldIrql;
BOOLEAN Free = FALSE;
NTSTATUS Status;
DPRINT("MmGetPageEntry(Address %x)\n", Address); DPRINT("MmGetPageEntry(Address %x)\n", PAddress);
page_dir = ADDR_TO_PDE(Address); Pde = ADDR_TO_PDE(PAddress);
DPRINT("page_dir %x *page_dir %x\n",page_dir,*page_dir); DPRINT("page_dir %x *page_dir %x\n",Pde,*Pde);
if ((*page_dir) == 0 && if (*Pde == 0)
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
{ {
(*page_dir) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)]; if (PAddress >= (PVOID)KERNEL_BASE)
{
oldIrql = KeRaiseIrqlToSynchLevel();
kePde = MmGlobalKernelPageDirectory + ADDR_TO_PDE_OFFSET(PAddress);
if (*kePde != 0)
{
*Pde = *kePde;
FLUSH_TLB; FLUSH_TLB;
} }
if ((*page_dir) == 0) else
{ {
NTSTATUS Status; KeLowerIrql(oldIrql);
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &npage); Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &npage);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
KeBugCheck(0); KeBugCheck(0);
} }
(*page_dir) = npage.QuadPart | 0x7; MiZeroPage(npage);
memset((PVOID)PAGE_ROUND_DOWN(ADDR_TO_PTE(Address)), 0, PAGE_SIZE); oldIrql = KeRaiseIrqlToSynchLevel();
if (*kePde != 0)
{
*Pde = *kePde;
FLUSH_TLB;
Free = TRUE;
}
else
{
*Pde = *kePde = npage.u.LowPart | PA_PRESENT | PA_READWRITE;
FLUSH_TLB; FLUSH_TLB;
} }
page_tlb = ADDR_TO_PTE(Address); }
DPRINT("page_tlb %x\n",page_tlb); KeLowerIrql(oldIrql);
return(page_tlb); }
else
{
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &npage);
if (!NT_SUCCESS(Status))
{
KeBugCheck(0);
}
MiZeroPage(npage);
*Pde = npage.u.LowPart | PA_PRESENT | PA_READWRITE | PA_USER;
FLUSH_TLB;
}
if (Free)
{
MmReleasePageMemoryConsumer(MC_NPPOOL, npage);
}
}
return ADDR_TO_PTE(PAddress);
} }
BOOLEAN MmIsDirtyPage(PEPROCESS Process, PVOID Address) BOOLEAN MmIsDirtyPage(PEPROCESS Process, PVOID Address)
@ -770,7 +862,7 @@ VOID MmSetDirtyPage(PEPROCESS Process, PVOID Address)
KeDetachProcess(); KeDetachProcess();
} }
} }
#if 0
VOID MmEnableVirtualMapping(PEPROCESS Process, PVOID Address) VOID MmEnableVirtualMapping(PEPROCESS Process, PVOID Address)
{ {
PULONG PageEntry; PULONG PageEntry;
@ -788,7 +880,7 @@ VOID MmEnableVirtualMapping(PEPROCESS Process, PVOID Address)
KeDetachProcess(); KeDetachProcess();
} }
} }
#endif
BOOLEAN MmIsPagePresent(PEPROCESS Process, PVOID Address) BOOLEAN MmIsPagePresent(PEPROCESS Process, PVOID Address)
{ {
return((MmGetPageEntryForProcess1(Process, Address)) & PA_PRESENT); return((MmGetPageEntryForProcess1(Process, Address)) & PA_PRESENT);