[FAST486]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Sun, 26 Oct 2014 23:37:54 +0000 (23:37 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Sun, 26 Oct 2014 23:37:54 +0000 (23:37 +0000)
Implement an (optional) instruction prefetch cache.
Implement the INVLPG instruction.

svn path=/trunk/; revision=65035

reactos/include/reactos/libs/fast486/fast486.h
reactos/lib/fast486/common.c
reactos/lib/fast486/common.h
reactos/lib/fast486/common.inl
reactos/lib/fast486/extraops.c
reactos/lib/fast486/opcodes.c
reactos/lib/fast486/opgroups.c

index efc87fe..2a933e5 100644 (file)
 
 #define FAST486_FPU_DEFAULT_CONTROL 0x037F
 
+#define FAST486_PAGE_SIZE 4096
+#define FAST486_CACHE_SIZE 32
+
+/*
+ * These are condiciones sine quibus non that should be respected, because
+ * otherwise when fetching DWORDs you would read extra garbage bytes
+ * (by reading outside of the prefetch buffer). The prefetch cache must
+ * also not cross a page boundary.
+ */
+C_ASSERT((FAST486_CACHE_SIZE >= sizeof(DWORD))
+         && (FAST486_CACHE_SIZE <= FAST486_PAGE_SIZE));
+
 struct _FAST486_STATE;
 typedef struct _FAST486_STATE FAST486_STATE, *PFAST486_STATE;
 
@@ -486,6 +498,11 @@ struct _FAST486_STATE
     FAST486_INT_STATUS IntStatus;
     UCHAR PendingIntNum;
     PULONG Tlb;
+#ifndef FAST486_NO_PREFETCH
+    BOOLEAN PrefetchValid;
+    ULONG PrefetchAddress;
+    UCHAR PrefetchCache[FAST486_CACHE_SIZE];
+#endif
 #ifndef FAST486_NO_FPU
     FAST486_FPU_DATA_REG FpuRegisters[FAST486_NUM_FPU_REGS];
     FAST486_FPU_STATUS_REG FpuStatus;
index 1e9311a..3bb29a5 100644 (file)
@@ -95,8 +95,40 @@ Fast486ReadMemory(PFAST486_STATE State,
     /* Find the linear address */
     LinearAddress = CachedDescriptor->Base + Offset;
 
-    /* Read from the linear address */
-    return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
+#ifndef FAST486_NO_PREFETCH
+    if (InstFetch && ((Offset + FAST486_CACHE_SIZE - 1) <= CachedDescriptor->Limit))
+    {
+        State->PrefetchAddress = LinearAddress;
+
+        if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
+            && (PAGE_OFFSET(State->PrefetchAddress) > (FAST486_PAGE_SIZE - FAST486_CACHE_SIZE)))
+        {
+            /* We mustn't prefetch across a page boundary */
+            State->PrefetchAddress = PAGE_ALIGN(State->PrefetchAddress)
+                                     | (FAST486_PAGE_SIZE - FAST486_CACHE_SIZE);
+        }
+
+        /* Prefetch */
+        if (Fast486ReadLinearMemory(State,
+                                    State->PrefetchAddress,
+                                    State->PrefetchCache,
+                                    FAST486_CACHE_SIZE))
+        {
+            State->PrefetchValid = TRUE;
+
+            RtlMoveMemory(Buffer,
+                          &State->PrefetchCache[LinearAddress - State->PrefetchAddress],
+                          Size);
+            return TRUE;
+        }
+        else return FALSE;
+    }
+    else
+#endif
+    {
+        /* Read from the linear address */
+        return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
+    }
 }
 
 BOOLEAN
@@ -156,6 +188,18 @@ Fast486WriteMemory(PFAST486_STATE State,
     /* Find the linear address */
     LinearAddress = CachedDescriptor->Base + Offset;
 
+#ifndef FAST486_NO_PREFETCH
+    if (State->PrefetchValid
+        && (LinearAddress >= State->PrefetchAddress)
+        && ((LinearAddress + Size) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
+    {
+        /* Update the prefetch */
+        RtlMoveMemory(&State->PrefetchCache[LinearAddress - State->PrefetchAddress],
+                      Buffer,
+                      min(Size, FAST486_CACHE_SIZE + State->PrefetchAddress - LinearAddress));
+    }
+#endif
+
     /* Write to the linear address */
     return Fast486WriteLinearMemory(State, LinearAddress, Buffer, Size);
 }
index 6b9cb6a..a87a3ee 100644 (file)
@@ -70,10 +70,6 @@ if (State->PrefixFlags & FAST486_PREFIX_LOCK)\
 #define GET_ADDR_PTE(x) (((x) >> 12) & 0x3FF)
 #define INVALID_TLB_FIELD 0xFFFFFFFF
 
-#ifndef PAGE_SIZE
-#define PAGE_SIZE   4096
-#endif
-
 typedef struct _FAST486_MOD_REG_RM
 {
     FAST486_GEN_REGS Register;
index 4990172..53d1dee 100644 (file)
@@ -163,9 +163,9 @@ Fast486ReadLinearMemory(PFAST486_STATE State,
 
         for (Page = PAGE_ALIGN(LinearAddress);
              Page <= PAGE_ALIGN(LinearAddress + Size - 1);
-             Page += PAGE_SIZE)
+             Page += FAST486_PAGE_SIZE)
         {
-            ULONG PageOffset = 0, PageLength = PAGE_SIZE;
+            ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
 
             /* Get the table entry */
             TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
@@ -230,9 +230,9 @@ Fast486WriteLinearMemory(PFAST486_STATE State,
 
         for (Page = PAGE_ALIGN(LinearAddress);
              Page <= PAGE_ALIGN(LinearAddress + Size - 1);
-             Page += PAGE_SIZE)
+             Page += FAST486_PAGE_SIZE)
         {
-            ULONG PageOffset = 0, PageLength = PAGE_SIZE;
+            ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
 
             /* Get the table entry */
             TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
@@ -522,6 +522,11 @@ Fast486LoadSegment(PFAST486_STATE State,
         {
             /* Loading the code segment */
 
+#ifndef FAST486_NO_PREFETCH
+            /* Invalidate the prefetch */
+            State->PrefetchValid = FALSE;
+#endif
+
             if (GET_SEGMENT_INDEX(Selector) == 0)
             {
                 Fast486Exception(State, FAST486_EXCEPTION_GP);
@@ -641,21 +646,39 @@ Fast486FetchByte(PFAST486_STATE State,
                  PUCHAR Data)
 {
     PFAST486_SEG_REG CachedDescriptor;
+    ULONG Offset;
+#ifndef FAST486_NO_PREFETCH
+    ULONG LinearAddress;
+#endif
 
     /* Get the cached descriptor of CS */
     CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
 
-    /* Read from memory */
-    if (!Fast486ReadMemory(State,
-                           FAST486_REG_CS,
-                           (CachedDescriptor->Size) ? State->InstPtr.Long
-                                                    : State->InstPtr.LowWord,
-                           TRUE,
-                           Data,
-                           sizeof(UCHAR)))
+    Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
+                                      : State->InstPtr.LowWord;
+#ifndef FAST486_NO_PREFETCH
+    LinearAddress = CachedDescriptor->Base + Offset;
+
+    if (State->PrefetchValid
+        && (LinearAddress >= State->PrefetchAddress)
+        && ((LinearAddress + sizeof(UCHAR)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
     {
-        /* Exception occurred during instruction fetch */
-        return FALSE;
+        *Data = *(PUCHAR)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
+    }
+    else
+#endif
+    {
+        /* Read from memory */
+        if (!Fast486ReadMemory(State,
+                               FAST486_REG_CS,
+                               Offset,
+                               TRUE,
+                               Data,
+                               sizeof(UCHAR)))
+        {
+            /* Exception occurred during instruction fetch */
+            return FALSE;
+        }
     }
 
     /* Advance the instruction pointer */
@@ -672,22 +695,41 @@ Fast486FetchWord(PFAST486_STATE State,
                  PUSHORT Data)
 {
     PFAST486_SEG_REG CachedDescriptor;
+    ULONG Offset;
+#ifndef FAST486_NO_PREFETCH
+    ULONG LinearAddress;
+#endif
 
     /* Get the cached descriptor of CS */
     CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
 
-    /* Read from memory */
-    // FIXME: Fix byte order on big-endian machines
-    if (!Fast486ReadMemory(State,
-                           FAST486_REG_CS,
-                           (CachedDescriptor->Size) ? State->InstPtr.Long
-                                                    : State->InstPtr.LowWord,
-                           TRUE,
-                           Data,
-                           sizeof(USHORT)))
+    Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
+                                      : State->InstPtr.LowWord;
+
+#ifndef FAST486_NO_PREFETCH
+    LinearAddress = CachedDescriptor->Base + Offset;
+
+    if (State->PrefetchValid
+        && (LinearAddress >= State->PrefetchAddress)
+        && ((LinearAddress + sizeof(USHORT)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
     {
-        /* Exception occurred during instruction fetch */
-        return FALSE;
+        *Data = *(PUSHORT)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
+    }
+    else
+#endif
+    {
+        /* Read from memory */
+        // FIXME: Fix byte order on big-endian machines
+        if (!Fast486ReadMemory(State,
+                               FAST486_REG_CS,
+                               Offset,
+                               TRUE,
+                               Data,
+                               sizeof(USHORT)))
+        {
+            /* Exception occurred during instruction fetch */
+            return FALSE;
+        }
     }
 
     /* Advance the instruction pointer */
@@ -704,22 +746,41 @@ Fast486FetchDword(PFAST486_STATE State,
                   PULONG Data)
 {
     PFAST486_SEG_REG CachedDescriptor;
+    ULONG Offset;
+#ifndef FAST486_NO_PREFETCH
+    ULONG LinearAddress;
+#endif
 
     /* Get the cached descriptor of CS */
     CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
 
-    /* Read from memory */
-    // FIXME: Fix byte order on big-endian machines
-    if (!Fast486ReadMemory(State,
-                           FAST486_REG_CS,
-                           (CachedDescriptor->Size) ? State->InstPtr.Long
-                                                    : State->InstPtr.LowWord,
-                           TRUE,
-                           Data,
-                           sizeof(ULONG)))
+    Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
+                                      : State->InstPtr.LowWord;
+
+#ifndef FAST486_NO_PREFETCH
+    LinearAddress = CachedDescriptor->Base + Offset;
+
+    if (State->PrefetchValid
+        && (LinearAddress >= State->PrefetchAddress)
+        && ((LinearAddress + sizeof(ULONG)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
     {
-        /* Exception occurred during instruction fetch */
-        return FALSE;
+        *Data = *(PULONG)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
+    }
+    else
+#endif
+    {
+        /* Read from memory */
+        // FIXME: Fix byte order on big-endian machines
+        if (!Fast486ReadMemory(State,
+                               FAST486_REG_CS,
+                               Offset,
+                               TRUE,
+                               Data,
+                               sizeof(ULONG)))
+        {
+            /* Exception occurred during instruction fetch */
+            return FALSE;
+        }
     }
 
     /* Advance the instruction pointer */
index 9d23cb9..eefd918 100644 (file)
@@ -686,6 +686,11 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
         }
     }
 
+#ifndef FAST486_NO_PREFETCH
+    /* Changing CR0 or CR3 can interfere with prefetching (because of paging) */
+    State->PrefetchValid = FALSE;
+#endif
+
     /* Load a value to the control register */
     State->ControlRegisters[ModRegRm.Register] = Value;
 }
index f31ce73..101361b 100644 (file)
@@ -4240,6 +4240,11 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes)
         {
             UCHAR BopCode;
 
+#ifndef FAST486_NO_PREFETCH
+            /* Invalidate the prefetch since BOP handlers can alter the memory */
+            State->PrefetchValid = FALSE;
+#endif
+
             /* Fetch the BOP code */
             if (!Fast486FetchByte(State, &BopCode))
             {
index 03eb091..bca294d 100644 (file)
@@ -2177,7 +2177,31 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
         /* INVLPG */
         case 7:
         {
-            UNIMPLEMENTED;
+#ifndef FAST486_NO_PREFETCH
+            /* Invalidate the prefetch */
+            State->PrefetchValid = FALSE;
+#endif
+
+            /* This is a privileged instruction */
+            if (Fast486GetCurrentPrivLevel(State) != 0)
+            {
+                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                return;
+            }
+
+            if (!ModRegRm.Memory)
+            {
+                /* The second operand must be a memory location */
+                Fast486Exception(State, FAST486_EXCEPTION_UD);
+                return;
+            }
+
+            if (State->Tlb != NULL)
+            {
+                /* Clear the TLB entry */
+                State->Tlb[ModRegRm.MemoryAddress >> 12] = INVALID_TLB_FIELD;
+            }
+
             break;
         }