[FAST486]

- Move the descriptor reading logic into a separate function.
- Implement hardware task switching and task gates.
- Flush the TLB when reloading CR3.


svn path=/trunk/; revision=65260
This commit is contained in:
Aleksandar Andrejevic 2014-11-04 22:58:02 +00:00
parent ca809b6cdc
commit b4648ec8fe
7 changed files with 607 additions and 227 deletions

View file

@ -75,14 +75,15 @@
#define FAST486_DR4_RESERVED 0xFFFF1FF0 #define FAST486_DR4_RESERVED 0xFFFF1FF0
#define FAST486_DR5_RESERVED 0x0000DC00 #define FAST486_DR5_RESERVED 0x0000DC00
#define FAST486_IDT_TASK_GATE 0x5 #define FAST486_LDT_SIGNATURE 0x02
#define FAST486_IDT_INT_GATE 0x6 #define FAST486_TASK_GATE_SIGNATURE 0x05
#define FAST486_IDT_TRAP_GATE 0x7 #define FAST486_IDT_INT_GATE 0x06
#define FAST486_IDT_INT_GATE_32 0xE #define FAST486_IDT_TRAP_GATE 0x07
#define FAST486_IDT_TRAP_GATE_32 0xF #define FAST486_TSS_SIGNATURE 0x09
#define FAST486_BUSY_TSS_SIGNATURE 0x0B
#define FAST486_LDT_SIGNATURE 0x02 #define FAST486_CALL_GATE_SIGNATURE 0x0C
#define FAST486_TSS_SIGNATURE 0x09 #define FAST486_IDT_INT_GATE_32 0x0E
#define FAST486_IDT_TRAP_GATE_32 0x0F
#define FAST486_PREFIX_SEG (1 << 0) #define FAST486_PREFIX_SEG (1 << 0)
#define FAST486_PREFIX_OPSIZE (1 << 1) #define FAST486_PREFIX_OPSIZE (1 << 1)
@ -270,7 +271,6 @@ typedef struct _FAST486_TASK_REG
USHORT Selector; USHORT Selector;
ULONG Base; ULONG Base;
ULONG Limit; ULONG Limit;
BOOLEAN Busy;
} FAST486_TASK_REG, *PFAST486_TASK_REG; } FAST486_TASK_REG, *PFAST486_TASK_REG;
#include <pshpack1.h> #include <pshpack1.h>

View file

@ -274,6 +274,12 @@ Fast486InterruptInternal(PFAST486_STATE State,
FAST486_TSS Tss; FAST486_TSS Tss;
USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector; USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector;
ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long; ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long;
if (GateType == FAST486_TASK_GATE_SIGNATURE)
{
/* Task call */
return Fast486TaskSwitch(State, FAST486_TASK_CALL, IdtEntry->Selector);
}
if (GateSize != (State->SegmentRegs[FAST486_REG_CS].Size)) if (GateSize != (State->SegmentRegs[FAST486_REG_CS].Size))
{ {
@ -484,4 +490,306 @@ Fast486ExceptionWithErrorCode(PFAST486_STATE State,
State->ExceptionCount = 0; State->ExceptionCount = 0;
} }
BOOLEAN
FASTCALL
Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Selector)
{
ULONG NewTssAddress;
ULONG NewTssLimit;
FAST486_TSS OldTss;
FAST486_TSS NewTss;
FAST486_SYSTEM_DESCRIPTOR NewTssDescriptor;
/* Read the old TSS */
if (!Fast486ReadLinearMemory(State,
State->TaskReg.Base,
&OldTss,
sizeof(OldTss)))
{
/* Exception occurred */
return FALSE;
}
/* If this is a task return, use the linked previous selector */
if (Type == FAST486_TASK_RETURN) Selector = LOWORD(OldTss.Link);
/* Make sure the entry exists in the GDT (not LDT!) */
if ((GET_SEGMENT_INDEX(Selector) == 0)
|| (Selector & SEGMENT_TABLE_INDICATOR)
|| GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
{
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, Selector);
return FALSE;
}
/* Get the TSS descriptor from the GDT */
if (!Fast486ReadLinearMemory(State,
State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
&NewTssDescriptor,
sizeof(NewTssDescriptor)))
{
/* Exception occurred */
return FALSE;
}
if (!NewTssDescriptor.Present)
{
/* Incoming task TSS not present */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
return FALSE;
}
/* Calculate the linear address of the new TSS */
NewTssAddress = NewTssDescriptor.Base;
NewTssAddress |= NewTssDescriptor.BaseMid << 16;
NewTssAddress |= NewTssDescriptor.BaseHigh << 24;
/* Calculate the limit of the new TSS */
NewTssLimit = NewTssDescriptor.Limit | (NewTssDescriptor.LimitHigh << 16);
if (NewTssDescriptor.Granularity) NewTssLimit <<= 12;
if (NewTssLimit < sizeof(FAST486_TSS))
{
/* TSS limit too small */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, Selector);
}
/*
* The incoming task shouldn't be busy if we're executing it as a
* new task, and it should be busy if we're returning to it.
*/
if (((NewTssDescriptor.Signature != FAST486_TSS_SIGNATURE)
|| (Type == FAST486_TASK_RETURN))
&& ((NewTssDescriptor.Signature != FAST486_BUSY_TSS_SIGNATURE)
|| (Type != FAST486_TASK_RETURN)))
{
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return FALSE;
}
/* Read the new TSS */
if (!Fast486ReadLinearMemory(State,
NewTssAddress,
&NewTss,
sizeof(NewTss)))
{
/* Exception occurred */
return FALSE;
}
if (Type != FAST486_TASK_CALL)
{
/* Clear the busy bit of the outgoing task */
FAST486_SYSTEM_DESCRIPTOR OldTssDescriptor;
if (!Fast486ReadLinearMemory(State,
State->Gdtr.Address
+ GET_SEGMENT_INDEX(State->TaskReg.Selector),
&OldTssDescriptor,
sizeof(OldTssDescriptor)))
{
/* Exception occurred */
return FALSE;
}
OldTssDescriptor.Signature = FAST486_TSS_SIGNATURE;
if (!Fast486WriteLinearMemory(State,
State->Gdtr.Address
+ GET_SEGMENT_INDEX(State->TaskReg.Selector),
&OldTssDescriptor,
sizeof(OldTssDescriptor)))
{
/* Exception occurred */
return FALSE;
}
}
else
{
/* Store the link */
NewTss.Link = State->TaskReg.Selector;
}
/* Save the current task into the TSS */
OldTss.Cr3 = State->ControlRegisters[FAST486_REG_CR3];
OldTss.Eip = State->InstPtr.Long;
OldTss.Eflags = State->Flags.Long;
OldTss.Eax = State->GeneralRegs[FAST486_REG_EAX].Long;
OldTss.Ecx = State->GeneralRegs[FAST486_REG_ECX].Long;
OldTss.Edx = State->GeneralRegs[FAST486_REG_EDX].Long;
OldTss.Ebx = State->GeneralRegs[FAST486_REG_EBX].Long;
OldTss.Esp = State->GeneralRegs[FAST486_REG_ESP].Long;
OldTss.Ebp = State->GeneralRegs[FAST486_REG_EBP].Long;
OldTss.Esi = State->GeneralRegs[FAST486_REG_ESI].Long;
OldTss.Edi = State->GeneralRegs[FAST486_REG_EDI].Long;
OldTss.Es = State->SegmentRegs[FAST486_REG_ES].Selector;
OldTss.Cs = State->SegmentRegs[FAST486_REG_CS].Selector;
OldTss.Ss = State->SegmentRegs[FAST486_REG_SS].Selector;
OldTss.Ds = State->SegmentRegs[FAST486_REG_DS].Selector;
OldTss.Fs = State->SegmentRegs[FAST486_REG_FS].Selector;
OldTss.Gs = State->SegmentRegs[FAST486_REG_GS].Selector;
OldTss.Ldtr = State->Ldtr.Selector;
/* Write back the old TSS */
if (!Fast486WriteLinearMemory(State,
State->TaskReg.Base,
&OldTss,
sizeof(OldTss)))
{
/* Exception occurred */
return FALSE;
}
/* Mark the new task as busy */
NewTssDescriptor.Signature = FAST486_BUSY_TSS_SIGNATURE;
/* Write back the new TSS descriptor */
if (!Fast486WriteLinearMemory(State,
State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
&NewTssDescriptor,
sizeof(NewTssDescriptor)))
{
/* Exception occurred */
return FALSE;
}
/* Set the task switch bit */
State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_TS;
/* Load the task register with the new values */
State->TaskReg.Selector = Selector;
State->TaskReg.Base = NewTssAddress;
State->TaskReg.Limit = NewTssLimit;
/* Change the page directory */
State->ControlRegisters[FAST486_REG_CR3] = NewTss.Cr3;
/* Flush the TLB */
if (State->Tlb) RtlZeroMemory(State->Tlb, NUM_TLB_ENTRIES * sizeof(ULONG));
#ifndef FAST486_NO_PREFETCH
/* Context switching invalidates the prefetch */
State->PrefetchValid = FALSE;
#endif
/* Load the registers */
State->InstPtr.Long = State->SavedInstPtr.Long = NewTss.Eip;
State->Flags.Long = NewTss.Eflags;
State->GeneralRegs[FAST486_REG_EAX].Long = NewTss.Eax;
State->GeneralRegs[FAST486_REG_ECX].Long = NewTss.Ecx;
State->GeneralRegs[FAST486_REG_EDX].Long = NewTss.Edx;
State->GeneralRegs[FAST486_REG_EBX].Long = NewTss.Ebx;
State->GeneralRegs[FAST486_REG_ESP].Long = NewTss.Esp;
State->GeneralRegs[FAST486_REG_EBP].Long = NewTss.Ebp;
State->GeneralRegs[FAST486_REG_ESI].Long = NewTss.Esi;
State->GeneralRegs[FAST486_REG_EDI].Long = NewTss.Edi;
/* Set the NT flag if nesting */
if (Type == FAST486_TASK_CALL) State->Flags.Nt = TRUE;
if (GET_SEGMENT_INDEX(NewTss.Ldtr) != 0)
{
BOOLEAN Valid;
FAST486_SYSTEM_DESCRIPTOR GdtEntry;
if (NewTss.Ldtr & SEGMENT_TABLE_INDICATOR)
{
/* This selector doesn't point to the GDT */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewTss.Ldtr);
return FALSE;
}
if (Fast486ReadDescriptorEntry(State,
NewTss.Ldtr,
&Valid,
(PFAST486_GDT_ENTRY)&GdtEntry))
{
/* Exception occurred */
return FALSE;
}
if (!Valid)
{
/* Invalid selector */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewTss.Ldtr);
return FALSE;
}
if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
{
/* This is not an LDT descriptor */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewTss.Ldtr);
return FALSE;
}
if (!GdtEntry.Present)
{
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewTss.Ldtr);
return FALSE;
}
/* Update the LDTR */
State->Ldtr.Selector = NewTss.Ldtr;
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;
}
else
{
/* The LDT of this task is empty */
RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
}
/* Load the new segments */
if (!Fast486LoadSegmentInternal(State,
FAST486_REG_CS,
NewTss.Cs,
FAST486_EXCEPTION_TS))
{
return FALSE;
}
if (!Fast486LoadSegmentInternal(State,
FAST486_REG_SS,
NewTss.Ss,
FAST486_EXCEPTION_TS))
{
return FALSE;
}
if (!Fast486LoadSegmentInternal(State,
FAST486_REG_ES,
NewTss.Es,
FAST486_EXCEPTION_TS))
{
return FALSE;
}
if (!Fast486LoadSegmentInternal(State,
FAST486_REG_DS,
NewTss.Ds,
FAST486_EXCEPTION_TS))
{
return FALSE;
}
if (!Fast486LoadSegmentInternal(State,
FAST486_REG_FS,
NewTss.Fs,
FAST486_EXCEPTION_TS))
{
return FALSE;
}
if (!Fast486LoadSegmentInternal(State,
FAST486_REG_GS,
NewTss.Gs,
FAST486_EXCEPTION_TS))
{
return FALSE;
}
return TRUE;
}
/* EOF */ /* EOF */

View file

@ -69,6 +69,7 @@ if (State->PrefixFlags & FAST486_PREFIX_LOCK)\
#define GET_ADDR_PDE(x) ((x) >> 22) #define GET_ADDR_PDE(x) ((x) >> 22)
#define GET_ADDR_PTE(x) (((x) >> 12) & 0x3FF) #define GET_ADDR_PTE(x) (((x) >> 12) & 0x3FF)
#define INVALID_TLB_FIELD 0xFFFFFFFF #define INVALID_TLB_FIELD 0xFFFFFFFF
#define NUM_TLB_ENTRIES 0x100000
typedef struct _FAST486_MOD_REG_RM typedef struct _FAST486_MOD_REG_RM
{ {
@ -81,6 +82,13 @@ typedef struct _FAST486_MOD_REG_RM
}; };
} FAST486_MOD_REG_RM, *PFAST486_MOD_REG_RM; } FAST486_MOD_REG_RM, *PFAST486_MOD_REG_RM;
typedef enum _FAST486_TASK_SWITCH_TYPE
{
FAST486_TASK_JUMP,
FAST486_TASK_CALL,
FAST486_TASK_RETURN
} FAST486_TASK_SWITCH_TYPE, *PFAST486_TASK_SWITCH_TYPE;
#include <pshpack1.h> #include <pshpack1.h>
typedef union _FAST486_PAGE_DIR typedef union _FAST486_PAGE_DIR
@ -166,6 +174,15 @@ Fast486ExceptionWithErrorCode
ULONG ErrorCode ULONG ErrorCode
); );
BOOLEAN
FASTCALL
Fast486TaskSwitch
(
PFAST486_STATE State,
FAST486_TASK_SWITCH_TYPE Type,
USHORT Selector
);
/* INLINED FUNCTIONS **********************************************************/ /* INLINED FUNCTIONS **********************************************************/
#include "common.inl" #include "common.inl"

View file

@ -426,11 +426,68 @@ Fast486StackPop(PFAST486_STATE State,
FORCEINLINE FORCEINLINE
BOOLEAN BOOLEAN
FASTCALL FASTCALL
Fast486LoadSegment(PFAST486_STATE State, Fast486ReadDescriptorEntry(PFAST486_STATE State,
FAST486_SEG_REGS Segment, USHORT Selector,
USHORT Selector) PBOOLEAN EntryValid,
PFAST486_GDT_ENTRY Entry)
{
if (!(Selector & SEGMENT_TABLE_INDICATOR))
{
/* Make sure the GDT contains the entry */
if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
{
*EntryValid = FALSE;
return TRUE;
}
/* Read the GDT */
if (!Fast486ReadLinearMemory(State,
State->Gdtr.Address
+ GET_SEGMENT_INDEX(Selector),
Entry,
sizeof(*Entry)))
{
/* Exception occurred */
*EntryValid = FALSE;
return FALSE;
}
}
else
{
/* Make sure the LDT contains the entry */
if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
{
*EntryValid = FALSE;
return TRUE;
}
/* Read the LDT */
if (!Fast486ReadLinearMemory(State,
State->Ldtr.Base
+ GET_SEGMENT_INDEX(Selector),
Entry,
sizeof(*Entry)))
{
/* Exception occurred */
*EntryValid = FALSE;
return FALSE;
}
}
*EntryValid = TRUE;
return TRUE;
}
FORCEINLINE
BOOLEAN
FASTCALL
Fast486LoadSegmentInternal(PFAST486_STATE State,
FAST486_SEG_REGS Segment,
USHORT Selector,
FAST486_EXCEPTIONS Exception)
{ {
PFAST486_SEG_REG CachedDescriptor; PFAST486_SEG_REG CachedDescriptor;
BOOLEAN Valid;
FAST486_GDT_ENTRY GdtEntry; FAST486_GDT_ENTRY GdtEntry;
ASSERT(Segment < FAST486_NUM_SEG_REGS); ASSERT(Segment < FAST486_NUM_SEG_REGS);
@ -441,45 +498,16 @@ Fast486LoadSegment(PFAST486_STATE State,
/* Check for protected mode */ /* Check for protected mode */
if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm) if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
{ {
if (!(Selector & SEGMENT_TABLE_INDICATOR)) if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
{ {
/* Make sure the GDT contains the entry */ /* Exception occurred */
if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1)) return FALSE;
{
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;
}
} }
else
{
/* Make sure the LDT contains the entry */
if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
{
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return FALSE;
}
/* Read the LDT */ if (!Valid)
if (!Fast486ReadLinearMemory(State, {
State->Ldtr.Base /* Invalid selector */
+ GET_SEGMENT_INDEX(Selector), Fast486ExceptionWithErrorCode(State, Exception, Selector);
&GdtEntry,
sizeof(GdtEntry)))
{
/* Exception occurred */
return FALSE;
}
} }
if (Segment == FAST486_REG_SS) if (Segment == FAST486_REG_SS)
@ -488,27 +516,27 @@ Fast486LoadSegment(PFAST486_STATE State,
if (GET_SEGMENT_INDEX(Selector) == 0) if (GET_SEGMENT_INDEX(Selector) == 0)
{ {
Fast486Exception(State, FAST486_EXCEPTION_GP); Fast486Exception(State, Exception);
return FALSE; return FALSE;
} }
if (!GdtEntry.SystemType) if (!GdtEntry.SystemType)
{ {
/* This is a special descriptor */ /* This is a special descriptor */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE; return FALSE;
} }
if (GdtEntry.Executable || !GdtEntry.ReadWrite) if (GdtEntry.Executable || !GdtEntry.ReadWrite)
{ {
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE; return FALSE;
} }
if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State)) if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
|| (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl)) || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
{ {
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE; return FALSE;
} }
@ -529,55 +557,53 @@ Fast486LoadSegment(PFAST486_STATE State,
if (GET_SEGMENT_INDEX(Selector) == 0) if (GET_SEGMENT_INDEX(Selector) == 0)
{ {
Fast486Exception(State, FAST486_EXCEPTION_GP); Fast486Exception(State, Exception);
return FALSE; return FALSE;
} }
if (!GdtEntry.SystemType) if (!GdtEntry.SystemType)
{ {
// TODO: Call/interrupt/task gates NOT IMPLEMENTED! /* Must be a segment descriptor */
UNIMPLEMENTED; Fast486ExceptionWithErrorCode(State, Exception, Selector);
}
if (!GdtEntry.Present)
{
Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE;
}
if (!GdtEntry.Executable)
{
Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE;
}
if (GdtEntry.DirConf)
{
/* Conforming Code Segment */
if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
{
/* Must be accessed from lower-privileged code */
Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE;
}
} }
else else
{ {
if (!GdtEntry.Present) /* Regular code segment */
if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State))
|| (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl))
{ {
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE; return FALSE;
} }
if (!GdtEntry.Executable)
{
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return FALSE;
}
if (GdtEntry.DirConf)
{
/* Conforming Code Segment */
if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
{
/* Must be accessed from lower-privileged code */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return FALSE;
}
}
else
{
/* Regular code segment */
if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State))
|| (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl))
{
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return FALSE;
}
}
/* Update CPL */
State->Cpl = GET_SEGMENT_RPL(Selector);
} }
/* Update CPL */
State->Cpl = GET_SEGMENT_RPL(Selector);
} }
else else
{ {
@ -588,20 +614,20 @@ Fast486LoadSegment(PFAST486_STATE State,
if (!GdtEntry.SystemType) if (!GdtEntry.SystemType)
{ {
/* This is a special descriptor */ /* This is a special descriptor */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE; return FALSE;
} }
if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl) if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
|| (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl)) || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
{ {
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE; return FALSE;
} }
if (!GdtEntry.Present) if (!GdtEntry.Present)
{ {
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE; return FALSE;
} }
} }
@ -639,6 +665,64 @@ Fast486LoadSegment(PFAST486_STATE State,
return TRUE; return TRUE;
} }
FORCEINLINE
BOOLEAN
FASTCALL
Fast486LoadSegment(PFAST486_STATE State,
FAST486_SEG_REGS Segment,
USHORT Selector)
{
return Fast486LoadSegmentInternal(State,
Segment,
Selector,
FAST486_EXCEPTION_GP);
}
FORCEINLINE
BOOLEAN
FASTCALL
Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN Call)
{
BOOLEAN Valid;
FAST486_SYSTEM_DESCRIPTOR Descriptor;
if (!Fast486ReadDescriptorEntry(State,
Selector,
&Valid,
(PFAST486_GDT_ENTRY)&Descriptor))
{
/* Exception occurred */
return FALSE;
}
if (!Valid)
{
/* Invalid selector */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return FALSE;
}
if (Descriptor.Signature == FAST486_TASK_GATE_SIGNATURE)
{
/* Task gate */
Fast486TaskSwitch(State,
Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP,
((PFAST486_IDT_ENTRY)&Descriptor)->Selector);
return FALSE;
}
else if (Descriptor.Signature == FAST486_CALL_GATE_SIGNATURE)
{
/* Call gate */
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
}
return TRUE;
}
FORCEINLINE FORCEINLINE
BOOLEAN BOOLEAN
FASTCALL FASTCALL

View file

@ -320,6 +320,7 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar)
{ {
BOOLEAN OperandSize, AddressSize; BOOLEAN OperandSize, AddressSize;
FAST486_MOD_REG_RM ModRegRm; FAST486_MOD_REG_RM ModRegRm;
BOOLEAN Valid;
USHORT Selector; USHORT Selector;
FAST486_GDT_ENTRY GdtEntry; FAST486_GDT_ENTRY GdtEntry;
DWORD AccessRights; DWORD AccessRights;
@ -368,45 +369,16 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar)
} }
} }
if (!(Selector & SEGMENT_TABLE_INDICATOR)) if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
{ {
/* Check if the GDT contains the entry */ /* Exception occurred */
if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1)) return;
{
State->Flags.Zf = FALSE;
return;
}
/* Read the GDT */
if (!Fast486ReadLinearMemory(State,
State->Gdtr.Address
+ GET_SEGMENT_INDEX(Selector),
&GdtEntry,
sizeof(GdtEntry)))
{
/* Exception occurred */
return;
}
} }
else
{
/* Check if the LDT contains the entry */
if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
{
State->Flags.Zf = FALSE;
return;
}
/* Read the LDT */ if (!Valid)
if (!Fast486ReadLinearMemory(State, {
State->Ldtr.Base State->Flags.Zf = FALSE;
+ GET_SEGMENT_INDEX(Selector), return;
&GdtEntry,
sizeof(GdtEntry)))
{
/* Exception occurred */
return;
}
} }
/* Privilege check */ /* Privilege check */
@ -432,6 +404,7 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)
{ {
BOOLEAN OperandSize, AddressSize; BOOLEAN OperandSize, AddressSize;
FAST486_MOD_REG_RM ModRegRm; FAST486_MOD_REG_RM ModRegRm;
BOOLEAN Valid;
USHORT Selector; USHORT Selector;
ULONG Limit; ULONG Limit;
FAST486_GDT_ENTRY GdtEntry; FAST486_GDT_ENTRY GdtEntry;
@ -480,45 +453,16 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)
} }
} }
if (!(Selector & SEGMENT_TABLE_INDICATOR)) if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
{ {
/* Check if the GDT contains the entry */ /* Exception occurred */
if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1)) return;
{
State->Flags.Zf = FALSE;
return;
}
/* Read the GDT */
if (!Fast486ReadLinearMemory(State,
State->Gdtr.Address
+ GET_SEGMENT_INDEX(Selector),
&GdtEntry,
sizeof(GdtEntry)))
{
/* Exception occurred */
return;
}
} }
else
{
/* Check if the LDT contains the entry */
if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
{
State->Flags.Zf = FALSE;
return;
}
/* Read the LDT */ if (!Valid)
if (!Fast486ReadLinearMemory(State, {
State->Ldtr.Base State->Flags.Zf = FALSE;
+ GET_SEGMENT_INDEX(Selector), return;
&GdtEntry,
sizeof(GdtEntry)))
{
/* Exception occurred */
return;
}
} }
/* Privilege check */ /* Privilege check */
@ -691,6 +635,12 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
State->PrefetchValid = FALSE; State->PrefetchValid = FALSE;
#endif #endif
if (State->Tlb && (ModRegRm.Register == (INT)FAST486_REG_CR3))
{
/* Flush the TLB */
RtlZeroMemory(State->Tlb, NUM_TLB_ENTRIES * sizeof(ULONG));
}
/* Load a value to the control register */ /* Load a value to the control register */
State->ControlRegisters[ModRegRm.Register] = Value; State->ControlRegisters[ModRegRm.Register] = Value;
} }

View file

@ -4079,6 +4079,15 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs)
return; return;
} }
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
{
if (!Fast486ProcessGate(State, Segment, Offset, TRUE))
{
/* Gate processed or exception occurred */
return;
}
}
/* Push the current code segment selector */ /* Push the current code segment selector */
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector)) if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
{ {
@ -4538,6 +4547,17 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
NO_LOCK_PREFIX(); NO_LOCK_PREFIX();
TOGGLE_OPSIZE(Size); TOGGLE_OPSIZE(Size);
/* Check if this is a nested task return */
if (State->Flags.Nt && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE))
{
/* Clear the NT flag of the current task */
State->Flags.Nt = FALSE;
/* Switch to the old task */
Fast486TaskSwitch(State, FAST486_TASK_RETURN, 0);
return;
}
/* Pop EIP */ /* Pop EIP */
if (!Fast486StackPop(State, &InstPtr)) if (!Fast486StackPop(State, &InstPtr))
{ {
@ -4597,14 +4617,6 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
return; return;
} }
if (State->Flags.Nt)
{
/* Nested task return */
UNIMPLEMENTED;
return;
}
if (NewFlags.Vm) if (NewFlags.Vm)
{ {
/* Return to VM86 mode */ /* Return to VM86 mode */
@ -5021,6 +5033,15 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs)
return; return;
} }
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
{
if (!Fast486ProcessGate(State, Segment, Offset, FALSE))
{
/* Gate processed or exception occurred */
return;
}
}
/* Load the new CS */ /* Load the new CS */
if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment)) if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
{ {

View file

@ -1420,6 +1420,15 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
return; return;
} }
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
{
if (!Fast486ProcessGate(State, Selector, Value, TRUE))
{
/* Gate processed or exception occurred */
return;
}
}
/* Push the current value of CS */ /* Push the current value of CS */
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector)) if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
{ {
@ -1473,6 +1482,15 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
return; return;
} }
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
{
if (!Fast486ProcessGate(State, Selector, Value, FALSE))
{
/* Gate processed or exception occurred */
return;
}
}
/* Load the new code segment */ /* Load the new code segment */
if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector)) if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
{ {
@ -1712,6 +1730,7 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
/* LLDT */ /* LLDT */
case 2: case 2:
{ {
BOOLEAN Valid;
USHORT Selector; USHORT Selector;
FAST486_SYSTEM_DESCRIPTOR GdtEntry; FAST486_SYSTEM_DESCRIPTOR GdtEntry;
@ -1739,24 +1758,29 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
return; return;
} }
/* Make sure the GDT contains the entry */ if (Selector & SEGMENT_TABLE_INDICATOR)
if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
{ {
/* This selector doesn't point to the GDT */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return; return;
} }
/* Read the GDT */ if (Fast486ReadDescriptorEntry(State,
if (!Fast486ReadLinearMemory(State, Selector,
State->Gdtr.Address &Valid,
+ GET_SEGMENT_INDEX(Selector), (PFAST486_GDT_ENTRY)&GdtEntry))
&GdtEntry,
sizeof(GdtEntry)))
{ {
/* Exception occurred */ /* Exception occurred */
return; return;
} }
if (!Valid)
{
/* Invalid selector */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return;
}
if (GET_SEGMENT_INDEX(Selector) == 0) if (GET_SEGMENT_INDEX(Selector) == 0)
{ {
RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr)); RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
@ -1788,6 +1812,7 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
/* LTR */ /* LTR */
case 3: case 3:
{ {
BOOLEAN Valid;
USHORT Selector; USHORT Selector;
FAST486_SYSTEM_DESCRIPTOR GdtEntry; FAST486_SYSTEM_DESCRIPTOR GdtEntry;
@ -1815,24 +1840,29 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
return; return;
} }
/* Make sure the GDT contains the entry */ if (Selector & SEGMENT_TABLE_INDICATOR)
if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
{ {
/* This selector doesn't point to the GDT */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return; return;
} }
/* Read the GDT */ if (Fast486ReadDescriptorEntry(State,
if (!Fast486ReadLinearMemory(State, Selector,
State->Gdtr.Address &Valid,
+ GET_SEGMENT_INDEX(Selector), (PFAST486_GDT_ENTRY)&GdtEntry))
&GdtEntry,
sizeof(GdtEntry)))
{ {
/* Exception occurred */ /* Exception occurred */
return; return;
} }
if (!Valid)
{
/* Invalid selector */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return;
}
if (GET_SEGMENT_INDEX(Selector) == 0) if (GET_SEGMENT_INDEX(Selector) == 0)
{ {
Fast486Exception(State, FAST486_EXCEPTION_GP); Fast486Exception(State, FAST486_EXCEPTION_GP);
@ -1857,7 +1887,6 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24); State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16); State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
if (GdtEntry.Granularity) State->TaskReg.Limit <<= 12; if (GdtEntry.Granularity) State->TaskReg.Limit <<= 12;
State->TaskReg.Busy = TRUE;
break; break;
} }
@ -1867,6 +1896,7 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
case 5: case 5:
{ {
USHORT Selector; USHORT Selector;
BOOLEAN Valid;
FAST486_GDT_ENTRY GdtEntry; FAST486_GDT_ENTRY GdtEntry;
/* Not recognized in real mode or virtual 8086 mode */ /* Not recognized in real mode or virtual 8086 mode */
@ -1893,47 +1923,17 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
return; return;
} }
if (!(Selector & SEGMENT_TABLE_INDICATOR)) if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
{ {
/* Make sure the GDT contains the entry */ /* Exception occurred */
if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1)) return;
{
/* Clear ZF */
State->Flags.Zf = FALSE;
return;
}
/* Read the GDT */
if (!Fast486ReadLinearMemory(State,
State->Gdtr.Address
+ GET_SEGMENT_INDEX(Selector),
&GdtEntry,
sizeof(GdtEntry)))
{
/* Exception occurred */
return;
}
} }
else
{
/* Make sure the LDT contains the entry */
if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
{
/* Clear ZF */
State->Flags.Zf = FALSE;
return;
}
/* Read the LDT */ if (!Valid)
if (!Fast486ReadLinearMemory(State, {
State->Ldtr.Base /* Clear ZF */
+ GET_SEGMENT_INDEX(Selector), State->Flags.Zf = FALSE;
&GdtEntry, return;
sizeof(GdtEntry)))
{
/* Exception occurred */
return;
}
} }
/* Set ZF if it is valid and accessible */ /* Set ZF if it is valid and accessible */