mirror of
https://github.com/reactos/reactos.git
synced 2025-04-19 12:08:55 +00:00
[FAST486]
Implement the extended opcode group 0x0F, 0x00 (SLDT, STR, LLDT, LTR, VERR, VERW). svn path=/branches/ntvdm/; revision=61264
This commit is contained in:
parent
de64fe5965
commit
5303c91efa
5 changed files with 315 additions and 3 deletions
|
@ -81,6 +81,8 @@
|
||||||
#define FAST486_IDT_INT_GATE_32 0xE
|
#define FAST486_IDT_INT_GATE_32 0xE
|
||||||
#define FAST486_IDT_TRAP_GATE_32 0xF
|
#define FAST486_IDT_TRAP_GATE_32 0xF
|
||||||
|
|
||||||
|
#define FAST486_TSS_SIGNATURE 0x09
|
||||||
|
|
||||||
#define FAST486_PREFIX_SEG (1 << 0)
|
#define FAST486_PREFIX_SEG (1 << 0)
|
||||||
#define FAST486_PREFIX_OPSIZE (1 << 1)
|
#define FAST486_PREFIX_OPSIZE (1 << 1)
|
||||||
#define FAST486_PREFIX_ADSIZE (1 << 2)
|
#define FAST486_PREFIX_ADSIZE (1 << 2)
|
||||||
|
@ -254,6 +256,14 @@ typedef struct _FAST486_SEG_REG
|
||||||
ULONG Base;
|
ULONG Base;
|
||||||
} FAST486_SEG_REG, *PFAST486_SEG_REG;
|
} 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)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -279,6 +289,24 @@ typedef struct
|
||||||
/* Verify the structure size */
|
/* Verify the structure size */
|
||||||
C_ASSERT(sizeof(FAST486_GDT_ENTRY) == sizeof(ULONGLONG));
|
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
|
typedef struct
|
||||||
{
|
{
|
||||||
ULONG Offset : 16;
|
ULONG Offset : 16;
|
||||||
|
@ -439,7 +467,8 @@ struct _FAST486_STATE
|
||||||
FAST486_SEG_REG SegmentRegs[FAST486_NUM_SEG_REGS];
|
FAST486_SEG_REG SegmentRegs[FAST486_NUM_SEG_REGS];
|
||||||
FAST486_REG InstPtr, SavedInstPtr;
|
FAST486_REG InstPtr, SavedInstPtr;
|
||||||
FAST486_FLAGS_REG Flags;
|
FAST486_FLAGS_REG Flags;
|
||||||
FAST486_TABLE_REG Gdtr, Idtr, Ldtr, Tss;
|
FAST486_TABLE_REG Gdtr, Idtr, Ldtr;
|
||||||
|
FAST486_TASK_REG TaskReg;
|
||||||
UCHAR Cpl;
|
UCHAR Cpl;
|
||||||
ULONG ControlRegisters[FAST486_NUM_CTRL_REGS];
|
ULONG ControlRegisters[FAST486_NUM_CTRL_REGS];
|
||||||
ULONG DebugRegisters[FAST486_NUM_DBG_REGS];
|
ULONG DebugRegisters[FAST486_NUM_DBG_REGS];
|
||||||
|
|
|
@ -178,7 +178,7 @@ Fast486InterruptInternal(PFAST486_STATE State,
|
||||||
{
|
{
|
||||||
/* Read the TSS */
|
/* Read the TSS */
|
||||||
if (!Fast486ReadLinearMemory(State,
|
if (!Fast486ReadLinearMemory(State,
|
||||||
State->Tss.Address,
|
State->TaskReg.Base,
|
||||||
&Tss,
|
&Tss,
|
||||||
sizeof(Tss)))
|
sizeof(Tss)))
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
FAST486_OPCODE_HANDLER_PROC
|
FAST486_OPCODE_HANDLER_PROC
|
||||||
Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] =
|
Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] =
|
||||||
{
|
{
|
||||||
NULL, // TODO: OPCODE 0x00 NOT IMPLEMENTED
|
Fast486OpcodeGroup0F00,
|
||||||
Fast486OpcodeGroup0F01,
|
Fast486OpcodeGroup0F01,
|
||||||
NULL, // TODO: OPCODE 0x02 NOT IMPLEMENTED
|
NULL, // TODO: OPCODE 0x02 NOT IMPLEMENTED
|
||||||
NULL, // TODO: OPCODE 0x03 NOT IMPLEMENTED
|
NULL, // TODO: OPCODE 0x03 NOT IMPLEMENTED
|
||||||
|
|
|
@ -1700,6 +1700,288 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
|
||||||
return TRUE;
|
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)
|
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01)
|
||||||
{
|
{
|
||||||
UCHAR TableReg[6];
|
UCHAR TableReg[6];
|
||||||
|
|
|
@ -42,6 +42,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6);
|
||||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7);
|
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7);
|
||||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE);
|
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE);
|
||||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF);
|
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF);
|
||||||
|
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00);
|
||||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01);
|
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01);
|
||||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9);
|
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9);
|
||||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA);
|
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA);
|
||||||
|
|
Loading…
Reference in a new issue