// // Fake Keyboard rom support // // This file provides interrim support for keyboard rom bios services. // It is only intended for use until Insignia produces proper rom support // for NTVDM // // Note: portions of this code were lifted from the following source. /* x86 v1.0 * * XBIOSKBD.C * Guest ROM BIOS keyboard emulation * * History * Created 20-Oct-90 by Jeff Parsons * * COPYRIGHT NOTICE * This source file may not be distributed, modified or incorporated into * another product without prior approval from the author, Jeff Parsons. * This file may be copied to designated servers and machines authorized to * access those servers, but that does not imply any form of approval. */ #include #include #include #include #include "softpc.h" #include "bop.h" #include "xbios.h" #include "xbioskbd.h" #include "xwincon.h" #include "fun.h" #include extern HANDLE InputHandle; #define MAX_KBD_BUFFER 256 CHAR KbdBuffer[MAX_KBD_BUFFER]; ULONG Head=0,Tail=0; HANDLE KbdSyncEvent; CRITICAL_SECTION csKbd; CRITICAL_SECTION csConsole; CRITICAL_SECTION csCtrlc; BOOL fEventThreadBlock = FALSE; HANDLE hConsoleWait; ULONG nCtrlc=0; HANDLE StdIn; static BYTE ServiceRoutine[] = { 0xC4, 0xC4, BOP_KBD, 0x50, 0x55, 0x8B, 0xEC, 0x9C, 0x58, 0x89, 0x46, 0x08, 0x5d, 0x58, 0xCF }; #define SERVICE_LENGTH sizeof(ServiceRoutine) /* BiosKbdInit - Initialize ROM BIOS keyboard support * * ENTRY * argc - # of command-line options * argv - pointer to first option pointer * ServiceAddress - linear address to put service routine at * * EXIT * TRUE if successful, FALSE if not */ BOOL BiosKbdInit(int argc, char *argv[], PVOID *ServiceAddress) { PVOID Address; argc, argv; memcpy(*ServiceAddress, ServiceRoutine, SERVICE_LENGTH); Address = (PVOID)(BIOSINT_KBD * 4); *((PWORD)Address) = RMOFF(*ServiceAddress); *(((PWORD)Address) + 1) = RMSEG(*ServiceAddress); (PCHAR)*ServiceAddress += SERVICE_LENGTH; StdIn = GetStdHandle(STD_INPUT_HANDLE); KbdSyncEvent = CreateEvent( NULL, TRUE, FALSE,NULL ); InitializeCriticalSection (&csKbd); InitializeCriticalSection(&csConsole); InitializeCriticalSection(&csCtrlc); hConsoleWait = CreateEvent (NULL,TRUE,FALSE,NULL); return TRUE; } /* BiosKbd - Emulate ROM BIOS keyboard functions * * ENTRY * None (x86 registers contain parameters) * * EXIT * None (x86 registers/memory updated appropriately) * * This function receives control on INT 16h, routes control to the * appropriate subfunction based on the function # in AH, and * then simulates an IRET and returns back to the instruction emulator. */ VOID BiosKbdReadLoop (VOID) { ULONG Temp; while (1) { Temp = Head + 1; if(Temp >= MAX_KBD_BUFFER) Temp =0; if(Temp == Tail){ Sleep (20); continue; } KbdBuffer[Head] = getche(); EnterCriticalSection(&csConsole); if(fEventThreadBlock == TRUE){ LeaveCriticalSection(&csConsole); WaitForSingleObject(hConsoleWait,-1); ResetEvent(hConsoleWait); continue; } else{ LeaveCriticalSection(&csConsole); } EnterCriticalSection(&csKbd); Head = Temp; LeaveCriticalSection(&csKbd); SetEvent(KbdSyncEvent); } } BOOL tkbhit(VOID) { if (Tail != Head || nCtrlc) return TRUE; return FALSE; } CHAR tgetch(VOID) { CHAR ch; while(TRUE) { EnterCriticalSection(&csCtrlc); if (nCtrlc){ nCtrlc--; LeaveCriticalSection(&csCtrlc); return (CHAR)0x3; // return ctrlc } LeaveCriticalSection(&csCtrlc); if (Tail != Head) { EnterCriticalSection(&csKbd); ch = KbdBuffer[Tail++]; if (Tail >= MAX_KBD_BUFFER) Tail = 0; LeaveCriticalSection(&csKbd); return ch; } WaitForSingleObject(KbdSyncEvent, -1); ResetEvent(KbdSyncEvent); } } VOID BiosKbd() { static ULONG ulch; DWORD nRead=0; switch(getAH()) { case KBDFUNC_READCHAR: if (ulch) { setAL(ulch & 0xff); setAH(ulch & 0xFF00); ulch = 0; } else { setAH(0); // zero scan code field for now setAL((BYTE)tgetch()); if (getAL() == 0 || getAL() == 0xE0) { setAL(0); setAH((BYTE)tgetch()); } } break; case KBDFUNC_PEEKCHAR: setZF(1); if (ulch) { setAL(ulch & 0xFF); setAH(ulch & 0xFF00); setZF(0); } else if(tkbhit()) { setAH(0); // zero scan code field for now setAL((BYTE)tgetch()); if (getAL() == 0 || getAL() == 0xE0) { setAL(0); setAH((BYTE)tgetch()); } ulch = getAL() | getAH()<<8 | 0x10000; setZF(0); } break; } } void nt_block_event_thread(void) { INPUT_RECORD InputRecord; DWORD nRecordsWritten; InputRecord.EventType = 1; InputRecord.Event.KeyEvent.bKeyDown = 1; InputRecord.Event.KeyEvent.wRepeatCount = 1; InputRecord.Event.KeyEvent.wVirtualKeyCode = 32; InputRecord.Event.KeyEvent.wVirtualScanCode = 41; InputRecord.Event.KeyEvent.uChar.AsciiChar = ' '; InputRecord.Event.KeyEvent.dwControlKeyState = 32; EnterCriticalSection(&csConsole); WriteConsoleInput(InputHandle,&InputRecord,1,&nRecordsWritten); InputRecord.EventType = 1; InputRecord.Event.KeyEvent.bKeyDown = 0; InputRecord.Event.KeyEvent.wRepeatCount = 1; InputRecord.Event.KeyEvent.wVirtualKeyCode = 32; InputRecord.Event.KeyEvent.wVirtualScanCode = 41; InputRecord.Event.KeyEvent.uChar.AsciiChar = ' '; InputRecord.Event.KeyEvent.dwControlKeyState = 32; WriteConsoleInput(InputHandle,&InputRecord,1,&nRecordsWritten); fEventThreadBlock = TRUE; LeaveCriticalSection(&csConsole); return; } void nt_resume_event_thread(void) { fEventThreadBlock = FALSE; SetEvent (hConsoleWait); return; } // TEMP Till we have proper multitasking in WOW extern BOOL VDMForWOW; extern ULONG iWOWTaskId; VOID VDMCtrlCHandler(ULONG ulCtrlType) { // DebugBreak(); if(ulCtrlType == SYSTEM_ROOT_CONSOLE_EVENT) { if(VDMForWOW) // Kill everything for WOW VDM ExitVDM(VDMForWOW,(ULONG)-1); else ExitVDM(FALSE,0); ExitProcess(0); return; } EnterCriticalSection(&csCtrlc); nCtrlc++; LeaveCriticalSection(&csCtrlc); SetEvent(KbdSyncEvent); }