mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 19:05:52 +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_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 @@ typedef struct _FAST486_TASK_REG
|
|||
USHORT Selector;
|
||||
ULONG Base;
|
||||
ULONG Limit;
|
||||
BOOLEAN Busy;
|
||||
} FAST486_TASK_REG, *PFAST486_TASK_REG;
|
||||
|
||||
#include <pshpack1.h>
|
||||
|
|
|
@ -274,6 +274,12 @@ Fast486InterruptInternal(PFAST486_STATE State,
|
|||
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 @@ Fast486ExceptionWithErrorCode(PFAST486_STATE State,
|
|||
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 */
|
||||
|
|
|
@ -69,6 +69,7 @@ if (State->PrefixFlags & FAST486_PREFIX_LOCK)\
|
|||
#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
|
||||
{
|
||||
|
@ -81,6 +82,13 @@ typedef struct _FAST486_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>
|
||||
|
||||
typedef union _FAST486_PAGE_DIR
|
||||
|
@ -166,6 +174,15 @@ Fast486ExceptionWithErrorCode
|
|||
ULONG ErrorCode
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
FASTCALL
|
||||
Fast486TaskSwitch
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
FAST486_TASK_SWITCH_TYPE Type,
|
||||
USHORT Selector
|
||||
);
|
||||
|
||||
/* INLINED FUNCTIONS **********************************************************/
|
||||
|
||||
#include "common.inl"
|
||||
|
|
|
@ -426,11 +426,68 @@ Fast486StackPop(PFAST486_STATE State,
|
|||
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 @@ Fast486LoadSegment(PFAST486_STATE State,
|
|||
/* Check for protected mode */
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
/* 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 (!Valid)
|
||||
{
|
||||
/* Invalid selector */
|
||||
Fast486ExceptionWithErrorCode(State, Exception, Selector);
|
||||
}
|
||||
|
||||
if (Segment == FAST486_REG_SS)
|
||||
|
@ -488,27 +516,27 @@ Fast486LoadSegment(PFAST486_STATE State,
|
|||
|
||||
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 @@ Fast486LoadSegment(PFAST486_STATE State,
|
|||
|
||||
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;
|
||||
/* 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))
|
||||
{
|
||||
/* Must be accessed from lower-privileged code */
|
||||
Fast486ExceptionWithErrorCode(State, Exception, Selector);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -588,20 +614,20 @@ Fast486LoadSegment(PFAST486_STATE State,
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
@ -639,6 +665,64 @@ Fast486LoadSegment(PFAST486_STATE State,
|
|||
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
|
||||
BOOLEAN
|
||||
FASTCALL
|
||||
|
|
|
@ -320,6 +320,7 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar)
|
|||
{
|
||||
BOOLEAN OperandSize, AddressSize;
|
||||
FAST486_MOD_REG_RM ModRegRm;
|
||||
BOOLEAN Valid;
|
||||
USHORT Selector;
|
||||
FAST486_GDT_ENTRY GdtEntry;
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
/* 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 (!Valid)
|
||||
{
|
||||
State->Flags.Zf = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Privilege check */
|
||||
|
@ -432,6 +404,7 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)
|
|||
{
|
||||
BOOLEAN OperandSize, AddressSize;
|
||||
FAST486_MOD_REG_RM ModRegRm;
|
||||
BOOLEAN Valid;
|
||||
USHORT Selector;
|
||||
ULONG Limit;
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
/* 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 (!Valid)
|
||||
{
|
||||
State->Flags.Zf = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Privilege check */
|
||||
|
@ -691,6 +635,12 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -4079,6 +4079,15 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs)
|
|||
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))
|
||||
{
|
||||
|
@ -4538,6 +4547,17 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
|
|||
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 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
|
|||
return;
|
||||
}
|
||||
|
||||
if (State->Flags.Nt)
|
||||
{
|
||||
/* Nested task return */
|
||||
|
||||
UNIMPLEMENTED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (NewFlags.Vm)
|
||||
{
|
||||
/* Return to VM86 mode */
|
||||
|
@ -5021,6 +5033,15 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs)
|
|||
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 */
|
||||
if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
|
||||
{
|
||||
|
|
|
@ -1420,6 +1420,15 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
|
|||
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 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
|
|||
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 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
|
|||
/* LLDT */
|
||||
case 2:
|
||||
{
|
||||
BOOLEAN Valid;
|
||||
USHORT Selector;
|
||||
FAST486_SYSTEM_DESCRIPTOR GdtEntry;
|
||||
|
||||
|
@ -1739,24 +1758,29 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
|
|||
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)))
|
||||
if (Fast486ReadDescriptorEntry(State,
|
||||
Selector,
|
||||
&Valid,
|
||||
(PFAST486_GDT_ENTRY)&GdtEntry))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Valid)
|
||||
{
|
||||
/* Invalid selector */
|
||||
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GET_SEGMENT_INDEX(Selector) == 0)
|
||||
{
|
||||
RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
|
||||
|
@ -1788,6 +1812,7 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
|
|||
/* LTR */
|
||||
case 3:
|
||||
{
|
||||
BOOLEAN Valid;
|
||||
USHORT Selector;
|
||||
FAST486_SYSTEM_DESCRIPTOR GdtEntry;
|
||||
|
||||
|
@ -1815,24 +1840,29 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
|
|||
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)))
|
||||
if (Fast486ReadDescriptorEntry(State,
|
||||
Selector,
|
||||
&Valid,
|
||||
(PFAST486_GDT_ENTRY)&GdtEntry))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Valid)
|
||||
{
|
||||
/* Invalid selector */
|
||||
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GET_SEGMENT_INDEX(Selector) == 0)
|
||||
{
|
||||
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.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
|
||||
if (GdtEntry.Granularity) State->TaskReg.Limit <<= 12;
|
||||
State->TaskReg.Busy = TRUE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1867,6 +1896,7 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
|
|||
case 5:
|
||||
{
|
||||
USHORT Selector;
|
||||
BOOLEAN Valid;
|
||||
FAST486_GDT_ENTRY GdtEntry;
|
||||
|
||||
/* Not recognized in real mode or virtual 8086 mode */
|
||||
|
@ -1893,47 +1923,17 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!(Selector & SEGMENT_TABLE_INDICATOR))
|
||||
if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
/* 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 (!Valid)
|
||||
{
|
||||
/* Clear ZF */
|
||||
State->Flags.Zf = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set ZF if it is valid and accessible */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue