[NTOS]: This is why you shouldn't let Antoine Dodson commit code.
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / pagfault.c
index ac56738..635458e 100644 (file)
@@ -42,9 +42,14 @@ MiCheckVirtualAddress(IN PVOID VirtualAddress,
         return MmSharedUserDataPte;
     }
     
-    /* Find the VAD, it must exist, since we only handle PEB/TEB */
+    /* Find the VAD, it might not exist if the address is bogus */
     Vad = MiLocateAddress(VirtualAddress);
-    ASSERT(Vad);
+    if (!Vad)
+    {
+        /* Bogus virtual address */
+        *ProtectCode = MM_NOACCESS;
+        return NULL;
+    }
     
     /* This must be a TEB/PEB VAD */
     ASSERT(Vad->u.VadFlags.PrivateMemory == TRUE);
@@ -99,18 +104,15 @@ MiCheckPdeForPagedPool(IN PVOID Address)
     //
     if (PointerPde->u.Hard.Valid == 0)
     {
-#ifndef _M_AMD64
-        /* This seems to be making the assumption that one PDE is one page long */
-        C_ASSERT(PAGE_SIZE == (PD_COUNT * (sizeof(MMPTE) * PDE_COUNT)));
-#endif
-        
+#ifdef _M_AMD64
+        ASSERT(FALSE);
+#else
         //
         // Copy it from our double-mapped system page directory
         //
         InterlockedExchangePte(PointerPde,
-                               MmSystemPagePtes[((ULONG_PTR)PointerPde &
-                                                 (PAGE_SIZE - 1)) /
-                                                sizeof(MMPTE)].u.Long);
+                               MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)].u.Long);
+#endif
     }
     
     //
@@ -172,9 +174,10 @@ MiResolveDemandZeroFault(IN PVOID Address,
                          IN PEPROCESS Process,
                          IN KIRQL OldIrql)
 {
-    PFN_NUMBER PageFrameNumber;
+    PFN_NUMBER PageFrameNumber = 0;
     MMPTE TempPte;
     BOOLEAN NeedZero = FALSE;
+    ULONG Color;
     DPRINT("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
             Address,
             Process);
@@ -189,9 +192,17 @@ MiResolveDemandZeroFault(IN PVOID Address,
         /* No forking yet */
         ASSERT(Process->ForkInProgress == NULL);
         
+        /* Get process color */
+        Color = MI_GET_NEXT_PROCESS_COLOR(Process);
+        
         /* We'll need a zero page */
         NeedZero = TRUE;
     }
+    else
+    {
+        /* Get the next system page color */
+        Color = MI_GET_NEXT_COLOR();
+    }
         
     //
     // Lock the PFN database
@@ -199,9 +210,21 @@ MiResolveDemandZeroFault(IN PVOID Address,
     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
     ASSERT(PointerPte->u.Hard.Valid == 0);
     
-    /* Get a page */
-    PageFrameNumber = MiRemoveAnyPage(0);
-    DPRINT("New pool page: %lx\n", PageFrameNumber);
+    /* Do we need a zero page? */
+    if (NeedZero)
+    {
+        /* Try to get one, if we couldn't grab a free page and zero it */
+        PageFrameNumber = MiRemoveZeroPageSafe(Color);
+        if (PageFrameNumber) NeedZero = FALSE;
+    }
+    
+    /* Did we get a page? */
+    if (!PageFrameNumber)
+    {
+        /* We either failed to find a zero page, or this is a system request */
+        PageFrameNumber = MiRemoveAnyPage(Color);
+        DPRINT("New pool page: %lx\n", PageFrameNumber);
+    }
     
     /* Initialize it */
     MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
@@ -456,6 +479,7 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
     ULONG ProtectionCode;
     PMMVAD Vad;
     PFN_NUMBER PageFrameIndex;
+    ULONG Color;
     DPRINT("ARM3 FAULT AT: %p\n", Address);
     
     //
@@ -463,7 +487,11 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
     //
     PointerPte = MiAddressToPte(Address);
     PointerPde = MiAddressToPde(Address);
-    
+#if (_MI_PAGING_LEVELS >= 3)
+    /* We need the PPE and PXE addresses */
+    ASSERT(FALSE);
+#endif
+
     //
     // Check for dispatch-level snafu
     //
@@ -488,6 +516,11 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
         //
         if (Mode == UserMode) return STATUS_ACCESS_VIOLATION;
         
+#if (_MI_PAGING_LEVELS >= 3)
+        /* Need to check PXE and PDE validity */
+        ASSERT(FALSE);
+#endif
+
         //
         // Is the PDE valid?
         //
@@ -497,12 +530,12 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
             // Debug spew (eww!)
             //
             DPRINT("Invalid PDE\n");
-            
+#if (_MI_PAGING_LEVELS == 2) 
             //
             // Handle mapping in "Special" PDE directoreis
             //
             MiCheckPdeForPagedPool(Address);
-            
+#endif
             //
             // Now we SHOULD be good
             //
@@ -556,7 +589,7 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
             // This might happen...not sure yet
             //
             DPRINT1("FAULT ON PAGE TABLES: %p %lx %lx!\n", Address, *PointerPte, *PointerPde);
-            
+#if (_MI_PAGING_LEVELS == 2) 
             //
             // Map in the page table
             //
@@ -565,7 +598,7 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
                 DPRINT1("PAGE TABLES FAULTED IN!\n");
                 return STATUS_SUCCESS;
             }
-            
+#endif
             //
             // Otherwise the page table doesn't actually exist
             //
@@ -609,10 +642,28 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
             return STATUS_SUCCESS;
         }
         
-        //
-        // We don't implement prototype PTEs
-        //
-        ASSERT(TempPte.u.Soft.Prototype == 0);
+        /* Check one kind of prototype PTE */
+        if (TempPte.u.Soft.Prototype)
+        {
+            /* The one used for protected pool... */
+            ASSERT(MmProtectFreedNonPagedPool == TRUE);
+            
+            /* Make sure protected pool is on, and that this is a pool address */
+            if ((MmProtectFreedNonPagedPool) &&
+                (((Address >= MmNonPagedPoolStart) &&
+                  (Address < (PVOID)((ULONG_PTR)MmNonPagedPoolStart +
+                                     MmSizeOfNonPagedPoolInBytes))) ||
+                 ((Address >= MmNonPagedPoolExpansionStart) &&
+                  (Address < MmNonPagedPoolEnd))))
+            {
+                /* Bad boy, bad boy, whatcha gonna do, whatcha gonna do when ARM3 comes for you! */
+                KeBugCheckEx(DRIVER_CAUGHT_MODIFYING_FREED_POOL,
+                             (ULONG_PTR)Address,
+                             StoreInstruction,
+                             Mode,
+                             4);
+            }
+        }
         
         //
         // We don't implement transition PTEs
@@ -650,6 +701,11 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
     /* Lock the working set */
     MiLockProcessWorkingSet(CurrentProcess, CurrentThread);
     
+#if (_MI_PAGING_LEVELS >= 3)
+    /* Need to check/handle PPE and PXE validity too */
+    ASSERT(FALSE);
+#endif
+
     /* First things first, is the PDE valid? */
     ASSERT(PointerPde != MiAddressToPde(PTE_BASE));
     ASSERT(PointerPde->u.Hard.LargePage == 0);
@@ -679,6 +735,10 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
 
         /* We should come back with APCs enabled, and with a valid PDE */
         ASSERT(KeAreAllApcsDisabled() == TRUE);
+#if (_MI_PAGING_LEVELS >= 3)
+        /* Need to check/handle PPE and PXE validity too */
+        ASSERT(FALSE);
+#endif
         ASSERT(PointerPde->u.Hard.Valid == 1);
     }
 
@@ -688,8 +748,23 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
 
     /* Check if this address range belongs to a valid allocation (VAD) */
     ProtoPte = MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
-    ASSERT(ProtectionCode != MM_NOACCESS);
-
+    if (ProtectionCode == MM_NOACCESS)
+    {
+        /* This is a bogus VA */
+        Status = STATUS_ACCESS_VIOLATION;
+        
+        /* Could be a not-yet-mapped paged pool page table */
+#if (_MI_PAGING_LEVELS == 2) 
+        MiCheckPdeForPagedPool(Address);
+#endif
+        /* See if that fixed it */
+        if (PointerPte->u.Hard.Valid == 1) Status = STATUS_SUCCESS;
+        
+        /* Return the status */
+        MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
+        return Status;
+    }
+    
     /* Did we get a prototype PTE back? */
     if (!ProtoPte)
     {
@@ -698,19 +773,25 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
 
         /* Lock the PFN database since we're going to grab a page */
         OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+        
+        /* Try to get a zero page */
+        Color = MI_GET_NEXT_PROCESS_COLOR(CurrentProcess);
+        PageFrameIndex = MiRemoveZeroPageSafe(Color);
+        if (!PageFrameIndex)
+        {
+            /* Grab a page out of there. Later we should grab a colored zero page */
+            PageFrameIndex = MiRemoveAnyPage(Color);
+            ASSERT(PageFrameIndex);
 
-        /* Grab a page out of there. Later we should grab a colored zero page */
-        PageFrameIndex = MiRemoveAnyPage(0);
-        ASSERT(PageFrameIndex);
-
-        /* Release the lock since we need to do some zeroing */
-        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+            /* Release the lock since we need to do some zeroing */
+            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
 
-        /* Zero out the page, since it's for user-mode */
-        MiZeroPfn(PageFrameIndex);
+            /* Zero out the page, since it's for user-mode */
+            MiZeroPfn(PageFrameIndex);
 
-        /* Grab the lock again so we can initialize the PFN entry */
-        OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+            /* Grab the lock again so we can initialize the PFN entry */
+            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+        }
 
         /* Initialize the PFN entry now */
         MiInitializePfn(PageFrameIndex, PointerPte, 1);