This is a patch i've been keeping for a while. Yes, it's not "as nt does it",
authorArt Yerkes <art.yerkes@gmail.com>
Mon, 28 Jul 2008 14:47:17 +0000 (14:47 +0000)
committerArt Yerkes <art.yerkes@gmail.com>
Mon, 28 Jul 2008 14:47:17 +0000 (14:47 +0000)
but it solves a practical problem, and isn't particularly invasive (the main
change is the call to KdpEnableSafeMem ... everything else could be macroed
out if desired).

This provides armour for kdbg and gdb that avoid faulting on bad addresses by
implementing a simple poor-man's mmu and letting the debuggers use it.

svn path=/trunk/; revision=34904

reactos/ntoskrnl/include/internal/kd.h
reactos/ntoskrnl/kd/i386/kdmemsup.c [new file with mode: 0644]
reactos/ntoskrnl/kd/kdinit.c
reactos/ntoskrnl/kd/wrappers/gdbstub.c
reactos/ntoskrnl/kdbg/kdb.c
reactos/ntoskrnl/ntoskrnl-generic.rbuild
reactos/ntoskrnl/vdm/vdmmain.c

index 26d4a33..a799b3b 100644 (file)
@@ -251,6 +251,27 @@ KdpBochsDebugPrint(
     IN ULONG Length
 );
 
+BOOLEAN
+STDCALL
+KdpSafeReadMemory(
+    IN ULONG_PTR Addr,
+    IN LONG Len,
+    OUT PVOID Value
+);
+
+BOOLEAN
+STDCALL
+KdpSafeWriteMemory(
+    IN ULONG_PTR Addr,
+    IN LONG Len,
+    IN ULONGLONG Value
+);
+
+VOID
+STDCALL
+KdpEnableSafeMem();
+
+
 /* KD GLOBALS  ***************************************************************/
 
 typedef
diff --git a/reactos/ntoskrnl/kd/i386/kdmemsup.c b/reactos/ntoskrnl/kd/i386/kdmemsup.c
new file mode 100644 (file)
index 0000000..c3054ac
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS Kernel
+ * FILE:            ntoskrnl/kd/i386/kdmemsup.c
+ * PURPOSE:         Kernel Debugger Safe Memory Support
+ *
+ * PROGRAMMERS:     arty
+ */
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <internal/debug.h>
+
+#define HIGH_PHYS_MASK 0x80000000
+#define PAGE_TABLE_MASK 0x3ff
+#define BIG_PAGE_SIZE (1<<22)
+#define CR4_PAGE_SIZE_BIT 0x10
+#define PDE_PRESENT_BIT 1
+#define PDE_W_BIT 2
+#define PDE_PS_BIT 0x80
+
+/* VARIABLES ***************************************************************/
+
+extern ULONG MmGlobalKernelPageDirectory[1024];
+static BOOLEAN KdpPhysAccess = FALSE;
+ULONG_PTR IdentityMapAddrHigh, IdentityMapAddrLow;
+extern PFN_TYPE NTAPI MmAllocEarlyPage();
+
+ULONGLONG
+FASTCALL
+KdpPhysRead(ULONG_PTR Addr, LONG Len)
+{
+    ULONGLONG Result = 0;
+    ULONG_PTR OldCR3 = __readcr3(), OldCR4 = __readcr4();
+
+    if (Addr & HIGH_PHYS_MASK)
+    {
+        Addr &= ~HIGH_PHYS_MASK;
+        __writecr3(IdentityMapAddrHigh);
+    }
+    else
+        __writecr3(IdentityMapAddrLow);
+
+    __writecr4(OldCR4|CR4_PAGE_SIZE_BIT); // Turn on large page translation
+    __invlpg((PVOID)Addr);
+
+    switch (Len)
+    {
+    case 8:
+        Result = *((PULONGLONG)Addr);
+        break;
+    case 4:
+        Result = *((PULONG)Addr);
+        break;
+    case 2:
+        Result = *((PUSHORT)Addr);
+        break;
+    case 1:
+        Result = *((PUCHAR)Addr);
+        break;
+    }
+    __writecr4(OldCR4); // Turn off large page translation
+    __writecr3(OldCR3);
+    __invlpg((PVOID)Addr);
+
+    return Result;
+}
+
+
+VOID
+NTAPI
+KdpPhysWrite(ULONG_PTR Addr, LONG Len, ULONGLONG Value)
+{
+    ULONG_PTR OldCR3 = __readcr3(), OldCR4 = __readcr4();
+
+    if (Addr & HIGH_PHYS_MASK)
+    {
+        Addr &= ~HIGH_PHYS_MASK;
+        __writecr3(IdentityMapAddrHigh);
+    }
+    else
+        __writecr3(IdentityMapAddrLow);
+
+    __writecr4(OldCR4|CR4_PAGE_SIZE_BIT); // Turn on large page translation
+    __invlpg((PVOID)Addr);
+
+    switch (Len)
+    {
+    case 8:
+        *((PULONGLONG)Addr) = Value;
+        break;
+    case 4:
+        *((PULONG)Addr) = Value;
+        break;
+    case 2:
+        *((PUSHORT)Addr) = Value;
+        break;
+    case 1:
+        *((PUCHAR)Addr) = Value;
+        break;
+    }
+    __writecr4(OldCR4); // Turn off large page translation
+    __writecr3(OldCR3);    
+    __invlpg((PVOID)Addr);
+}
+
+BOOLEAN
+NTAPI
+KdpTranslateAddress(ULONG_PTR Addr, PULONG_PTR ResultAddr)
+{
+    ULONG_PTR CR3Value = __readcr3();
+    ULONG_PTR CR4Value = __readcr4();
+    ULONG_PTR PageDirectory = (CR3Value & ~(PAGE_SIZE-1)) + 
+        ((Addr >> 22) * sizeof(ULONG));
+    ULONG_PTR PageDirectoryEntry = KdpPhysRead(PageDirectory, sizeof(ULONG));
+
+    /* Not present -> fail */
+    if (!(PageDirectoryEntry & PDE_PRESENT_BIT))
+    {
+        return FALSE;
+    }
+
+    /* Big Page? */
+    if ((PageDirectoryEntry & PDE_PS_BIT) && (CR4Value & CR4_PAGE_SIZE_BIT))
+    {
+        *ResultAddr = (PageDirectoryEntry & ~(BIG_PAGE_SIZE-1)) +
+            (Addr & (BIG_PAGE_SIZE-1));
+        return TRUE;
+    }
+    else
+    {
+        ULONG_PTR PageTableAddr = 
+            (PageDirectoryEntry & ~(PAGE_SIZE-1)) +
+            ((Addr >> PAGE_SHIFT) & PAGE_TABLE_MASK) * sizeof(ULONG);
+        ULONG_PTR PageTableEntry = KdpPhysRead(PageTableAddr, sizeof(ULONG));
+        if (PageTableEntry & PDE_PRESENT_BIT)
+        {
+            *ResultAddr = (PageTableEntry & ~(PAGE_SIZE-1)) +
+                (Addr & (PAGE_SIZE-1));
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+BOOLEAN
+NTAPI
+KdpSafeReadMemory(ULONG_PTR Addr, LONG Len, PVOID Value)
+{
+    ULONG_PTR ResultPhysAddr;
+
+    if (!KdpPhysAccess)
+    {
+        memcpy(Value, (PVOID)Addr, Len);
+        return TRUE;
+    }
+
+    memset(Value, 0, Len);
+            
+    if (!KdpTranslateAddress(Addr, &ResultPhysAddr))
+        return FALSE;
+
+    switch (Len)
+    {
+    case 8:
+        *((PULONGLONG)Value) = KdpPhysRead(ResultPhysAddr, Len);
+        break;
+    case 4:
+        *((PULONG)Value) = KdpPhysRead(ResultPhysAddr, Len);
+        break;
+    case 2:
+        *((PUSHORT)Value) = KdpPhysRead(ResultPhysAddr, Len);
+        break;
+    case 1:
+        *((PUCHAR)Value) = KdpPhysRead(ResultPhysAddr, Len);
+        break;
+    }
+
+    return TRUE;
+}
+
+BOOLEAN
+NTAPI
+KdpSafeWriteMemory(ULONG_PTR Addr, LONG Len, ULONGLONG Value)
+{
+    ULONG_PTR ResultPhysAddr;
+
+    if (!KdpPhysAccess)
+    {
+        memcpy((PVOID)Addr, &Value, Len);
+        return TRUE;
+    }
+            
+    if (!KdpTranslateAddress(Addr, &ResultPhysAddr))
+        return FALSE;
+
+    KdpPhysWrite(ResultPhysAddr, Len, Value);
+    return TRUE;
+}
+
+VOID
+NTAPI
+KdpEnableSafeMem()
+{
+    int i;
+    PULONG IdentityMapVirt;
+    PHYSICAL_ADDRESS IdentityMapPhys, Highest = { };
+
+    if (KdpPhysAccess)
+        return;
+
+    Highest.LowPart = (ULONG)-1;
+    /* Allocate a physical page and map it to copy the phys copy code onto */
+    IdentityMapVirt = (PULONG)MmAllocateContiguousMemory(2 * PAGE_SIZE, Highest);
+    IdentityMapPhys = MmGetPhysicalAddress(IdentityMapVirt);
+    IdentityMapAddrHigh = IdentityMapPhys.LowPart;
+
+    /* Copy the kernel space */
+    memcpy(IdentityMapVirt,
+           MmGlobalKernelPageDirectory,
+           PAGE_SIZE);
+
+    /* Set up 512 4Mb pages (high 2Gig identity mapped) */
+    for (i = 0; i < 512; i++)
+    {
+        IdentityMapVirt[i] = 
+            HIGH_PHYS_MASK | (i << 22) | PDE_PS_BIT | PDE_W_BIT | PDE_PRESENT_BIT;
+    }
+
+    /* Allocate a physical page and map it to copy the phys copy code onto */
+    IdentityMapAddrLow = IdentityMapAddrHigh + PAGE_SIZE;
+    IdentityMapVirt += PAGE_SIZE / sizeof(ULONG);
+
+    /* Copy the kernel space */
+    memcpy(IdentityMapVirt,
+           MmGlobalKernelPageDirectory,
+           PAGE_SIZE);
+
+    /* Set up 512 4Mb pages (low 2Gig identity mapped) */
+    for (i = 0; i < 512; i++)
+    {
+        IdentityMapVirt[i] = (i << 22) | PDE_PS_BIT | PDE_W_BIT | PDE_PRESENT_BIT;
+    }
+
+    KdpPhysAccess = TRUE;
+}
index 927a89b..dfbb09f 100644 (file)
@@ -257,6 +257,8 @@ KdInitSystem(ULONG BootPhase,
         if (WrapperInitRoutine) WrapperInitRoutine(&WrapperTable, 0);
         return TRUE;
     }
+    else
+       KdpEnableSafeMem();
 
     /* Call the Initialization Routines of the Registered Providers */
     KdpCallInitRoutine(BootPhase);
index 1e23ef9..aedf32d 100644 (file)
@@ -322,19 +322,9 @@ static volatile void *GspAccessLocation = NULL;
 static CHAR
 GspReadMemSafe(PCHAR Address)
 {
-  CHAR ch;
-
-  if (NULL == Address)
-    {
-      GspMemoryError = TRUE;
-      return '\0';
-    }
-
-  GspAccessLocation = Address;
-  ch = *Address;
-  GspAccessLocation = NULL;
-
-  return ch;
+    CHAR ch;
+    KdpSafeReadMemory((ULONG_PTR)Address, 1, &ch);
+    return ch;
 }
 
 /* Convert the memory pointed to by Address into hex, placing result in Buffer */
@@ -455,19 +445,11 @@ GspHex2Mem(PCHAR Buffer,
   return Buffer + 2 * Count;
 }
 
-static CHAR
-GspWriteMemSafeGetContent(PVOID Context, ULONG Offset)
-{
-  ASSERT(0 == Offset);
-
-  return *((PCHAR) Context);
-}
-
 static void
 GspWriteMemSafe(PCHAR Address,
   CHAR Ch)
 {
-  GspWriteMem(Address, 1, TRUE, GspWriteMemSafeGetContent, &Ch);
+    KdpSafeWriteMemory((ULONG_PTR)Address, 1, Ch);
 }
 
 
index 0edf8a5..a07882a 100644 (file)
@@ -1658,21 +1658,31 @@ KdbpSafeReadMemory(OUT PVOID Dest,
                    IN PVOID Src,
                    IN ULONG Bytes)
 {
-   NTSTATUS Status = STATUS_SUCCESS;
+    BOOLEAN Result = TRUE;
 
-   _SEH_TRY
-   {
-      RtlCopyMemory(Dest,
-                    Src,
-                    Bytes);
-   }
-   _SEH_HANDLE
-   {
-      Status = _SEH_GetExceptionCode();
-   }
-   _SEH_END;
+    switch (Bytes)
+    {
+    case 1:
+    case 2:
+    case 4:
+    case 8:
+        Result = KdpSafeReadMemory((ULONG_PTR)Src, Bytes, Dest);
+        break;
+    default:
+    {
+        ULONG_PTR Start, End, Write;
+        for (Start = (ULONG_PTR)Src, 
+                 End = Start + Bytes, 
+                 Write = (ULONG_PTR)Dest; 
+             Result && (Start < End); 
+             Start++, Write++)
+            if (!KdpSafeReadMemory(Start, 1, (PVOID)Write))
+                Result = FALSE;
+        break;
+    }
+    }
 
-   return Status;
+    return Result ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
 }
 
 NTSTATUS
@@ -1680,19 +1690,16 @@ KdbpSafeWriteMemory(OUT PVOID Dest,
                     IN PVOID Src,
                     IN ULONG Bytes)
 {
-   NTSTATUS Status = STATUS_SUCCESS;
-
-   _SEH_TRY
-   {
-      RtlCopyMemory(Dest,
-                    Src,
-                    Bytes);
-   }
-   _SEH_HANDLE
-   {
-      Status = _SEH_GetExceptionCode();
-   }
-   _SEH_END;
-
-   return Status;
+    BOOLEAN Result;
+    ULONG_PTR Start, End, Write;
+
+    for (Start = (ULONG_PTR)Src, 
+             End = Start + Bytes, 
+             Write = (ULONG_PTR)Dest; 
+         Result && (Start < End); 
+         Start++, Write++)
+        if (!KdpSafeReadMemory(Start, 1, (PVOID)Write))
+            Result = FALSE;
+
+    return Result ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
 }
index 80b9398..2696ae5 100644 (file)
                        <file>pnproot.c</file>
                </directory>
        </directory>
+       <if property="DBG" value="1">
+               <directory name="kd">
+                       <directory name="i386">
+                               <file>kdmemsup.c</file>
+                       </directory>
+               </directory>
+       </if>
        <if property="_WINKD_" value="0">
                <directory name="kdbg">
                        <if property="ARCH" value="i386">
index 57ab312..880c44a 100644 (file)
@@ -23,16 +23,10 @@ VOID
 INIT_FUNCTION
 NtEarlyInitVdm(VOID)
 {
-    /* GCC 3.4 hack */
-    PVOID start = (PVOID)0x0;
-
-    /*
-     * Save various BIOS data tables. At this point the lower 4MB memory
-     * map is still active so we can just copy the data from low memory.
-     * HACK HACK HACK: We should just map Physical Memory!!!
-     */
+    PCHAR start = MmCreateHyperspaceMapping(0);
     memcpy(OrigIVT, start, 1024);
-    memcpy(OrigBDA, (PVOID)0x400, 256);
+    memcpy(OrigBDA, start+0x400, 256);
+    MmDeleteHyperspaceMapping(start);
 }
 
 VOID