[FAST486]

Fix the emulation of the Local Descriptor Table.


svn path=/branches/ntvdm/; revision=61268
This commit is contained in:
Aleksandar Andrejevic 2013-12-14 02:13:01 +00:00
parent aac5c65456
commit 18b844dffa
3 changed files with 80 additions and 47 deletions

View file

@ -81,6 +81,7 @@
#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_LDT_SIGNATURE 0x02
#define FAST486_TSS_SIGNATURE 0x09 #define FAST486_TSS_SIGNATURE 0x09
#define FAST486_PREFIX_SEG (1 << 0) #define FAST486_PREFIX_SEG (1 << 0)
@ -256,6 +257,13 @@ 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;
} FAST486_LDT_REG;
typedef struct typedef struct
{ {
USHORT Selector; USHORT Selector;
@ -302,10 +310,10 @@ typedef struct
ULONG Reserved : 2; ULONG Reserved : 2;
ULONG Granularity : 1; ULONG Granularity : 1;
ULONG BaseHigh : 8; ULONG BaseHigh : 8;
} FAST486_TSS_DESCRIPTOR, *PFAST486_TSS_DESCRIPTOR; } FAST486_SYSTEM_DESCRIPTOR, *PFAST486_SYSTEM_DESCRIPTOR;
/* Verify the structure size */ /* Verify the structure size */
C_ASSERT(sizeof(FAST486_TSS_DESCRIPTOR) == sizeof(ULONGLONG)); C_ASSERT(sizeof(FAST486_SYSTEM_DESCRIPTOR) == sizeof(ULONGLONG));
typedef struct typedef struct
{ {
@ -467,7 +475,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; FAST486_TABLE_REG Gdtr, Idtr;
FAST486_LDT_REG Ldtr;
FAST486_TASK_REG TaskReg; FAST486_TASK_REG TaskReg;
UCHAR Cpl; UCHAR Cpl;
ULONG ControlRegisters[FAST486_NUM_CTRL_REGS]; ULONG ControlRegisters[FAST486_NUM_CTRL_REGS];

View file

@ -420,7 +420,7 @@ Fast486LoadSegment(PFAST486_STATE State,
else else
{ {
/* Make sure the LDT contains the entry */ /* 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); Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return FALSE; return FALSE;
@ -428,7 +428,7 @@ Fast486LoadSegment(PFAST486_STATE State,
/* Read the LDT */ /* Read the LDT */
if (!Fast486ReadLinearMemory(State, if (!Fast486ReadLinearMemory(State,
State->Ldtr.Address State->Ldtr.Base
+ GET_SEGMENT_INDEX(Selector), + GET_SEGMENT_INDEX(Selector),
&GdtEntry, &GdtEntry,
sizeof(GdtEntry))) sizeof(GdtEntry)))

View file

@ -1702,10 +1702,8 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00) FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
{ {
UCHAR TableReg[6];
FAST486_MOD_REG_RM ModRegRm; FAST486_MOD_REG_RM ModRegRm;
BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
FAST486_SEG_REGS Segment = FAST486_REG_DS;
NO_LOCK_PREFIX(); NO_LOCK_PREFIX();
TOGGLE_ADSIZE(AddressSize); TOGGLE_ADSIZE(AddressSize);
@ -1716,36 +1714,23 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
return FALSE; 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 */ /* Check which operation this is */
switch (ModRegRm.Register) switch (ModRegRm.Register)
{ {
/* SLDT */ /* SLDT */
case 0: 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); Fast486Exception(State, FAST486_EXCEPTION_UD);
return FALSE;
} }
/* Fill the 6-byte table register */ return Fast486WriteModrmWordOperands(State,
RtlCopyMemory(TableReg, &State->Ldtr.Size, sizeof(USHORT)); &ModRegRm,
RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Ldtr.Address, sizeof(ULONG)); FALSE,
State->Ldtr.Selector);
/* Store the LDTR */
return Fast486WriteMemory(State,
Segment,
ModRegRm.MemoryAddress,
TableReg,
sizeof(TableReg));
} }
/* STR */ /* STR */
@ -1767,6 +1752,16 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
/* LLDT */ /* LLDT */
case 2: 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 */ /* This is a privileged instruction */
if (Fast486GetCurrentPrivLevel(State) != 0) if (Fast486GetCurrentPrivLevel(State) != 0)
{ {
@ -1774,28 +1769,57 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
return FALSE; return FALSE;
} }
if (!ModRegRm.Memory) if (!Fast486ReadModrmWordOperands(State,
{ &ModRegRm,
/* The second operand must be a memory location */ NULL,
Fast486Exception(State, FAST486_EXCEPTION_UD); &Selector))
return FALSE;
}
/* Read the new LDTR */
if (!Fast486ReadMemory(State,
Segment,
ModRegRm.MemoryAddress,
FALSE,
TableReg,
sizeof(TableReg)))
{ {
/* Exception occurred */ /* Exception occurred */
return FALSE; return FALSE;
} }
/* Load the new LDT */ /* Make sure the GDT contains the entry */
State->Ldtr.Size = *((PUSHORT)TableReg); if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
State->Ldtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]); {
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_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; return TRUE;
} }
@ -1804,7 +1828,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
case 3: case 3:
{ {
USHORT Selector; USHORT Selector;
FAST486_TSS_DESCRIPTOR GdtEntry; FAST486_SYSTEM_DESCRIPTOR GdtEntry;
/* Not recognized in real mode or virtual 8086 mode */ /* Not recognized in real mode or virtual 8086 mode */
if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
@ -1930,7 +1954,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
else else
{ {
/* Make sure the LDT contains the entry */ /* 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 */ /* Clear ZF */
State->Flags.Zf = FALSE; State->Flags.Zf = FALSE;
@ -1939,7 +1963,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
/* Read the LDT */ /* Read the LDT */
if (!Fast486ReadLinearMemory(State, if (!Fast486ReadLinearMemory(State,
State->Ldtr.Address State->Ldtr.Base
+ GET_SEGMENT_INDEX(Selector), + GET_SEGMENT_INDEX(Selector),
&GdtEntry, &GdtEntry,
sizeof(GdtEntry))) sizeof(GdtEntry)))