[FAST486][NTVDM]

- Introduce a Fast486Initialize which is used to set up the CPU callbacks (and use default ones if some of the given callbacks are NULL), and to reset it the first time. Now Fast486Reset is meant to be used for only resetting the CPU to a safe state.
- Hence we are now sure that State->WhateverCallback is never NULL (and is theoretically valid), so don't do NULL-checks when calling them, but call them directly. The default cases for those checks become the default calls for the default callbacks.
- Remove the now-unneeded EmulatorIdle function.

svn path=/branches/ntvdm/; revision=60814
This commit is contained in:
Hermès Bélusca-Maïto 2013-11-01 01:46:58 +00:00
parent 1c12c6fe0d
commit 861776bd7e
7 changed files with 221 additions and 207 deletions

View file

@ -389,6 +389,21 @@ struct _FAST486_STATE
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
VOID
NTAPI
Fast486Initialize(PFAST486_STATE State,
FAST486_MEM_READ_PROC MemReadCallback,
FAST486_MEM_WRITE_PROC MemWriteCallback,
FAST486_IO_READ_PROC IoReadCallback,
FAST486_IO_WRITE_PROC IoWriteCallback,
FAST486_IDLE_PROC IdleCallback,
FAST486_BOP_PROC BopCallback,
FAST486_INT_ACK_PROC IntAckCallback);
VOID
NTAPI
Fast486Reset(PFAST486_STATE State);
VOID VOID
NTAPI NTAPI
Fast486Continue(PFAST486_STATE State); Fast486Continue(PFAST486_STATE State);
@ -409,10 +424,6 @@ VOID
NTAPI NTAPI
Fast486DumpState(PFAST486_STATE State); Fast486DumpState(PFAST486_STATE State);
VOID
NTAPI
Fast486Reset(PFAST486_STATE State);
VOID VOID
NTAPI NTAPI
Fast486Interrupt(PFAST486_STATE State, UCHAR Number); Fast486Interrupt(PFAST486_STATE State, UCHAR Number);

View file

@ -65,7 +65,6 @@ Fast486ReadMemory(PFAST486_STATE State,
{ {
/* Read beyond limit */ /* Read beyond limit */
Fast486Exception(State, FAST486_EXCEPTION_GP); Fast486Exception(State, FAST486_EXCEPTION_GP);
return FALSE; return FALSE;
} }
@ -91,7 +90,6 @@ Fast486ReadMemory(PFAST486_STATE State,
if (!CachedDescriptor->Executable) if (!CachedDescriptor->Executable)
{ {
/* Data segment not executable */ /* Data segment not executable */
Fast486Exception(State, FAST486_EXCEPTION_GP); Fast486Exception(State, FAST486_EXCEPTION_GP);
return FALSE; return FALSE;
} }
@ -101,7 +99,6 @@ Fast486ReadMemory(PFAST486_STATE State,
if (CachedDescriptor->Executable && (!CachedDescriptor->ReadWrite)) if (CachedDescriptor->Executable && (!CachedDescriptor->ReadWrite))
{ {
/* Code segment not readable */ /* Code segment not readable */
Fast486Exception(State, FAST486_EXCEPTION_GP); Fast486Exception(State, FAST486_EXCEPTION_GP);
return FALSE; return FALSE;
} }
@ -149,38 +146,18 @@ Fast486ReadMemory(PFAST486_STATE State,
PageLength = PAGE_OFFSET(LinearAddress + Size); PageLength = PAGE_OFFSET(LinearAddress + Size);
} }
/* Did the host provide a memory hook? */ /* Read the entry */
if (State->MemReadCallback)
{
/* Yes, call the host */
State->MemReadCallback(State, State->MemReadCallback(State,
(TableEntry.Address << 12) | PageOffset, (TableEntry.Address << 12) | PageOffset,
Buffer, Buffer,
PageLength); PageLength);
} }
else
{
/* Read the memory directly */
RtlMoveMemory(Buffer,
(PVOID)((TableEntry.Address << 12) | PageOffset),
PageLength);
}
}
} }
else else
{ {
/* Did the host provide a memory hook? */ /* Read the entry */
if (State->MemReadCallback)
{
/* Yes, call the host */
State->MemReadCallback(State, LinearAddress, Buffer, Size); State->MemReadCallback(State, LinearAddress, Buffer, Size);
} }
else
{
/* Read the memory directly */
RtlMoveMemory(Buffer, (PVOID)LinearAddress, Size);
}
}
return TRUE; return TRUE;
} }
@ -229,14 +206,12 @@ Fast486WriteMemory(PFAST486_STATE State,
if (CachedDescriptor->Executable) if (CachedDescriptor->Executable)
{ {
/* Code segment not writable */ /* Code segment not writable */
Fast486Exception(State, FAST486_EXCEPTION_GP); Fast486Exception(State, FAST486_EXCEPTION_GP);
return FALSE; return FALSE;
} }
else if (!CachedDescriptor->ReadWrite) else if (!CachedDescriptor->ReadWrite)
{ {
/* Data segment not writeable */ /* Data segment not writeable */
Fast486Exception(State, FAST486_EXCEPTION_GP); Fast486Exception(State, FAST486_EXCEPTION_GP);
return FALSE; return FALSE;
} }
@ -285,38 +260,18 @@ Fast486WriteMemory(PFAST486_STATE State,
PageLength = PAGE_OFFSET(LinearAddress + Size); PageLength = PAGE_OFFSET(LinearAddress + Size);
} }
/* Did the host provide a memory hook? */ /* Write the entry */
if (State->MemWriteCallback)
{
/* Yes, call the host */
State->MemWriteCallback(State, State->MemWriteCallback(State,
(TableEntry.Address << 12) | PageOffset, (TableEntry.Address << 12) | PageOffset,
Buffer, Buffer,
PageLength); PageLength);
} }
else
{
/* Read the memory directly */
RtlMoveMemory((PVOID)((TableEntry.Address << 12) | PageOffset),
Buffer,
PageLength);
}
}
} }
else else
{ {
/* Did the host provide a memory hook? */ /* Write the entry */
if (State->MemWriteCallback)
{
/* Yes, call the host */
State->MemWriteCallback(State, LinearAddress, Buffer, Size); State->MemWriteCallback(State, LinearAddress, Buffer, Size);
} }
else
{
/* Write the memory directly */
RtlMoveMemory((PVOID)LinearAddress, Buffer, Size);
}
}
return TRUE; return TRUE;
} }
@ -339,17 +294,10 @@ Fast486InterruptInternal(PFAST486_STATE State,
{ {
/* Read the TSS */ /* Read the TSS */
// FIXME: This code is only correct when paging is disabled!!! // FIXME: This code is only correct when paging is disabled!!!
if (State->MemReadCallback)
{
State->MemReadCallback(State, State->MemReadCallback(State,
State->Tss.Address, State->Tss.Address,
&Tss, &Tss,
sizeof(Tss)); sizeof(Tss));
}
else
{
RtlMoveMemory(&Tss, (PVOID)State->Tss.Address, sizeof(Tss));
}
/* Check the new (higher) privilege level */ /* Check the new (higher) privilege level */
switch (GET_SEGMENT_RPL(SegmentSelector)) switch (GET_SEGMENT_RPL(SegmentSelector))

View file

@ -186,21 +186,11 @@ Fast486LoadSegment(PFAST486_STATE State,
/* Read the GDT */ /* Read the GDT */
// FIXME: This code is only correct when paging is disabled!!! // FIXME: This code is only correct when paging is disabled!!!
if (State->MemReadCallback)
{
State->MemReadCallback(State, State->MemReadCallback(State,
State->Gdtr.Address State->Gdtr.Address
+ GET_SEGMENT_INDEX(Selector), + GET_SEGMENT_INDEX(Selector),
&GdtEntry, &GdtEntry,
sizeof(GdtEntry)); sizeof(GdtEntry));
}
else
{
RtlMoveMemory(&GdtEntry,
(PVOID)(State->Gdtr.Address
+ GET_SEGMENT_INDEX(Selector)),
sizeof(GdtEntry));
}
if (Segment == FAST486_REG_SS) if (Segment == FAST486_REG_SS)
{ {
@ -399,8 +389,6 @@ Fast486GetIntVector(PFAST486_STATE State,
{ {
/* Read from the IDT */ /* Read from the IDT */
// FIXME: This code is only correct when paging is disabled!!! // FIXME: This code is only correct when paging is disabled!!!
if (State->MemReadCallback)
{
State->MemReadCallback(State, State->MemReadCallback(State,
State->Idtr.Address State->Idtr.Address
+ Number * sizeof(*IdtEntry), + Number * sizeof(*IdtEntry),
@ -408,33 +396,15 @@ Fast486GetIntVector(PFAST486_STATE State,
sizeof(*IdtEntry)); sizeof(*IdtEntry));
} }
else else
{
RtlMoveMemory(IdtEntry,
(PVOID)(State->Idtr.Address
+ Number * sizeof(*IdtEntry)),
sizeof(*IdtEntry));
}
}
else
{ {
/* Read from the real-mode IVT */ /* Read from the real-mode IVT */
/* Paging is always disabled in real mode */ /* Paging is always disabled in real mode */
if (State->MemReadCallback)
{
State->MemReadCallback(State, State->MemReadCallback(State,
State->Idtr.Address State->Idtr.Address
+ Number * sizeof(FarPointer), + Number * sizeof(FarPointer),
&FarPointer, &FarPointer,
sizeof(FarPointer)); sizeof(FarPointer));
}
else
{
RtlMoveMemory(&FarPointer,
(PVOID)(State->Idtr.Address
+ Number * sizeof(FarPointer)),
sizeof(FarPointer));
}
/* Fill a fake IDT entry */ /* Fill a fake IDT entry */
IdtEntry->Offset = LOWORD(FarPointer); IdtEntry->Offset = LOWORD(FarPointer);
@ -458,6 +428,7 @@ FORCEINLINE
BOOLEAN BOOLEAN
Fast486CalculateParity(UCHAR Number) Fast486CalculateParity(UCHAR Number)
{ {
// See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1; return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
} }

View file

@ -124,38 +124,146 @@ Fast486ExecutionControl(PFAST486_STATE State, INT Command)
|| (Fast486OpcodeHandlers[Opcode] == Fast486OpcodePrefix)); || (Fast486OpcodeHandlers[Opcode] == Fast486OpcodePrefix));
} }
/* DEFAULT CALLBACKS **********************************************************/
static VOID
NTAPI
Fast486MemReadCallback(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
{
UNREFERENCED_PARAMETER(State);
RtlMoveMemory(Buffer, (PVOID)Address, Size);
}
static VOID
NTAPI
Fast486MemWriteCallback(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
{
UNREFERENCED_PARAMETER(State);
RtlMoveMemory((PVOID)Address, Buffer, Size);
}
static VOID
NTAPI
Fast486IoReadCallback(PFAST486_STATE State, ULONG Port, PVOID Buffer, ULONG Size)
{
UNREFERENCED_PARAMETER(State);
UNREFERENCED_PARAMETER(Port);
UNREFERENCED_PARAMETER(Buffer);
UNREFERENCED_PARAMETER(Size);
}
static VOID
NTAPI
Fast486IoWriteCallback(PFAST486_STATE State, ULONG Port, PVOID Buffer, ULONG Size)
{
UNREFERENCED_PARAMETER(State);
UNREFERENCED_PARAMETER(Port);
UNREFERENCED_PARAMETER(Buffer);
UNREFERENCED_PARAMETER(Size);
}
static VOID
NTAPI
Fast486IdleCallback(PFAST486_STATE State)
{
UNREFERENCED_PARAMETER(State);
}
static VOID
NTAPI
Fast486BopCallback(PFAST486_STATE State, UCHAR BopCode)
{
UNREFERENCED_PARAMETER(State);
UNREFERENCED_PARAMETER(BopCode);
}
static UCHAR
NTAPI
Fast486IntAckCallback(PFAST486_STATE State)
{
UNREFERENCED_PARAMETER(State);
/* Return something... */
return 0;
}
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
VOID VOID
NTAPI NTAPI
Fast486Continue(PFAST486_STATE State) Fast486Initialize(PFAST486_STATE State,
FAST486_MEM_READ_PROC MemReadCallback,
FAST486_MEM_WRITE_PROC MemWriteCallback,
FAST486_IO_READ_PROC IoReadCallback,
FAST486_IO_WRITE_PROC IoWriteCallback,
FAST486_IDLE_PROC IdleCallback,
FAST486_BOP_PROC BopCallback,
FAST486_INT_ACK_PROC IntAckCallback)
{ {
/* Call the internal function */ /* Set the callbacks (or use default ones if some are NULL) */
Fast486ExecutionControl(State, FAST486_CONTINUE); State->MemReadCallback = (MemReadCallback ? MemReadCallback : Fast486MemReadCallback );
State->MemWriteCallback = (MemWriteCallback ? MemWriteCallback : Fast486MemWriteCallback);
State->IoReadCallback = (IoReadCallback ? IoReadCallback : Fast486IoReadCallback );
State->IoWriteCallback = (IoWriteCallback ? IoWriteCallback : Fast486IoWriteCallback );
State->IdleCallback = (IdleCallback ? IdleCallback : Fast486IdleCallback );
State->BopCallback = (BopCallback ? BopCallback : Fast486BopCallback );
State->IntAckCallback = (IntAckCallback ? IntAckCallback : Fast486IntAckCallback );
/* Reset the CPU */
Fast486Reset(State);
} }
VOID VOID
NTAPI NTAPI
Fast486StepInto(PFAST486_STATE State) Fast486Reset(PFAST486_STATE State)
{ {
/* Call the internal function */ USHORT i;
Fast486ExecutionControl(State, FAST486_STEP_INTO);
}
VOID FAST486_MEM_READ_PROC MemReadCallback = State->MemReadCallback;
NTAPI FAST486_MEM_WRITE_PROC MemWriteCallback = State->MemWriteCallback;
Fast486StepOver(PFAST486_STATE State) FAST486_IO_READ_PROC IoReadCallback = State->IoReadCallback;
{ FAST486_IO_WRITE_PROC IoWriteCallback = State->IoWriteCallback;
/* Call the internal function */ FAST486_IDLE_PROC IdleCallback = State->IdleCallback;
Fast486ExecutionControl(State, FAST486_STEP_OVER); FAST486_BOP_PROC BopCallback = State->BopCallback;
} FAST486_INT_ACK_PROC IntAckCallback = State->IntAckCallback;
VOID /* Clear the entire structure */
NTAPI RtlZeroMemory(State, sizeof(*State));
Fast486StepOut(PFAST486_STATE State)
{ /* Initialize the registers */
/* Call the internal function */ State->Flags.AlwaysSet = 1;
Fast486ExecutionControl(State, FAST486_STEP_OUT); State->InstPtr.LowWord = 0xFFF0;
/* Initialize segments */
for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
{
/* Set the selector, base and limit, other values don't apply in real mode */
State->SegmentRegs[i].Selector = 0;
State->SegmentRegs[i].Base = 0;
State->SegmentRegs[i].Limit = 0xFFFF;
}
/* Initialize the code segment */
State->SegmentRegs[FAST486_REG_CS].Selector = 0xF000;
State->SegmentRegs[FAST486_REG_CS].Base = 0xFFFF0000;
/* Initialize the IDT */
State->Idtr.Size = 0x3FF;
State->Idtr.Address = 0;
/* Initialize CR0 */
State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_ET;
/* Restore the callbacks */
State->MemReadCallback = MemReadCallback;
State->MemWriteCallback = MemWriteCallback;
State->IoReadCallback = IoReadCallback;
State->IoWriteCallback = IoWriteCallback;
State->IdleCallback = IdleCallback;
State->BopCallback = BopCallback;
State->IntAckCallback = IntAckCallback;
} }
VOID VOID
@ -244,52 +352,34 @@ Fast486DumpState(PFAST486_STATE State)
VOID VOID
NTAPI NTAPI
Fast486Reset(PFAST486_STATE State) Fast486Continue(PFAST486_STATE State)
{ {
INT i; /* Call the internal function */
FAST486_MEM_READ_PROC MemReadCallback = State->MemReadCallback; Fast486ExecutionControl(State, FAST486_CONTINUE);
FAST486_MEM_WRITE_PROC MemWriteCallback = State->MemWriteCallback; }
FAST486_IO_READ_PROC IoReadCallback = State->IoReadCallback;
FAST486_IO_WRITE_PROC IoWriteCallback = State->IoWriteCallback;
FAST486_IDLE_PROC IdleCallback = State->IdleCallback;
FAST486_BOP_PROC BopCallback = State->BopCallback;
FAST486_INT_ACK_PROC IntAckCallback = State->IntAckCallback;
/* Clear the entire structure */ VOID
RtlZeroMemory(State, sizeof(*State)); NTAPI
Fast486StepInto(PFAST486_STATE State)
{
/* Call the internal function */
Fast486ExecutionControl(State, FAST486_STEP_INTO);
}
/* Initialize the registers */ VOID
State->Flags.AlwaysSet = 1; NTAPI
State->InstPtr.LowWord = 0xFFF0; Fast486StepOver(PFAST486_STATE State)
{
/* Call the internal function */
Fast486ExecutionControl(State, FAST486_STEP_OVER);
}
/* Initialize segments */ VOID
for (i = 0; i < FAST486_NUM_SEG_REGS; i++) NTAPI
{ Fast486StepOut(PFAST486_STATE State)
/* Set the selector, base and limit, other values don't apply in real mode */ {
State->SegmentRegs[i].Selector = 0; /* Call the internal function */
State->SegmentRegs[i].Base = 0; Fast486ExecutionControl(State, FAST486_STEP_OUT);
State->SegmentRegs[i].Limit = 0xFFFF;
}
/* Initialize the code segment */
State->SegmentRegs[FAST486_REG_CS].Selector = 0xF000;
State->SegmentRegs[FAST486_REG_CS].Base = 0xFFFF0000;
/* Initialize the IDT */
State->Idtr.Size = 0x3FF;
State->Idtr.Address = 0;
/* Initialize CR0 */
State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_ET;
/* Restore the callbacks */
State->MemReadCallback = MemReadCallback;
State->MemWriteCallback = MemWriteCallback;
State->IoReadCallback = IoReadCallback;
State->IoWriteCallback = IoWriteCallback;
State->IdleCallback = IdleCallback;
State->BopCallback = BopCallback;
State->IntAckCallback = IntAckCallback;
} }
VOID VOID

View file

@ -4613,7 +4613,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeInt)
FAST486_OPCODE_HANDLER(Fast486OpcodeIret) FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
{ {
INT i; USHORT i;
ULONG InstPtr, CodeSel, StackPtr, StackSel; ULONG InstPtr, CodeSel, StackPtr, StackSel;
FAST486_FLAGS_REG NewFlags; FAST486_FLAGS_REG NewFlags;
BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size; BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;

View file

@ -250,10 +250,6 @@ static VOID WINAPI EmulatorBiosOperation(PFAST486_STATE State, UCHAR BopCode)
} }
} }
static VOID WINAPI EmulatorIdle(PFAST486_STATE State)
{
}
static UCHAR WINAPI EmulatorIntAcknowledge(PFAST486_STATE State) static UCHAR WINAPI EmulatorIntAcknowledge(PFAST486_STATE State)
{ {
UNREFERENCED_PARAMETER(State); UNREFERENCED_PARAMETER(State);
@ -264,23 +260,21 @@ static UCHAR WINAPI EmulatorIntAcknowledge(PFAST486_STATE State)
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
BOOLEAN EmulatorInitialize() BOOLEAN EmulatorInitialize(VOID)
{ {
/* Allocate memory for the 16-bit address space */ /* Allocate memory for the 16-bit address space */
BaseAddress = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_ADDRESS); BaseAddress = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_ADDRESS);
if (BaseAddress == NULL) return FALSE; if (BaseAddress == NULL) return FALSE;
/* Set the callbacks */ /* Initialize the CPU */
EmulatorContext.MemReadCallback = EmulatorReadMemory; Fast486Initialize(&EmulatorContext,
EmulatorContext.MemWriteCallback = EmulatorWriteMemory; EmulatorReadMemory,
EmulatorContext.IoReadCallback = EmulatorReadIo; // Must be != NULL EmulatorWriteMemory,
EmulatorContext.IoWriteCallback = EmulatorWriteIo; // Must be != NULL EmulatorReadIo,
EmulatorContext.IdleCallback = EmulatorIdle; // Must be != NULL EmulatorWriteIo,
EmulatorContext.BopCallback = EmulatorBiosOperation; NULL,
EmulatorContext.IntAckCallback = EmulatorIntAcknowledge; EmulatorBiosOperation,
EmulatorIntAcknowledge);
/* Reset the CPU */
Fast486Reset(&EmulatorContext);
/* Enable interrupts */ /* Enable interrupts */
EmulatorSetFlag(EMULATOR_FLAG_IF); EmulatorSetFlag(EMULATOR_FLAG_IF);
@ -288,6 +282,12 @@ BOOLEAN EmulatorInitialize()
return TRUE; return TRUE;
} }
VOID EmulatorCleanup(VOID)
{
/* Free the memory allocated for the 16-bit address space */
if (BaseAddress != NULL) HeapFree(GetProcessHeap(), 0, BaseAddress);
}
VOID EmulatorSetStack(WORD Segment, DWORD Offset) VOID EmulatorSetStack(WORD Segment, DWORD Offset)
{ {
Fast486SetStack(&EmulatorContext, Segment, Offset); Fast486SetStack(&EmulatorContext, Segment, Offset);
@ -365,12 +365,6 @@ VOID EmulatorStep(VOID)
Fast486StepInto(&EmulatorContext); Fast486StepInto(&EmulatorContext);
} }
VOID EmulatorCleanup(VOID)
{
/* Free the memory allocated for the 16-bit address space */
if (BaseAddress != NULL) HeapFree(GetProcessHeap(), 0, BaseAddress);
}
VOID EmulatorSetA20(BOOLEAN Enabled) VOID EmulatorSetA20(BOOLEAN Enabled)
{ {
A20Line = Enabled; A20Line = Enabled;

View file

@ -85,7 +85,7 @@ extern FAST486_STATE EmulatorContext;
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
BOOLEAN EmulatorInitialize(); BOOLEAN EmulatorInitialize(VOID);
VOID EmulatorSetStack(WORD Segment, DWORD Offset); VOID EmulatorSetStack(WORD Segment, DWORD Offset);
VOID EmulatorExecute(WORD Segment, WORD Offset); VOID EmulatorExecute(WORD Segment, WORD Offset);
VOID EmulatorInterrupt(BYTE Number); VOID EmulatorInterrupt(BYTE Number);
@ -96,8 +96,8 @@ VOID EmulatorSetRegister(ULONG Register, ULONG Value);
BOOLEAN EmulatorGetFlag(ULONG Flag); BOOLEAN EmulatorGetFlag(ULONG Flag);
VOID EmulatorSetFlag(ULONG Flag); VOID EmulatorSetFlag(ULONG Flag);
VOID EmulatorClearFlag(ULONG Flag); VOID EmulatorClearFlag(ULONG Flag);
VOID EmulatorStep(); VOID EmulatorStep(VOID);
VOID EmulatorCleanup(); VOID EmulatorCleanup(VOID);
VOID EmulatorSetA20(BOOLEAN Enabled); VOID EmulatorSetA20(BOOLEAN Enabled);
#endif // _EMULATOR_H_ #endif // _EMULATOR_H_