From bc64e37fd1c97d74327f6d44c78257976c198cf8 Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Sun, 26 Oct 2014 23:37:54 +0000 Subject: [PATCH] [FAST486] Implement an (optional) instruction prefetch cache. Implement the INVLPG instruction. svn path=/trunk/; revision=65035 --- .../include/reactos/libs/fast486/fast486.h | 17 +++ reactos/lib/fast486/common.c | 48 ++++++- reactos/lib/fast486/common.h | 4 - reactos/lib/fast486/common.inl | 133 +++++++++++++----- reactos/lib/fast486/extraops.c | 5 + reactos/lib/fast486/opcodes.c | 5 + reactos/lib/fast486/opgroups.c | 26 +++- 7 files changed, 195 insertions(+), 43 deletions(-) diff --git a/reactos/include/reactos/libs/fast486/fast486.h b/reactos/include/reactos/libs/fast486/fast486.h index efc87fefc73..2a933e51a49 100644 --- a/reactos/include/reactos/libs/fast486/fast486.h +++ b/reactos/include/reactos/libs/fast486/fast486.h @@ -93,6 +93,18 @@ #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; diff --git a/reactos/lib/fast486/common.c b/reactos/lib/fast486/common.c index 1e9311ae00b..3bb29a58601 100644 --- a/reactos/lib/fast486/common.c +++ b/reactos/lib/fast486/common.c @@ -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); } diff --git a/reactos/lib/fast486/common.h b/reactos/lib/fast486/common.h index 6b9cb6aa09e..a87a3eeb7a1 100644 --- a/reactos/lib/fast486/common.h +++ b/reactos/lib/fast486/common.h @@ -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; diff --git a/reactos/lib/fast486/common.inl b/reactos/lib/fast486/common.inl index 4990172fb1a..53d1deeb246 100644 --- a/reactos/lib/fast486/common.inl +++ b/reactos/lib/fast486/common.inl @@ -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 */ diff --git a/reactos/lib/fast486/extraops.c b/reactos/lib/fast486/extraops.c index 9d23cb97394..eefd918aa6f 100644 --- a/reactos/lib/fast486/extraops.c +++ b/reactos/lib/fast486/extraops.c @@ -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; } diff --git a/reactos/lib/fast486/opcodes.c b/reactos/lib/fast486/opcodes.c index f31ce73d7f6..101361b0251 100644 --- a/reactos/lib/fast486/opcodes.c +++ b/reactos/lib/fast486/opcodes.c @@ -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)) { diff --git a/reactos/lib/fast486/opgroups.c b/reactos/lib/fast486/opgroups.c index 03eb09181d2..bca294d2c96 100644 --- a/reactos/lib/fast486/opgroups.c +++ b/reactos/lib/fast486/opgroups.c @@ -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; }