Author: aandrejevic Date: Tue Nov 4 22:58:02 2014 New Revision: 65260
URL: http://svn.reactos.org/svn/reactos?rev=65260&view=rev Log: [FAST486] - Move the descriptor reading logic into a separate function. - Implement hardware task switching and task gates. - Flush the TLB when reloading CR3.
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] Tue Nov 4 22:58:02 2014 @@ -75,14 +75,15 @@ #define FAST486_DR4_RESERVED 0xFFFF1FF0 #define FAST486_DR5_RESERVED 0x0000DC00
-#define FAST486_IDT_TASK_GATE 0x5 -#define FAST486_IDT_INT_GATE 0x6 -#define FAST486_IDT_TRAP_GATE 0x7 -#define FAST486_IDT_INT_GATE_32 0xE -#define FAST486_IDT_TRAP_GATE_32 0xF - -#define FAST486_LDT_SIGNATURE 0x02 -#define FAST486_TSS_SIGNATURE 0x09 +#define FAST486_LDT_SIGNATURE 0x02 +#define FAST486_TASK_GATE_SIGNATURE 0x05 +#define FAST486_IDT_INT_GATE 0x06 +#define FAST486_IDT_TRAP_GATE 0x07 +#define FAST486_TSS_SIGNATURE 0x09 +#define FAST486_BUSY_TSS_SIGNATURE 0x0B +#define FAST486_CALL_GATE_SIGNATURE 0x0C +#define FAST486_IDT_INT_GATE_32 0x0E +#define FAST486_IDT_TRAP_GATE_32 0x0F
#define FAST486_PREFIX_SEG (1 << 0) #define FAST486_PREFIX_OPSIZE (1 << 1) @@ -270,7 +271,6 @@ USHORT Selector; ULONG Base; ULONG Limit; - BOOLEAN Busy; } FAST486_TASK_REG, *PFAST486_TASK_REG;
#include <pshpack1.h>
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] Tue Nov 4 22:58:02 2014 @@ -274,6 +274,12 @@ FAST486_TSS Tss; USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector; ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long; + + if (GateType == FAST486_TASK_GATE_SIGNATURE) + { + /* Task call */ + return Fast486TaskSwitch(State, FAST486_TASK_CALL, IdtEntry->Selector); + }
if (GateSize != (State->SegmentRegs[FAST486_REG_CS].Size)) { @@ -484,4 +490,306 @@ State->ExceptionCount = 0; }
+BOOLEAN +FASTCALL +Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Selector) +{ + ULONG NewTssAddress; + ULONG NewTssLimit; + FAST486_TSS OldTss; + FAST486_TSS NewTss; + FAST486_SYSTEM_DESCRIPTOR NewTssDescriptor; + + /* Read the old TSS */ + if (!Fast486ReadLinearMemory(State, + State->TaskReg.Base, + &OldTss, + sizeof(OldTss))) + { + /* Exception occurred */ + return FALSE; + } + + /* If this is a task return, use the linked previous selector */ + if (Type == FAST486_TASK_RETURN) Selector = LOWORD(OldTss.Link); + + /* Make sure the entry exists in the GDT (not LDT!) */ + if ((GET_SEGMENT_INDEX(Selector) == 0) + || (Selector & SEGMENT_TABLE_INDICATOR) + || GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1)) + { + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, Selector); + return FALSE; + } + + /* Get the TSS descriptor from the GDT */ + if (!Fast486ReadLinearMemory(State, + State->Gdtr.Address + GET_SEGMENT_INDEX(Selector), + &NewTssDescriptor, + sizeof(NewTssDescriptor))) + { + /* Exception occurred */ + return FALSE; + } + + if (!NewTssDescriptor.Present) + { + /* Incoming task TSS not present */ + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); + return FALSE; + } + + /* Calculate the linear address of the new TSS */ + NewTssAddress = NewTssDescriptor.Base; + NewTssAddress |= NewTssDescriptor.BaseMid << 16; + NewTssAddress |= NewTssDescriptor.BaseHigh << 24; + + /* Calculate the limit of the new TSS */ + NewTssLimit = NewTssDescriptor.Limit | (NewTssDescriptor.LimitHigh << 16); + if (NewTssDescriptor.Granularity) NewTssLimit <<= 12; + + if (NewTssLimit < sizeof(FAST486_TSS)) + { + /* TSS limit too small */ + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, Selector); + } + + /* + * The incoming task shouldn't be busy if we're executing it as a + * new task, and it should be busy if we're returning to it. + */ + if (((NewTssDescriptor.Signature != FAST486_TSS_SIGNATURE) + || (Type == FAST486_TASK_RETURN)) + && ((NewTssDescriptor.Signature != FAST486_BUSY_TSS_SIGNATURE) + || (Type != FAST486_TASK_RETURN))) + { + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); + return FALSE; + } + + /* Read the new TSS */ + if (!Fast486ReadLinearMemory(State, + NewTssAddress, + &NewTss, + sizeof(NewTss))) + { + /* Exception occurred */ + return FALSE; + } + + if (Type != FAST486_TASK_CALL) + { + /* Clear the busy bit of the outgoing task */ + FAST486_SYSTEM_DESCRIPTOR OldTssDescriptor; + + if (!Fast486ReadLinearMemory(State, + State->Gdtr.Address + + GET_SEGMENT_INDEX(State->TaskReg.Selector), + &OldTssDescriptor, + sizeof(OldTssDescriptor))) + { + /* Exception occurred */ + return FALSE; + } + + OldTssDescriptor.Signature = FAST486_TSS_SIGNATURE; + + if (!Fast486WriteLinearMemory(State, + State->Gdtr.Address + + GET_SEGMENT_INDEX(State->TaskReg.Selector), + &OldTssDescriptor, + sizeof(OldTssDescriptor))) + { + /* Exception occurred */ + return FALSE; + } + } + else + { + /* Store the link */ + NewTss.Link = State->TaskReg.Selector; + } + + /* Save the current task into the TSS */ + OldTss.Cr3 = State->ControlRegisters[FAST486_REG_CR3]; + OldTss.Eip = State->InstPtr.Long; + OldTss.Eflags = State->Flags.Long; + OldTss.Eax = State->GeneralRegs[FAST486_REG_EAX].Long; + OldTss.Ecx = State->GeneralRegs[FAST486_REG_ECX].Long; + OldTss.Edx = State->GeneralRegs[FAST486_REG_EDX].Long; + OldTss.Ebx = State->GeneralRegs[FAST486_REG_EBX].Long; + OldTss.Esp = State->GeneralRegs[FAST486_REG_ESP].Long; + OldTss.Ebp = State->GeneralRegs[FAST486_REG_EBP].Long; + OldTss.Esi = State->GeneralRegs[FAST486_REG_ESI].Long; + OldTss.Edi = State->GeneralRegs[FAST486_REG_EDI].Long; + OldTss.Es = State->SegmentRegs[FAST486_REG_ES].Selector; + OldTss.Cs = State->SegmentRegs[FAST486_REG_CS].Selector; + OldTss.Ss = State->SegmentRegs[FAST486_REG_SS].Selector; + OldTss.Ds = State->SegmentRegs[FAST486_REG_DS].Selector; + OldTss.Fs = State->SegmentRegs[FAST486_REG_FS].Selector; + OldTss.Gs = State->SegmentRegs[FAST486_REG_GS].Selector; + OldTss.Ldtr = State->Ldtr.Selector; + + /* Write back the old TSS */ + if (!Fast486WriteLinearMemory(State, + State->TaskReg.Base, + &OldTss, + sizeof(OldTss))) + { + /* Exception occurred */ + return FALSE; + } + + /* Mark the new task as busy */ + NewTssDescriptor.Signature = FAST486_BUSY_TSS_SIGNATURE; + + /* Write back the new TSS descriptor */ + if (!Fast486WriteLinearMemory(State, + State->Gdtr.Address + GET_SEGMENT_INDEX(Selector), + &NewTssDescriptor, + sizeof(NewTssDescriptor))) + { + /* Exception occurred */ + return FALSE; + } + + /* Set the task switch bit */ + State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_TS; + + /* Load the task register with the new values */ + State->TaskReg.Selector = Selector; + State->TaskReg.Base = NewTssAddress; + State->TaskReg.Limit = NewTssLimit; + + /* Change the page directory */ + State->ControlRegisters[FAST486_REG_CR3] = NewTss.Cr3; + + /* Flush the TLB */ + if (State->Tlb) RtlZeroMemory(State->Tlb, NUM_TLB_ENTRIES * sizeof(ULONG)); + +#ifndef FAST486_NO_PREFETCH + /* Context switching invalidates the prefetch */ + State->PrefetchValid = FALSE; +#endif + + /* Load the registers */ + State->InstPtr.Long = State->SavedInstPtr.Long = NewTss.Eip; + State->Flags.Long = NewTss.Eflags; + State->GeneralRegs[FAST486_REG_EAX].Long = NewTss.Eax; + State->GeneralRegs[FAST486_REG_ECX].Long = NewTss.Ecx; + State->GeneralRegs[FAST486_REG_EDX].Long = NewTss.Edx; + State->GeneralRegs[FAST486_REG_EBX].Long = NewTss.Ebx; + State->GeneralRegs[FAST486_REG_ESP].Long = NewTss.Esp; + State->GeneralRegs[FAST486_REG_EBP].Long = NewTss.Ebp; + State->GeneralRegs[FAST486_REG_ESI].Long = NewTss.Esi; + State->GeneralRegs[FAST486_REG_EDI].Long = NewTss.Edi; + + /* Set the NT flag if nesting */ + if (Type == FAST486_TASK_CALL) State->Flags.Nt = TRUE; + + if (GET_SEGMENT_INDEX(NewTss.Ldtr) != 0) + { + BOOLEAN Valid; + FAST486_SYSTEM_DESCRIPTOR GdtEntry; + + if (NewTss.Ldtr & SEGMENT_TABLE_INDICATOR) + { + /* This selector doesn't point to the GDT */ + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewTss.Ldtr); + return FALSE; + } + + if (Fast486ReadDescriptorEntry(State, + NewTss.Ldtr, + &Valid, + (PFAST486_GDT_ENTRY)&GdtEntry)) + { + /* Exception occurred */ + return FALSE; + } + + if (!Valid) + { + /* Invalid selector */ + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewTss.Ldtr); + return FALSE; + } + + if (GdtEntry.Signature != FAST486_LDT_SIGNATURE) + { + /* This is not an LDT descriptor */ + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewTss.Ldtr); + return FALSE; + } + + if (!GdtEntry.Present) + { + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewTss.Ldtr); + return FALSE; + } + + /* Update the LDTR */ + State->Ldtr.Selector = NewTss.Ldtr; + State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24); + State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16); + if (GdtEntry.Granularity) State->Ldtr.Limit <<= 12; + } + else + { + /* The LDT of this task is empty */ + RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr)); + } + + /* Load the new segments */ + if (!Fast486LoadSegmentInternal(State, + FAST486_REG_CS, + NewTss.Cs, + FAST486_EXCEPTION_TS)) + { + return FALSE; + } + + if (!Fast486LoadSegmentInternal(State, + FAST486_REG_SS, + NewTss.Ss, + FAST486_EXCEPTION_TS)) + { + return FALSE; + } + + if (!Fast486LoadSegmentInternal(State, + FAST486_REG_ES, + NewTss.Es, + FAST486_EXCEPTION_TS)) + { + return FALSE; + } + + if (!Fast486LoadSegmentInternal(State, + FAST486_REG_DS, + NewTss.Ds, + FAST486_EXCEPTION_TS)) + { + return FALSE; + } + + if (!Fast486LoadSegmentInternal(State, + FAST486_REG_FS, + NewTss.Fs, + FAST486_EXCEPTION_TS)) + { + return FALSE; + } + + if (!Fast486LoadSegmentInternal(State, + FAST486_REG_GS, + NewTss.Gs, + FAST486_EXCEPTION_TS)) + { + return FALSE; + } + + return TRUE; +} + /* EOF */
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] Tue Nov 4 22:58:02 2014 @@ -69,6 +69,7 @@ #define GET_ADDR_PDE(x) ((x) >> 22) #define GET_ADDR_PTE(x) (((x) >> 12) & 0x3FF) #define INVALID_TLB_FIELD 0xFFFFFFFF +#define NUM_TLB_ENTRIES 0x100000
typedef struct _FAST486_MOD_REG_RM { @@ -80,6 +81,13 @@ ULONG MemoryAddress; }; } FAST486_MOD_REG_RM, *PFAST486_MOD_REG_RM; + +typedef enum _FAST486_TASK_SWITCH_TYPE +{ + FAST486_TASK_JUMP, + FAST486_TASK_CALL, + FAST486_TASK_RETURN +} FAST486_TASK_SWITCH_TYPE, *PFAST486_TASK_SWITCH_TYPE;
#include <pshpack1.h>
@@ -166,6 +174,15 @@ ULONG ErrorCode );
+BOOLEAN +FASTCALL +Fast486TaskSwitch +( + PFAST486_STATE State, + FAST486_TASK_SWITCH_TYPE Type, + USHORT Selector +); + /* INLINED FUNCTIONS **********************************************************/
#include "common.inl"
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] Tue Nov 4 22:58:02 2014 @@ -426,11 +426,68 @@ FORCEINLINE BOOLEAN FASTCALL -Fast486LoadSegment(PFAST486_STATE State, - FAST486_SEG_REGS Segment, - USHORT Selector) +Fast486ReadDescriptorEntry(PFAST486_STATE State, + USHORT Selector, + PBOOLEAN EntryValid, + PFAST486_GDT_ENTRY Entry) +{ + if (!(Selector & SEGMENT_TABLE_INDICATOR)) + { + /* Make sure the GDT contains the entry */ + if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1)) + { + *EntryValid = FALSE; + return TRUE; + } + + /* Read the GDT */ + if (!Fast486ReadLinearMemory(State, + State->Gdtr.Address + + GET_SEGMENT_INDEX(Selector), + Entry, + sizeof(*Entry))) + { + /* Exception occurred */ + *EntryValid = FALSE; + return FALSE; + } + } + else + { + /* Make sure the LDT contains the entry */ + if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1)) + { + *EntryValid = FALSE; + return TRUE; + } + + /* Read the LDT */ + if (!Fast486ReadLinearMemory(State, + State->Ldtr.Base + + GET_SEGMENT_INDEX(Selector), + Entry, + sizeof(*Entry))) + { + /* Exception occurred */ + *EntryValid = FALSE; + return FALSE; + } + } + + *EntryValid = TRUE; + return TRUE; +} + +FORCEINLINE +BOOLEAN +FASTCALL +Fast486LoadSegmentInternal(PFAST486_STATE State, + FAST486_SEG_REGS Segment, + USHORT Selector, + FAST486_EXCEPTIONS Exception) { PFAST486_SEG_REG CachedDescriptor; + BOOLEAN Valid; FAST486_GDT_ENTRY GdtEntry;
ASSERT(Segment < FAST486_NUM_SEG_REGS); @@ -441,45 +498,16 @@ /* Check for protected mode */ if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm) { - if (!(Selector & SEGMENT_TABLE_INDICATOR)) - { - /* Make sure the GDT contains the entry */ - if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1)) - { - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); - return FALSE; - } - - /* Read the GDT */ - if (!Fast486ReadLinearMemory(State, - State->Gdtr.Address - + GET_SEGMENT_INDEX(Selector), - &GdtEntry, - sizeof(GdtEntry))) - { - /* Exception occurred */ - return FALSE; - } - } - else - { - /* Make sure the LDT contains the entry */ - if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1)) - { - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); - return FALSE; - } - - /* Read the LDT */ - if (!Fast486ReadLinearMemory(State, - State->Ldtr.Base - + GET_SEGMENT_INDEX(Selector), - &GdtEntry, - sizeof(GdtEntry))) - { - /* Exception occurred */ - return FALSE; - } + if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry)) + { + /* Exception occurred */ + return FALSE; + } + + if (!Valid) + { + /* Invalid selector */ + Fast486ExceptionWithErrorCode(State, Exception, Selector); }
if (Segment == FAST486_REG_SS) @@ -488,27 +516,27 @@
if (GET_SEGMENT_INDEX(Selector) == 0) { - Fast486Exception(State, FAST486_EXCEPTION_GP); + Fast486Exception(State, Exception); return FALSE; }
if (!GdtEntry.SystemType) { /* This is a special descriptor */ - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); + Fast486ExceptionWithErrorCode(State, Exception, Selector); return FALSE; }
if (GdtEntry.Executable || !GdtEntry.ReadWrite) { - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); + Fast486ExceptionWithErrorCode(State, Exception, Selector); return FALSE; }
if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State)) || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl)) { - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); + Fast486ExceptionWithErrorCode(State, Exception, Selector); return FALSE; }
@@ -529,55 +557,53 @@
if (GET_SEGMENT_INDEX(Selector) == 0) { - Fast486Exception(State, FAST486_EXCEPTION_GP); + Fast486Exception(State, Exception); return FALSE; }
if (!GdtEntry.SystemType) { - // TODO: Call/interrupt/task gates NOT IMPLEMENTED! - UNIMPLEMENTED; - } - else - { - if (!GdtEntry.Present) + /* Must be a segment descriptor */ + Fast486ExceptionWithErrorCode(State, Exception, Selector); + } + + if (!GdtEntry.Present) + { + Fast486ExceptionWithErrorCode(State, Exception, Selector); + return FALSE; + } + + if (!GdtEntry.Executable) + { + Fast486ExceptionWithErrorCode(State, Exception, Selector); + return FALSE; + } + + if (GdtEntry.DirConf) + { + /* Conforming Code Segment */ + + if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State)) { - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); + /* Must be accessed from lower-privileged code */ + Fast486ExceptionWithErrorCode(State, Exception, Selector); return FALSE; } - - if (!GdtEntry.Executable) + } + else + { + /* Regular code segment */ + + if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State)) + || (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl)) { - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); + Fast486ExceptionWithErrorCode(State, Exception, Selector); return FALSE; } - - if (GdtEntry.DirConf) - { - /* Conforming Code Segment */ - - if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State)) - { - /* Must be accessed from lower-privileged code */ - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); - return FALSE; - } - } - else - { - /* Regular code segment */ - - if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State)) - || (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl)) - { - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); - return FALSE; - } - } - - /* Update CPL */ - State->Cpl = GET_SEGMENT_RPL(Selector); - } + } + + /* Update CPL */ + State->Cpl = GET_SEGMENT_RPL(Selector); } else { @@ -588,20 +614,20 @@ if (!GdtEntry.SystemType) { /* This is a special descriptor */ - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); + Fast486ExceptionWithErrorCode(State, Exception, Selector); return FALSE; }
if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl) || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl)) { - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); + Fast486ExceptionWithErrorCode(State, Exception, Selector); return FALSE; }
if (!GdtEntry.Present) { - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); + Fast486ExceptionWithErrorCode(State, Exception, Selector); return FALSE; } } @@ -642,6 +668,64 @@ FORCEINLINE BOOLEAN FASTCALL +Fast486LoadSegment(PFAST486_STATE State, + FAST486_SEG_REGS Segment, + USHORT Selector) +{ + return Fast486LoadSegmentInternal(State, + Segment, + Selector, + FAST486_EXCEPTION_GP); +} + +FORCEINLINE +BOOLEAN +FASTCALL +Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN Call) +{ + BOOLEAN Valid; + FAST486_SYSTEM_DESCRIPTOR Descriptor; + + if (!Fast486ReadDescriptorEntry(State, + Selector, + &Valid, + (PFAST486_GDT_ENTRY)&Descriptor)) + { + /* Exception occurred */ + return FALSE; + } + + if (!Valid) + { + /* Invalid selector */ + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); + return FALSE; + } + + if (Descriptor.Signature == FAST486_TASK_GATE_SIGNATURE) + { + /* Task gate */ + + Fast486TaskSwitch(State, + Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP, + ((PFAST486_IDT_ENTRY)&Descriptor)->Selector); + + return FALSE; + } + else if (Descriptor.Signature == FAST486_CALL_GATE_SIGNATURE) + { + /* Call gate */ + + // TODO: NOT IMPLEMENTED + UNIMPLEMENTED; + } + + return TRUE; +} + +FORCEINLINE +BOOLEAN +FASTCALL Fast486FetchByte(PFAST486_STATE State, PUCHAR Data) {
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] Tue Nov 4 22:58:02 2014 @@ -320,6 +320,7 @@ { BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm; + BOOLEAN Valid; USHORT Selector; FAST486_GDT_ENTRY GdtEntry; DWORD AccessRights; @@ -368,45 +369,16 @@ } }
- if (!(Selector & SEGMENT_TABLE_INDICATOR)) - { - /* Check if the GDT contains the entry */ - if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1)) - { - State->Flags.Zf = FALSE; - return; - } - - /* Read the GDT */ - if (!Fast486ReadLinearMemory(State, - State->Gdtr.Address - + GET_SEGMENT_INDEX(Selector), - &GdtEntry, - sizeof(GdtEntry))) - { - /* Exception occurred */ - return; - } - } - else - { - /* Check if the LDT contains the entry */ - if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1)) - { - State->Flags.Zf = FALSE; - return; - } - - /* Read the LDT */ - if (!Fast486ReadLinearMemory(State, - State->Ldtr.Base - + GET_SEGMENT_INDEX(Selector), - &GdtEntry, - sizeof(GdtEntry))) - { - /* Exception occurred */ - return; - } + if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry)) + { + /* Exception occurred */ + return; + } + + if (!Valid) + { + State->Flags.Zf = FALSE; + return; }
/* Privilege check */ @@ -432,6 +404,7 @@ { BOOLEAN OperandSize, AddressSize; FAST486_MOD_REG_RM ModRegRm; + BOOLEAN Valid; USHORT Selector; ULONG Limit; FAST486_GDT_ENTRY GdtEntry; @@ -480,45 +453,16 @@ } }
- if (!(Selector & SEGMENT_TABLE_INDICATOR)) - { - /* Check if the GDT contains the entry */ - if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1)) - { - State->Flags.Zf = FALSE; - return; - } - - /* Read the GDT */ - if (!Fast486ReadLinearMemory(State, - State->Gdtr.Address - + GET_SEGMENT_INDEX(Selector), - &GdtEntry, - sizeof(GdtEntry))) - { - /* Exception occurred */ - return; - } - } - else - { - /* Check if the LDT contains the entry */ - if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1)) - { - State->Flags.Zf = FALSE; - return; - } - - /* Read the LDT */ - if (!Fast486ReadLinearMemory(State, - State->Ldtr.Base - + GET_SEGMENT_INDEX(Selector), - &GdtEntry, - sizeof(GdtEntry))) - { - /* Exception occurred */ - return; - } + if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry)) + { + /* Exception occurred */ + return; + } + + if (!Valid) + { + State->Flags.Zf = FALSE; + return; }
/* Privilege check */ @@ -690,6 +634,12 @@ /* Changing CR0 or CR3 can interfere with prefetching (because of paging) */ State->PrefetchValid = FALSE; #endif + + if (State->Tlb && (ModRegRm.Register == (INT)FAST486_REG_CR3)) + { + /* Flush the TLB */ + RtlZeroMemory(State->Tlb, NUM_TLB_ENTRIES * sizeof(ULONG)); + }
/* 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] Tue Nov 4 22:58:02 2014 @@ -4079,6 +4079,15 @@ return; }
+ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) + { + if (!Fast486ProcessGate(State, Segment, Offset, TRUE)) + { + /* Gate processed or exception occurred */ + return; + } + } + /* Push the current code segment selector */ if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector)) { @@ -4537,6 +4546,17 @@
NO_LOCK_PREFIX(); TOGGLE_OPSIZE(Size); + + /* Check if this is a nested task return */ + if (State->Flags.Nt && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)) + { + /* Clear the NT flag of the current task */ + State->Flags.Nt = FALSE; + + /* Switch to the old task */ + Fast486TaskSwitch(State, FAST486_TASK_RETURN, 0); + return; + }
/* Pop EIP */ if (!Fast486StackPop(State, &InstPtr)) @@ -4597,14 +4617,6 @@ return; }
- if (State->Flags.Nt) - { - /* Nested task return */ - - UNIMPLEMENTED; - return; - } - if (NewFlags.Vm) { /* Return to VM86 mode */ @@ -5019,6 +5031,15 @@ { /* Exception occurred */ return; + } + + if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) + { + if (!Fast486ProcessGate(State, Segment, Offset, FALSE)) + { + /* Gate processed or exception occurred */ + return; + } }
/* Load the new CS */
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] Tue Nov 4 22:58:02 2014 @@ -1420,6 +1420,15 @@ return; }
+ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) + { + if (!Fast486ProcessGate(State, Selector, Value, TRUE)) + { + /* Gate processed or exception occurred */ + return; + } + } + /* Push the current value of CS */ if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector)) { @@ -1473,6 +1482,15 @@ return; }
+ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) + { + if (!Fast486ProcessGate(State, Selector, Value, FALSE)) + { + /* Gate processed or exception occurred */ + return; + } + } + /* Load the new code segment */ if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector)) { @@ -1712,6 +1730,7 @@ /* LLDT */ case 2: { + BOOLEAN Valid; USHORT Selector; FAST486_SYSTEM_DESCRIPTOR GdtEntry;
@@ -1739,21 +1758,26 @@ return; }
- /* Make sure the GDT contains the entry */ - if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1)) - { + if (Selector & SEGMENT_TABLE_INDICATOR) + { + /* This selector doesn't point to the GDT */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); return; }
- /* Read the GDT */ - if (!Fast486ReadLinearMemory(State, - State->Gdtr.Address - + GET_SEGMENT_INDEX(Selector), - &GdtEntry, - sizeof(GdtEntry))) - { - /* Exception occurred */ + if (Fast486ReadDescriptorEntry(State, + Selector, + &Valid, + (PFAST486_GDT_ENTRY)&GdtEntry)) + { + /* Exception occurred */ + return; + } + + if (!Valid) + { + /* Invalid selector */ + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); return; }
@@ -1788,6 +1812,7 @@ /* LTR */ case 3: { + BOOLEAN Valid; USHORT Selector; FAST486_SYSTEM_DESCRIPTOR GdtEntry;
@@ -1815,21 +1840,26 @@ return; }
- /* Make sure the GDT contains the entry */ - if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1)) - { + if (Selector & SEGMENT_TABLE_INDICATOR) + { + /* This selector doesn't point to the GDT */ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); return; }
- /* Read the GDT */ - if (!Fast486ReadLinearMemory(State, - State->Gdtr.Address - + GET_SEGMENT_INDEX(Selector), - &GdtEntry, - sizeof(GdtEntry))) - { - /* Exception occurred */ + if (Fast486ReadDescriptorEntry(State, + Selector, + &Valid, + (PFAST486_GDT_ENTRY)&GdtEntry)) + { + /* Exception occurred */ + return; + } + + if (!Valid) + { + /* Invalid selector */ + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); return; }
@@ -1857,7 +1887,6 @@ State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24); State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16); if (GdtEntry.Granularity) State->TaskReg.Limit <<= 12; - State->TaskReg.Busy = TRUE;
break; } @@ -1867,6 +1896,7 @@ case 5: { USHORT Selector; + BOOLEAN Valid; FAST486_GDT_ENTRY GdtEntry;
/* Not recognized in real mode or virtual 8086 mode */ @@ -1893,47 +1923,17 @@ return; }
- if (!(Selector & SEGMENT_TABLE_INDICATOR)) - { - /* Make sure the GDT contains the entry */ - if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1)) - { - /* Clear ZF */ - State->Flags.Zf = FALSE; - return; - } - - /* Read the GDT */ - if (!Fast486ReadLinearMemory(State, - State->Gdtr.Address - + GET_SEGMENT_INDEX(Selector), - &GdtEntry, - sizeof(GdtEntry))) - { - /* Exception occurred */ - return; - } - } - else - { - /* Make sure the LDT contains the entry */ - if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1)) - { - /* Clear ZF */ - State->Flags.Zf = FALSE; - return; - } - - /* Read the LDT */ - if (!Fast486ReadLinearMemory(State, - State->Ldtr.Base - + GET_SEGMENT_INDEX(Selector), - &GdtEntry, - sizeof(GdtEntry))) - { - /* Exception occurred */ - return; - } + if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry)) + { + /* Exception occurred */ + return; + } + + if (!Valid) + { + /* Clear ZF */ + State->Flags.Zf = FALSE; + return; }
/* Set ZF if it is valid and accessible */