mirror of
https://github.com/reactos/reactos.git
synced 2024-08-27 13:48:42 +00:00
[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. svn path=/trunk/; revision=67361
This commit is contained in:
parent
2273067742
commit
91dfded93d
|
@ -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 WORD FreeBlocks = XMS_BLOCKS;
|
|||
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 @@ static VOID WINAPI XmsBopProcedure(LPWORD Stack)
|
|||
/* 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 @@ static VOID WINAPI XmsBopProcedure(LPWORD Stack)
|
|||
setAX(FreeBlocks);
|
||||
setDX(XMS_BLOCKS);
|
||||
setBL(XMS_STATUS_SUCCESS);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -162,6 +162,11 @@ VOID EmulatorSetA20(BOOLEAN Enabled)
|
|||
A20Line = Enabled;
|
||||
}
|
||||
|
||||
BOOLEAN EmulatorGetA20(VOID)
|
||||
{
|
||||
return A20Line;
|
||||
}
|
||||
|
||||
static VOID WINAPI EmulatorDebugBreakBop(LPWORD Stack)
|
||||
{
|
||||
DPRINT1("NTVDM: BOP_DEBUGGER\n");
|
||||
|
|
|
@ -134,6 +134,7 @@ VOID EmulatorTerminate(VOID);
|
|||
|
||||
VOID EmulatorInterruptSignal(VOID);
|
||||
VOID EmulatorSetA20(BOOLEAN Enabled);
|
||||
BOOLEAN EmulatorGetA20(VOID);
|
||||
|
||||
BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput);
|
||||
VOID EmulatorCleanup(VOID);
|
||||
|
|
|
@ -181,7 +181,11 @@ static VOID WINAPI PS2WritePort(USHORT Port, BYTE Data)
|
|||
/* 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 @@ static VOID WINAPI PS2WritePort(USHORT Port, BYTE Data)
|
|||
/* Update the A20 line setting */
|
||||
EmulatorSetA20(Data & (1 << 1));
|
||||
|
||||
// FIXME: Add the status of IRQ1 and IRQ12
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue