Author: hbelusca Date: Thu Apr 23 01:02:36 2015 New Revision: 67361
URL: http://svn.reactos.org/svn/reactos?rev=67361&view=rev Log: [NTVDM] - Report A20 line status in the PS/2 controller output port. - Properly implement XMS functions 3 and 5 (Global Enable/Disable A20 line), 4 and 6 (Local Enable/Disable A20 line) and 7 (Get A20 line status) using flag+counter and PS/2 I/O calls. - Fix XMS driver version report.
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.c trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.h trunk/reactos/subsystems/mvdm/ntvdm/emulator.c trunk/reactos/subsystems/mvdm/ntvdm/emulator.h trunk/reactos/subsystems/mvdm/ntvdm/hardware/ps2.c
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.c [iso-8859-1] Thu Apr 23 01:02:36 2015 @@ -13,6 +13,8 @@ #include "ntvdm.h" #include "emulator.h" #include "cpu/bop.h" +#include "io.h" +#include "hardware/ps2.h"
#include "dos.h" #include "dos/dem.h" @@ -44,6 +46,125 @@ static RTL_BITMAP AllocBitmap; static ULONG BitmapBuffer[(XMS_BLOCKS + 31) / 32];
+/* + * Flag used by Global Enable/Disable A20 functions, so that they don't + * need to re-change the state of A20 if it was already enabled/disabled. + */ +static BOOLEAN IsA20Enabled = FALSE; +/* + * This flag is set to TRUE or FALSE when A20 line was already disabled or + * enabled when XMS driver was loaded. + * In case A20 was disabled, we are allowed to modify it. In case A20 was + * already enabled, we are not allowed to touch it. + */ +static BOOLEAN CanChangeA20 = TRUE; +/* + * Count for enabling or disabling the A20 line. The A20 line is enabled + * only if the enabling count is greater than or equal to 0. + */ +static LONG A20EnableCount = 0; + +/* HELPERS FOR A20 LINE *******************************************************/ + +static BOOLEAN PCAT_A20Control(BYTE Control, PBOOLEAN A20Status) +{ + BYTE ControllerOutput; + + /* Retrieve PS/2 controller output byte */ + IOWriteB(PS2_CONTROL_PORT, 0xD0); + ControllerOutput = IOReadB(PS2_DATA_PORT); + + switch (Control) + { + case 0: /* Disable A20 line */ + ControllerOutput &= ~0x02; + IOWriteB(PS2_CONTROL_PORT, 0xD1); + IOWriteB(PS2_DATA_PORT, ControllerOutput); + break; + + case 1: /* Enable A20 line */ + ControllerOutput |= 0x02; + IOWriteB(PS2_CONTROL_PORT, 0xD1); + IOWriteB(PS2_DATA_PORT, ControllerOutput); + break; + + default: /* Get A20 status */ + break; + } + + if (A20Status) + *A20Status = (ControllerOutput & 0x02) != 0; + + /* Return success */ + return TRUE; +} + +static VOID XmsLocalEnableA20(VOID) +{ + /* Enable A20 only if we can do so, otherwise make the caller believe we enabled it */ + if (!CanChangeA20) goto Quit; + + /* The count is zero so enable A20 */ + if (A20EnableCount == 0 && !PCAT_A20Control(1, NULL)) + goto Fail; + + ++A20EnableCount; + +Quit: + setAX(0x0001); /* Line successfully enabled */ + setBL(XMS_STATUS_SUCCESS); + return; + +Fail: + setAX(0x0000); /* Line failed to be enabled */ + setBL(XMS_STATUS_A20_ERROR); + return; +} + +static VOID XmsLocalDisableA20(VOID) +{ + /* Disable A20 only if we can do so, otherwise make the caller believe we disabled it */ + if (!CanChangeA20) goto Quit; + + /* If the count is already zero, fail */ + if (A20EnableCount == 0) goto Fail; + + --A20EnableCount; + + /* The count is zero so disable A20 */ + if (A20EnableCount == 0 && !PCAT_A20Control(0, NULL)) + goto Fail; + +Quit: + setAX(0x0001); /* Line successfully disabled */ + setBL(XMS_STATUS_SUCCESS); + return; + +Fail: + setAX(0x0000); /* Line failed to be enabled */ + setBL(XMS_STATUS_A20_ERROR); + return; +} + +static VOID XmsGetA20State(VOID) +{ + BOOLEAN A20Status = FALSE; + + /* + * NOTE: The XMS specification explicitely says that this check is done + * in a hardware-independent manner, by checking whether high memory wraps. + * For our purposes we just call the emulator API. + */ + + /* Get A20 status */ + if (PCAT_A20Control(2, &A20Status)) + setBL(XMS_STATUS_SUCCESS); + else + setBL(XMS_STATUS_A20_ERROR); + + setAX(A20Status); +} + /* PRIVATE FUNCTIONS **********************************************************/
static inline PXMS_HANDLE GetHandleRecord(WORD Handle) @@ -158,23 +279,75 @@ /* Get XMS Version */ case 0x00: { - setAX(0x0300); /* XMS version 3.0 */ + setAX(0x0300); /* XMS version 3.00 */ + setBX(0x0301); /* Driver version 3.01 */ setDX(0x0001); /* HMA present */ - break; }
/* Global Enable A20 */ case 0x03: { - EmulatorSetA20(TRUE); + /* Enable A20 if needed */ + if (!IsA20Enabled) + { + XmsLocalEnableA20(); + if (getAX() != 1) + { + /* XmsLocalEnableA20 failed and already set AX and BL to their correct values */ + break; + } + + IsA20Enabled = TRUE; + } + + setAX(0x0001); /* Line successfully enabled */ + setBL(XMS_STATUS_SUCCESS); break; }
/* Global Disable A20 */ case 0x04: { - EmulatorSetA20(FALSE); + /* Disable A20 if needed */ + if (IsA20Enabled) + { + XmsLocalDisableA20(); + if (getAX() != 1) + { + /* XmsLocalDisableA20 failed and already set AX and BL to their correct values */ + break; + } + + IsA20Enabled = FALSE; + } + + setAX(0x0001); /* Line successfully disabled */ + setBL(XMS_STATUS_SUCCESS); + break; + } + + /* Local Enable A20 */ + case 0x05: + { + /* This call sets AX and BL to their correct values */ + XmsLocalEnableA20(); + break; + } + + /* Local Disable A20 */ + case 0x06: + { + /* This call sets AX and BL to their correct values */ + XmsLocalDisableA20(); + break; + } + + /* Query A20 State */ + case 0x07: + { + /* This call sets AX and BL to their correct values */ + XmsGetA20State(); break; }
@@ -184,7 +357,6 @@ setAX(FreeBlocks); setDX(XMS_BLOCKS); setBL(XMS_STATUS_SUCCESS); - break; }
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.h [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.h [iso-8859-1] Thu Apr 23 01:02:36 2015 @@ -15,6 +15,7 @@
#define XMS_STATUS_SUCCESS 0x00 #define XMS_STATUS_NOT_IMPLEMENTED 0x80 +#define XMS_STATUS_A20_ERROR 0x82 #define XMS_STATUS_HMA_IN_USE 0x91 #define XMS_STATUS_OUT_OF_MEMORY 0xA0 #define XMS_STATUS_OUT_OF_HANDLES 0xA1
Modified: trunk/reactos/subsystems/mvdm/ntvdm/emulator.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/emula... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/emulator.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/emulator.c [iso-8859-1] Thu Apr 23 01:02:36 2015 @@ -162,6 +162,11 @@ A20Line = Enabled; }
+BOOLEAN EmulatorGetA20(VOID) +{ + return A20Line; +} + static VOID WINAPI EmulatorDebugBreakBop(LPWORD Stack) { DPRINT1("NTVDM: BOP_DEBUGGER\n");
Modified: trunk/reactos/subsystems/mvdm/ntvdm/emulator.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/emula... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/emulator.h [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/emulator.h [iso-8859-1] Thu Apr 23 01:02:36 2015 @@ -134,6 +134,7 @@
VOID EmulatorInterruptSignal(VOID); VOID EmulatorSetA20(BOOLEAN Enabled); +BOOLEAN EmulatorGetA20(VOID);
BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput); VOID EmulatorCleanup(VOID);
Modified: trunk/reactos/subsystems/mvdm/ntvdm/hardware/ps2.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/hardw... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/hardware/ps2.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/hardware/ps2.c [iso-8859-1] Thu Apr 23 01:02:36 2015 @@ -181,7 +181,11 @@ /* Read controller output port */ case 0xD0: { - // TODO: Not implemented + /* Bit 0 always set, and bit 1 is the A20 gate state */ + OutputBuffer = (!!EmulatorGetA20() << 1) | 0x01; + // FIXME: Set the status of IRQ1 and IRQ12 + + StatusRegister |= (1 << 0); // There is something to read break; }
@@ -231,6 +235,8 @@ /* Update the A20 line setting */ EmulatorSetA20(Data & (1 << 1));
+ // FIXME: Add the status of IRQ1 and IRQ12 + break; }