mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 20:05:41 +00:00
[FAST486]
- Implement call gates. - Fix Fast486InterruptInternal and get rid of ugly hacks. - Fix IRET (CS loaded too early). - Add a structure definition for the 16-bit TSS (not supported yet). svn path=/trunk/; revision=67545
This commit is contained in:
parent
866f04e377
commit
ac4f5ac401
5 changed files with 368 additions and 146 deletions
|
@ -75,15 +75,18 @@
|
||||||
#define FAST486_DR4_RESERVED 0xFFFF1FF0
|
#define FAST486_DR4_RESERVED 0xFFFF1FF0
|
||||||
#define FAST486_DR5_RESERVED 0x0000DC00
|
#define FAST486_DR5_RESERVED 0x0000DC00
|
||||||
|
|
||||||
#define FAST486_LDT_SIGNATURE 0x02
|
#define FAST486_TSS_16_SIGNATURE 0x01
|
||||||
#define FAST486_TASK_GATE_SIGNATURE 0x05
|
#define FAST486_LDT_SIGNATURE 0x02
|
||||||
#define FAST486_IDT_INT_GATE 0x06
|
#define FAST486_BUSY_TSS_16_SIGNATURE 0x03
|
||||||
#define FAST486_IDT_TRAP_GATE 0x07
|
#define FAST486_CALL_GATE_16_SIGNATURE 0x04
|
||||||
#define FAST486_TSS_SIGNATURE 0x09
|
#define FAST486_TASK_GATE_SIGNATURE 0x05
|
||||||
#define FAST486_BUSY_TSS_SIGNATURE 0x0B
|
#define FAST486_IDT_INT_GATE 0x06
|
||||||
#define FAST486_CALL_GATE_SIGNATURE 0x0C
|
#define FAST486_IDT_TRAP_GATE 0x07
|
||||||
#define FAST486_IDT_INT_GATE_32 0x0E
|
#define FAST486_TSS_SIGNATURE 0x09
|
||||||
#define FAST486_IDT_TRAP_GATE_32 0x0F
|
#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_SEG (1 << 0)
|
||||||
#define FAST486_PREFIX_OPSIZE (1 << 1)
|
#define FAST486_PREFIX_OPSIZE (1 << 1)
|
||||||
|
@ -354,6 +357,62 @@ typedef struct
|
||||||
/* Verify the structure size */
|
/* Verify the structure size */
|
||||||
C_ASSERT(sizeof(FAST486_IDT_ENTRY) == sizeof(ULONGLONG));
|
C_ASSERT(sizeof(FAST486_IDT_ENTRY) == sizeof(ULONGLONG));
|
||||||
|
|
||||||
|
typedef struct _FAST486_TSS
|
||||||
|
{
|
||||||
|
ULONG Link;
|
||||||
|
ULONG Esp0;
|
||||||
|
ULONG Ss0;
|
||||||
|
ULONG Esp1;
|
||||||
|
ULONG Ss1;
|
||||||
|
ULONG Esp2;
|
||||||
|
ULONG Ss2;
|
||||||
|
ULONG Cr3;
|
||||||
|
ULONG Eip;
|
||||||
|
ULONG Eflags;
|
||||||
|
ULONG Eax;
|
||||||
|
ULONG Ecx;
|
||||||
|
ULONG Edx;
|
||||||
|
ULONG Ebx;
|
||||||
|
ULONG Esp;
|
||||||
|
ULONG Ebp;
|
||||||
|
ULONG Esi;
|
||||||
|
ULONG Edi;
|
||||||
|
ULONG Es;
|
||||||
|
ULONG Cs;
|
||||||
|
ULONG Ss;
|
||||||
|
ULONG Ds;
|
||||||
|
ULONG Fs;
|
||||||
|
ULONG Gs;
|
||||||
|
ULONG Ldtr;
|
||||||
|
ULONG IopbOffset;
|
||||||
|
} FAST486_TSS, *PFAST486_TSS;
|
||||||
|
|
||||||
|
typedef struct _FAST486_LEGACY_TSS
|
||||||
|
{
|
||||||
|
USHORT Link;
|
||||||
|
USHORT Sp0;
|
||||||
|
USHORT Ss0;
|
||||||
|
USHORT Sp1;
|
||||||
|
USHORT Ss1;
|
||||||
|
USHORT Sp2;
|
||||||
|
USHORT Ss2;
|
||||||
|
USHORT Ip;
|
||||||
|
USHORT Flags;
|
||||||
|
USHORT Ax;
|
||||||
|
USHORT Cx;
|
||||||
|
USHORT Dx;
|
||||||
|
USHORT Bx;
|
||||||
|
USHORT Sp;
|
||||||
|
USHORT Bp;
|
||||||
|
USHORT Si;
|
||||||
|
USHORT Di;
|
||||||
|
USHORT Es;
|
||||||
|
USHORT Cs;
|
||||||
|
USHORT Ss;
|
||||||
|
USHORT Ds;
|
||||||
|
USHORT Ldtr;
|
||||||
|
} FAST486_LEGACY_TSS, *PFAST486_LEGACY_TSS;
|
||||||
|
|
||||||
#include <poppack.h>
|
#include <poppack.h>
|
||||||
|
|
||||||
typedef struct _FAST486_TABLE_REG
|
typedef struct _FAST486_TABLE_REG
|
||||||
|
@ -392,36 +451,6 @@ typedef union _FAST486_FLAGS_REG
|
||||||
};
|
};
|
||||||
} FAST486_FLAGS_REG, *PFAST486_FLAGS_REG;
|
} FAST486_FLAGS_REG, *PFAST486_FLAGS_REG;
|
||||||
|
|
||||||
typedef struct _FAST486_TSS
|
|
||||||
{
|
|
||||||
ULONG Link;
|
|
||||||
ULONG Esp0;
|
|
||||||
ULONG Ss0;
|
|
||||||
ULONG Esp1;
|
|
||||||
ULONG Ss1;
|
|
||||||
ULONG Esp2;
|
|
||||||
ULONG Ss2;
|
|
||||||
ULONG Cr3;
|
|
||||||
ULONG Eip;
|
|
||||||
ULONG Eflags;
|
|
||||||
ULONG Eax;
|
|
||||||
ULONG Ecx;
|
|
||||||
ULONG Edx;
|
|
||||||
ULONG Ebx;
|
|
||||||
ULONG Esp;
|
|
||||||
ULONG Ebp;
|
|
||||||
ULONG Esi;
|
|
||||||
ULONG Edi;
|
|
||||||
ULONG Es;
|
|
||||||
ULONG Cs;
|
|
||||||
ULONG Ss;
|
|
||||||
ULONG Ds;
|
|
||||||
ULONG Fs;
|
|
||||||
ULONG Gs;
|
|
||||||
ULONG Ldtr;
|
|
||||||
ULONG IopbOffset;
|
|
||||||
} FAST486_TSS, *PFAST486_TSS;
|
|
||||||
|
|
||||||
typedef struct _FAST486_FPU_DATA_REG
|
typedef struct _FAST486_FPU_DATA_REG
|
||||||
{
|
{
|
||||||
ULONGLONG Mantissa;
|
ULONGLONG Mantissa;
|
||||||
|
|
|
@ -292,38 +292,30 @@ Fast486InterruptInternal(PFAST486_STATE State,
|
||||||
BOOLEAN PushErrorCode,
|
BOOLEAN PushErrorCode,
|
||||||
ULONG ErrorCode)
|
ULONG ErrorCode)
|
||||||
{
|
{
|
||||||
USHORT SegmentSelector = IdtEntry->Selector;
|
BOOLEAN GateSize = (IdtEntry->Type == FAST486_IDT_INT_GATE_32) ||
|
||||||
ULONG Offset = MAKELONG(IdtEntry->Offset, IdtEntry->OffsetHigh);
|
(IdtEntry->Type == FAST486_IDT_TRAP_GATE_32);
|
||||||
ULONG GateType = IdtEntry->Type;
|
USHORT OldCs = State->SegmentRegs[FAST486_REG_CS].Selector;
|
||||||
BOOLEAN GateSize = (GateType == FAST486_IDT_INT_GATE_32) ||
|
ULONG OldEip = State->InstPtr.Long;
|
||||||
(GateType == FAST486_IDT_TRAP_GATE_32);
|
ULONG OldFlags = State->Flags.Long;
|
||||||
|
UCHAR OldCpl = State->Cpl;
|
||||||
BOOLEAN Success = FALSE;
|
|
||||||
ULONG OldPrefixFlags = State->PrefixFlags;
|
|
||||||
|
|
||||||
/* Check for protected mode */
|
/* Check for protected mode */
|
||||||
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
|
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
|
||||||
{
|
{
|
||||||
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)
|
if (IdtEntry->Type == FAST486_TASK_GATE_SIGNATURE)
|
||||||
{
|
{
|
||||||
/* Task call */
|
/* Task call */
|
||||||
return Fast486TaskSwitch(State, FAST486_TASK_CALL, IdtEntry->Selector);
|
return Fast486TaskSwitch(State, FAST486_TASK_CALL, IdtEntry->Selector);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GateSize != (State->SegmentRegs[FAST486_REG_CS].Size))
|
|
||||||
{
|
|
||||||
/* The gate size doesn't match the current operand size, so set the OPSIZE flag. */
|
|
||||||
State->PrefixFlags |= FAST486_PREFIX_OPSIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the interrupt handler is more privileged or if we're in V86 mode */
|
/* Check if the interrupt handler is more privileged or if we're in V86 mode */
|
||||||
if ((Fast486GetCurrentPrivLevel(State) > GET_SEGMENT_RPL(SegmentSelector))
|
if ((OldCpl > GET_SEGMENT_RPL(IdtEntry->Selector)) || State->Flags.Vm)
|
||||||
|| State->Flags.Vm)
|
|
||||||
{
|
{
|
||||||
|
FAST486_TSS Tss;
|
||||||
|
|
||||||
/* Read the TSS */
|
/* Read the TSS */
|
||||||
if (!Fast486ReadLinearMemory(State,
|
if (!Fast486ReadLinearMemory(State,
|
||||||
State->TaskReg.Base,
|
State->TaskReg.Base,
|
||||||
|
@ -331,29 +323,11 @@ Fast486InterruptInternal(PFAST486_STATE State,
|
||||||
sizeof(Tss)))
|
sizeof(Tss)))
|
||||||
{
|
{
|
||||||
/* Exception occurred */
|
/* Exception occurred */
|
||||||
goto Cleanup;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Switch to the new privilege level */
|
/* Switch to the new privilege level */
|
||||||
State->Cpl = GET_SEGMENT_RPL(SegmentSelector);
|
State->Cpl = GET_SEGMENT_RPL(IdtEntry->Selector);
|
||||||
|
|
||||||
if (State->Flags.Vm)
|
|
||||||
{
|
|
||||||
/* Clear the VM flag */
|
|
||||||
State->Flags.Vm = FALSE;
|
|
||||||
|
|
||||||
/* Push GS, FS, DS and ES */
|
|
||||||
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector)) goto Cleanup;
|
|
||||||
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector)) goto Cleanup;
|
|
||||||
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_DS].Selector)) goto Cleanup;
|
|
||||||
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_ES].Selector)) goto Cleanup;
|
|
||||||
|
|
||||||
/* Now load them with NULL selectors, since they are useless in protected mode */
|
|
||||||
if (!Fast486LoadSegment(State, FAST486_REG_GS, 0)) goto Cleanup;
|
|
||||||
if (!Fast486LoadSegment(State, FAST486_REG_FS, 0)) goto Cleanup;
|
|
||||||
if (!Fast486LoadSegment(State, FAST486_REG_DS, 0)) goto Cleanup;
|
|
||||||
if (!Fast486LoadSegment(State, FAST486_REG_ES, 0)) goto Cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check the new (higher) privilege level */
|
/* Check the new (higher) privilege level */
|
||||||
switch (State->Cpl)
|
switch (State->Cpl)
|
||||||
|
@ -363,7 +337,7 @@ Fast486InterruptInternal(PFAST486_STATE State,
|
||||||
if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss0))
|
if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss0))
|
||||||
{
|
{
|
||||||
/* Exception occurred */
|
/* Exception occurred */
|
||||||
goto Cleanup;
|
return FALSE;
|
||||||
}
|
}
|
||||||
State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp0;
|
State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp0;
|
||||||
|
|
||||||
|
@ -375,7 +349,7 @@ Fast486InterruptInternal(PFAST486_STATE State,
|
||||||
if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss1))
|
if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss1))
|
||||||
{
|
{
|
||||||
/* Exception occurred */
|
/* Exception occurred */
|
||||||
goto Cleanup;
|
return FALSE;
|
||||||
}
|
}
|
||||||
State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp1;
|
State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp1;
|
||||||
|
|
||||||
|
@ -387,7 +361,7 @@ Fast486InterruptInternal(PFAST486_STATE State,
|
||||||
if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss2))
|
if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss2))
|
||||||
{
|
{
|
||||||
/* Exception occurred */
|
/* Exception occurred */
|
||||||
goto Cleanup;
|
return FALSE;
|
||||||
}
|
}
|
||||||
State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp2;
|
State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp2;
|
||||||
|
|
||||||
|
@ -400,73 +374,90 @@ Fast486InterruptInternal(PFAST486_STATE State,
|
||||||
ASSERT(FALSE);
|
ASSERT(FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load new CS */
|
||||||
|
if (!Fast486LoadSegment(State, FAST486_REG_CS, IdtEntry->Selector))
|
||||||
|
{
|
||||||
|
/* An exception occurred during the jump */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GateSize)
|
||||||
|
{
|
||||||
|
/* 32-bit code segment, use EIP */
|
||||||
|
State->InstPtr.Long = MAKELONG(IdtEntry->Offset, IdtEntry->OffsetHigh);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* 16-bit code segment, use IP */
|
||||||
|
State->InstPtr.LowWord = IdtEntry->Offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the interrupt handler is more privileged or we're in VM86 mode (again) */
|
||||||
|
if ((OldCpl > GET_SEGMENT_RPL(IdtEntry->Selector)) || State->Flags.Vm)
|
||||||
|
{
|
||||||
|
if (State->Flags.Vm)
|
||||||
|
{
|
||||||
|
/* Clear the VM flag */
|
||||||
|
State->Flags.Vm = FALSE;
|
||||||
|
|
||||||
|
/* Push GS, FS, DS and ES */
|
||||||
|
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector)) return FALSE;
|
||||||
|
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector)) return FALSE;
|
||||||
|
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_DS].Selector)) return FALSE;
|
||||||
|
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_ES].Selector)) return FALSE;
|
||||||
|
|
||||||
|
/* Now load them with NULL selectors, since they are useless in protected mode */
|
||||||
|
if (!Fast486LoadSegment(State, FAST486_REG_GS, 0)) return FALSE;
|
||||||
|
if (!Fast486LoadSegment(State, FAST486_REG_FS, 0)) return FALSE;
|
||||||
|
if (!Fast486LoadSegment(State, FAST486_REG_DS, 0)) return FALSE;
|
||||||
|
if (!Fast486LoadSegment(State, FAST486_REG_ES, 0)) return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Push SS selector */
|
/* Push SS selector */
|
||||||
if (!Fast486StackPush(State, OldSs)) goto Cleanup;
|
if (!Fast486StackPushInternal(State, GateSize, OldSs)) return FALSE;
|
||||||
|
|
||||||
/* Push stack pointer */
|
/* Push the stack pointer */
|
||||||
if (!Fast486StackPush(State, OldEsp)) goto Cleanup;
|
if (!Fast486StackPushInternal(State, GateSize, OldEsp)) return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (State->SegmentRegs[FAST486_REG_CS].Size)
|
/* Load new CS */
|
||||||
|
if (!Fast486LoadSegment(State, FAST486_REG_CS, IdtEntry->Selector))
|
||||||
{
|
{
|
||||||
/* Set OPSIZE, because INT always pushes 16-bit values in real mode */
|
/* An exception occurred during the jump */
|
||||||
State->PrefixFlags |= FAST486_PREFIX_OPSIZE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set the new IP */
|
||||||
|
State->InstPtr.LowWord = IdtEntry->Offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push EFLAGS */
|
/* Push EFLAGS */
|
||||||
if (!Fast486StackPush(State, State->Flags.Long)) goto Cleanup;
|
if (!Fast486StackPushInternal(State, GateSize, OldFlags)) return FALSE;
|
||||||
|
|
||||||
/* Push CS selector */
|
/* Push CS selector */
|
||||||
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector)) goto Cleanup;
|
if (!Fast486StackPushInternal(State, GateSize, OldCs)) return FALSE;
|
||||||
|
|
||||||
/* Push the instruction pointer */
|
/* Push the instruction pointer */
|
||||||
if (!Fast486StackPush(State, State->InstPtr.Long)) goto Cleanup;
|
if (!Fast486StackPushInternal(State, GateSize, OldEip)) return FALSE;
|
||||||
|
|
||||||
if (PushErrorCode)
|
if (PushErrorCode)
|
||||||
{
|
{
|
||||||
/* Push the error code */
|
/* Push the error code */
|
||||||
if (!Fast486StackPush(State, ErrorCode))
|
if (!Fast486StackPushInternal(State, GateSize, ErrorCode)) return FALSE;
|
||||||
{
|
|
||||||
/* An exception occurred */
|
|
||||||
goto Cleanup;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((GateType == FAST486_IDT_INT_GATE) || (GateType == FAST486_IDT_INT_GATE_32))
|
if ((IdtEntry->Type == FAST486_IDT_INT_GATE)
|
||||||
|
|| (IdtEntry->Type == FAST486_IDT_INT_GATE_32))
|
||||||
{
|
{
|
||||||
/* Disable interrupts after a jump to an interrupt gate handler */
|
/* Disable interrupts after a jump to an interrupt gate handler */
|
||||||
State->Flags.If = FALSE;
|
State->Flags.If = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load new CS */
|
return TRUE;
|
||||||
if (!Fast486LoadSegment(State, FAST486_REG_CS, SegmentSelector))
|
|
||||||
{
|
|
||||||
/* An exception occurred during the jump */
|
|
||||||
goto Cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GateSize)
|
|
||||||
{
|
|
||||||
/* 32-bit code segment, use EIP */
|
|
||||||
State->InstPtr.Long = Offset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* 16-bit code segment, use IP */
|
|
||||||
State->InstPtr.LowWord = LOWORD(Offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
Success = TRUE;
|
|
||||||
|
|
||||||
Cleanup:
|
|
||||||
/* Restore the prefix flags */
|
|
||||||
State->PrefixFlags = OldPrefixFlags;
|
|
||||||
|
|
||||||
return Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
|
@ -876,4 +867,180 @@ Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Se
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
FASTCALL
|
||||||
|
Fast486CallGate(PFAST486_STATE State,
|
||||||
|
PFAST486_CALL_GATE Gate,
|
||||||
|
BOOLEAN Call)
|
||||||
|
{
|
||||||
|
BOOLEAN Valid;
|
||||||
|
FAST486_GDT_ENTRY NewCodeSegment;
|
||||||
|
BOOLEAN GateSize = (Gate->Type == FAST486_CALL_GATE_SIGNATURE);
|
||||||
|
FAST486_TSS Tss;
|
||||||
|
USHORT OldCs = State->SegmentRegs[FAST486_REG_CS].Selector;
|
||||||
|
ULONG OldEip = State->InstPtr.Long;
|
||||||
|
USHORT OldCpl = State->Cpl;
|
||||||
|
USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector;
|
||||||
|
ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long;
|
||||||
|
ULONG ParamBuffer[32]; /* Maximum possible size - 32 DWORDs */
|
||||||
|
PULONG LongParams = (PULONG)ParamBuffer;
|
||||||
|
PUSHORT ShortParams = (PUSHORT)ParamBuffer;
|
||||||
|
|
||||||
|
if (!Gate->Selector)
|
||||||
|
{
|
||||||
|
/* The code segment is NULL */
|
||||||
|
Fast486Exception(State, FAST486_EXCEPTION_GP);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Fast486ReadDescriptorEntry(State, Gate->Selector, &Valid, &NewCodeSegment))
|
||||||
|
{
|
||||||
|
/* Exception occurred */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Valid || (NewCodeSegment.Dpl > Fast486GetCurrentPrivLevel(State)))
|
||||||
|
{
|
||||||
|
/* Code segment invalid */
|
||||||
|
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Gate->Selector);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Call && Gate->ParamCount)
|
||||||
|
{
|
||||||
|
/* Read the parameters */
|
||||||
|
if (!Fast486ReadMemory(State,
|
||||||
|
FAST486_REG_SS,
|
||||||
|
OldEsp,
|
||||||
|
FALSE,
|
||||||
|
ParamBuffer,
|
||||||
|
Gate->ParamCount * sizeof(ULONG)))
|
||||||
|
{
|
||||||
|
/* Exception occurred */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the new code segment is more privileged */
|
||||||
|
if (NewCodeSegment.Dpl < OldCpl)
|
||||||
|
{
|
||||||
|
if (Call)
|
||||||
|
{
|
||||||
|
/* Read the TSS */
|
||||||
|
if (!Fast486ReadLinearMemory(State,
|
||||||
|
State->TaskReg.Base,
|
||||||
|
&Tss,
|
||||||
|
sizeof(Tss)))
|
||||||
|
{
|
||||||
|
/* Exception occurred */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Switch to the new privilege level */
|
||||||
|
State->Cpl = NewCodeSegment.Dpl;
|
||||||
|
|
||||||
|
/* Check the new (higher) privilege level */
|
||||||
|
switch (State->Cpl)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss0))
|
||||||
|
{
|
||||||
|
/* Exception occurred */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss1))
|
||||||
|
{
|
||||||
|
/* Exception occurred */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss2))
|
||||||
|
{
|
||||||
|
/* Exception occurred */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp2;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
/* Should never reach here! */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!NewCodeSegment.DirConf)
|
||||||
|
{
|
||||||
|
/* This is not allowed for jumps */
|
||||||
|
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Gate->Selector);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load new CS */
|
||||||
|
if (!Fast486LoadSegment(State, FAST486_REG_CS, Gate->Selector))
|
||||||
|
{
|
||||||
|
/* An exception occurred during the jump */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the instruction pointer */
|
||||||
|
if (GateSize) State->InstPtr.Long = MAKELONG(Gate->Offset, Gate->OffsetHigh);
|
||||||
|
else State->InstPtr.Long = Gate->Offset;
|
||||||
|
|
||||||
|
if (Call)
|
||||||
|
{
|
||||||
|
INT i;
|
||||||
|
|
||||||
|
/* Check if the new code segment is more privileged (again) */
|
||||||
|
if (NewCodeSegment.Dpl < OldCpl)
|
||||||
|
{
|
||||||
|
/* Push SS selector */
|
||||||
|
if (!Fast486StackPushInternal(State, GateSize, OldSs)) return FALSE;
|
||||||
|
|
||||||
|
/* Push stack pointer */
|
||||||
|
if (!Fast486StackPushInternal(State, GateSize, OldEsp)) return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Push the parameters in reverse order */
|
||||||
|
for (i = Gate->ParamCount - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (!Fast486StackPushInternal(State,
|
||||||
|
GateSize,
|
||||||
|
GateSize ? LongParams[i] : ShortParams[i]))
|
||||||
|
{
|
||||||
|
/* Exception occurred */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Push the parameter count */
|
||||||
|
if (!Fast486StackPushInternal(State, GateSize, Gate->ParamCount)) return FALSE;
|
||||||
|
|
||||||
|
/* Push CS selector */
|
||||||
|
if (!Fast486StackPushInternal(State, GateSize, OldCs)) return FALSE;
|
||||||
|
|
||||||
|
/* Push the instruction pointer */
|
||||||
|
if (!Fast486StackPushInternal(State, GateSize, OldEip)) return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -183,6 +183,15 @@ Fast486TaskSwitch
|
||||||
USHORT Selector
|
USHORT Selector
|
||||||
);
|
);
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
FASTCALL
|
||||||
|
Fast486CallGate
|
||||||
|
(
|
||||||
|
PFAST486_STATE State,
|
||||||
|
PFAST486_CALL_GATE Gate,
|
||||||
|
BOOLEAN Call
|
||||||
|
);
|
||||||
|
|
||||||
/* INLINED FUNCTIONS **********************************************************/
|
/* INLINED FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
#include "common.inl"
|
#include "common.inl"
|
||||||
|
|
|
@ -297,19 +297,12 @@ Fast486Exception(PFAST486_STATE State,
|
||||||
FORCEINLINE
|
FORCEINLINE
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
FASTCALL
|
FASTCALL
|
||||||
Fast486StackPush(PFAST486_STATE State,
|
Fast486StackPushInternal(PFAST486_STATE State, BOOLEAN Size, ULONG Value)
|
||||||
ULONG Value)
|
|
||||||
{
|
{
|
||||||
BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
|
|
||||||
ULONG StackPointer = State->GeneralRegs[FAST486_REG_ESP].Long;
|
ULONG StackPointer = State->GeneralRegs[FAST486_REG_ESP].Long;
|
||||||
|
|
||||||
/* The OPSIZE prefix toggles the size */
|
|
||||||
TOGGLE_OPSIZE(Size);
|
|
||||||
|
|
||||||
if (Size)
|
if (Size)
|
||||||
{
|
{
|
||||||
/* 32-bit size */
|
|
||||||
|
|
||||||
/* Check if ESP is between 1 and 3 */
|
/* Check if ESP is between 1 and 3 */
|
||||||
if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1
|
if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1
|
||||||
&& State->GeneralRegs[FAST486_REG_ESP].Long <= 3)
|
&& State->GeneralRegs[FAST486_REG_ESP].Long <= 3)
|
||||||
|
@ -344,9 +337,6 @@ Fast486StackPush(PFAST486_STATE State,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* 16-bit size */
|
|
||||||
USHORT ShortValue = LOWORD(Value);
|
|
||||||
|
|
||||||
/* Check if SP is 1 */
|
/* Check if SP is 1 */
|
||||||
if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 1)
|
if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 1)
|
||||||
{
|
{
|
||||||
|
@ -360,7 +350,7 @@ Fast486StackPush(PFAST486_STATE State,
|
||||||
State->SegmentRegs[FAST486_REG_SS].Size
|
State->SegmentRegs[FAST486_REG_SS].Size
|
||||||
? StackPointer - sizeof(USHORT)
|
? StackPointer - sizeof(USHORT)
|
||||||
: LOWORD(StackPointer - sizeof(USHORT)),
|
: LOWORD(StackPointer - sizeof(USHORT)),
|
||||||
&ShortValue,
|
&Value,
|
||||||
sizeof(USHORT)))
|
sizeof(USHORT)))
|
||||||
{
|
{
|
||||||
/* Exception occurred */
|
/* Exception occurred */
|
||||||
|
@ -382,6 +372,20 @@ Fast486StackPush(PFAST486_STATE State,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCEINLINE
|
||||||
|
BOOLEAN
|
||||||
|
FASTCALL
|
||||||
|
Fast486StackPush(PFAST486_STATE State, ULONG Value)
|
||||||
|
{
|
||||||
|
BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
|
||||||
|
|
||||||
|
/* The OPSIZE prefix toggles the size */
|
||||||
|
TOGGLE_OPSIZE(Size);
|
||||||
|
|
||||||
|
/* Call the internal function */
|
||||||
|
return Fast486StackPushInternal(State, Size, Value);
|
||||||
|
}
|
||||||
|
|
||||||
FORCEINLINE
|
FORCEINLINE
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
FASTCALL
|
FASTCALL
|
||||||
|
@ -778,12 +782,25 @@ Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case FAST486_CALL_GATE_16_SIGNATURE:
|
||||||
case FAST486_CALL_GATE_SIGNATURE:
|
case FAST486_CALL_GATE_SIGNATURE:
|
||||||
{
|
{
|
||||||
// TODO: NOT IMPLEMENTED
|
if ((Descriptor.Dpl < Fast486GetCurrentPrivLevel(State))
|
||||||
UNIMPLEMENTED;
|
&& (Descriptor.Dpl < GET_SEGMENT_RPL(Selector)))
|
||||||
|
{
|
||||||
|
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
Fast486Exception(State, FAST486_EXCEPTION_UD);
|
if (!Descriptor.Present)
|
||||||
|
{
|
||||||
|
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Fast486CallGate(State, (PFAST486_CALL_GATE)&Descriptor, Call);
|
||||||
|
|
||||||
|
/* The gate has been processed here, so return FALSE */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4707,17 +4707,6 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load the new CS */
|
|
||||||
if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
|
|
||||||
{
|
|
||||||
/* Exception occurred */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set EIP */
|
|
||||||
if (Size) State->InstPtr.Long = InstPtr;
|
|
||||||
else State->InstPtr.LowWord = LOWORD(InstPtr);
|
|
||||||
|
|
||||||
if (GET_SEGMENT_RPL(CodeSel) > OldCpl)
|
if (GET_SEGMENT_RPL(CodeSel) > OldCpl)
|
||||||
{
|
{
|
||||||
/* Pop ESP */
|
/* Pop ESP */
|
||||||
|
@ -4735,6 +4724,17 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load the new CS */
|
||||||
|
if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
|
||||||
|
{
|
||||||
|
/* Exception occurred */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set EIP */
|
||||||
|
if (Size) State->InstPtr.Long = InstPtr;
|
||||||
|
else State->InstPtr.LowWord = LOWORD(InstPtr);
|
||||||
|
|
||||||
/* Update the CPL */
|
/* Update the CPL */
|
||||||
State->Cpl = GET_SEGMENT_RPL(CodeSel);
|
State->Cpl = GET_SEGMENT_RPL(CodeSel);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue