PVOID Buffer,
ULONG Size)
{
- INT Cpl = Fast486GetCurrentPrivLevel(State);
-
/* Check if paging is enabled */
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
{
ULONG Page;
FAST486_PAGE_TABLE TableEntry;
+ INT Cpl = Fast486GetCurrentPrivLevel(State);
+ ULONG BufferOffset = 0;
for (Page = PAGE_ALIGN(LinearAddress);
Page <= PAGE_ALIGN(LinearAddress + Size - 1);
/* Check if this is the first page */
if (Page == PAGE_ALIGN(LinearAddress))
{
- /* Start copying from the offset from the beginning of the page */
+ /* Start reading from the offset from the beginning of the page */
PageOffset = PAGE_OFFSET(LinearAddress);
+ PageLength -= PageOffset;
}
/* Check if this is the last page */
if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
{
- /* Copy only a part of the page */
- PageLength = PAGE_OFFSET(LinearAddress + Size);
+ /* Read only a part of the page */
+ PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
}
/* Read the memory */
State->MemReadCallback(State,
(TableEntry.Address << 12) | PageOffset,
- Buffer,
+ (PVOID)((ULONG_PTR)Buffer + BufferOffset),
PageLength);
+
+ BufferOffset += PageLength;
}
}
else
PVOID Buffer,
ULONG Size)
{
- INT Cpl = Fast486GetCurrentPrivLevel(State);
-
/* Check if paging is enabled */
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
{
ULONG Page;
FAST486_PAGE_TABLE TableEntry;
+ INT Cpl = Fast486GetCurrentPrivLevel(State);
+ ULONG BufferOffset = 0;
for (Page = PAGE_ALIGN(LinearAddress);
Page <= PAGE_ALIGN(LinearAddress + Size - 1);
/* Check if this is the first page */
if (Page == PAGE_ALIGN(LinearAddress))
{
- /* Start copying from the offset from the beginning of the page */
+ /* Start writing from the offset from the beginning of the page */
PageOffset = PAGE_OFFSET(LinearAddress);
+ PageLength -= PageOffset;
}
/* Check if this is the last page */
if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
{
- /* Copy only a part of the page */
- PageLength = PAGE_OFFSET(LinearAddress + Size);
+ /* Write only a part of the page */
+ PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
}
/* Write the memory */
State->MemWriteCallback(State,
(TableEntry.Address << 12) | PageOffset,
- Buffer,
+ (PVOID)((ULONG_PTR)Buffer + BufferOffset),
PageLength);
+
+ BufferOffset += PageLength;
}
}
else
Fast486StackPush(PFAST486_STATE State,
ULONG Value)
{
- BOOLEAN Size = State->SegmentRegs[FAST486_REG_SS].Size;
+ BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
/* The OPSIZE prefix toggles the size */
if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
}
/* Subtract ESP by 4 */
- State->GeneralRegs[FAST486_REG_ESP].Long -= 4;
+ State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
/* Store the value in SS:ESP */
return Fast486WriteMemory(State,
USHORT ShortValue = LOWORD(Value);
/* Check if SP is 1 */
- if (State->GeneralRegs[FAST486_REG_ESP].Long == 1)
+ if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 1)
{
Fast486Exception(State, FAST486_EXCEPTION_SS);
return FALSE;
}
/* Subtract SP by 2 */
- State->GeneralRegs[FAST486_REG_ESP].LowWord -= 2;
+ State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
/* Store the value in SS:SP */
return Fast486WriteMemory(State,
Fast486StackPop(PFAST486_STATE State,
PULONG Value)
{
- ULONG LongValue;
- USHORT ShortValue;
- BOOLEAN Size = State->SegmentRegs[FAST486_REG_SS].Size;
+ BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
/* The OPSIZE prefix toggles the size */
TOGGLE_OPSIZE(Size);
if (Size)
{
/* 32-bit size */
+ ULONG LongValue;
/* Check if ESP is 0xFFFFFFFF */
if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
}
/* Increment ESP by 4 */
- State->GeneralRegs[FAST486_REG_ESP].Long += 4;
+ State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(ULONG);
/* Store the value in the result */
*Value = LongValue;
else
{
/* 16-bit size */
+ USHORT ShortValue;
/* Check if SP is 0xFFFF */
if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
}
/* Increment SP by 2 */
- State->GeneralRegs[FAST486_REG_ESP].LowWord += 2;
+ State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(USHORT);
/* Store the value in the result */
*Value = ShortValue;
FORCEINLINE
BOOLEAN
Fast486LoadSegment(PFAST486_STATE State,
- INT Segment,
+ FAST486_SEG_REGS Segment,
USHORT Selector)
{
PFAST486_SEG_REG CachedDescriptor;
/* Check for protected mode */
if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
{
- /* Make sure the GDT contains the entry */
- if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
+ if (!(Selector & SEGMENT_TABLE_INDICATOR))
{
- Fast486Exception(State, FAST486_EXCEPTION_GP);
- return FALSE;
- }
+ /* 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)))
+ /* Read the GDT */
+ if (!Fast486ReadLinearMemory(State,
+ State->Gdtr.Address
+ + GET_SEGMENT_INDEX(Selector),
+ &GdtEntry,
+ sizeof(GdtEntry)))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+ }
+ else
{
- /* Exception occurred */
- return FALSE;
+ /* 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 (Segment == FAST486_REG_SS)
if (!GdtEntry.SystemType)
{
/* This is a special descriptor */
- Fast486Exception(State, FAST486_EXCEPTION_GP);
+ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return FALSE;
}
if (GdtEntry.Executable || !GdtEntry.ReadWrite)
{
- Fast486Exception(State, FAST486_EXCEPTION_GP);
+ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return FALSE;
}
if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
|| (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
{
- Fast486Exception(State, FAST486_EXCEPTION_GP);
+ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
return FALSE;
}
if (!GdtEntry.Present)
{
- Fast486Exception(State, FAST486_EXCEPTION_SS);
+ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_SS, Selector);
return FALSE;
}
}
else if (Segment == FAST486_REG_CS)
{
/* Loading the code segment */
- // TODO: Implement security checks, call gates, etc...
-
- /* Update CPL */
- State->Cpl = GET_SEGMENT_RPL(Selector);
- }
- else
- {
- /* Loading a data segment */
- if (!GdtEntry.SystemType)
+ if (GET_SEGMENT_INDEX(Selector) == 0)
{
- /* This is a special descriptor */
Fast486Exception(State, FAST486_EXCEPTION_GP);
return FALSE;
}
- if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
- || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
+ if (!GdtEntry.SystemType)
{
- Fast486Exception(State, FAST486_EXCEPTION_GP);
- return FALSE;
+ // TODO: Call/interrupt/task gates NOT IMPLEMENTED!
+ UNIMPLEMENTED;
}
+ else
+ {
+ if (!GdtEntry.Present)
+ {
+ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
+ return FALSE;
+ }
- if (!GdtEntry.Present)
+ 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);
+ }
+ }
+ else
+ {
+ /* Loading a data segment */
+
+ if (GET_SEGMENT_INDEX(Selector) != 0)
{
- Fast486Exception(State, FAST486_EXCEPTION_NP);
- return FALSE;
+ if (!GdtEntry.SystemType)
+ {
+ /* This is a special descriptor */
+ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+ return FALSE;
+ }
+
+ if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
+ || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
+ {
+ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+ return FALSE;
+ }
+
+ if (!GdtEntry.Present)
+ {
+ Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* This is a NULL selector */
+ RtlZeroMemory(&GdtEntry, sizeof(GdtEntry));
}
}
CachedDescriptor->DirConf = GdtEntry.DirConf;
CachedDescriptor->Executable = GdtEntry.Executable;
CachedDescriptor->SystemType = GdtEntry.SystemType;
+ CachedDescriptor->Rpl = GET_SEGMENT_RPL(Selector);
CachedDescriptor->Dpl = GdtEntry.Dpl;
CachedDescriptor->Present = GdtEntry.Present;
CachedDescriptor->Size = GdtEntry.Size;
}
}
+ if ((SibByte & 0x07) == FAST486_REG_ESP)
+ {
+ /* Check if there is no segment override */
+ if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
+ {
+ /* Add a SS: prefix */
+ State->PrefixFlags |= FAST486_PREFIX_SEG;
+ State->SegmentOverride = FAST486_REG_SS;
+ }
+ }
+
/* Calculate the address */
ModRegRm->MemoryAddress = Base + Index * Scale;
}
{
FAST486_SEG_REGS Segment = FAST486_REG_DS;
- /* Get the register value */
- if (ModRegRm->Register & 0x04)
- {
- /* AH, CH, DH, BH */
- *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
- }
- else
- {
- /* AL, CL, DL, BL */
- *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
- }
-
- if (!ModRegRm->Memory)
+ if (RegValue)
{
- /* Get the second register value */
- if (ModRegRm->SecondRegister & 0x04)
+ /* Get the register value */
+ if (ModRegRm->Register & 0x04)
{
/* AH, CH, DH, BH */
- *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
+ *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
}
else
{
/* AL, CL, DL, BL */
- *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
+ *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
}
}
- else
+
+ if (RmValue)
{
- /* Check for the segment override */
- if (State->PrefixFlags & FAST486_PREFIX_SEG)
+ if (!ModRegRm->Memory)
{
- /* Use the override segment instead */
- Segment = State->SegmentOverride;
+ /* Get the second register value */
+ if (ModRegRm->SecondRegister & 0x04)
+ {
+ /* AH, CH, DH, BH */
+ *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
+ }
+ else
+ {
+ /* AL, CL, DL, BL */
+ *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
+ }
}
-
- /* Read memory */
- if (!Fast486ReadMemory(State,
- Segment,
- ModRegRm->MemoryAddress,
- FALSE,
- RmValue,
- sizeof(UCHAR)))
+ else
{
- /* Exception occurred */
- return FALSE;
+ /* Check for the segment override */
+ if (State->PrefixFlags & FAST486_PREFIX_SEG)
+ {
+ /* Use the override segment instead */
+ Segment = State->SegmentOverride;
+ }
+
+ /* Read memory */
+ if (!Fast486ReadMemory(State,
+ Segment,
+ ModRegRm->MemoryAddress,
+ FALSE,
+ RmValue,
+ sizeof(UCHAR)))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
}
}
{
FAST486_SEG_REGS Segment = FAST486_REG_DS;
- /* Get the register value */
- *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
-
- if (!ModRegRm->Memory)
+ if (RegValue)
{
- /* Get the second register value */
- *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
+ /* Get the register value */
+ *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
}
- else
+
+ if (RmValue)
{
- /* Check for the segment override */
- if (State->PrefixFlags & FAST486_PREFIX_SEG)
+ if (!ModRegRm->Memory)
{
- /* Use the override segment instead */
- Segment = State->SegmentOverride;
+ /* Get the second register value */
+ *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
}
-
- /* Read memory */
- if (!Fast486ReadMemory(State,
- Segment,
- ModRegRm->MemoryAddress,
- FALSE,
- RmValue,
- sizeof(USHORT)))
+ else
{
- /* Exception occurred */
- return FALSE;
+ /* Check for the segment override */
+ if (State->PrefixFlags & FAST486_PREFIX_SEG)
+ {
+ /* Use the override segment instead */
+ Segment = State->SegmentOverride;
+ }
+
+ /* Read memory */
+ if (!Fast486ReadMemory(State,
+ Segment,
+ ModRegRm->MemoryAddress,
+ FALSE,
+ RmValue,
+ sizeof(USHORT)))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
}
}
{
FAST486_SEG_REGS Segment = FAST486_REG_DS;
- /* Get the register value */
- *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
-
- if (!ModRegRm->Memory)
+ if (RegValue)
{
- /* Get the second register value */
- *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
+ /* Get the register value */
+ *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
}
- else
+
+ if (RmValue)
{
- /* Check for the segment override */
- if (State->PrefixFlags & FAST486_PREFIX_SEG)
+ if (!ModRegRm->Memory)
{
- /* Use the override segment instead */
- Segment = State->SegmentOverride;
+ /* Get the second register value */
+ *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
}
-
- /* Read memory */
- if (!Fast486ReadMemory(State,
- Segment,
- ModRegRm->MemoryAddress,
- FALSE,
- RmValue,
- sizeof(ULONG)))
+ else
{
- /* Exception occurred */
- return FALSE;
+ /* Check for the segment override */
+ if (State->PrefixFlags & FAST486_PREFIX_SEG)
+ {
+ /* Use the override segment instead */
+ Segment = State->SegmentOverride;
+ }
+
+ /* Read memory */
+ if (!Fast486ReadMemory(State,
+ Segment,
+ ModRegRm->MemoryAddress,
+ FALSE,
+ RmValue,
+ sizeof(ULONG)))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
}
}