Author: aandrejevic Date: Sun Oct 26 23:37:54 2014 New Revision: 65035
URL: http://svn.reactos.org/svn/reactos?rev=65035&view=rev Log: [FAST486] Implement an (optional) instruction prefetch cache. Implement the INVLPG instruction.
Modified: trunk/reactos/include/reactos/libs/fast486/fast486.h trunk/reactos/lib/fast486/common.c trunk/reactos/lib/fast486/common.h trunk/reactos/lib/fast486/common.inl trunk/reactos/lib/fast486/extraops.c trunk/reactos/lib/fast486/opcodes.c trunk/reactos/lib/fast486/opgroups.c
Modified: trunk/reactos/include/reactos/libs/fast486/fast486.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/libs/fast48... ============================================================================== --- trunk/reactos/include/reactos/libs/fast486/fast486.h [iso-8859-1] (original) +++ trunk/reactos/include/reactos/libs/fast486/fast486.h [iso-8859-1] Sun Oct 26 23:37:54 2014 @@ -92,6 +92,18 @@ #define FAST486_PREFIX_REP (1 << 5)
#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 @@ 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;
Modified: trunk/reactos/lib/fast486/common.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.c?rev=65... ============================================================================== --- trunk/reactos/lib/fast486/common.c [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/common.c [iso-8859-1] Sun Oct 26 23:37:54 2014 @@ -95,8 +95,40 @@ /* 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 @@ -155,6 +187,18 @@
/* 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);
Modified: trunk/reactos/lib/fast486/common.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.h?rev=65... ============================================================================== --- trunk/reactos/lib/fast486/common.h [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/common.h [iso-8859-1] Sun Oct 26 23:37:54 2014 @@ -69,10 +69,6 @@ #define GET_ADDR_PDE(x) ((x) >> 22) #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 {
Modified: trunk/reactos/lib/fast486/common.inl URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.inl?rev=... ============================================================================== --- trunk/reactos/lib/fast486/common.inl [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/common.inl [iso-8859-1] Sun Oct 26 23:37:54 2014 @@ -163,9 +163,9 @@
for (Page = PAGE_ALIGN(LinearAddress); Page <= PAGE_ALIGN(LinearAddress + Size - 1); - Page += PAGE_SIZE) - { - ULONG PageOffset = 0, PageLength = PAGE_SIZE; + Page += FAST486_PAGE_SIZE) + { + ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
/* Get the table entry */ TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE); @@ -230,9 +230,9 @@
for (Page = PAGE_ALIGN(LinearAddress); Page <= PAGE_ALIGN(LinearAddress + Size - 1); - Page += PAGE_SIZE) - { - ULONG PageOffset = 0, PageLength = PAGE_SIZE; + Page += FAST486_PAGE_SIZE) + { + ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
/* Get the table entry */ TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE); @@ -521,6 +521,11 @@ else if (Segment == FAST486_REG_CS) { /* Loading the code segment */ + +#ifndef FAST486_NO_PREFETCH + /* Invalidate the prefetch */ + State->PrefetchValid = FALSE; +#endif
if (GET_SEGMENT_INDEX(Selector) == 0) { @@ -641,21 +646,39 @@ 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))) - { - /* Exception occurred during instruction fetch */ - return FALSE; + 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))) + { + *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 @@ 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))) - { - /* Exception occurred during instruction fetch */ - return FALSE; + 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))) + { + *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 @@ 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))) - { - /* Exception occurred during instruction fetch */ - return FALSE; + 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))) + { + *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 */
Modified: trunk/reactos/lib/fast486/extraops.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/extraops.c?rev=... ============================================================================== --- trunk/reactos/lib/fast486/extraops.c [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/extraops.c [iso-8859-1] Sun Oct 26 23:37:54 2014 @@ -686,6 +686,11 @@ } }
+#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; }
Modified: trunk/reactos/lib/fast486/opcodes.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/opcodes.c?rev=6... ============================================================================== --- trunk/reactos/lib/fast486/opcodes.c [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/opcodes.c [iso-8859-1] Sun Oct 26 23:37:54 2014 @@ -4240,6 +4240,11 @@ { 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)) {
Modified: trunk/reactos/lib/fast486/opgroups.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/opgroups.c?rev=... ============================================================================== --- trunk/reactos/lib/fast486/opgroups.c [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/opgroups.c [iso-8859-1] Sun Oct 26 23:37:54 2014 @@ -2177,7 +2177,31 @@ /* 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; }