[SOFT386]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Fri, 13 Sep 2013 23:01:18 +0000 (23:01 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Fri, 13 Sep 2013 23:01:18 +0000 (23:01 +0000)
Start implementing paging support.
Add support for exception error codes.

svn path=/branches/ntvdm/; revision=60089

lib/soft386/common.c
lib/soft386/common.h

index 5aba195..00045f5 100644 (file)
@@ -28,6 +28,18 @@ Soft386GetCurrentPrivLevel(PSOFT386_STATE State)
     return GET_SEGMENT_RPL(State->SegmentRegs[SOFT386_REG_CS].Selector);
 }
 
+static
+inline
+ULONG
+Soft386GetPageTableEntry(PSOFT386_STATE State,
+                         ULONG VirtualAddress)
+{
+    // TODO: NOT IMPLEMENTED
+    UNIMPLEMENTED;
+
+    return 0;
+}
+
 /* PUBLIC FUNCTIONS ***********************************************************/
 
 inline
@@ -41,6 +53,7 @@ Soft386ReadMemory(PSOFT386_STATE State,
 {
     ULONG LinearAddress;
     PSOFT386_SEG_REG CachedDescriptor;
+    INT Cpl = Soft386GetCurrentPrivLevel(State);
 
     ASSERT(SegmentReg < SOFT386_NUM_SEG_REGS);
 
@@ -97,18 +110,75 @@ Soft386ReadMemory(PSOFT386_STATE State,
     /* Find the linear address */
     LinearAddress = CachedDescriptor->Base + Offset;
 
-    // TODO: Paging support!
-
-    /* Did the host provide a memory hook? */
-    if (State->MemReadCallback)
+    /* Check if paging is enabled */
+    if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PG)
     {
-        /* Yes, call the host */
-        State->MemReadCallback(State, LinearAddress, Buffer, Size);
+        ULONG Page;
+        SOFT386_PAGE_TABLE TableEntry;
+
+        for (Page = PAGE_ALIGN(LinearAddress);
+             Page <= PAGE_ALIGN(LinearAddress + Size - 1);
+             Page += PAGE_SIZE)
+        {
+            ULONG PageOffset = 0, PageLength = PAGE_SIZE;
+
+            /* Get the table entry */
+            TableEntry.Value = Soft386GetPageTableEntry(State, Page);
+
+            if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
+            {
+                /* Exception */
+                Soft386ExceptionWithErrorCode(State,
+                                              SOFT386_EXCEPTION_PF,
+                                              TableEntry.Value & 0x07);
+                return FALSE;
+            }
+
+            /* Check if this is the first page */
+            if (Page == PAGE_ALIGN(LinearAddress))
+            {
+                /* Start copying from the offset from the beginning of the page */
+                PageOffset = PAGE_OFFSET(LinearAddress);
+            }
+
+            /* Check if this is the last page */
+            if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
+            {   
+                /* Copy only a part of the page */
+                PageLength = PAGE_OFFSET(LinearAddress + Size);
+            }
+
+            /* Did the host provide a memory hook? */
+            if (State->MemReadCallback)
+            {
+                /* Yes, call the host */
+                State->MemReadCallback(State,
+                                       (TableEntry.Address << 12) | PageOffset,
+                                       Buffer,
+                                       PageLength);
+            }
+            else
+            {
+                /* Read the memory directly */
+                RtlMoveMemory(Buffer,
+                              (PVOID)((TableEntry.Address << 12) | PageOffset),
+                              PageLength);
+            }
+        }
     }
     else
     {
-        /* Read the memory directly */
-        RtlMoveMemory(Buffer, (PVOID)LinearAddress, Size);
+        /* Did the host provide a memory hook? */
+        if (State->MemReadCallback)
+        {
+            /* Yes, call the host */
+            State->MemReadCallback(State, LinearAddress, Buffer, Size);
+        }
+        else
+        {
+            /* Read the memory directly */
+            RtlMoveMemory(Buffer, (PVOID)LinearAddress, Size);
+        }
     }
 
     return TRUE;
@@ -124,6 +194,7 @@ Soft386WriteMemory(PSOFT386_STATE State,
 {
     ULONG LinearAddress;
     PSOFT386_SEG_REG CachedDescriptor;
+    INT Cpl = Soft386GetCurrentPrivLevel(State);
 
     ASSERT(SegmentReg < SOFT386_NUM_SEG_REGS);
 
@@ -174,18 +245,77 @@ Soft386WriteMemory(PSOFT386_STATE State,
     /* Find the linear address */
     LinearAddress = CachedDescriptor->Base + Offset;
 
-    // TODO: Paging support!
-
-    /* Did the host provide a memory hook? */
-    if (State->MemWriteCallback)
+    /* Check if paging is enabled */
+    if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PG)
     {
-        /* Yes, call the host */
-        State->MemWriteCallback(State, LinearAddress, Buffer, Size);
+        ULONG Page;
+        SOFT386_PAGE_TABLE TableEntry;
+
+        for (Page = PAGE_ALIGN(LinearAddress);
+             Page <= PAGE_ALIGN(LinearAddress + Size - 1);
+             Page += PAGE_SIZE)
+        {
+            ULONG PageOffset = 0, PageLength = PAGE_SIZE;
+
+            /* Get the table entry */
+            TableEntry.Value = Soft386GetPageTableEntry(State, Page);
+
+            if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
+                || ((State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_WP)
+                && !TableEntry.Writeable))
+            {
+                /* Exception */
+                Soft386ExceptionWithErrorCode(State,
+                                              SOFT386_EXCEPTION_PF,
+                                              TableEntry.Value & 0x07);
+                return FALSE;
+            }
+
+            /* Check if this is the first page */
+            if (Page == PAGE_ALIGN(LinearAddress))
+            {
+                /* Start copying from the offset from the beginning of the page */
+                PageOffset = PAGE_OFFSET(LinearAddress);
+            }
+
+            /* Check if this is the last page */
+            if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
+            {   
+                /* Copy only a part of the page */
+                PageLength = PAGE_OFFSET(LinearAddress + Size);
+            }
+
+            /* Did the host provide a memory hook? */
+            if (State->MemWriteCallback)
+            {
+                /* Yes, call the host */
+                State->MemWriteCallback(State,
+                                        (TableEntry.Address << 12) | PageOffset,
+                                        Buffer,
+                                        PageLength);
+            }
+            else
+            {
+                /* Read the memory directly */
+                RtlMoveMemory((PVOID)((TableEntry.Address << 12) | PageOffset),
+                              Buffer,
+                              PageLength);
+            }
+        }
     }
     else
     {
-        /* Write the memory directly */
-        RtlMoveMemory((PVOID)LinearAddress, Buffer, Size);
+        /* Did the host provide a memory hook? */
+        if (State->MemWriteCallback)
+        {
+            /* Yes, call the host */
+            State->MemWriteCallback(State, LinearAddress, Buffer, Size);
+        }
+        else
+        {
+            /* Write the memory directly */
+            RtlMoveMemory((PVOID)LinearAddress, Buffer, Size);
+        }
     }
 
     return TRUE;
@@ -709,7 +839,7 @@ Soft386GetIntVector(PSOFT386_STATE State,
 
 VOID
 FASTCALL
-Soft386Exception(PSOFT386_STATE State, INT ExceptionCode)
+Soft386ExceptionWithErrorCode(PSOFT386_STATE State, INT ExceptionCode, ULONG ErrorCode)
 {
     SOFT386_IDT_ENTRY IdtEntry;
 
@@ -752,6 +882,20 @@ Soft386Exception(PSOFT386_STATE State, INT ExceptionCode)
          */
         return;
     }
+
+    if (EXCEPTION_HAS_ERROR_CODE(ExceptionCode))
+    {
+        /* Push the error code */
+        Soft386StackPush(State, ErrorCode);
+    }
+}
+
+inline
+VOID
+Soft386Exception(PSOFT386_STATE State, INT ExceptionCode)
+{
+    /* Call the internal function */
+    Soft386ExceptionWithErrorCode(State, ExceptionCode, 0);
 }
 
 inline
index 92a7219..9325f17 100644 (file)
 #define SIGN_FLAG_LONG 0x80000000
 #define GET_SEGMENT_RPL(s) ((s) & 3)
 #define GET_SEGMENT_INDEX(s) ((s) & 0xFFF8)
+#define EXCEPTION_HAS_ERROR_CODE(x) (((x) == 8) || ((x) >= 10 && (x) <= 14))
+#define PAGE_ALIGN(x) ((x) & 0xFFFFF000)
+#define PAGE_OFFSET(x) ((x) & 0x00000FFF)
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
 
 typedef struct _SOFT386_MOD_REG_RM
 {
@@ -32,6 +39,47 @@ typedef struct _SOFT386_MOD_REG_RM
     };
 } SOFT386_MOD_REG_RM, *PSOFT386_MOD_REG_RM;
 
+#pragma pack(push, 1)
+
+typedef struct _SOFT386_PAGE_DIR
+{
+    union
+    {
+        ULONG Present : 1;
+        ULONG Writeable : 1;
+        ULONG Usermode : 1;
+        ULONG WriteThrough : 1;
+        ULONG NoCache : 1;
+        ULONG Accessed : 1;
+        ULONG AlwaysZero : 1;
+        ULONG Size : 1;
+        ULONG Unused : 4;
+        ULONG TableAddress : 20;
+    };
+    ULONG Value;
+} SOFT386_PAGE_DIR, *PSOFT386_PAGE_DIR;
+
+typedef struct _SOFT386_PAGE_TABLE
+{
+    union
+    {
+        ULONG Present : 1;
+        ULONG Writeable : 1;
+        ULONG Usermode : 1;
+        ULONG WriteThrough : 1;
+        ULONG NoCache : 1;
+        ULONG Accessed : 1;
+        ULONG Dirty : 1;
+        ULONG AlwaysZero : 1;
+        ULONG Global : 1;
+        ULONG Unused : 3;
+        ULONG Address : 20;
+    };
+    ULONG Value;
+} SOFT386_PAGE_TABLE, *PSOFT386_PAGE_TABLE;
+
+#pragma pack(pop)
+
 /* FUNCTIONS ******************************************************************/
 
 inline
@@ -126,7 +174,16 @@ Soft386GetIntVector
 );
 
 VOID
-__fastcall
+FASTCALL
+Soft386ExceptionWithErrorCode
+(
+    PSOFT386_STATE State,
+    INT ExceptionCode,
+    ULONG ErrorCode
+);
+
+inline
+VOID
 Soft386Exception
 (
     PSOFT386_STATE State,