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?re... ============================================================================== --- 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?re... ============================================================================== --- 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?rev... ============================================================================== --- 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?rev... ============================================================================== --- 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);