[FAST486]

Modularize linear memory access by adding two new functions:
Fast486ReadLinearMemory and Fast486WriteLinearMemory.
Implement Fast486GetPageTableEntry.


svn path=/branches/ntvdm/; revision=60923
This commit is contained in:
Aleksandar Andrejevic 2013-11-10 22:27:24 +00:00
parent 7c036fd0f7
commit c3c7bb89c1
6 changed files with 264 additions and 146 deletions

View file

@ -401,6 +401,7 @@ struct _FAST486_STATE
FAST486_SEG_REGS SegmentOverride;
FAST486_INT_STATUS IntStatus;
UCHAR PendingIntNum;
PULONG Tlb;
};
/* FUNCTIONS ******************************************************************/
@ -414,7 +415,8 @@ Fast486Initialize(PFAST486_STATE State,
FAST486_IO_WRITE_PROC IoWriteCallback,
FAST486_IDLE_PROC IdleCallback,
FAST486_BOP_PROC BopCallback,
FAST486_INT_ACK_PROC IntAckCallback);
FAST486_INT_ACK_PROC IntAckCallback,
PULONG Tlb);
VOID
NTAPI

View file

@ -29,19 +29,6 @@
#include <fast486.h>
#include "common.h"
/* PRIVATE FUNCTIONS **********************************************************/
static inline
ULONG
Fast486GetPageTableEntry(PFAST486_STATE State,
ULONG VirtualAddress)
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
return 0;
}
/* PUBLIC FUNCTIONS ***********************************************************/
BOOLEAN
@ -54,7 +41,6 @@ Fast486ReadMemory(PFAST486_STATE State,
{
ULONG LinearAddress;
PFAST486_SEG_REG CachedDescriptor;
INT Cpl = Fast486GetCurrentPrivLevel(State);
ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
@ -108,58 +94,8 @@ Fast486ReadMemory(PFAST486_STATE State,
/* Find the linear address */
LinearAddress = CachedDescriptor->Base + Offset;
/* 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);
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;
/* Read from the linear address */
return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
}
BOOLEAN
@ -171,7 +107,6 @@ Fast486WriteMemory(PFAST486_STATE State,
{
ULONG LinearAddress;
PFAST486_SEG_REG CachedDescriptor;
INT Cpl = Fast486GetCurrentPrivLevel(State);
ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
@ -220,60 +155,8 @@ Fast486WriteMemory(PFAST486_STATE State,
/* Find the linear address */
LinearAddress = CachedDescriptor->Base + Offset;
/* 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);
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;
/* Write to the linear address */
return Fast486WriteLinearMemory(State, LinearAddress, Buffer, Size);
}
BOOLEAN
@ -293,11 +176,14 @@ Fast486InterruptInternal(PFAST486_STATE State,
if (Fast486GetCurrentPrivLevel(State) > GET_SEGMENT_RPL(SegmentSelector))
{
/* Read the TSS */
// FIXME: This code is only correct when paging is disabled!!!
State->MemReadCallback(State,
State->Tss.Address,
&Tss,
sizeof(Tss));
if (!Fast486ReadLinearMemory(State,
State->Tss.Address,
&Tss,
sizeof(Tss)))
{
/* Exception occurred */
return FALSE;
}
/* Check the new (higher) privilege level */
switch (GET_SEGMENT_RPL(SegmentSelector))

View file

@ -56,6 +56,9 @@
#define PAGE_ALIGN(x) ((x) & 0xFFFFF000)
#define PAGE_OFFSET(x) ((x) & 0x00000FFF)
#define GET_ADDR_PDE(x) ((x) >> 22)
#define GET_ADDR_PTE(x) (((x) >> 12) & 0x3FF)
#define INVALID_TLB_FIELD 0xFFFFFFFF
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
@ -92,6 +95,8 @@ typedef union _FAST486_PAGE_DIR
ULONG Value;
} FAST486_PAGE_DIR, *PFAST486_PAGE_DIR;
C_ASSERT(sizeof(FAST486_PAGE_DIR) == sizeof(ULONG));
typedef union _FAST486_PAGE_TABLE
{
struct
@ -111,6 +116,8 @@ typedef union _FAST486_PAGE_TABLE
ULONG Value;
} FAST486_PAGE_TABLE, *PFAST486_PAGE_TABLE;
C_ASSERT(sizeof(FAST486_PAGE_DIR) == sizeof(ULONG));
#pragma pack(pop)
/* FUNCTIONS ******************************************************************/

View file

@ -19,8 +19,222 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "common.h"
/* PUBLIC FUNCTIONS ***********************************************************/
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,
@ -185,12 +399,15 @@ Fast486LoadSegment(PFAST486_STATE State,
}
/* Read the GDT */
// FIXME: This code is only correct when paging is disabled!!!
State->MemReadCallback(State,
State->Gdtr.Address
+ GET_SEGMENT_INDEX(Selector),
&GdtEntry,
sizeof(GdtEntry));
if (!Fast486ReadLinearMemory(State,
State->Gdtr.Address
+ GET_SEGMENT_INDEX(Selector),
&GdtEntry,
sizeof(GdtEntry)))
{
/* Exception occurred */
return FALSE;
}
if (Segment == FAST486_REG_SS)
{
@ -388,12 +605,15 @@ Fast486GetIntVector(PFAST486_STATE State,
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
{
/* Read from the IDT */
// FIXME: This code is only correct when paging is disabled!!!
State->MemReadCallback(State,
State->Idtr.Address
+ Number * sizeof(*IdtEntry),
IdtEntry,
sizeof(*IdtEntry));
if (!Fast486ReadLinearMemory(State,
State->Idtr.Address
+ Number * sizeof(*IdtEntry),
IdtEntry,
sizeof(*IdtEntry)))
{
/* Exception occurred */
return FALSE;
}
}
else
{
@ -417,10 +637,6 @@ Fast486GetIntVector(PFAST486_STATE State,
IdtEntry->OffsetHigh = 0;
}
/*
* Once paging support is implemented this function
* will not always return true
*/
return TRUE;
}

View file

@ -203,7 +203,8 @@ Fast486Initialize(PFAST486_STATE State,
FAST486_IO_WRITE_PROC IoWriteCallback,
FAST486_IDLE_PROC IdleCallback,
FAST486_BOP_PROC BopCallback,
FAST486_INT_ACK_PROC IntAckCallback)
FAST486_INT_ACK_PROC IntAckCallback,
PULONG Tlb)
{
/* Set the callbacks (or use default ones if some are NULL) */
State->MemReadCallback = (MemReadCallback ? MemReadCallback : Fast486MemReadCallback );
@ -214,6 +215,9 @@ Fast486Initialize(PFAST486_STATE State,
State->BopCallback = (BopCallback ? BopCallback : Fast486BopCallback );
State->IntAckCallback = (IntAckCallback ? IntAckCallback : Fast486IntAckCallback );
/* Set the TLB (if given) */
State->Tlb = Tlb;
/* Reset the CPU */
Fast486Reset(State);
}
@ -231,6 +235,7 @@ Fast486Reset(PFAST486_STATE State)
FAST486_IDLE_PROC IdleCallback = State->IdleCallback;
FAST486_BOP_PROC BopCallback = State->BopCallback;
FAST486_INT_ACK_PROC IntAckCallback = State->IntAckCallback;
PULONG Tlb = State->Tlb;
/* Clear the entire structure */
RtlZeroMemory(State, sizeof(*State));
@ -266,7 +271,7 @@ Fast486Reset(PFAST486_STATE State)
/* Initialize CR0 */
State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_ET;
/* Restore the callbacks */
/* Restore the callbacks and TLB */
State->MemReadCallback = MemReadCallback;
State->MemWriteCallback = MemWriteCallback;
State->IoReadCallback = IoReadCallback;
@ -274,6 +279,7 @@ Fast486Reset(PFAST486_STATE State)
State->IdleCallback = IdleCallback;
State->BopCallback = BopCallback;
State->IntAckCallback = IntAckCallback;
State->Tlb = Tlb;
}
VOID

View file

@ -296,7 +296,8 @@ BOOLEAN EmulatorInitialize(VOID)
EmulatorWriteIo,
NULL,
EmulatorBiosOperation,
EmulatorIntAcknowledge);
EmulatorIntAcknowledge,
NULL /* TODO: Use a TLB */);
/* Enable interrupts */
EmulatorSetFlag(EMULATOR_FLAG_IF);