* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "common.h"
+
/* PUBLIC FUNCTIONS ***********************************************************/
+FORCEINLINE
+INT
+Fast486GetCurrentPrivLevel(PFAST486_STATE State)
+{
+ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+ {
+ /* In protected mode, return the RPL of the CS */
+ return GET_SEGMENT_RPL(State->SegmentRegs[FAST486_REG_CS].Selector);
+ }
+ else
+ {
+ /* Real mode is always in supervisor mode */
+ return 0;
+ }
+}
+
+FORCEINLINE
+ULONG
+Fast486GetPageTableEntry(PFAST486_STATE State,
+ ULONG VirtualAddress,
+ BOOLEAN MarkAsDirty)
+{
+ ULONG PdeIndex = GET_ADDR_PDE(VirtualAddress);
+ ULONG PteIndex = GET_ADDR_PTE(VirtualAddress);
+ FAST486_PAGE_DIR DirectoryEntry;
+ FAST486_PAGE_TABLE TableEntry;
+ ULONG PageDirectory = State->ControlRegisters[FAST486_REG_CR3];
+
+ if ((State->Tlb != NULL)
+ && (State->Tlb[VirtualAddress >> 12] != INVALID_TLB_FIELD))
+ {
+ /* Return the cached entry */
+ return State->Tlb[VirtualAddress >> 12];
+ }
+
+ /* Read the directory entry */
+ State->MemReadCallback(State,
+ PageDirectory + PdeIndex * sizeof(ULONG),
+ &DirectoryEntry.Value,
+ sizeof(DirectoryEntry));
+
+ /* Make sure it is present */
+ if (!DirectoryEntry.Present) return 0;
+
+ /* Was the directory entry accessed before? */
+ if (!DirectoryEntry.Accessed)
+ {
+ /* Well, it is now */
+ DirectoryEntry.Accessed = TRUE;
+
+ /* Write back the directory entry */
+ State->MemWriteCallback(State,
+ PageDirectory + PdeIndex * sizeof(ULONG),
+ &DirectoryEntry.Value,
+ sizeof(DirectoryEntry));
+ }
+
+ /* Read the table entry */
+ State->MemReadCallback(State,
+ (DirectoryEntry.TableAddress << 12)
+ + PteIndex * sizeof(ULONG),
+ &TableEntry.Value,
+ sizeof(TableEntry));
+
+ /* Make sure it is present */
+ if (!TableEntry.Present) return 0;
+
+ if (MarkAsDirty) TableEntry.Dirty = TRUE;
+
+ /* Was the table entry accessed before? */
+ if (!TableEntry.Accessed)
+ {
+ /* Well, it is now */
+ TableEntry.Accessed = TRUE;
+
+ /* Write back the table entry */
+ State->MemWriteCallback(State,
+ (DirectoryEntry.TableAddress << 12)
+ + PteIndex * sizeof(ULONG),
+ &TableEntry.Value,
+ sizeof(TableEntry));
+ }
+
+ /*
+ * The resulting permissions depend on the permissions
+ * in the page directory table too
+ */
+ TableEntry.Writeable &= DirectoryEntry.Writeable;
+ TableEntry.Usermode &= DirectoryEntry.Usermode;
+
+ if (State->Tlb != NULL)
+ {
+ /* Set the TLB entry */
+ State->Tlb[VirtualAddress >> 12] = TableEntry.Value;
+ }
+
+ /* Return the table entry */
+ return TableEntry.Value;
+}
+
+FORCEINLINE
+BOOLEAN
+Fast486ReadLinearMemory(PFAST486_STATE State,
+ ULONG LinearAddress,
+ 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;
+
+ for (Page = PAGE_ALIGN(LinearAddress);
+ Page <= PAGE_ALIGN(LinearAddress + Size - 1);
+ Page += PAGE_SIZE)
+ {
+ ULONG PageOffset = 0, PageLength = PAGE_SIZE;
+
+ /* Get the table entry */
+ TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
+
+ if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
+ {
+ /* Exception */
+ Fast486ExceptionWithErrorCode(State,
+ FAST486_EXCEPTION_PF,
+ TableEntry.Value & 0x07);
+ return FALSE;
+ }
+
+ /* Check if this is the first page */
+ if (Page == PAGE_ALIGN(LinearAddress))
+ {
+ /* Start copying from the offset from the beginning of the page */
+ PageOffset = PAGE_OFFSET(LinearAddress);
+ }
+
+ /* 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 the memory */
+ State->MemReadCallback(State,
+ (TableEntry.Address << 12) | PageOffset,
+ Buffer,
+ PageLength);
+ }
+ }
+ else
+ {
+ /* Read the memory */
+ State->MemReadCallback(State, LinearAddress, Buffer, Size);
+ }
+
+ return TRUE;
+}
+
+FORCEINLINE
+BOOLEAN
+Fast486WriteLinearMemory(PFAST486_STATE State,
+ ULONG LinearAddress,
+ 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;
+
+ for (Page = PAGE_ALIGN(LinearAddress);
+ Page <= PAGE_ALIGN(LinearAddress + Size - 1);
+ Page += PAGE_SIZE)
+ {
+ ULONG PageOffset = 0, PageLength = PAGE_SIZE;
+
+ /* Get the table entry */
+ TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
+
+ if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
+ || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
+ && !TableEntry.Writeable))
+ {
+ /* Exception */
+ Fast486ExceptionWithErrorCode(State,
+ FAST486_EXCEPTION_PF,
+ TableEntry.Value & 0x07);
+ return FALSE;
+ }
+
+ /* Check if this is the first page */
+ if (Page == PAGE_ALIGN(LinearAddress))
+ {
+ /* Start copying from the offset from the beginning of the page */
+ PageOffset = PAGE_OFFSET(LinearAddress);
+ }
+
+ /* 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 the memory */
+ State->MemWriteCallback(State,
+ (TableEntry.Address << 12) | PageOffset,
+ Buffer,
+ PageLength);
+ }
+ }
+ else
+ {
+ /* Write the memory */
+ State->MemWriteCallback(State, LinearAddress, Buffer, Size);
+ }
+
+ return TRUE;
+}
+
FORCEINLINE
VOID
Fast486Exception(PFAST486_STATE State,
}
/* Increment SP by 2 */
- State->GeneralRegs[FAST486_REG_ESP].Long += 2;
+ State->GeneralRegs[FAST486_REG_ESP].LowWord += 2;
/* Store the value in the result */
*Value = ShortValue;
}
/* Read the GDT */
- // FIXME: This code is only correct when paging is disabled!!!
- if (State->MemReadCallback)
+ if (!Fast486ReadLinearMemory(State,
+ State->Gdtr.Address
+ + GET_SEGMENT_INDEX(Selector),
+ &GdtEntry,
+ sizeof(GdtEntry)))
{
- State->MemReadCallback(State,
- State->Gdtr.Address
- + GET_SEGMENT_INDEX(Selector),
- &GdtEntry,
- sizeof(GdtEntry));
- }
- else
- {
- RtlMoveMemory(&GdtEntry,
- (PVOID)(State->Gdtr.Address
- + GET_SEGMENT_INDEX(Selector)),
- sizeof(GdtEntry));
+ /* Exception occurred */
+ return FALSE;
}
if (Segment == FAST486_REG_SS)
/* Update the cache entry */
CachedDescriptor->Selector = Selector;
- CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseHigh << 24);
+ CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
CachedDescriptor->Accessed = GdtEntry.Accessed;
CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
{
/* Read from the IDT */
- // FIXME: This code is only correct when paging is disabled!!!
- if (State->MemReadCallback)
+ if (!Fast486ReadLinearMemory(State,
+ State->Idtr.Address
+ + Number * sizeof(*IdtEntry),
+ IdtEntry,
+ sizeof(*IdtEntry)))
{
- State->MemReadCallback(State,
- State->Idtr.Address
- + Number * sizeof(*IdtEntry),
- IdtEntry,
- sizeof(*IdtEntry));
- }
- else
- {
- RtlMoveMemory(IdtEntry,
- (PVOID)(State->Idtr.Address
- + Number * sizeof(*IdtEntry)),
- sizeof(*IdtEntry));
+ /* Exception occurred */
+ return FALSE;
}
}
else
{
/* Read from the real-mode IVT */
-
+
/* Paging is always disabled in real mode */
- if (State->MemReadCallback)
- {
- State->MemReadCallback(State,
- State->Idtr.Address
- + Number * sizeof(FarPointer),
- &FarPointer,
- sizeof(FarPointer));
- }
- else
- {
- RtlMoveMemory(&FarPointer,
- (PVOID)(State->Idtr.Address
- + Number * sizeof(FarPointer)),
- sizeof(FarPointer));
- }
+ State->MemReadCallback(State,
+ State->Idtr.Address
+ + Number * sizeof(FarPointer),
+ &FarPointer,
+ sizeof(FarPointer));
/* Fill a fake IDT entry */
IdtEntry->Offset = LOWORD(FarPointer);
IdtEntry->OffsetHigh = 0;
}
- /*
- * Once paging support is implemented this function
- * will not always return true
- */
return TRUE;
}
BOOLEAN
Fast486CalculateParity(UCHAR Number)
{
+ // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
}
Index = (SibByte >> 3) & 0x07;
if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
else Index = 0;
- Base = State->GeneralRegs[SibByte & 0x07].Long;
+
+ if ((SibByte & 0x07) != FAST486_REG_EBP)
+ {
+ /* Use the register a base */
+ Base = State->GeneralRegs[SibByte & 0x07].Long;
+ }
+ else
+ {
+ /* Fetch the base */
+ if (!Fast486FetchDword(State, &Base))
+ {
+ /* Exception occurred */
+ return FALSE;
+ }
+ }
/* Calculate the address */
ModRegRm->MemoryAddress = Base + Index * Scale;
if (Mode == 1)
{
CHAR Offset;
-
+
/* Fetch the byte */
if (!Fast486FetchByte(State, (PUCHAR)&Offset))
{
else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
{
LONG Offset;
-
+
/* Fetch the dword */
if (!Fast486FetchDword(State, (PULONG)&Offset))
{
switch (RegMem)
{
case 0:
- case 2:
{
- /* (SS:)[BX + SI] */
+ /* [BX + SI] */
ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
+ State->GeneralRegs[FAST486_REG_ESI].LowWord;
}
case 1:
- case 3:
{
- /* (SS:)[BX + DI] */
+ /* [BX + DI] */
ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
+ State->GeneralRegs[FAST486_REG_EDI].LowWord;
break;
}
+ case 2:
+ {
+ /* SS:[BP + SI] */
+ ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
+ + State->GeneralRegs[FAST486_REG_ESI].LowWord;
+
+ break;
+ }
+
+ case 3:
+ {
+ /* SS:[BP + DI] */
+ ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
+ + State->GeneralRegs[FAST486_REG_EDI].LowWord;
+
+ break;
+ }
+
case 4:
{
/* [SI] */
if (Mode == 1)
{
CHAR Offset;
-
+
/* Fetch the byte */
if (!Fast486FetchByte(State, (PUCHAR)&Offset))
{
else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
{
SHORT Offset;
-
+
/* Fetch the word */
if (!Fast486FetchWord(State, (PUSHORT)&Offset))
{