[FAST486]

Fix the limit calculation when using page granularity.
RETF can also perform inter-privilege returns.
Fix the privilege checks when loading CS. DPL != CPL is only a #GP
when we're doing a jump or a call.


svn path=/trunk/; revision=65280
This commit is contained in:
Aleksandar Andrejevic 2014-11-06 05:16:14 +00:00
parent 453e370737
commit e42640b500
5 changed files with 109 additions and 20 deletions

View file

@ -553,7 +553,12 @@ Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Se
/* Calculate the limit of the new TSS */
NewTssLimit = NewTssDescriptor.Limit | (NewTssDescriptor.LimitHigh << 16);
if (NewTssDescriptor.Granularity) NewTssLimit <<= 12;
if (NewTssDescriptor.Granularity)
{
NewTssLimit <<= 12;
NewTssLimit |= 0x00000FFF;
}
if (NewTssLimit < sizeof(FAST486_TSS))
{
@ -739,7 +744,12 @@ Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Se
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;
if (GdtEntry.Granularity)
{
State->Ldtr.Limit <<= 12;
State->Ldtr.Limit |= 0x00000FFF;
}
}
else
{

View file

@ -594,16 +594,12 @@ Fast486LoadSegmentInternal(PFAST486_STATE State,
{
/* Regular code segment */
if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State))
|| (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl))
if ((GET_SEGMENT_RPL(Selector) < Fast486GetCurrentPrivLevel(State)))
{
Fast486ExceptionWithErrorCode(State, Exception, Selector);
return FALSE;
}
}
/* Update CPL */
State->Cpl = GET_SEGMENT_RPL(Selector);
}
else
{
@ -653,7 +649,11 @@ Fast486LoadSegmentInternal(PFAST486_STATE State,
CachedDescriptor->Size = GdtEntry.Size;
/* Check for page granularity */
if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
if (GdtEntry.Granularity)
{
CachedDescriptor->Limit <<= 12;
CachedDescriptor->Limit |= 0x00000FFF;
}
}
else
{
@ -730,6 +730,13 @@ Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN
default:
{
/* Security check for jumps and calls only */
if (State->Cpl != Descriptor.Dpl)
{
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return FALSE;
}
return TRUE;
}
}

View file

@ -475,7 +475,12 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)
/* Calculate the limit */
Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
if (GdtEntry.Granularity) Limit <<= 12;
if (GdtEntry.Granularity)
{
Limit <<= 12;
Limit |= 0x00000FFF;
}
/* Set ZF */
State->Flags.Zf = TRUE;

View file

@ -4474,6 +4474,63 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar)
return;
}
if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
{
INT i;
INT OldCpl = Fast486GetCurrentPrivLevel(State);
ULONG StackPtr;
ULONG StackSel;
if (GET_SEGMENT_RPL(Segment) > OldCpl)
{
/* Pop ESP */
if (!Fast486StackPop(State, &StackPtr))
{
/* Exception */
return;
}
/* Pop SS */
if (!Fast486StackPop(State, &StackSel))
{
/* Exception */
return;
}
/* Load new SS */
if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel))
{
/* Exception */
return;
}
/* Set ESP */
if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr;
else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
}
/* Update the CPL */
State->Cpl = GET_SEGMENT_RPL(Segment);
if (State->Cpl > OldCpl)
{
/* Check segment security */
for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
{
/* Don't check CS or SS */
if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
if ((State->Cpl > State->SegmentRegs[i].Dpl)
&& (!State->SegmentRegs[i].Executable
|| !State->SegmentRegs[i].DirConf))
{
/* Load the NULL descriptor in the segment */
if (!Fast486LoadSegment(State, i, 0)) return;
}
}
}
}
/* Load new (E)IP, and if necessary, pop the parameters */
if (Size)
{
@ -4582,7 +4639,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
/* Check for protected mode */
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
{
INT Cpl = Fast486GetCurrentPrivLevel(State);
INT OldCpl = Fast486GetCurrentPrivLevel(State);
if (State->Flags.Vm)
{
@ -4660,7 +4717,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
if (Size) State->InstPtr.Long = InstPtr;
else State->InstPtr.LowWord = LOWORD(InstPtr);
if (GET_SEGMENT_RPL(CodeSel) > Cpl)
if (GET_SEGMENT_RPL(CodeSel) > OldCpl)
{
/* Pop ESP */
if (!Fast486StackPop(State, &StackPtr))
@ -4688,27 +4745,27 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
}
/* Update the CPL */
State->Cpl = GET_SEGMENT_RPL(CodeSel);
/* Set the new flags */
if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
State->Flags.AlwaysSet = TRUE;
/* Set additional flags */
if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
if (OldCpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
if (OldCpl == 0) State->Flags.Iopl = NewFlags.Iopl;
if (GET_SEGMENT_RPL(CodeSel) > Cpl)
if (State->Cpl > OldCpl)
{
/* Update the CPL */
Cpl = Fast486GetCurrentPrivLevel(State);
/* Check segment security */
for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
{
/* Don't check CS or SS */
if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
if ((Cpl > State->SegmentRegs[i].Dpl)
if ((State->Cpl > State->SegmentRegs[i].Dpl)
&& (!State->SegmentRegs[i].Executable
|| !State->SegmentRegs[i].DirConf))
{

View file

@ -1804,7 +1804,12 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
State->Ldtr.Selector = Selector;
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;
if (GdtEntry.Granularity)
{
State->Ldtr.Limit <<= 12;
State->Ldtr.Limit |= 0x00000FFF;
}
break;
}
@ -1886,7 +1891,12 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
State->TaskReg.Selector = Selector;
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;
if (GdtEntry.Granularity)
{
State->TaskReg.Limit <<= 12;
State->TaskReg.Limit |= 0x00000FFF;
}
break;
}