From: Aleksandar Andrejevic Date: Fri, 13 Dec 2013 03:32:41 +0000 (+0000) Subject: [FAST486] X-Git-Tag: backups/0.3.17@66124~1365^2~182 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=5303c91efa8e2c05f1b8f2126d08730a657bb5a1 [FAST486] Implement the extended opcode group 0x0F, 0x00 (SLDT, STR, LLDT, LTR, VERR, VERW). svn path=/branches/ntvdm/; revision=61264 --- diff --git a/include/reactos/libs/fast486/fast486.h b/include/reactos/libs/fast486/fast486.h index ffeccf3ff0a..61e132825e4 100644 --- a/include/reactos/libs/fast486/fast486.h +++ b/include/reactos/libs/fast486/fast486.h @@ -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]; diff --git a/lib/fast486/common.c b/lib/fast486/common.c index aef8d004820..36f026ec331 100644 --- a/lib/fast486/common.c +++ b/lib/fast486/common.c @@ -178,7 +178,7 @@ Fast486InterruptInternal(PFAST486_STATE State, { /* Read the TSS */ if (!Fast486ReadLinearMemory(State, - State->Tss.Address, + State->TaskReg.Base, &Tss, sizeof(Tss))) { diff --git a/lib/fast486/extraops.c b/lib/fast486/extraops.c index b76aa4302b8..02880588461 100644 --- a/lib/fast486/extraops.c +++ b/lib/fast486/extraops.c @@ -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 diff --git a/lib/fast486/opgroups.c b/lib/fast486/opgroups.c index e260acd5623..bfc0caa7079 100644 --- a/lib/fast486/opgroups.c +++ b/lib/fast486/opgroups.c @@ -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]; diff --git a/lib/fast486/opgroups.h b/lib/fast486/opgroups.h index fdd941f3bdd..bf55cce9c3f 100644 --- a/lib/fast486/opgroups.h +++ b/lib/fast486/opgroups.h @@ -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);