[FAST486]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Sat, 14 Dec 2013 02:13:01 +0000 (02:13 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Sat, 14 Dec 2013 02:13:01 +0000 (02:13 +0000)
Fix the emulation of the Local Descriptor Table.

svn path=/branches/ntvdm/; revision=61268

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

index 61e1328..c660a25 100644 (file)
@@ -81,6 +81,7 @@
 #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_PREFIX_SEG      (1 << 0)
@@ -256,6 +257,13 @@ typedef struct _FAST486_SEG_REG
     ULONG Base;
 } FAST486_SEG_REG, *PFAST486_SEG_REG;
 
+typedef struct
+{
+    USHORT Selector;
+    ULONG Base;
+    ULONG Limit;
+} FAST486_LDT_REG;
+
 typedef struct
 {
     USHORT Selector;
@@ -302,10 +310,10 @@ typedef struct
     ULONG Reserved      : 2;
     ULONG Granularity   : 1;
     ULONG BaseHigh      : 8;
-} FAST486_TSS_DESCRIPTOR, *PFAST486_TSS_DESCRIPTOR;
+} FAST486_SYSTEM_DESCRIPTOR, *PFAST486_SYSTEM_DESCRIPTOR;
 
 /* Verify the structure size */
-C_ASSERT(sizeof(FAST486_TSS_DESCRIPTOR) == sizeof(ULONGLONG));
+C_ASSERT(sizeof(FAST486_SYSTEM_DESCRIPTOR) == sizeof(ULONGLONG));
 
 typedef struct
 {
@@ -467,7 +475,8 @@ struct _FAST486_STATE
     FAST486_SEG_REG SegmentRegs[FAST486_NUM_SEG_REGS];
     FAST486_REG InstPtr, SavedInstPtr;
     FAST486_FLAGS_REG Flags;
-    FAST486_TABLE_REG Gdtr, Idtr, Ldtr;
+    FAST486_TABLE_REG Gdtr, Idtr;
+    FAST486_LDT_REG Ldtr;
     FAST486_TASK_REG TaskReg;
     UCHAR Cpl;
     ULONG ControlRegisters[FAST486_NUM_CTRL_REGS];
index 2282434..61e69a6 100644 (file)
@@ -420,7 +420,7 @@ Fast486LoadSegment(PFAST486_STATE State,
         else
         {
             /* Make sure the LDT contains the entry */
-            if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Size + 1))
+            if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
             {
                 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
                 return FALSE;
@@ -428,7 +428,7 @@ Fast486LoadSegment(PFAST486_STATE State,
 
             /* Read the LDT */
             if (!Fast486ReadLinearMemory(State,
-                                         State->Ldtr.Address
+                                         State->Ldtr.Base
                                          + GET_SEGMENT_INDEX(Selector),
                                          &GdtEntry,
                                          sizeof(GdtEntry)))
index bfc0caa..be4d701 100644 (file)
@@ -1702,10 +1702,8 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
 
 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
 {
-    UCHAR TableReg[6];
     FAST486_MOD_REG_RM ModRegRm;
     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
-    FAST486_SEG_REGS Segment = FAST486_REG_DS;
 
     NO_LOCK_PREFIX();
     TOGGLE_ADSIZE(AddressSize);
@@ -1716,36 +1714,23 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
         return FALSE;
     }
 
-    /* Check for the segment override */
-    if (State->PrefixFlags & FAST486_PREFIX_SEG)
-    {
-        /* Use the override segment instead */
-        Segment = State->SegmentOverride;
-    }
-
     /* Check which operation this is */
     switch (ModRegRm.Register)
     {
         /* SLDT */
         case 0:
         {
-            if (!ModRegRm.Memory)
+            /* Not recognized in real mode or virtual 8086 mode */
+            if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+                || State->Flags.Vm)
             {
-                /* The second operand must be a memory location */
                 Fast486Exception(State, FAST486_EXCEPTION_UD);
-                return FALSE;
             }
 
-            /* Fill the 6-byte table register */
-            RtlCopyMemory(TableReg, &State->Ldtr.Size, sizeof(USHORT));
-            RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Ldtr.Address, sizeof(ULONG));
-
-            /* Store the LDTR */
-            return Fast486WriteMemory(State,
-                                      Segment,
-                                      ModRegRm.MemoryAddress,
-                                      TableReg,
-                                      sizeof(TableReg));
+            return Fast486WriteModrmWordOperands(State,
+                                                 &ModRegRm,
+                                                 FALSE,
+                                                 State->Ldtr.Selector);
         }
 
         /* STR */
@@ -1767,6 +1752,16 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
         /* LLDT */
         case 2:
         {
+            USHORT Selector;
+            FAST486_SYSTEM_DESCRIPTOR GdtEntry;
+
+            /* Not recognized in real mode or virtual 8086 mode */
+            if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+                || State->Flags.Vm)
+            {
+                Fast486Exception(State, FAST486_EXCEPTION_UD);
+            }
+
             /* This is a privileged instruction */
             if (Fast486GetCurrentPrivLevel(State) != 0)
             {
@@ -1774,28 +1769,57 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
                 return FALSE;
             }
 
-            if (!ModRegRm.Memory)
+            if (!Fast486ReadModrmWordOperands(State,
+                                              &ModRegRm,
+                                              NULL,
+                                              &Selector))
             {
-                /* The second operand must be a memory location */
-                Fast486Exception(State, FAST486_EXCEPTION_UD);
+                /* Exception occurred */
                 return FALSE;
             }
 
-            /* Read the new LDTR */
-            if (!Fast486ReadMemory(State,
-                                   Segment,
-                                   ModRegRm.MemoryAddress,
-                                   FALSE,
-                                   TableReg,
-                                   sizeof(TableReg)))
+            /* 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;
             }
 
-            /* Load the new LDT */
-            State->Ldtr.Size = *((PUSHORT)TableReg);
-            State->Ldtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
+            if (GET_SEGMENT_INDEX(Selector) == 0)
+            {
+                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                return FALSE;
+            }
+
+            if (!GdtEntry.Present)
+            {
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
+                return FALSE;
+            }
+
+            if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
+            {
+                /* This is not a LDT descriptor */
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                return FALSE;
+            }
+
+            /* Update the LDTR */
+            State->Ldtr.Selector = Selector;
+            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;
 
             return TRUE;
         }
@@ -1804,7 +1828,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
         case 3:
         {
             USHORT Selector;
-            FAST486_TSS_DESCRIPTOR GdtEntry;
+            FAST486_SYSTEM_DESCRIPTOR GdtEntry;
 
             /* Not recognized in real mode or virtual 8086 mode */
             if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
@@ -1930,7 +1954,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
             else
             {
                 /* Make sure the LDT contains the entry */
-                if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Size + 1))
+                if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
                 {
                     /* Clear ZF */
                     State->Flags.Zf = FALSE;
@@ -1939,7 +1963,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
 
                 /* Read the LDT */
                 if (!Fast486ReadLinearMemory(State,
-                                             State->Ldtr.Address
+                                             State->Ldtr.Base
                                              + GET_SEGMENT_INDEX(Selector),
                                              &GdtEntry,
                                              sizeof(GdtEntry)))