Author: aandrejevic
Date: Tue Nov 4 22:58:02 2014
New Revision: 65260
URL:
http://svn.reactos.org/svn/reactos?rev=65260&view=rev
Log:
[FAST486]
- Move the descriptor reading logic into a separate function.
- Implement hardware task switching and task gates.
- Flush the TLB when reloading CR3.
Modified:
trunk/reactos/include/reactos/libs/fast486/fast486.h
trunk/reactos/lib/fast486/common.c
trunk/reactos/lib/fast486/common.h
trunk/reactos/lib/fast486/common.inl
trunk/reactos/lib/fast486/extraops.c
trunk/reactos/lib/fast486/opcodes.c
trunk/reactos/lib/fast486/opgroups.c
Modified: trunk/reactos/include/reactos/libs/fast486/fast486.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/libs/fast4…
==============================================================================
--- trunk/reactos/include/reactos/libs/fast486/fast486.h [iso-8859-1] (original)
+++ trunk/reactos/include/reactos/libs/fast486/fast486.h [iso-8859-1] Tue Nov 4 22:58:02
2014
@@ -75,14 +75,15 @@
#define FAST486_DR4_RESERVED 0xFFFF1FF0
#define FAST486_DR5_RESERVED 0x0000DC00
-#define FAST486_IDT_TASK_GATE 0x5
-#define FAST486_IDT_INT_GATE 0x6
-#define FAST486_IDT_TRAP_GATE 0x7
-#define FAST486_IDT_INT_GATE_32 0xE
-#define FAST486_IDT_TRAP_GATE_32 0xF
-
-#define FAST486_LDT_SIGNATURE 0x02
-#define FAST486_TSS_SIGNATURE 0x09
+#define FAST486_LDT_SIGNATURE 0x02
+#define FAST486_TASK_GATE_SIGNATURE 0x05
+#define FAST486_IDT_INT_GATE 0x06
+#define FAST486_IDT_TRAP_GATE 0x07
+#define FAST486_TSS_SIGNATURE 0x09
+#define FAST486_BUSY_TSS_SIGNATURE 0x0B
+#define FAST486_CALL_GATE_SIGNATURE 0x0C
+#define FAST486_IDT_INT_GATE_32 0x0E
+#define FAST486_IDT_TRAP_GATE_32 0x0F
#define FAST486_PREFIX_SEG (1 << 0)
#define FAST486_PREFIX_OPSIZE (1 << 1)
@@ -270,7 +271,6 @@
USHORT Selector;
ULONG Base;
ULONG Limit;
- BOOLEAN Busy;
} FAST486_TASK_REG, *PFAST486_TASK_REG;
#include <pshpack1.h>
Modified: trunk/reactos/lib/fast486/common.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.c?rev=6…
==============================================================================
--- trunk/reactos/lib/fast486/common.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/common.c [iso-8859-1] Tue Nov 4 22:58:02 2014
@@ -274,6 +274,12 @@
FAST486_TSS Tss;
USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector;
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))
{
@@ -484,4 +490,306 @@
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 */
Modified: trunk/reactos/lib/fast486/common.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.h?rev=6…
==============================================================================
--- trunk/reactos/lib/fast486/common.h [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/common.h [iso-8859-1] Tue Nov 4 22:58:02 2014
@@ -69,6 +69,7 @@
#define GET_ADDR_PDE(x) ((x) >> 22)
#define GET_ADDR_PTE(x) (((x) >> 12) & 0x3FF)
#define INVALID_TLB_FIELD 0xFFFFFFFF
+#define NUM_TLB_ENTRIES 0x100000
typedef struct _FAST486_MOD_REG_RM
{
@@ -80,6 +81,13 @@
ULONG MemoryAddress;
};
} 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>
@@ -166,6 +174,15 @@
ULONG ErrorCode
);
+BOOLEAN
+FASTCALL
+Fast486TaskSwitch
+(
+ PFAST486_STATE State,
+ FAST486_TASK_SWITCH_TYPE Type,
+ USHORT Selector
+);
+
/* INLINED FUNCTIONS **********************************************************/
#include "common.inl"
Modified: trunk/reactos/lib/fast486/common.inl
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.inl?rev…
==============================================================================
--- trunk/reactos/lib/fast486/common.inl [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/common.inl [iso-8859-1] Tue Nov 4 22:58:02 2014
@@ -426,11 +426,68 @@
FORCEINLINE
BOOLEAN
FASTCALL
-Fast486LoadSegment(PFAST486_STATE State,
- FAST486_SEG_REGS Segment,
- USHORT Selector)
+Fast486ReadDescriptorEntry(PFAST486_STATE State,
+ 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;
+ BOOLEAN Valid;
FAST486_GDT_ENTRY GdtEntry;
ASSERT(Segment < FAST486_NUM_SEG_REGS);
@@ -441,45 +498,16 @@
/* Check for protected mode */
if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) &&
!State->Flags.Vm)
{
- if (!(Selector & SEGMENT_TABLE_INDICATOR))
- {
- /* 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;
- }
- }
- 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 (!Fast486ReadLinearMemory(State,
- State->Ldtr.Base
- + GET_SEGMENT_INDEX(Selector),
- &GdtEntry,
- sizeof(GdtEntry)))
- {
- /* Exception occurred */
- return FALSE;
- }
+ if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+
+ if (!Valid)
+ {
+ /* Invalid selector */
+ Fast486ExceptionWithErrorCode(State, Exception, Selector);
}
if (Segment == FAST486_REG_SS)
@@ -488,27 +516,27 @@
if (GET_SEGMENT_INDEX(Selector) == 0)
{
- Fast486Exception(State, FAST486_EXCEPTION_GP);
+ Fast486Exception(State, Exception);
return FALSE;
}
if (!GdtEntry.SystemType)
{
/* This is a special descriptor */
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+ Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE;
}
if (GdtEntry.Executable || !GdtEntry.ReadWrite)
{
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+ Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE;
}
if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
|| (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
{
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+ Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE;
}
@@ -529,55 +557,53 @@
if (GET_SEGMENT_INDEX(Selector) == 0)
{
- Fast486Exception(State, FAST486_EXCEPTION_GP);
+ Fast486Exception(State, Exception);
return FALSE;
}
if (!GdtEntry.SystemType)
{
- // TODO: Call/interrupt/task gates NOT IMPLEMENTED!
- UNIMPLEMENTED;
- }
- else
- {
- if (!GdtEntry.Present)
+ /* Must be a segment descriptor */
+ 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))
{
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP,
Selector);
+ /* Must be accessed from lower-privileged code */
+ Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE;
}
-
- if (!GdtEntry.Executable)
+ }
+ else
+ {
+ /* Regular code segment */
+
+ if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State))
+ || (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl))
{
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP,
Selector);
+ 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, 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
{
@@ -588,20 +614,20 @@
if (!GdtEntry.SystemType)
{
/* This is a special descriptor */
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP,
Selector);
+ Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE;
}
if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
|| (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
{
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP,
Selector);
+ Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE;
}
if (!GdtEntry.Present)
{
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP,
Selector);
+ Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE;
}
}
@@ -642,6 +668,64 @@
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
+BOOLEAN
+FASTCALL
Fast486FetchByte(PFAST486_STATE State,
PUCHAR Data)
{
Modified: trunk/reactos/lib/fast486/extraops.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/extraops.c?rev…
==============================================================================
--- trunk/reactos/lib/fast486/extraops.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/extraops.c [iso-8859-1] Tue Nov 4 22:58:02 2014
@@ -320,6 +320,7 @@
{
BOOLEAN OperandSize, AddressSize;
FAST486_MOD_REG_RM ModRegRm;
+ BOOLEAN Valid;
USHORT Selector;
FAST486_GDT_ENTRY GdtEntry;
DWORD AccessRights;
@@ -368,45 +369,16 @@
}
}
- if (!(Selector & SEGMENT_TABLE_INDICATOR))
- {
- /* Check if the GDT contains the entry */
- if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
- {
- 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 (!Fast486ReadLinearMemory(State,
- State->Ldtr.Base
- + GET_SEGMENT_INDEX(Selector),
- &GdtEntry,
- sizeof(GdtEntry)))
- {
- /* Exception occurred */
- return;
- }
+ if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ if (!Valid)
+ {
+ State->Flags.Zf = FALSE;
+ return;
}
/* Privilege check */
@@ -432,6 +404,7 @@
{
BOOLEAN OperandSize, AddressSize;
FAST486_MOD_REG_RM ModRegRm;
+ BOOLEAN Valid;
USHORT Selector;
ULONG Limit;
FAST486_GDT_ENTRY GdtEntry;
@@ -480,45 +453,16 @@
}
}
- if (!(Selector & SEGMENT_TABLE_INDICATOR))
- {
- /* Check if the GDT contains the entry */
- if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
- {
- 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 (!Fast486ReadLinearMemory(State,
- State->Ldtr.Base
- + GET_SEGMENT_INDEX(Selector),
- &GdtEntry,
- sizeof(GdtEntry)))
- {
- /* Exception occurred */
- return;
- }
+ if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ if (!Valid)
+ {
+ State->Flags.Zf = FALSE;
+ return;
}
/* Privilege check */
@@ -690,6 +634,12 @@
/* Changing CR0 or CR3 can interfere with prefetching (because of paging) */
State->PrefetchValid = FALSE;
#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 */
State->ControlRegisters[ModRegRm.Register] = Value;
Modified: trunk/reactos/lib/fast486/opcodes.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/opcodes.c?rev=…
==============================================================================
--- trunk/reactos/lib/fast486/opcodes.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/opcodes.c [iso-8859-1] Tue Nov 4 22:58:02 2014
@@ -4079,6 +4079,15 @@
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 */
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
{
@@ -4537,6 +4546,17 @@
NO_LOCK_PREFIX();
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 */
if (!Fast486StackPop(State, &InstPtr))
@@ -4597,14 +4617,6 @@
return;
}
- if (State->Flags.Nt)
- {
- /* Nested task return */
-
- UNIMPLEMENTED;
- return;
- }
-
if (NewFlags.Vm)
{
/* Return to VM86 mode */
@@ -5019,6 +5031,15 @@
{
/* Exception occurred */
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 */
Modified: trunk/reactos/lib/fast486/opgroups.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/opgroups.c?rev…
==============================================================================
--- trunk/reactos/lib/fast486/opgroups.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/opgroups.c [iso-8859-1] Tue Nov 4 22:58:02 2014
@@ -1420,6 +1420,15 @@
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 */
if (!Fast486StackPush(State,
State->SegmentRegs[FAST486_REG_CS].Selector))
{
@@ -1473,6 +1482,15 @@
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 */
if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
{
@@ -1712,6 +1730,7 @@
/* LLDT */
case 2:
{
+ BOOLEAN Valid;
USHORT Selector;
FAST486_SYSTEM_DESCRIPTOR GdtEntry;
@@ -1739,21 +1758,26 @@
return;
}
- /* Make sure the GDT contains the entry */
- if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
- {
+ if (Selector & SEGMENT_TABLE_INDICATOR)
+ {
+ /* This selector doesn't point to the GDT */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return;
}
- /* Read the GDT */
- if (!Fast486ReadLinearMemory(State,
- State->Gdtr.Address
- + GET_SEGMENT_INDEX(Selector),
- &GdtEntry,
- sizeof(GdtEntry)))
- {
- /* Exception occurred */
+ if (Fast486ReadDescriptorEntry(State,
+ Selector,
+ &Valid,
+ (PFAST486_GDT_ENTRY)&GdtEntry))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ if (!Valid)
+ {
+ /* Invalid selector */
+ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return;
}
@@ -1788,6 +1812,7 @@
/* LTR */
case 3:
{
+ BOOLEAN Valid;
USHORT Selector;
FAST486_SYSTEM_DESCRIPTOR GdtEntry;
@@ -1815,21 +1840,26 @@
return;
}
- /* Make sure the GDT contains the entry */
- if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
- {
+ if (Selector & SEGMENT_TABLE_INDICATOR)
+ {
+ /* This selector doesn't point to the GDT */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return;
}
- /* Read the GDT */
- if (!Fast486ReadLinearMemory(State,
- State->Gdtr.Address
- + GET_SEGMENT_INDEX(Selector),
- &GdtEntry,
- sizeof(GdtEntry)))
- {
- /* Exception occurred */
+ if (Fast486ReadDescriptorEntry(State,
+ Selector,
+ &Valid,
+ (PFAST486_GDT_ENTRY)&GdtEntry))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ if (!Valid)
+ {
+ /* Invalid selector */
+ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return;
}
@@ -1857,7 +1887,6 @@
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;
break;
}
@@ -1867,6 +1896,7 @@
case 5:
{
USHORT Selector;
+ BOOLEAN Valid;
FAST486_GDT_ENTRY GdtEntry;
/* Not recognized in real mode or virtual 8086 mode */
@@ -1893,47 +1923,17 @@
return;
}
- 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;
- }
-
- /* 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 (!Fast486ReadLinearMemory(State,
- State->Ldtr.Base
- + GET_SEGMENT_INDEX(Selector),
- &GdtEntry,
- sizeof(GdtEntry)))
- {
- /* Exception occurred */
- return;
- }
+ if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ if (!Valid)
+ {
+ /* Clear ZF */
+ State->Flags.Zf = FALSE;
+ return;
}
/* Set ZF if it is valid and accessible */