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/…
==============================================================================
--- 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/…
==============================================================================
--- 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/emul…
==============================================================================
--- 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/emul…
==============================================================================
--- 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/hard…
==============================================================================
--- 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;
}