Author: aandrejevic
Date: Fri Jun 28 20:52:40 2013
New Revision: 59350
URL:
http://svn.reactos.org/svn/reactos?rev=59350&view=rev
Log:
[NTVDM]
Implement "Get DOS Version" API call.
Implement BIOS keyboard IRQ handler and some "INT 16h" functions.
Modified:
branches/ntvdm/subsystems/ntvdm/bios.c
branches/ntvdm/subsystems/ntvdm/bios.h
branches/ntvdm/subsystems/ntvdm/dos.c
branches/ntvdm/subsystems/ntvdm/dos.h
branches/ntvdm/subsystems/ntvdm/emulator.c
Modified: branches/ntvdm/subsystems/ntvdm/bios.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/bios.c?r…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/bios.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/bios.c [iso-8859-1] Fri Jun 28 20:52:40 2013
@@ -11,12 +11,17 @@
#include "bios.h"
#include "emulator.h"
#include "pic.h"
+#include "ps2.h"
#include "timer.h"
/* PRIVATE VARIABLES **********************************************************/
static BYTE CursorRow, CursorCol;
static WORD ConsoleWidth, ConsoleHeight;
+static BYTE BiosKeyboardMap[256];
+static WORD BiosKbdBuffer[BIOS_KBD_BUFFER_SIZE];
+static UINT BiosKbdBufferStart = 0, BiosKbdBufferEnd = 0;
+static BOOLEAN BiosKbdBufferEmpty = TRUE;
/* PRIVATE FUNCTIONS **********************************************************/
@@ -38,12 +43,54 @@
return Result;
}
+static BOOLEAN BiosKbdBufferPush(WORD Data)
+{
+ /* If it's full, fail */
+ if (!BiosKbdBufferEmpty && (BiosKbdBufferStart == BiosKbdBufferEnd))
+ {
+ return FALSE;
+ }
+
+ /* Otherwise, add the value to the queue */
+ BiosKbdBuffer[BiosKbdBufferEnd] = Data;
+ BiosKbdBufferEnd++;
+ BiosKbdBufferEnd %= BIOS_KBD_BUFFER_SIZE;
+ BiosKbdBufferEmpty = FALSE;
+
+ /* Return success */
+ return TRUE;
+}
+
+static BOOLEAN BiosKbdBufferTop(LPWORD Data)
+{
+ /* If it's empty, fail */
+ if (BiosKbdBufferEmpty) return FALSE;
+
+ /* Otherwise, get the value and return success */
+ *Data = BiosKbdBuffer[BiosKbdBufferStart];
+ return TRUE;
+}
+
+static BOOLEAN BiosKbdBufferPop()
+{
+ /* If it's empty, fail */
+ if (BiosKbdBufferEmpty) return FALSE;
+
+ /* Otherwise, remove the value and return success */
+ BiosKbdBufferStart++;
+ BiosKbdBufferStart %= BIOS_KBD_BUFFER_SIZE;
+ if (BiosKbdBufferStart == BiosKbdBufferEnd) BiosKbdBufferEmpty = TRUE;
+
+ return TRUE;
+}
+
/* PUBLIC FUNCTIONS ***********************************************************/
BOOLEAN BiosInitialize()
{
INT i;
WORD Offset = 0;
+ HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
LPWORD IntVecTable = (LPWORD)((ULONG_PTR)BaseAddress);
@@ -84,6 +131,9 @@
CursorRow = ConsoleInfo.dwCursorPosition.Y;
ConsoleWidth = ConsoleInfo.dwSize.X;
ConsoleHeight = ConsoleInfo.dwSize.Y;
+
+ /* Set the console input mode */
+ SetConsoleMode(ConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);
/* Initialize the PIC */
PicWriteCommand(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
@@ -183,6 +233,56 @@
*(PCHAR)((ULONG_PTR)BaseAddress + i) = LOBYTE(Attribute);
}
}
+}
+
+WORD BiosPeekCharacter()
+{
+ WORD CharacterData;
+
+ /* Check if there is a key available */
+ if (BiosKbdBufferEmpty) return 0xFFFF;
+
+ /* Get the key from the queue, but don't remove it */
+ BiosKbdBufferTop(&CharacterData);
+
+ return CharacterData;
+}
+
+WORD BiosGetCharacter()
+{
+ WORD CharacterData;
+ HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
+ INPUT_RECORD InputRecord;
+ DWORD Count;
+
+ /* Check if there is a key available */
+ if (!BiosKbdBufferEmpty)
+ {
+ /* Get the key from the queue, and remove it */
+ BiosKbdBufferTop(&CharacterData);
+ BiosKbdBufferPop();
+ }
+ else
+ {
+ while (TRUE)
+ {
+ /* Wait for a console event */
+ WaitForSingleObject(ConsoleInput, INFINITE);
+
+ /* Read the event, and make sure it's a keypress */
+ if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
continue;
+ if (InputRecord.EventType != KEY_EVENT) continue;
+ if (!InputRecord.Event.KeyEvent.bKeyDown) continue;
+
+ /* Save the scan code and end the loop */
+ CharacterData = (InputRecord.Event.KeyEvent.wVirtualScanCode << 8)
+ | InputRecord.Event.KeyEvent.uChar.AsciiChar;
+
+ break;
+ }
+ }
+
+ return CharacterData;
}
VOID BiosVideoService()
@@ -270,8 +370,100 @@
}
}
+VOID BiosKeyboardService()
+{
+ DWORD Eax = EmulatorGetRegister(EMULATOR_REG_AX);
+
+ switch (HIBYTE(Eax))
+ {
+ case 0x00:
+ {
+ /* Read the character (and wait if necessary) */
+ EmulatorSetRegister(EMULATOR_REG_AX, BiosGetCharacter());
+
+ break;
+ }
+
+ case 0x01:
+ {
+ WORD Data = BiosPeekCharacter();
+
+ if (Data != 0xFFFF)
+ {
+ /* There is a character, clear ZF and return it */
+ EmulatorSetRegister(EMULATOR_REG_AX, Data);
+ EmulatorClearFlag(EMULATOR_FLAG_ZF);
+ }
+ else
+ {
+ /* No character, set ZF */
+ EmulatorSetFlag(EMULATOR_FLAG_ZF);
+ }
+
+ break;
+ }
+ }
+}
+
VOID BiosHandleIrq(BYTE IrqNumber)
{
+ switch (IrqNumber)
+ {
+ /* PIT IRQ */
+ case 0:
+ {
+ /* Perform the system timer interrupt */
+ EmulatorInterrupt(0x1C);
+
+ break;
+ }
+
+ /* Keyboard IRQ */
+ case 1:
+ {
+ BYTE ScanCode, VirtualKey;
+ WORD Character;
+
+ /* Check if there is a scancode available */
+ if (!(KeyboardReadStatus() & 1)) break;
+
+ /* Get the scan code and virtual key code */
+ ScanCode = KeyboardReadData();
+ VirtualKey = MapVirtualKey(ScanCode, MAPVK_VSC_TO_VK);
+
+ /* Check if this is a key press or release */
+ if (!(ScanCode & (1 << 7)))
+ {
+ /* Key press */
+ if (VirtualKey == VK_NUMLOCK
+ || VirtualKey == VK_CAPITAL
+ || VirtualKey == VK_SCROLL)
+ {
+ /* For toggle keys, toggle the lowest bit in the keyboard map */
+ BiosKeyboardMap[VirtualKey] ^= ~(1 << 0);
+ }
+
+ /* Set the highest bit */
+ BiosKeyboardMap[VirtualKey] |= (1 << 7);
+
+ /* Find out which character this is */
+ ToAscii(ScanCode, VirtualKey, BiosKeyboardMap, &Character, 0);
+
+ /* Push it onto the BIOS keyboard queue */
+ BiosKbdBufferPush((ScanCode << 8) | (Character & 0xFF));
+ }
+ else
+ {
+ /* Key release, unset the highest bit */
+ BiosKeyboardMap[VirtualKey] &= ~(1 << 7);
+ }
+
+ break;
+ }
+ }
+
+ /* Send End-of-Interrupt to the PIC */
+ if (IrqNumber > 8) PicWriteCommand(PIC_SLAVE_CMD, PIC_OCW2_EOI);
PicWriteCommand(PIC_MASTER_CMD, PIC_OCW2_EOI);
}
Modified: branches/ntvdm/subsystems/ntvdm/bios.h
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/bios.h?r…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/bios.h [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/bios.h [iso-8859-1] Fri Jun 28 20:52:40 2013
@@ -23,14 +23,19 @@
#define BIOS_PIC_SLAVE_INT 0x70
#define BIOS_SEGMENT 0xF000
#define VIDEO_BIOS_INTERRUPT 0x10
+#define VIDEO_KBD_INTERRUPT 0x16
#define CONSOLE_FONT_HEIGHT 8
+#define BIOS_KBD_BUFFER_SIZE 256
/* FUNCTIONS ******************************************************************/
BOOLEAN BiosInitialize();
VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress);
VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress);
+WORD BiosPeekCharacter();
+WORD BiosGetCharacter();
VOID BiosVideoService();
+VOID BiosKeyboardService();
VOID BiosHandleIrq(BYTE IrqNumber);
#endif
Modified: branches/ntvdm/subsystems/ntvdm/dos.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/dos.c?re…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/dos.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/dos.c [iso-8859-1] Fri Jun 28 20:52:40 2013
@@ -9,6 +9,7 @@
/* INCLUDES *******************************************************************/
#include "dos.h"
+#include "bios.h"
#include "emulator.h"
/* PRIVATE VARIABLES **********************************************************/
@@ -83,6 +84,14 @@
*DestBuffer = 0;
return DestSegment;
+}
+
+static VOID DosChangeMemoryOwner(WORD Segment, WORD NewOwner)
+{
+ PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment - 1);
+
+ /* Just set the owner */
+ Mcb->OwnerPsp = NewOwner;
}
/* PUBLIC FUNCTIONS ***********************************************************/
@@ -412,6 +421,9 @@
CommandLine, ExeSize + (sizeof(DOS_PSP) >> 4) + i,
EnvBlock);
+ /* The process owns its own memory */
+ DosChangeMemoryOwner(Segment, Segment);
+
/* Copy the program to Segment:0100 */
RtlCopyMemory((PVOID)((ULONG_PTR)BaseAddress
+ TO_LINEAR(Segment, 0x100)),
@@ -548,7 +560,13 @@
CHAR DosReadCharacter()
{
// TODO: STDIN can be redirected under DOS 2.0+
- return _getch();
+ CHAR Character = 0;
+
+ /* A zero value for the character indicates a special key */
+ do Character = BiosGetCharacter();
+ while (!Character);
+
+ return Character;
}
VOID DosPrintCharacter(CHAR Character)
@@ -749,6 +767,15 @@
break;
}
+ /* Get DOS Version */
+ case 0x30:
+ {
+ PDOS_PSP PspBlock = SEGMENT_TO_PSP(CurrentPsp);
+
+ EmulatorSetRegister(EMULATOR_REG_AX, PspBlock->DosVersion);
+ break;
+ }
+
/* Get Interrupt Vector */
case 0x35:
{
@@ -879,6 +906,7 @@
/* Unsupported */
default:
{
+ DPRINT1("DOS Function INT 0x21, AH = 0x%02X NOT IMPLEMENTED!\n",
HIBYTE(Eax));
EmulatorSetFlag(EMULATOR_FLAG_CF);
}
}
Modified: branches/ntvdm/subsystems/ntvdm/dos.h
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/dos.h?re…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/dos.h [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/dos.h [iso-8859-1] Fri Jun 28 20:52:40 2013
@@ -15,7 +15,7 @@
/* DEFINES ********************************************************************/
-#define DOS_VERSION 0x0600
+#define DOS_VERSION MAKEWORD(6, 0)
#define DOS_CONFIG_PATH L"%SystemRoot%\\system32\\CONFIG.NT"
#define DOS_COMMAND_INTERPRETER
L"%SystemRoot%\\system32\\COMMAND.COM /k
%SystemRoot%\\system32\\AUTOEXEC.NT"
#define FIRST_MCB_SEGMENT 0x1000
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] Fri Jun 28 20:52:40 2013
@@ -214,6 +214,12 @@
BiosVideoService();
break;
}
+ case VIDEO_KBD_INTERRUPT:
+ {
+ /* This is the keyboard BIOS interrupt, call the BIOS */
+ BiosKeyboardService();
+ break;
+ }
case 0x20:
{
DosInt20h(CodeSegment);