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/dos32krnl/himem.c?rev=67361&r1=67360&r2=67361&view=diff
==============================================================================
--- 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/dos32krnl/himem.h?rev=67361&r1=67360&r2=67361&view=diff
==============================================================================
--- 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/emulator.c?rev=67361&r1=67360&r2=67361&view=diff
==============================================================================
--- 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/emulator.h?rev=67361&r1=67360&r2=67361&view=diff
==============================================================================
--- 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/hardware/ps2.c?rev=67361&r1=67360&r2=67361&view=diff
==============================================================================
--- 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;
                 }
 


Reply via email to