* Fast486 386/486 CPU Emulation Library
* opgroups.c
*
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
{
- /* Exception occurred - restore SP */
- if (OperandSize) State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
- else State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
-
+ /* Exception occurred */
return;
}
return;
}
- if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+ if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+ && !State->Flags.Vm)
{
if (!Fast486ProcessGate(State, Selector, Value, TRUE))
{
return;
}
- if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+ if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+ && !State->Flags.Vm)
{
if (!Fast486ProcessGate(State, Selector, Value, FALSE))
{
return;
}
+ if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+ && !State->Flags.Vm)
+ {
+ 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))
{
return;
}
+ if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+ && !State->Flags.Vm)
+ {
+ if (!Fast486ProcessGate(State, Selector, Value, FALSE))
+ {
+ /* Gate processed or exception occurred */
+ return;
+ }
+ }
+
/* Load the new code segment */
if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
{
return;
}
- if (GdtEntry.Signature != FAST486_TSS_SIGNATURE)
+ if (GdtEntry.Signature != FAST486_TSS_SIGNATURE
+ && GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
+ && GdtEntry.Signature != FAST486_TSS_16_SIGNATURE
+ && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
{
/* This is not a TSS descriptor */
Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
State->TaskReg.Limit |= 0x00000FFF;
}
+ if (GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
+ && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
+ {
+ /* Set the busy bit of this TSS descriptor and write it back */
+ GdtEntry.Signature |= 2;
+
+ Fast486WriteLinearMemory(State,
+ State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
+ &GdtEntry,
+ sizeof(GdtEntry),
+ FALSE /* We already made sure CPL is 0 */);
+ }
+
break;
}
return;
}
- /* This is a privileged instruction */
- if (Fast486GetCurrentPrivLevel(State) != 0)
- {
- Fast486Exception(State, FAST486_EXCEPTION_GP);
- return;
- }
-
if (!Fast486ReadModrmWordOperands(State,
&ModRegRm,
NULL,
/* Set ZF if it is valid and accessible */
State->Flags.Zf = GdtEntry.Present // must be present
- && GdtEntry.SystemType // must be a segment
- && (((ModRegRm.Register == 4)
- /* code segments are only readable if the RW bit is set */
- && (!GdtEntry.Executable || GdtEntry.ReadWrite))
- || ((ModRegRm.Register == 5)
- /* code segments are never writable, data segments are writable when RW is set */
- && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
- /*
- * for segments other than conforming code segments,
- * both RPL and CPL must be less than or equal to DPL
- */
- && ((!GdtEntry.Executable || !GdtEntry.DirConf)
- && ((GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
- && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl)))
- /* for conforming code segments, DPL must be less than or equal to CPL */
- && ((GdtEntry.Executable && GdtEntry.DirConf)
- && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State)));
+ && GdtEntry.SystemType // must be a segment
+ && (((ModRegRm.Register == 4)
+ /* code segments are only readable if the RW bit is set */
+ && (!GdtEntry.Executable || GdtEntry.ReadWrite))
+ || ((ModRegRm.Register == 5)
+ /* code segments are never writable, data segments are writable when RW is set */
+ && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
+ /*
+ * for segments other than conforming code segments,
+ * both RPL and CPL must be less than or equal to DPL
+ */
+ && (((!GdtEntry.Executable || !GdtEntry.DirConf)
+ && (GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
+ && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl))
+ /* for conforming code segments, DPL must be less than or equal to CPL */
+ || ((GdtEntry.Executable && GdtEntry.DirConf)
+ && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State))));
break;
{
USHORT MachineStatusWord;
- /* This is a privileged instruction */
- if (Fast486GetCurrentPrivLevel(State) != 0)
+ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
{
- Fast486Exception(State, FAST486_EXCEPTION_GP);
- return;
+ /* This is a privileged instruction */
+ if (Fast486GetCurrentPrivLevel(State) != 0)
+ {
+ Fast486Exception(State, FAST486_EXCEPTION_GP);
+ return;
+ }
}
/* Read the new Machine Status Word */
return;
}
- /* This instruction cannot be used to return to real mode */
- if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
- && !(MachineStatusWord & FAST486_CR0_PE))
- {
- Fast486Exception(State, FAST486_EXCEPTION_GP);
- return;
- }
-
- /* Set the lowest 4 bits */
- State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF0;
+ /* Set the lowest 4 bits, but never clear bit 0 */
+ State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF1;
State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
break;