Author: aandrejevic Date: Wed Jun 26 17:15:45 2013 New Revision: 59343
URL: http://svn.reactos.org/svn/reactos?rev=59343&view=rev Log: [NTVDM] Use 286 mode in softx86. Implement "Get / Set Disk Transfer Area". Start implementation of PS/2 controller. Improve hardware interrupts. Fix CLI / STI / HLT instruction support.
Modified: branches/ntvdm/subsystems/ntvdm/dos.c branches/ntvdm/subsystems/ntvdm/emulator.c branches/ntvdm/subsystems/ntvdm/hardware.c branches/ntvdm/subsystems/ntvdm/ntvdm.h
Modified: branches/ntvdm/subsystems/ntvdm/dos.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/dos.c?rev... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/dos.c [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/dos.c [iso-8859-1] Wed Jun 26 17:15:45 2013 @@ -9,6 +9,7 @@ #include "ntvdm.h"
WORD CurrentPsp = SYSTEM_PSP, LastError = 0; +DWORD DiskTransferArea;
static VOID DosCombineFreeBlocks(WORD StartBlock) { @@ -433,6 +434,7 @@
/* Execute */ CurrentPsp = Segment; + DiskTransferArea = MAKELONG(0x80, Segment); EmulatorExecute(Segment + Header->e_cs, sizeof(DOS_PSP) + Header->e_ip);
Success = TRUE; @@ -466,6 +468,7 @@
/* Execute */ CurrentPsp = Segment; + DiskTransferArea = MAKELONG(0x80, Segment); EmulatorExecute(Segment, 0x100);
Success = TRUE; @@ -635,6 +638,13 @@ break; }
+ /* Set Disk Transfer Area */ + case 0x1A: + { + DiskTransferArea = MAKELONG(LOWORD(Edx), DataSegment); + break; + } + /* Set Interrupt Vector */ case 0x25: { @@ -721,6 +731,15 @@ break; }
+ /* Get Disk Transfer Area */ + case 0x2F: + { + EmulatorSetRegister(EMULATOR_REG_ES, HIWORD(DiskTransferArea)); + EmulatorSetRegister(EMULATOR_REG_BX, LOWORD(DiskTransferArea)); + + break; + } + /* Get Interrupt Vector */ case 0x35: {
Modified: branches/ntvdm/subsystems/ntvdm/emulator.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/emulator.... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/emulator.c [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/emulator.c [iso-8859-1] Wed Jun 26 17:15:45 2013 @@ -14,9 +14,13 @@
softx86_ctx EmulatorContext; softx87_ctx FpuEmulatorContext; +static BOOLEAN A20Line = FALSE;
static VOID EmulatorReadMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) { + /* If the A20 line is disabled, mask bit 20 */ + if (!A20Line) Address &= ~(1 << 20); + /* Make sure the requested address is valid */ if ((Address + Size) >= MAX_ADDRESS) return;
@@ -35,6 +39,9 @@
static VOID EmulatorWriteMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) { + /* If the A20 line is disabled, mask bit 20 */ + if (!A20Line) Address &= ~(1 << 20); + /* Make sure the requested address is valid */ if ((Address + Size) >= MAX_ADDRESS) return;
@@ -71,25 +78,45 @@ *Buffer = PicReadData(Address); break; } - } -} - -static VOID EmulatorWriteIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) -{ - BYTE Byte = *Buffer; - - switch (Address) - { - case PIT_COMMAND_PORT: - { - PitWriteCommand(Byte); - break; - }
case PIT_DATA_PORT(0): case PIT_DATA_PORT(1): case PIT_DATA_PORT(2): { + *Buffer = PitReadData(Address - PIT_DATA_PORT(0)); + break; + } + + case PS2_CONTROL_PORT: + { + *Buffer = KeyboardReadStatus(); + break; + } + + case PS2_DATA_PORT: + { + *Buffer = KeyboardReadData(); + break; + } + } +} + +static VOID EmulatorWriteIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) +{ + BYTE Byte = *Buffer; + + switch (Address) + { + case PIT_COMMAND_PORT: + { + PitWriteCommand(Byte); + break; + } + + case PIT_DATA_PORT(0): + case PIT_DATA_PORT(1): + case PIT_DATA_PORT(2): + { PitWriteData(Address - PIT_DATA_PORT(0), Byte); break; } @@ -105,6 +132,18 @@ case PIC_SLAVE_DATA: { PicWriteData(Address, Byte); + break; + } + + case PS2_CONTROL_PORT: + { + KeyboardWriteCommand(Byte); + break; + } + + case PS2_DATA_PORT: + { + KeyboardWriteData(Byte); break; } } @@ -187,6 +226,16 @@ } }
+static VOID EmulatorHardwareInt(PVOID Context, BYTE Number) +{ + /* Do nothing */ +} + +static VOID EmulatorHardwareIntAck(PVOID Context, BYTE Number) +{ + /* Do nothing */ +} + /* PUBLIC FUNCTIONS ***********************************************************/
BOOLEAN EmulatorInitialize() @@ -196,7 +245,7 @@ if (BaseAddress == NULL) return FALSE;
/* Initialize the softx86 CPU emulator */ - if (!softx86_init(&EmulatorContext, SX86_CPULEVEL_80186)) + if (!softx86_init(&EmulatorContext, SX86_CPULEVEL_80286)) { HeapFree(GetProcessHeap(), 0, BaseAddress); return FALSE; @@ -220,9 +269,14 @@
/* Set interrupt callbacks */ EmulatorContext.callbacks->on_sw_int = EmulatorSoftwareInt; + EmulatorContext.callbacks->on_hw_int = EmulatorHardwareInt; + EmulatorContext.callbacks->on_hw_int_ack = EmulatorHardwareIntAck;
/* Connect the emulated FPU to the emulated CPU */ softx87_connect_to_CPU(&EmulatorContext, &FpuEmulatorContext); + + /* Enable interrupts */ + EmulatorSetFlag(EMULATOR_FLAG_IF);
return TRUE; } @@ -252,6 +306,12 @@ softx86_make_simple_interrupt_call(&EmulatorContext, &Segment, &Offset); }
+VOID EmulatorExternalInterrupt(BYTE Number) +{ + /* Call the softx86 API */ + softx86_ext_hw_signal(&EmulatorContext, Number); +} + ULONG EmulatorGetRegister(ULONG Register) { if (Register < EMULATOR_REG_ES) @@ -294,7 +354,11 @@ VOID EmulatorStep() { /* Call the softx86 API */ - softx86_step(&EmulatorContext); + if (!softx86_step(&EmulatorContext)) + { + /* Invalid opcode */ + EmulatorInterrupt(EMULATOR_EXCEPTION_INVALID_OPCODE); + } }
VOID EmulatorCleanup() @@ -307,4 +371,9 @@ softx87_free(&FpuEmulatorContext); }
+VOID EmulatorSetA20(BOOLEAN Enabled) +{ + A20Line = Enabled; +} + /* EOF */
Modified: branches/ntvdm/subsystems/ntvdm/hardware.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/hardware.... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/hardware.c [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/hardware.c [iso-8859-1] Wed Jun 26 17:15:45 2013 @@ -53,6 +53,9 @@ static BOOLEAN KeyboardQueueEmpty = TRUE; static UINT KeyboardQueueStart = 0; static UINT KeyboardQueueEnd = 0; +static BYTE KeyboardResponse = 0; +static BOOLEAN KeyboardReadResponse = FALSE, KeyboardWriteResponse = FALSE; +static BYTE KeyboardConfig = PS2_DEFAULT_CONFIG;
static BOOLEAN KeyboardQueuePush(BYTE ScanCode) { @@ -73,7 +76,6 @@ return TRUE; }
-#if 0 static BOOLEAN KeyboardQueuePop(BYTE *ScanCode) { /* Make sure the keyboard queue is not empty */ @@ -94,7 +96,6 @@
return TRUE; } -#endif
/* PUBLIC FUNCTIONS ***********************************************************/
@@ -248,7 +249,7 @@
/* Set the appropriate bit in the ISR and interrupt the CPU */ if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= 1 << Number; - EmulatorInterrupt(MasterPic.IntOffset + Number); + EmulatorExternalInterrupt(MasterPic.IntOffset + Number); } else if (Number >= 8 && Number < 16) { @@ -279,7 +280,7 @@
/* Set the appropriate bit in the ISR and interrupt the CPU */ if (!SlavePic.AutoEoi) SlavePic.InServiceRegister |= 1 << Number; - EmulatorInterrupt(SlavePic.IntOffset + Number); + EmulatorExternalInterrupt(SlavePic.IntOffset + Number); } }
@@ -497,6 +498,203 @@ } }
+BYTE KeyboardReadStatus() +{ + BYTE Status = 0; + + /* Set the first bit if the data can be read */ + if (KeyboardReadResponse || !KeyboardQueueEmpty) Status |= 1 << 0; + + /* Always set bit 2 */ + Status |= 1 << 2; + + /* Set bit 3 if the next byte goes to the controller */ + if (KeyboardWriteResponse) Status |= 1 << 3; + + return Status; +} + +VOID KeyboardWriteCommand(BYTE Command) +{ + switch (Command) + { + /* Read configuration byte */ + case 0x20: + { + KeyboardResponse = KeyboardConfig; + KeyboardReadResponse = TRUE; + + break; + } + + /* Write configuration byte */ + case 0x60: + /* Write controller output port */ + case 0xD1: + /* Write keyboard output buffer */ + case 0xD2: + /* Write mouse output buffer */ + case 0xD3: + /* Write mouse input buffer */ + case 0xD4: + { + /* These commands require a response */ + KeyboardResponse = Command; + KeyboardWriteResponse = TRUE; + + break; + } + + /* Disable mouse */ + case 0xA7: + { + // TODO: Mouse support + + break; + } + + /* Enable mouse */ + case 0xA8: + { + // TODO: Mouse support + + break; + } + + /* Test mouse port */ + case 0xA9: + { + KeyboardResponse = 0; + KeyboardReadResponse = TRUE; + + break; + } + + /* Test PS/2 controller */ + case 0xAA: + { + KeyboardResponse = 0x55; + KeyboardReadResponse = TRUE; + + break; + } + + /* Disable keyboard */ + case 0xAD: + { + // TODO: Not implemented + break; + } + + /* Enable keyboard */ + case 0xAE: + { + // TODO: Not implemented + break; + } + + /* Read controller output port */ + case 0xD0: + { + // TODO: Not implemented + break; + } + + /* CPU Reset */ + case 0xF0: + case 0xF2: + case 0xF4: + case 0xF6: + case 0xF8: + case 0xFA: + case 0xFC: + case 0xFE: + { + /* Stop the simulation */ + VdmRunning = FALSE; + + break; + } + } +} + +BYTE KeyboardReadData() +{ + BYTE Value = 0; + + /* If there was a response byte from the controller, return it */ + if (KeyboardReadResponse) + { + KeyboardReadResponse = FALSE; + return KeyboardResponse; + } + + /* Otherwise, read the data from the queue */ + KeyboardQueuePop(&Value); + + return Value; +} + +VOID KeyboardWriteData(BYTE Data) +{ + /* Check if the controller is waiting for a response */ + if (KeyboardWriteResponse) + { + KeyboardWriteResponse = FALSE; + + /* Check which command it was */ + switch (KeyboardResponse) + { + /* Write configuration byte */ + case 0x60: + { + KeyboardConfig = Data; + break; + } + + /* Write controller output */ + case 0xD1: + { + /* Check if bit 0 is unset */ + if (!(Data & (1 << 0))) + { + /* CPU disabled - end simulation */ + VdmRunning = FALSE; + } + + /* Update the A20 line setting */ + EmulatorSetA20(Data & (1 << 1)); + + break; + } + + case 0xD2: + { + /* Push the data byte to the keyboard queue */ + KeyboardQueuePush(Data); + + break; + } + + case 0xD3: + { + // TODO: Mouse support + break; + } + + case 0xD4: + { + // TODO: Mouse support + break; + } + } + + return; + } + + // TODO: Implement PS/2 device commands +} + VOID CheckForInputEvents() { PINPUT_RECORD Buffer;
Modified: branches/ntvdm/subsystems/ntvdm/ntvdm.h URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ntvdm.h?r... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/ntvdm.h [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/ntvdm.h [iso-8859-1] Wed Jun 26 17:15:45 2013 @@ -74,6 +74,9 @@ #define KEYBOARD_BUFFER_SIZE 32 #define PS2_DATA_PORT 0x60 #define PS2_CONTROL_PORT 0x64 +#define PS2_DEFAULT_CONFIG 0x05 +#define KEYBOARD_ACK 0xFA +#define KEYBOARD_RESEND 0xFE
#define EMULATOR_FLAG_CF (1 << 0) #define EMULATOR_FLAG_PF (1 << 2) @@ -91,6 +94,18 @@ #define EMULATOR_FLAG_VIF (1 << 19) #define EMULATOR_FLAG_VIP (1 << 20) #define EMULATOR_FLAG_ID (1 << 21) + +enum +{ + EMULATOR_EXCEPTION_DIVISION_BY_ZERO, + EMULATOR_EXCEPTION_DEBUG, + EMULATOR_EXCEPTION_NMI, + EMULATOR_EXCEPTION_BREAKPOINT, + EMULATOR_EXCEPTION_OVERFLOW, + EMULATOR_EXCEPTION_BOUND, + EMULATOR_EXCEPTION_INVALID_OPCODE, + EMULATOR_EXCEPTION_NO_FPU +};
typedef enum { @@ -226,9 +241,14 @@ VOID PitWriteData(BYTE Channel, BYTE Value); VOID PitDecrementCount(); VOID CheckForInputEvents(); +BYTE KeyboardReadStatus(); +VOID KeyboardWriteCommand(BYTE Command); +BYTE KeyboardReadData(); +VOID KeyboardWriteData(BYTE Data); VOID EmulatorSetStack(WORD Segment, WORD Offset); VOID EmulatorExecute(WORD Segment, WORD Offset); VOID EmulatorInterrupt(BYTE Number); +VOID EmulatorExternalInterrupt(BYTE Number); ULONG EmulatorGetRegister(ULONG Register); VOID EmulatorSetRegister(ULONG Register, ULONG Value); VOID EmulatorSetFlag(ULONG Flag); @@ -237,5 +257,7 @@ BOOLEAN EmulatorInitialize(); VOID EmulatorStep(); VOID EmulatorCleanup(); +VOID EmulatorHalt(); +VOID EmulatorSetA20(BOOLEAN Enabled);
/* EOF */