[FAST486]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Fri, 13 Dec 2013 03:32:41 +0000 (03:32 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Fri, 13 Dec 2013 03:32:41 +0000 (03:32 +0000)
Implement the extended opcode group 0x0F, 0x00 (SLDT, STR, LLDT, LTR, VERR, VERW).

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

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

index ffeccf3..61e1328 100644 (file)
@@ -81,6 +81,8 @@
 #define FAST486_IDT_INT_GATE_32     0xE
 #define FAST486_IDT_TRAP_GATE_32    0xF
 
+#define FAST486_TSS_SIGNATURE 0x09
+
 #define FAST486_PREFIX_SEG      (1 << 0)
 #define FAST486_PREFIX_OPSIZE   (1 << 1)
 #define FAST486_PREFIX_ADSIZE   (1 << 2)
@@ -254,6 +256,14 @@ typedef struct _FAST486_SEG_REG
     ULONG Base;
 } FAST486_SEG_REG, *PFAST486_SEG_REG;
 
+typedef struct
+{
+    USHORT Selector;
+    ULONG Base;
+    ULONG Limit;
+    BOOLEAN Busy;
+} FAST486_TASK_REG, *PFAST486_TASK_REG;
+
 #pragma pack(push, 1)
 
 typedef struct
@@ -279,6 +289,24 @@ typedef struct
 /* Verify the structure size */
 C_ASSERT(sizeof(FAST486_GDT_ENTRY) == sizeof(ULONGLONG));
 
+typedef struct
+{
+    ULONG Limit         : 16;
+    ULONG Base          : 16;
+    ULONG BaseMid       : 8;
+    ULONG Signature     : 5;
+    ULONG Dpl           : 2;
+    ULONG Present       : 1;
+    ULONG LimitHigh     : 4;
+    ULONG Avl           : 1;
+    ULONG Reserved      : 2;
+    ULONG Granularity   : 1;
+    ULONG BaseHigh      : 8;
+} FAST486_TSS_DESCRIPTOR, *PFAST486_TSS_DESCRIPTOR;
+
+/* Verify the structure size */
+C_ASSERT(sizeof(FAST486_TSS_DESCRIPTOR) == sizeof(ULONGLONG));
+
 typedef struct
 {
     ULONG Offset : 16;
@@ -439,7 +467,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, Tss;
+    FAST486_TABLE_REG Gdtr, Idtr, Ldtr;
+    FAST486_TASK_REG TaskReg;
     UCHAR Cpl;
     ULONG ControlRegisters[FAST486_NUM_CTRL_REGS];
     ULONG DebugRegisters[FAST486_NUM_DBG_REGS];
index aef8d00..36f026e 100644 (file)
@@ -178,7 +178,7 @@ Fast486InterruptInternal(PFAST486_STATE State,
         {
             /* Read the TSS */
             if (!Fast486ReadLinearMemory(State,
-                                         State->Tss.Address,
+                                         State->TaskReg.Base,
                                          &Tss,
                                          sizeof(Tss)))
             {
index b76aa43..0288058 100644 (file)
@@ -37,7 +37,7 @@
 FAST486_OPCODE_HANDLER_PROC
 Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] =
 {
-    NULL, // TODO: OPCODE 0x00 NOT IMPLEMENTED
+    Fast486OpcodeGroup0F00,
     Fast486OpcodeGroup0F01,
     NULL, // TODO: OPCODE 0x02 NOT IMPLEMENTED
     NULL, // TODO: OPCODE 0x03 NOT IMPLEMENTED
index e260acd..bfc0caa 100644 (file)
@@ -1700,6 +1700,288 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
     return TRUE;
 }
 
+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);
+
+    if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
+    {
+        /* Exception occurred */
+        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)
+            {
+                /* 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));
+        }
+
+        /* STR */
+        case 1:
+        {
+            /* 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);
+            }
+
+            return Fast486WriteModrmWordOperands(State,
+                                                 &ModRegRm,
+                                                 FALSE,
+                                                 State->TaskReg.Selector);
+        }
+
+        /* LLDT */
+        case 2:
+        {
+            /* This is a privileged instruction */
+            if (Fast486GetCurrentPrivLevel(State) != 0)
+            {
+                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                return FALSE;
+            }
+
+            if (!ModRegRm.Memory)
+            {
+                /* The second operand must be a memory location */
+                Fast486Exception(State, FAST486_EXCEPTION_UD);
+                return FALSE;
+            }
+
+            /* Read the new LDTR */
+            if (!Fast486ReadMemory(State,
+                                   Segment,
+                                   ModRegRm.MemoryAddress,
+                                   FALSE,
+                                   TableReg,
+                                   sizeof(TableReg)))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+
+            /* Load the new LDT */
+            State->Ldtr.Size = *((PUSHORT)TableReg);
+            State->Ldtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
+
+            return TRUE;
+        }
+
+        /* LTR */
+        case 3:
+        {
+            USHORT Selector;
+            FAST486_TSS_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)
+            {
+                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                return FALSE;
+            }
+
+            if (!Fast486ReadModrmWordOperands(State,
+                                              &ModRegRm,
+                                              NULL,
+                                              &Selector))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+
+            /* 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;
+            }
+
+            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_TSS_SIGNATURE)
+            {
+                /* This is not a TSS descriptor */
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                return FALSE;
+            }
+
+            /* Update the TR */
+            State->TaskReg.Selector = Selector;
+            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;
+
+            return TRUE;
+        }
+
+        /* VERR/VERW */
+        case 4:
+        case 5:
+        {
+            USHORT Selector;
+            FAST486_GDT_ENTRY 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)
+            {
+                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                return FALSE;
+            }
+
+            if (!Fast486ReadModrmWordOperands(State,
+                                              &ModRegRm,
+                                              NULL,
+                                              &Selector))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+
+            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 TRUE;
+                }
+
+                /* 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.Size + 1))
+                {
+                    /* Clear ZF */
+                    State->Flags.Zf = FALSE;
+                    return TRUE;
+                }
+
+                /* Read the LDT */
+                if (!Fast486ReadLinearMemory(State,
+                                             State->Ldtr.Address
+                                             + GET_SEGMENT_INDEX(Selector),
+                                             &GdtEntry,
+                                             sizeof(GdtEntry)))
+                {
+                    /* Exception occurred */
+                    return FALSE;
+                }
+            }
+
+            /* Set ZF if it is valid and accessible */
+            State->Flags.Zf = GdtEntry.Present // must be present
+                               && GdtEntry.SystemType // must be a segment
+                               && (((ModRegRm.Register == 4)
+                               /* code segments are only readable if the RW bit is set */
+                               && (!GdtEntry.Executable || GdtEntry.ReadWrite))
+                               || ((ModRegRm.Register == 5)
+                               /* code segments are never writable, data segments are writable when RW is set */
+                               && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
+                               /*
+                                * for segments other than conforming code segments,
+                                * both RPL and CPL must be less than or equal to DPL
+                                */
+                               && ((!GdtEntry.Executable || !GdtEntry.DirConf)
+                               && ((GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
+                               && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl)))
+                               /* for conforming code segments, DPL must be less than or equal to CPL */
+                               && ((GdtEntry.Executable && GdtEntry.DirConf)
+                               && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State)));
+
+
+            return TRUE;
+        }
+
+        /* Invalid */
+        default:
+        {
+            Fast486Exception(State, FAST486_EXCEPTION_UD);
+            return FALSE;
+        }
+    }
+}
+
 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01)
 {
     UCHAR TableReg[6];
index fdd941f..bf55cce 100644 (file)
@@ -42,6 +42,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6);
 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7);
 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE);
 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF);
+FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00);
 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01);
 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9);
 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA);