[FAST486]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Tue, 4 Nov 2014 22:58:02 +0000 (22:58 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Tue, 4 Nov 2014 22:58:02 +0000 (22:58 +0000)
- Move the descriptor reading logic into a separate function.
- Implement hardware task switching and task gates.
- Flush the TLB when reloading CR3.

svn path=/trunk/; revision=65260

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 379ad08..e31cce1 100644 (file)
 #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 @@ typedef struct _FAST486_TASK_REG
     USHORT Selector;
     ULONG Base;
     ULONG Limit;
-    BOOLEAN Busy;
 } FAST486_TASK_REG, *PFAST486_TASK_REG;
 
 #include <pshpack1.h>
index a9fb89c..c776d2f 100644 (file)
@@ -274,6 +274,12 @@ Fast486InterruptInternal(PFAST486_STATE State,
         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 @@ Fast486ExceptionWithErrorCode(PFAST486_STATE State,
     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 */
index a87a3ee..d934f20 100644 (file)
@@ -69,6 +69,7 @@ if (State->PrefixFlags & FAST486_PREFIX_LOCK)\
 #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
 {
@@ -81,6 +82,13 @@ typedef struct _FAST486_MOD_REG_RM
     };
 } 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>
 
 typedef union _FAST486_PAGE_DIR
@@ -166,6 +174,15 @@ Fast486ExceptionWithErrorCode
     ULONG ErrorCode
 );
 
+BOOLEAN
+FASTCALL
+Fast486TaskSwitch
+(
+    PFAST486_STATE State,
+    FAST486_TASK_SWITCH_TYPE Type,
+    USHORT Selector
+);
+
 /* INLINED FUNCTIONS **********************************************************/
 
 #include "common.inl"
index 53d1dee..06dafe8 100644 (file)
@@ -426,11 +426,68 @@ Fast486StackPop(PFAST486_STATE State,
 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 @@ Fast486LoadSegment(PFAST486_STATE State,
     /* Check for protected mode */
     if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
     {
-        if (!(Selector & SEGMENT_TABLE_INDICATOR))
+        if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
         {
-            /* 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;
-            }
+            /* 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 (!Valid)
+        {
+            /* Invalid selector */
+            Fast486ExceptionWithErrorCode(State, Exception, Selector);
         }
 
         if (Segment == FAST486_REG_SS)
@@ -488,27 +516,27 @@ Fast486LoadSegment(PFAST486_STATE State,
 
             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 @@ Fast486LoadSegment(PFAST486_STATE State,
 
             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;
+                /* Must be a segment descriptor */
+                Fast486ExceptionWithErrorCode(State, Exception, Selector);
             }
-            else
+
+            if (!GdtEntry.Present)
             {
-                if (!GdtEntry.Present)
-                {
-                    Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
-                    return FALSE;
-                }
+                Fast486ExceptionWithErrorCode(State, Exception, Selector);
+                return FALSE;
+            }
+
+            if (!GdtEntry.Executable)
+            {
+                Fast486ExceptionWithErrorCode(State, Exception, Selector);
+                return FALSE;
+            }
 
-                if (!GdtEntry.Executable)
+            if (GdtEntry.DirConf)
+            {
+                /* Conforming Code Segment */
+
+                if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
                 {
-                    Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                    /* Must be accessed from lower-privileged code */
+                    Fast486ExceptionWithErrorCode(State, Exception, Selector);
                     return FALSE;
                 }
+            }
+            else
+            {
+                /* Regular code segment */
 
-                if (GdtEntry.DirConf)
+                if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State))
+                    || (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl))
                 {
-                    /* 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;
-                    }
+                    Fast486ExceptionWithErrorCode(State, Exception, Selector);
+                    return FALSE;
                 }
-
-                /* Update CPL */
-                State->Cpl = GET_SEGMENT_RPL(Selector);
             }
+
+            /* Update CPL */
+            State->Cpl = GET_SEGMENT_RPL(Selector);
         }
         else
         {
@@ -588,20 +614,20 @@ Fast486LoadSegment(PFAST486_STATE State,
                 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;
                 }
             }
@@ -639,6 +665,64 @@ Fast486LoadSegment(PFAST486_STATE State,
     return TRUE;
 }
 
+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
index eefd918..0b96d31 100644 (file)
@@ -320,6 +320,7 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar)
 {
     BOOLEAN OperandSize, AddressSize;
     FAST486_MOD_REG_RM ModRegRm;
+    BOOLEAN Valid;
     USHORT Selector;
     FAST486_GDT_ENTRY GdtEntry;
     DWORD AccessRights;
@@ -368,45 +369,16 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar)
         }
     }
 
-    if (!(Selector & SEGMENT_TABLE_INDICATOR))
+    if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
     {
-        /* 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;
-        }
+        /* 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 (!Valid)
+    {
+        State->Flags.Zf = FALSE;
+        return;
     }
 
     /* Privilege check */
@@ -432,6 +404,7 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)
 {
     BOOLEAN OperandSize, AddressSize;
     FAST486_MOD_REG_RM ModRegRm;
+    BOOLEAN Valid;
     USHORT Selector;
     ULONG Limit;
     FAST486_GDT_ENTRY GdtEntry;
@@ -480,45 +453,16 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)
         }
     }
 
-    if (!(Selector & SEGMENT_TABLE_INDICATOR))
+    if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
     {
-        /* 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;
-        }
+        /* 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 (!Valid)
+    {
+        State->Flags.Zf = FALSE;
+        return;
     }
 
     /* Privilege check */
@@ -691,6 +635,12 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
     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;
 }
index 1a8e247..0e004ea 100644 (file)
@@ -4079,6 +4079,15 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs)
         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))
     {
@@ -4538,6 +4547,17 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
     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 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
             return;
         }
 
-        if (State->Flags.Nt)
-        {
-            /* Nested task return */
-
-            UNIMPLEMENTED;
-            return;
-        }
-
         if (NewFlags.Vm)
         {
             /* Return to VM86 mode */
@@ -5021,6 +5033,15 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs)
         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 */
     if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
     {
index bca294d..2c99e47 100644 (file)
@@ -1420,6 +1420,15 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
                 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 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
                 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 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
         /* LLDT */
         case 2:
         {
+            BOOLEAN Valid;
             USHORT Selector;
             FAST486_SYSTEM_DESCRIPTOR GdtEntry;
 
@@ -1739,24 +1758,29 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
                 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)))
+            if (Fast486ReadDescriptorEntry(State,
+                                           Selector,
+                                           &Valid,
+                                           (PFAST486_GDT_ENTRY)&GdtEntry))
             {
                 /* Exception occurred */
                 return;
             }
 
+            if (!Valid)
+            {
+                /* Invalid selector */
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                return;
+            }
+
             if (GET_SEGMENT_INDEX(Selector) == 0)
             {
                 RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
@@ -1788,6 +1812,7 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
         /* LTR */
         case 3:
         {
+            BOOLEAN Valid;
             USHORT Selector;
             FAST486_SYSTEM_DESCRIPTOR GdtEntry;
 
@@ -1815,24 +1840,29 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
                 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)))
+            if (Fast486ReadDescriptorEntry(State,
+                                           Selector,
+                                           &Valid,
+                                           (PFAST486_GDT_ENTRY)&GdtEntry))
             {
                 /* Exception occurred */
                 return;
             }
 
+            if (!Valid)
+            {
+                /* Invalid selector */
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                return;
+            }
+
             if (GET_SEGMENT_INDEX(Selector) == 0)
             {
                 Fast486Exception(State, FAST486_EXCEPTION_GP);
@@ -1857,7 +1887,6 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
             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 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
         case 5:
         {
             USHORT Selector;
+            BOOLEAN Valid;
             FAST486_GDT_ENTRY GdtEntry;
 
             /* Not recognized in real mode or virtual 8086 mode */
@@ -1893,47 +1923,17 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
                 return;
             }
 
-            if (!(Selector & SEGMENT_TABLE_INDICATOR))
+            if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
             {
-                /* 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;
-                }
+                /* 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 (!Valid)
+            {
+                /* Clear ZF */
+                State->Flags.Zf = FALSE;
+                return;
             }
 
             /* Set ZF if it is valid and accessible */