mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 22:52:54 +00:00
[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:
parent
ca809b6cdc
commit
b4648ec8fe
7 changed files with 607 additions and 227 deletions
|
@ -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>
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue