diff --git a/subsystems/ntvdm/CMakeLists.txt b/subsystems/ntvdm/CMakeLists.txt index e34e58c3fc7..933d4c19df1 100644 --- a/subsystems/ntvdm/CMakeLists.txt +++ b/subsystems/ntvdm/CMakeLists.txt @@ -7,6 +7,7 @@ spec2def(ntvdm.exe ntvdm.spec) list(APPEND SOURCE bios/bios.c + bios/kbdbios.c bios/vidbios.c hardware/cmos.c hardware/pic.c diff --git a/subsystems/ntvdm/bios/bios.c b/subsystems/ntvdm/bios/bios.c index 9c8039de024..3d133dce598 100644 --- a/subsystems/ntvdm/bios/bios.c +++ b/subsystems/ntvdm/bios/bios.c @@ -14,74 +14,23 @@ #include "bios.h" #include "io.h" +#include "hardware/cmos.h" #include "hardware/pic.h" -#include "hardware/ps2.h" #include "hardware/timer.h" #include "int32.h" -#include "registers.h" /* PRIVATE VARIABLES **********************************************************/ PBIOS_DATA_AREA Bda; -static BYTE BiosKeyboardMap[256]; /* PRIVATE FUNCTIONS **********************************************************/ -static BOOLEAN BiosKbdBufferPush(WORD Data) +static VOID WINAPI BiosException(LPWORD Stack) { - /* Get the location of the element after the tail */ - WORD NextElement = Bda->KeybdBufferTail + sizeof(WORD); - - /* Wrap it around if it's at or beyond the end */ - if (NextElement >= Bda->KeybdBufferEnd) NextElement = Bda->KeybdBufferStart; - - /* If it's full, fail */ - if (NextElement == Bda->KeybdBufferHead) return FALSE; - - /* Put the value in the queue */ - *((LPWORD)((ULONG_PTR)Bda + Bda->KeybdBufferTail)) = Data; - Bda->KeybdBufferTail += sizeof(WORD); - - /* Check if we are at, or have passed, the end of the buffer */ - if (Bda->KeybdBufferTail >= Bda->KeybdBufferEnd) - { - /* Return it to the beginning */ - Bda->KeybdBufferTail = Bda->KeybdBufferStart; - } - - /* Return success */ - return TRUE; -} - -static BOOLEAN BiosKbdBufferTop(LPWORD Data) -{ - /* If it's empty, fail */ - if (Bda->KeybdBufferHead == Bda->KeybdBufferTail) return FALSE; - - /* Otherwise, get the value and return success */ - *Data = *((LPWORD)((ULONG_PTR)Bda + Bda->KeybdBufferHead)); - - return TRUE; -} - -static BOOLEAN BiosKbdBufferPop(VOID) -{ - /* If it's empty, fail */ - if (Bda->KeybdBufferHead == Bda->KeybdBufferTail) return FALSE; - - /* Remove the value from the queue */ - Bda->KeybdBufferHead += sizeof(WORD); - - /* Check if we are at, or have passed, the end of the buffer */ - if (Bda->KeybdBufferHead >= Bda->KeybdBufferEnd) - { - /* Return it to the beginning */ - Bda->KeybdBufferHead = Bda->KeybdBufferStart; - } - - /* Return success */ - return TRUE; + /* Get the exception number and call the emulator API */ + BYTE ExceptionNumber = LOBYTE(Stack[STACK_INT_NUM]); + EmulatorException(ExceptionNumber, Stack); } static VOID WINAPI BiosEquipmentService(LPWORD Stack) @@ -135,8 +84,17 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) /* Get Extended Memory Size */ case 0x88: { - /* Return the number of KB of RAM after 1 MB */ - setAX((MAX_ADDRESS - 0x100000) / 1024); + UCHAR Low, High; + + /* + * Return the (usable) extended memory (after 1 MB) + * size in kB from CMOS. + */ + IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_ACTUAL_EXT_MEMORY_LOW); + Low = IOReadB(CMOS_DATA_PORT); + IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_ACTUAL_EXT_MEMORY_HIGH); + High = IOReadB(CMOS_DATA_PORT); + setAX(MAKEWORD(Low, High)); /* Clear CF */ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; @@ -152,88 +110,6 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) } } -static VOID WINAPI BiosKeyboardService(LPWORD Stack) -{ - switch (getAH()) - { - /* Wait for keystroke and read */ - case 0x00: - /* Wait for extended keystroke and read */ - case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h - { - /* Read the character (and wait if necessary) */ - setAX(BiosGetCharacter()); - break; - } - - /* Get keystroke status */ - case 0x01: - /* Get extended keystroke status */ - case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h - { - WORD Data = BiosPeekCharacter(); - - if (Data != 0xFFFF) - { - /* There is a character, clear ZF and return it */ - Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF; - setAX(Data); - } - else - { - /* No character, set ZF */ - Stack[STACK_FLAGS] |= EMULATOR_FLAG_ZF; - } - - break; - } - - /* Get shift status */ - case 0x02: - { - /* Return the lower byte of the keyboard shift status word */ - setAL(LOBYTE(Bda->KeybdShiftFlags)); - break; - } - - /* Reserved */ - case 0x04: - { - DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n"); - break; - } - - /* Push keystroke */ - case 0x05: - { - /* Return 0 if success, 1 if failure */ - setAL(BiosKbdBufferPush(getCX()) == FALSE); - break; - } - - /* Get extended shift status */ - case 0x12: - { - /* - * Be careful! The returned word is similar to Bda->KeybdShiftFlags - * but the high byte is organized differently: - * the bytes 2 and 3 of the high byte are not the same... - */ - WORD KeybdShiftFlags = (Bda->KeybdShiftFlags & 0xF3FF); - - /* Return the extended keyboard shift status word */ - setAX(KeybdShiftFlags); - break; - } - - default: - { - DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n", - getAH()); - } - } -} - static VOID WINAPI BiosTimeService(LPWORD Stack) { switch (getAH()) @@ -278,206 +154,201 @@ static VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack) Bda->TickCounter++; } -/* PUBLIC FUNCTIONS ***********************************************************/ -WORD BiosPeekCharacter(VOID) +// From SeaBIOS +static VOID PicSetIRQMask(USHORT off, USHORT on) { - WORD CharacterData = 0; - - /* Get the key from the queue, but don't remove it */ - if (BiosKbdBufferTop(&CharacterData)) return CharacterData; - else return 0xFFFF; + UCHAR pic1off = off, pic1on = on, pic2off = off>>8, pic2on = on>>8; + IOWriteB(PIC_MASTER_DATA, (IOReadB(PIC_MASTER_DATA) & ~pic1off) | pic1on); + IOWriteB(PIC_SLAVE_DATA , (IOReadB(PIC_SLAVE_DATA ) & ~pic2off) | pic2on); } -WORD BiosGetCharacter(VOID) +// From SeaBIOS +VOID EnableHwIRQ(UCHAR hwirq, EMULATOR_INT32_PROC func) { - WORD CharacterData = 0; + UCHAR vector; - /* Check if there is a key available */ - if (BiosKbdBufferTop(&CharacterData)) - { - /* A key was available, remove it from the queue */ - BiosKbdBufferPop(); - } + PicSetIRQMask(1 << hwirq, 0); + if (hwirq < 8) + vector = BIOS_PIC_MASTER_INT + hwirq; else - { - /* No key available. Set the handler CF to repeat the BOP */ - setCF(1); - // CharacterData = 0xFFFF; - } + vector = BIOS_PIC_SLAVE_INT + hwirq - 8; - return CharacterData; + RegisterInt32(vector, func); } -BOOLEAN BiosInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput) + +VOID PicIRQComplete(LPWORD Stack) { - /* Initialize the BDA */ - Bda = (PBIOS_DATA_AREA)SEG_OFF_TO_PTR(BDA_SEGMENT, 0); - Bda->EquipmentList = BIOS_EQUIPMENT_LIST; - /* - * Conventional memory size is 640 kB, - * see: http://webpages.charter.net/danrollins/techhelp/0184.HTM - * and see Ralf Brown: http://www.ctyme.com/intr/rb-0598.htm - * for more information. - */ - Bda->MemorySize = 0x0280; - Bda->KeybdBufferStart = FIELD_OFFSET(BIOS_DATA_AREA, KeybdBuffer); - Bda->KeybdBufferEnd = Bda->KeybdBufferStart + BIOS_KBD_BUFFER_SIZE * sizeof(WORD); - Bda->KeybdBufferHead = Bda->KeybdBufferTail = 0; - - /* Initialize the 32-bit Interrupt system */ - InitializeInt32(BIOS_SEGMENT); - - /* Register the BIOS 32-bit Interrupts */ - RegisterInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService ); - RegisterInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize ); - RegisterInt32(BIOS_MISC_INTERRUPT , BiosMiscService ); - RegisterInt32(BIOS_KBD_INTERRUPT , BiosKeyboardService ); - RegisterInt32(BIOS_TIME_INTERRUPT , BiosTimeService ); - RegisterInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt); - - /* Some interrupts are in fact addresses to tables */ - ((PDWORD)BaseAddress)[0x1D] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x1E] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x1F] = (DWORD)NULL; - - ((PDWORD)BaseAddress)[0x41] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x43] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x44] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x46] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x48] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x49] = (DWORD)NULL; - - /* Initialize the Video BIOS */ - if (!VidBiosInitialize(ConsoleOutput)) return FALSE; - - /* Set the console input mode */ - SetConsoleMode(ConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT); - - /* Initialize PS2 */ - PS2Initialize(ConsoleInput); + /* Get the interrupt number */ + BYTE IntNum = LOBYTE(Stack[STACK_INT_NUM]); /* - * The POST (Power On-Self Test) + * If this was a PIC IRQ, send an End-of-Interrupt to the PIC. */ - /* Initialize the master and the slave PICs */ + if (IntNum >= BIOS_PIC_MASTER_INT && IntNum < BIOS_PIC_MASTER_INT + 8) + { + /* It was an IRQ from the master PIC */ + IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI); + } + else if (IntNum >= BIOS_PIC_SLAVE_INT && IntNum < BIOS_PIC_SLAVE_INT + 8) + { + /* It was an IRQ from the slave PIC */ + IOWriteB(PIC_SLAVE_CMD , PIC_OCW2_EOI); + IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI); + } +} + +static VOID WINAPI BiosHandleMasterPicIRQ(LPWORD Stack) +{ + BYTE IrqNumber; + + IOWriteB(PIC_MASTER_CMD, PIC_OCW3_READ_ISR /* == 0x0B */); + IrqNumber = IOReadB(PIC_MASTER_CMD); + + DPRINT1("Master - IrqNumber = 0x%x\n", IrqNumber); + + PicIRQComplete(Stack); +} + +static VOID WINAPI BiosHandleSlavePicIRQ(LPWORD Stack) +{ + BYTE IrqNumber; + + IOWriteB(PIC_SLAVE_CMD, PIC_OCW3_READ_ISR /* == 0x0B */); + IrqNumber = IOReadB(PIC_SLAVE_CMD); + + DPRINT1("Slave - IrqNumber = 0x%x\n", IrqNumber); + + PicIRQComplete(Stack); +} + +// Timer IRQ 0 +static VOID WINAPI BiosTimerIrq(LPWORD Stack) +{ + /* + * Perform the system timer interrupt. + * + * Do not call directly BiosSystemTimerInterrupt(Stack); + * because some programs may hook only BIOS_SYS_TIMER_INTERRUPT + * for their purpose... + */ + EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT); + PicIRQComplete(Stack); +} + + +static VOID BiosHwSetup(VOID) +{ + /* Initialize the master and the slave PICs (cascade mode) */ IOWriteB(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4); IOWriteB(PIC_SLAVE_CMD , PIC_ICW1 | PIC_ICW1_ICW4); - /* Set the interrupt offsets */ + /* + * Set the interrupt vector offsets for each PIC + * (base IRQs: 0x08-0x0F for IRQ 0-7, 0x70-0x77 for IRQ 8-15) + */ IOWriteB(PIC_MASTER_DATA, BIOS_PIC_MASTER_INT); IOWriteB(PIC_SLAVE_DATA , BIOS_PIC_SLAVE_INT ); - /* Tell the master PIC there is a slave at IRQ 2 */ + /* Tell the master PIC that there is a slave PIC at IRQ 2 */ IOWriteB(PIC_MASTER_DATA, 1 << 2); + /* Tell the slave PIC its cascade identity */ IOWriteB(PIC_SLAVE_DATA , 2); /* Make sure both PICs are in 8086 mode */ - IOWriteB(PIC_MASTER_DATA, PIC_ICW4_8086 /* | PIC_ICW4_AEOI */); + IOWriteB(PIC_MASTER_DATA, PIC_ICW4_8086); IOWriteB(PIC_SLAVE_DATA , PIC_ICW4_8086); /* Clear the masks for both PICs */ - IOWriteB(PIC_MASTER_DATA, 0x00); - IOWriteB(PIC_SLAVE_DATA , 0x00); + // IOWriteB(PIC_MASTER_DATA, 0x00); + // IOWriteB(PIC_SLAVE_DATA , 0x00); + /* Disable all IRQs */ + IOWriteB(PIC_MASTER_DATA, 0xFF); + IOWriteB(PIC_SLAVE_DATA , 0xFF); + /* Initialize the PIT */ IOWriteB(PIT_COMMAND_PORT, 0x34); IOWriteB(PIT_DATA_PORT(0), 0x00); IOWriteB(PIT_DATA_PORT(0), 0x00); + EnableHwIRQ(0, BiosTimerIrq); +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +/* + * The BIOS POST (Power On-Self Test) + */ +BOOLEAN BiosInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput) +{ + UCHAR Low, High; + UCHAR i; + + /* Initialize the BDA */ + Bda = (PBIOS_DATA_AREA)SEG_OFF_TO_PTR(BDA_SEGMENT, 0); + Bda->EquipmentList = BIOS_EQUIPMENT_LIST; + + /* + * Retrieve the conventional memory size + * in kB from CMOS, typically 640 kB. + */ + IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_LOW); + Low = IOReadB(CMOS_DATA_PORT); + IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_HIGH); + High = IOReadB(CMOS_DATA_PORT); + Bda->MemorySize = MAKEWORD(Low, High); + + /* Initialize the 32-bit Interrupt system */ + InitializeInt32(BIOS_SEGMENT); + + /* Register the BIOS 32-bit Interrupts */ + + /* Initialize the exception vector interrupts to a default Exception handler */ + for (i = 0; i < 8; i++) + RegisterInt32(i, BiosException); + + /* Initialize HW vector interrupts to a default HW handler */ + for (i = BIOS_PIC_MASTER_INT; i < BIOS_PIC_MASTER_INT + 8; i++) + RegisterInt32(i, BiosHandleMasterPicIRQ); + for (i = BIOS_PIC_SLAVE_INT ; i < BIOS_PIC_SLAVE_INT + 8; i++) + RegisterInt32(i, BiosHandleSlavePicIRQ); + + /* Initialize software vector handlers */ + RegisterInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService ); + RegisterInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize ); + RegisterInt32(BIOS_MISC_INTERRUPT , BiosMiscService ); + RegisterInt32(BIOS_TIME_INTERRUPT , BiosTimeService ); + RegisterInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt); + + /* Some interrupts are in fact addresses to tables */ + ((PDWORD)BaseAddress)[0x1E] = (DWORD)NULL; + ((PDWORD)BaseAddress)[0x41] = (DWORD)NULL; + ((PDWORD)BaseAddress)[0x46] = (DWORD)NULL; + ((PDWORD)BaseAddress)[0x48] = (DWORD)NULL; + ((PDWORD)BaseAddress)[0x49] = (DWORD)NULL; + + /* Initialize platform hardware (PIC/PIT chips, ...) */ + BiosHwSetup(); + + /* Initialize the Keyboard BIOS */ + if (!KbdBiosInitialize(ConsoleInput)) return FALSE; + + /* Set the console input mode */ + SetConsoleMode(ConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT); + + /* Initialize the Video BIOS */ + if (!VidBiosInitialize(ConsoleOutput)) return FALSE; + return TRUE; } VOID BiosCleanup(VOID) { - PS2Cleanup(); VidBiosCleanup(); -} - -VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack) -{ - switch (IrqNumber) - { - /* PIT IRQ */ - case 0: - { - /* Perform the system timer interrupt */ - EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT); - break; - } - - /* Keyboard IRQ */ - case 1: - { - BYTE ScanCode, VirtualKey; - WORD Character; - - /* Get the scan code and virtual key code */ - ScanCode = IOReadB(PS2_DATA_PORT); - VirtualKey = MapVirtualKey(ScanCode & 0x7F, 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 || - VirtualKey == VK_INSERT) - { - /* 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 */ - Character = 0; - if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) == 0) - { - /* Not ASCII */ - Character = 0; - } - - /* Push it onto the BIOS keyboard queue */ - BiosKbdBufferPush(MAKEWORD(Character, ScanCode)); - } - else - { - /* Key release, unset the highest bit */ - BiosKeyboardMap[VirtualKey] &= ~(1 << 7); - } - - /* Clear the keyboard flags */ - Bda->KeybdShiftFlags = 0; - - /* Set the appropriate flags based on the state */ - if (BiosKeyboardMap[VK_RSHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_RSHIFT; - if (BiosKeyboardMap[VK_LSHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LSHIFT; - if (BiosKeyboardMap[VK_CONTROL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CTRL; - if (BiosKeyboardMap[VK_MENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_ALT; - if (BiosKeyboardMap[VK_SCROLL] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SCROLL_ON; - if (BiosKeyboardMap[VK_NUMLOCK] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_NUMLOCK_ON; - if (BiosKeyboardMap[VK_CAPITAL] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CAPSLOCK_ON; - if (BiosKeyboardMap[VK_INSERT] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_INSERT_ON; - if (BiosKeyboardMap[VK_RMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_RALT; - if (BiosKeyboardMap[VK_LMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LALT; - if (BiosKeyboardMap[VK_SNAPSHOT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SYSRQ; - if (BiosKeyboardMap[VK_PAUSE] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_PAUSE; - if (BiosKeyboardMap[VK_SCROLL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SCROLL; - if (BiosKeyboardMap[VK_NUMLOCK] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_NUMLOCK; - if (BiosKeyboardMap[VK_CAPITAL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CAPSLOCK; - if (BiosKeyboardMap[VK_INSERT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_INSERT; - - break; - } - } - - /* Send End-of-Interrupt to the PIC */ - if (IrqNumber >= 8) IOWriteB(PIC_SLAVE_CMD, PIC_OCW2_EOI); - IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI); + KbdBiosCleanup(); } /* EOF */ diff --git a/subsystems/ntvdm/bios/bios.h b/subsystems/ntvdm/bios/bios.h index 7daf0062e8a..cd0df097f2d 100644 --- a/subsystems/ntvdm/bios/bios.h +++ b/subsystems/ntvdm/bios/bios.h @@ -12,6 +12,7 @@ /* INCLUDES *******************************************************************/ #include "ntvdm.h" +#include "kbdbios.h" #include "vidbios.h" /* DEFINES ********************************************************************/ @@ -28,29 +29,10 @@ #define BIOS_EQUIPMENT_INTERRUPT 0x11 #define BIOS_MEMORY_SIZE 0x12 #define BIOS_MISC_INTERRUPT 0x15 -#define BIOS_KBD_INTERRUPT 0x16 #define BIOS_TIME_INTERRUPT 0x1A #define BIOS_SYS_TIMER_INTERRUPT 0x1C -#define BIOS_KBD_BUFFER_SIZE 16 -#define BIOS_EQUIPMENT_LIST 0x2C // HACK: Disable FPU for now - -#define BDA_KBDFLAG_RSHIFT (1 << 0) -#define BDA_KBDFLAG_LSHIFT (1 << 1) -#define BDA_KBDFLAG_CTRL (1 << 2) -#define BDA_KBDFLAG_ALT (1 << 3) -#define BDA_KBDFLAG_SCROLL_ON (1 << 4) -#define BDA_KBDFLAG_NUMLOCK_ON (1 << 5) -#define BDA_KBDFLAG_CAPSLOCK_ON (1 << 6) -#define BDA_KBDFLAG_INSERT_ON (1 << 7) -#define BDA_KBDFLAG_RALT (1 << 8) -#define BDA_KBDFLAG_LALT (1 << 9) -#define BDA_KBDFLAG_SYSRQ (1 << 10) -#define BDA_KBDFLAG_PAUSE (1 << 11) -#define BDA_KBDFLAG_SCROLL (1 << 12) -#define BDA_KBDFLAG_NUMLOCK (1 << 13) -#define BDA_KBDFLAG_CAPSLOCK (1 << 14) -#define BDA_KBDFLAG_INSERT (1 << 15) +#define BIOS_EQUIPMENT_LIST 0x2C // HACK: Disable FPU for now /* * BIOS Data Area at 0040:XXXX @@ -134,12 +116,13 @@ C_ASSERT(sizeof(BIOS_DATA_AREA) == 0x133); extern PBIOS_DATA_AREA Bda; -WORD BiosPeekCharacter(VOID); -WORD BiosGetCharacter(VOID); +/**HACK!!**/typedef VOID (WINAPI *EMULATOR_INT32_PROC)(LPWORD Stack);/**HACK!!**/ + +VOID EnableHwIRQ(UCHAR hwirq, EMULATOR_INT32_PROC func); +VOID PicIRQComplete(LPWORD Stack); BOOLEAN BiosInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput); VOID BiosCleanup(VOID); -VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack); #endif // _BIOS_H_ diff --git a/subsystems/ntvdm/bios/kbdbios.c b/subsystems/ntvdm/bios/kbdbios.c new file mode 100644 index 00000000000..e1049b98c83 --- /dev/null +++ b/subsystems/ntvdm/bios/kbdbios.c @@ -0,0 +1,290 @@ +/* + * COPYRIGHT: GPL - See COPYING in the top level directory + * PROJECT: ReactOS Virtual DOS Machine + * FILE: kbdbios.c + * PURPOSE: VDM Keyboard BIOS + * PROGRAMMERS: Aleksandar Andrejevic + */ + +/* INCLUDES *******************************************************************/ + +#define NDEBUG + +#include "emulator.h" +// #include "kbdbios.h" +#include "bios.h" + +#include "io.h" +#include "hardware/ps2.h" + +#include "int32.h" + +/* PRIVATE VARIABLES **********************************************************/ + +static BYTE BiosKeyboardMap[256]; + +/* PRIVATE FUNCTIONS **********************************************************/ + +static BOOLEAN BiosKbdBufferPush(WORD Data) +{ + /* Get the location of the element after the tail */ + WORD NextElement = Bda->KeybdBufferTail + sizeof(WORD); + + /* Wrap it around if it's at or beyond the end */ + if (NextElement >= Bda->KeybdBufferEnd) NextElement = Bda->KeybdBufferStart; + + /* If it's full, fail */ + if (NextElement == Bda->KeybdBufferHead) return FALSE; + + /* Put the value in the queue */ + *((LPWORD)((ULONG_PTR)Bda + Bda->KeybdBufferTail)) = Data; + Bda->KeybdBufferTail += sizeof(WORD); + + /* Check if we are at, or have passed, the end of the buffer */ + if (Bda->KeybdBufferTail >= Bda->KeybdBufferEnd) + { + /* Return it to the beginning */ + Bda->KeybdBufferTail = Bda->KeybdBufferStart; + } + + /* Return success */ + return TRUE; +} + +static BOOLEAN BiosKbdBufferTop(LPWORD Data) +{ + /* If it's empty, fail */ + if (Bda->KeybdBufferHead == Bda->KeybdBufferTail) return FALSE; + + /* Otherwise, get the value and return success */ + *Data = *((LPWORD)((ULONG_PTR)Bda + Bda->KeybdBufferHead)); + + return TRUE; +} + +static BOOLEAN BiosKbdBufferPop(VOID) +{ + /* If it's empty, fail */ + if (Bda->KeybdBufferHead == Bda->KeybdBufferTail) return FALSE; + + /* Remove the value from the queue */ + Bda->KeybdBufferHead += sizeof(WORD); + + /* Check if we are at, or have passed, the end of the buffer */ + if (Bda->KeybdBufferHead >= Bda->KeybdBufferEnd) + { + /* Return it to the beginning */ + Bda->KeybdBufferHead = Bda->KeybdBufferStart; + } + + /* Return success */ + return TRUE; +} + +WORD BiosPeekCharacter(VOID) +{ + WORD CharacterData = 0; + + /* Get the key from the queue, but don't remove it */ + if (BiosKbdBufferTop(&CharacterData)) return CharacterData; + else return 0xFFFF; +} + +WORD BiosGetCharacter(VOID) +{ + WORD CharacterData = 0; + + /* Check if there is a key available */ + if (BiosKbdBufferTop(&CharacterData)) + { + /* A key was available, remove it from the queue */ + BiosKbdBufferPop(); + } + else + { + /* No key available. Set the handler CF to repeat the BOP */ + setCF(1); + // CharacterData = 0xFFFF; + } + + return CharacterData; +} + +static VOID WINAPI BiosKeyboardService(LPWORD Stack) +{ + switch (getAH()) + { + /* Wait for keystroke and read */ + case 0x00: + /* Wait for extended keystroke and read */ + case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h + { + /* Read the character (and wait if necessary) */ + setAX(BiosGetCharacter()); + break; + } + + /* Get keystroke status */ + case 0x01: + /* Get extended keystroke status */ + case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h + { + WORD Data = BiosPeekCharacter(); + + if (Data != 0xFFFF) + { + /* There is a character, clear ZF and return it */ + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF; + setAX(Data); + } + else + { + /* No character, set ZF */ + Stack[STACK_FLAGS] |= EMULATOR_FLAG_ZF; + } + + break; + } + + /* Get shift status */ + case 0x02: + { + /* Return the lower byte of the keyboard shift status word */ + setAL(LOBYTE(Bda->KeybdShiftFlags)); + break; + } + + /* Reserved */ + case 0x04: + { + DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n"); + break; + } + + /* Push keystroke */ + case 0x05: + { + /* Return 0 if success, 1 if failure */ + setAL(BiosKbdBufferPush(getCX()) == FALSE); + break; + } + + /* Get extended shift status */ + case 0x12: + { + /* + * Be careful! The returned word is similar to Bda->KeybdShiftFlags + * but the high byte is organized differently: + * the bytes 2 and 3 of the high byte are not the same... + */ + WORD KeybdShiftFlags = (Bda->KeybdShiftFlags & 0xF3FF); + + /* Return the extended keyboard shift status word */ + setAX(KeybdShiftFlags); + break; + } + + default: + { + DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n", + getAH()); + } + } +} + +// Keyboard IRQ 1 +static VOID WINAPI BiosKeyboardIrq(LPWORD Stack) +{ + BYTE ScanCode, VirtualKey; + WORD Character; + + /* Get the scan code and virtual key code */ + ScanCode = IOReadB(PS2_DATA_PORT); + VirtualKey = MapVirtualKey(ScanCode & 0x7F, 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 || + VirtualKey == VK_INSERT) + { + /* 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 */ + Character = 0; + if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) == 0) + { + /* Not ASCII */ + Character = 0; + } + + /* Push it onto the BIOS keyboard queue */ + BiosKbdBufferPush(MAKEWORD(Character, ScanCode)); + } + else + { + /* Key release, unset the highest bit */ + BiosKeyboardMap[VirtualKey] &= ~(1 << 7); + } + + /* Clear the keyboard flags */ + Bda->KeybdShiftFlags = 0; + + /* Set the appropriate flags based on the state */ + if (BiosKeyboardMap[VK_RSHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_RSHIFT; + if (BiosKeyboardMap[VK_LSHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LSHIFT; + if (BiosKeyboardMap[VK_CONTROL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CTRL; + if (BiosKeyboardMap[VK_MENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_ALT; + if (BiosKeyboardMap[VK_SCROLL] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SCROLL_ON; + if (BiosKeyboardMap[VK_NUMLOCK] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_NUMLOCK_ON; + if (BiosKeyboardMap[VK_CAPITAL] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CAPSLOCK_ON; + if (BiosKeyboardMap[VK_INSERT] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_INSERT_ON; + if (BiosKeyboardMap[VK_RMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_RALT; + if (BiosKeyboardMap[VK_LMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LALT; + if (BiosKeyboardMap[VK_SNAPSHOT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SYSRQ; + if (BiosKeyboardMap[VK_PAUSE] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_PAUSE; + if (BiosKeyboardMap[VK_SCROLL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SCROLL; + if (BiosKeyboardMap[VK_NUMLOCK] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_NUMLOCK; + if (BiosKeyboardMap[VK_CAPITAL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CAPSLOCK; + if (BiosKeyboardMap[VK_INSERT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_INSERT; + + PicIRQComplete(Stack); +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +BOOLEAN KbdBiosInitialize(HANDLE ConsoleInput) +{ + /* Initialize the BDA */ + Bda->KeybdBufferStart = FIELD_OFFSET(BIOS_DATA_AREA, KeybdBuffer); + Bda->KeybdBufferEnd = Bda->KeybdBufferStart + BIOS_KBD_BUFFER_SIZE * sizeof(WORD); + Bda->KeybdBufferHead = Bda->KeybdBufferTail = 0; + + /* Register the BIOS 32-bit Interrupts */ + + /* Initialize software vector handlers */ + RegisterInt32(BIOS_KBD_INTERRUPT, BiosKeyboardService); + + /* Set up the HW vector interrupts */ + EnableHwIRQ(1, BiosKeyboardIrq); + // EnableHwIRQ(12, BiosMouseIrq); + + /* Set the console input mode */ + // SetConsoleMode(ConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT); + + return TRUE; +} + +VOID KbdBiosCleanup(VOID) +{ +} + +/* EOF */ diff --git a/subsystems/ntvdm/bios/kbdbios.h b/subsystems/ntvdm/bios/kbdbios.h new file mode 100644 index 00000000000..efa53c899c0 --- /dev/null +++ b/subsystems/ntvdm/bios/kbdbios.h @@ -0,0 +1,49 @@ +/* + * COPYRIGHT: GPL - See COPYING in the top level directory + * PROJECT: ReactOS Virtual DOS Machine + * FILE: kbdbios.h + * PURPOSE: VDM Keyboard BIOS + * PROGRAMMERS: Aleksandar Andrejevic + */ + +#ifndef _KBDBIOS_H_ +#define _KBDBIOS_H_ + +/* INCLUDES *******************************************************************/ + +#include "ntvdm.h" + +/* DEFINES ********************************************************************/ + +#define BIOS_KBD_INTERRUPT 0x16 + +#define BIOS_KBD_BUFFER_SIZE 16 + +#define BDA_KBDFLAG_RSHIFT (1 << 0) +#define BDA_KBDFLAG_LSHIFT (1 << 1) +#define BDA_KBDFLAG_CTRL (1 << 2) +#define BDA_KBDFLAG_ALT (1 << 3) +#define BDA_KBDFLAG_SCROLL_ON (1 << 4) +#define BDA_KBDFLAG_NUMLOCK_ON (1 << 5) +#define BDA_KBDFLAG_CAPSLOCK_ON (1 << 6) +#define BDA_KBDFLAG_INSERT_ON (1 << 7) +#define BDA_KBDFLAG_RALT (1 << 8) +#define BDA_KBDFLAG_LALT (1 << 9) +#define BDA_KBDFLAG_SYSRQ (1 << 10) +#define BDA_KBDFLAG_PAUSE (1 << 11) +#define BDA_KBDFLAG_SCROLL (1 << 12) +#define BDA_KBDFLAG_NUMLOCK (1 << 13) +#define BDA_KBDFLAG_CAPSLOCK (1 << 14) +#define BDA_KBDFLAG_INSERT (1 << 15) + +/* FUNCTIONS ******************************************************************/ + +WORD BiosPeekCharacter(VOID); +WORD BiosGetCharacter(VOID); + +BOOLEAN KbdBiosInitialize(HANDLE ConsoleInput); +VOID KbdBiosCleanup(VOID); + +#endif // _KBDBIOS_H_ + +/* EOF */ diff --git a/subsystems/ntvdm/bios/vidbios.c b/subsystems/ntvdm/bios/vidbios.c index 8d0d1a897fe..4bc86b3d54b 100644 --- a/subsystems/ntvdm/bios/vidbios.c +++ b/subsystems/ntvdm/bios/vidbios.c @@ -18,7 +18,6 @@ #include "hardware/vga.h" #include "int32.h" -#include "registers.h" /* MACROS *********************************************************************/ @@ -32,8 +31,6 @@ /* PRIVATE VARIABLES **********************************************************/ -static HANDLE VidBiosConsoleOutput = INVALID_HANDLE_VALUE; - /* * VGA Register Configurations for BIOS Video Modes * The configurations come from DOSBox. @@ -1537,8 +1534,6 @@ static VOID WINAPI VidBiosVideoService(LPWORD Stack) BOOLEAN VidBiosInitialize(HANDLE ConsoleOutput) { - CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; - /* Some interrupts are in fact addresses to tables */ ((PDWORD)BaseAddress)[0x1D] = (DWORD)NULL; ((PDWORD)BaseAddress)[0x1F] = (DWORD)NULL; @@ -1546,25 +1541,24 @@ BOOLEAN VidBiosInitialize(HANDLE ConsoleOutput) ((PDWORD)BaseAddress)[0x43] = (DWORD)NULL; ((PDWORD)BaseAddress)[0x44] = (DWORD)NULL; - /* Save the default BIOS console output handle for cleanup */ - if (ConsoleOutput == INVALID_HANDLE_VALUE) return FALSE; - VidBiosConsoleOutput = ConsoleOutput; - - /* Initialize VGA */ - if (!VgaInitialize(ConsoleOutput)) return FALSE; - /* Set the default video mode */ VidBiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE); - GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo); + /* Set some screen properties if the console output handle is valid */ + if (ConsoleOutput != INVALID_HANDLE_VALUE) + { + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; - /* Copy console data into VGA memory */ - VidBiosCopyTextConsoleToVgaMemory(ConsoleOutput, &ConsoleInfo.dwSize); + GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo); - /* Update the cursor position for the current page */ - VidBiosSetCursorPosition(ConsoleInfo.dwCursorPosition.Y, - ConsoleInfo.dwCursorPosition.X, - Bda->VideoPage); + /* Copy console data into VGA memory */ + VidBiosCopyTextConsoleToVgaMemory(ConsoleOutput, &ConsoleInfo.dwSize); + + /* Update the cursor position for the current page */ + VidBiosSetCursorPosition(ConsoleInfo.dwCursorPosition.Y, + ConsoleInfo.dwCursorPosition.X, + Bda->VideoPage); + } /* Register the BIOS 32-bit Interrupts */ RegisterInt32(BIOS_VIDEO_INTERRUPT, VidBiosVideoService); @@ -1574,8 +1568,6 @@ BOOLEAN VidBiosInitialize(HANDLE ConsoleOutput) VOID VidBiosCleanup(VOID) { - /* Restore the old screen buffer */ - SetConsoleActiveScreenBuffer(VidBiosConsoleOutput); } /* EOF */ diff --git a/subsystems/ntvdm/emulator.c b/subsystems/ntvdm/emulator.c index 3ac58862ad4..c8b2c1366f7 100644 --- a/subsystems/ntvdm/emulator.c +++ b/subsystems/ntvdm/emulator.c @@ -15,6 +15,7 @@ #include "bios/bios.h" #include "hardware/cmos.h" #include "hardware/pic.h" +#include "hardware/ps2.h" #include "hardware/speaker.h" #include "hardware/timer.h" #include "hardware/vga.h" @@ -22,7 +23,6 @@ #include "bop.h" #include "vddsup.h" #include "io.h" -#include "registers.h" /* PRIVATE VARIABLES **********************************************************/ @@ -32,6 +32,18 @@ BOOLEAN VdmRunning = TRUE; static BOOLEAN A20Line = FALSE; +LPCWSTR ExceptionName[] = +{ + L"Division By Zero", + L"Debug", + L"Unexpected Error", + L"Breakpoint", + L"Integer Overflow", + L"Bound Range Exceeded", + L"Invalid Opcode", + L"FPU Not Available" +}; + /* BOP Identifiers */ #define BOP_DEBUGGER 0x56 // Break into the debugger from a 16-bit app @@ -115,7 +127,7 @@ VOID WINAPI EmulatorDebugBreak(LPWORD Stack) /* PUBLIC FUNCTIONS ***********************************************************/ -BOOLEAN EmulatorInitialize(VOID) +BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput) { /* Allocate memory for the 16-bit address space */ BaseAddress = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_ADDRESS); @@ -148,6 +160,16 @@ BOOLEAN EmulatorInitialize(VOID) CmosInitialize(); SpeakerInitialize(); + /* Initialize the PS2 port */ + PS2Initialize(ConsoleInput); + + /* Set the console input mode */ + // SetConsoleMode(ConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT); + + /* Initialize the VGA */ + // if (!VgaInitialize(ConsoleOutput)) return FALSE; + VgaInitialize(ConsoleOutput); + /* Register the DebugBreak BOP */ RegisterBop(BOP_DEBUGGER, EmulatorDebugBreak); @@ -159,6 +181,9 @@ BOOLEAN EmulatorInitialize(VOID) VOID EmulatorCleanup(VOID) { + // VgaCleanup(); + PS2Cleanup(); + SpeakerCleanup(); CmosCleanup(); // PitCleanup(); @@ -170,6 +195,40 @@ VOID EmulatorCleanup(VOID) if (BaseAddress != NULL) HeapFree(GetProcessHeap(), 0, BaseAddress); } +VOID EmulatorException(BYTE ExceptionNumber, LPWORD Stack) +{ + WORD CodeSegment, InstructionPointer; + PBYTE Opcode; + + ASSERT(ExceptionNumber < 8); + + /* Get the CS:IP */ + InstructionPointer = Stack[STACK_IP]; + CodeSegment = Stack[STACK_CS]; + Opcode = (PBYTE)SEG_OFF_TO_PTR(CodeSegment, InstructionPointer); + + /* Display a message to the user */ + DisplayMessage(L"Exception: %s occured at %04X:%04X\n" + L"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", + ExceptionName[ExceptionNumber], + CodeSegment, + InstructionPointer, + Opcode[0], + Opcode[1], + Opcode[2], + Opcode[3], + Opcode[4], + Opcode[5], + Opcode[6], + Opcode[7], + Opcode[8], + Opcode[9]); + + /* Stop the VDM */ + VdmRunning = FALSE; + return; +} + // FIXME: This function assumes 16-bit mode!!! VOID EmulatorExecute(WORD Segment, WORD Offset) { diff --git a/subsystems/ntvdm/emulator.h b/subsystems/ntvdm/emulator.h index 6ce20c743e1..3e25b5f39d2 100644 --- a/subsystems/ntvdm/emulator.h +++ b/subsystems/ntvdm/emulator.h @@ -105,7 +105,9 @@ UCHAR WINAPI EmulatorIntAcknowledge PFAST486_STATE State ); -BOOLEAN EmulatorInitialize(VOID); +VOID EmulatorException(BYTE ExceptionNumber, LPWORD Stack); + +BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput); VOID EmulatorExecute(WORD Segment, WORD Offset); VOID EmulatorInterrupt(BYTE Number); VOID EmulatorInterruptSignal(VOID); diff --git a/subsystems/ntvdm/hardware/cmos.c b/subsystems/ntvdm/hardware/cmos.c index ee268c940d5..3bf34b530fa 100644 --- a/subsystems/ntvdm/hardware/cmos.c +++ b/subsystems/ntvdm/hardware/cmos.c @@ -12,8 +12,8 @@ #include "emulator.h" #include "cmos.h" + #include "io.h" -#include "bios/bios.h" #include "pic.h" /* PRIVATE VARIABLES **********************************************************/ @@ -138,18 +138,6 @@ BYTE CmosReadData(VOID) return Value; } - case CMOS_REG_BASE_MEMORY_LOW: - return Bda->MemorySize & 0xFF; - - case CMOS_REG_BASE_MEMORY_HIGH: - return Bda->MemorySize >> 8; - - case CMOS_REG_EXT_MEMORY_LOW: - return ((MAX_ADDRESS - 0x100000) / 1024) & 0xFF; - - case CMOS_REG_EXT_MEMORY_HIGH: - return ((MAX_ADDRESS - 0x100000) / 1024) >> 8; - case CMOS_REG_STATUS_A: case CMOS_REG_STATUS_B: case CMOS_REG_STATUS_D: @@ -295,6 +283,26 @@ VOID CmosWriteData(BYTE Value) // Status registers C and D are read-only break; + /* Is the following correct? */ + case CMOS_REG_EXT_MEMORY_LOW: + case CMOS_REG_ACTUAL_EXT_MEMORY_LOW: + { + /* Sync EMS and UMS */ + CmosMemory.Regs[CMOS_REG_EXT_MEMORY_LOW] = + CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_LOW] = Value; + break; + } + + /* Is the following correct? */ + case CMOS_REG_EXT_MEMORY_HIGH: + case CMOS_REG_ACTUAL_EXT_MEMORY_HIGH: + { + /* Sync EMS and UMS */ + CmosMemory.Regs[CMOS_REG_EXT_MEMORY_HIGH] = + CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_HIGH] = Value; + break; + } + default: { CmosMemory.Regs[SelectedRegister] = Value; @@ -309,6 +317,7 @@ VOID CmosWriteData(BYTE Value) BYTE WINAPI CmosReadPort(ULONG Port) { + ASSERT(Port == CMOS_DATA_PORT); return CmosReadData(); } @@ -430,6 +439,23 @@ VOID CmosInitialize(VOID) CmosMemory.Diagnostics = 0x00; // Diagnostics must not find any errors. CmosMemory.ShutdownStatus = 0x00; + /* Memory settings */ + + /* + * Conventional memory size is 640 kB, + * see: http://webpages.charter.net/danrollins/techhelp/0184.HTM + * and see Ralf Brown: http://www.ctyme.com/intr/rb-0598.htm + * for more information. + */ + CmosMemory.Regs[CMOS_REG_BASE_MEMORY_LOW ] = LOBYTE(0x0280); + CmosMemory.Regs[CMOS_REG_BASE_MEMORY_HIGH] = HIBYTE(0x0280); + + CmosMemory.Regs[CMOS_REG_EXT_MEMORY_LOW] = + CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_LOW] = LOBYTE((MAX_ADDRESS - 0x100000) / 1024); + + CmosMemory.Regs[CMOS_REG_EXT_MEMORY_HIGH] = + CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_HIGH] = HIBYTE((MAX_ADDRESS - 0x100000) / 1024); + /* Register the I/O Ports */ RegisterIoPort(CMOS_ADDRESS_PORT, NULL , CmosWritePort); RegisterIoPort(CMOS_DATA_PORT , CmosReadPort, CmosWritePort); diff --git a/subsystems/ntvdm/hardware/cmos.h b/subsystems/ntvdm/hardware/cmos.h index 0736951f88c..f84d27ccc28 100644 --- a/subsystems/ntvdm/hardware/cmos.h +++ b/subsystems/ntvdm/hardware/cmos.h @@ -63,11 +63,13 @@ typedef enum _CMOS_REGISTERS CMOS_REG_STATUS_D, CMOS_REG_DIAGNOSTICS, CMOS_REG_SHUTDOWN_STATUS, - CMOS_REG_BASE_MEMORY_LOW = 0x15, - CMOS_REG_BASE_MEMORY_HIGH = 0x16, - CMOS_REG_EXT_MEMORY_LOW = 0x17, - CMOS_REG_EXT_MEMORY_HIGH = 0x18, - CMOS_REG_MAX = 0x40 + CMOS_REG_BASE_MEMORY_LOW = 0x15, + CMOS_REG_BASE_MEMORY_HIGH = 0x16, + CMOS_REG_EXT_MEMORY_LOW = 0x17, + CMOS_REG_EXT_MEMORY_HIGH = 0x18, + CMOS_REG_ACTUAL_EXT_MEMORY_LOW = 0x30, + CMOS_REG_ACTUAL_EXT_MEMORY_HIGH = 0x31, + CMOS_REG_MAX = 0x40 } CMOS_REGISTERS, *PCMOS_REGISTERS; /* diff --git a/subsystems/ntvdm/hardware/vga.c b/subsystems/ntvdm/hardware/vga.c index 265f577b1ed..2d51f3c391f 100644 --- a/subsystems/ntvdm/hardware/vga.c +++ b/subsystems/ntvdm/hardware/vga.c @@ -14,7 +14,6 @@ #include "vga.h" #include "io.h" -#include "bios/bios.h" /* PRIVATE VARIABLES **********************************************************/ diff --git a/subsystems/ntvdm/int32.c b/subsystems/ntvdm/int32.c index 6e2dfcdab31..d61625148a8 100644 --- a/subsystems/ntvdm/int32.c +++ b/subsystems/ntvdm/int32.c @@ -15,23 +15,9 @@ #include "int32.h" #include "bop.h" -#include "bios/bios.h" -#include "registers.h" /* PRIVATE VARIABLES **********************************************************/ -LPCWSTR ExceptionName[] = -{ - L"Division By Zero", - L"Debug", - L"Unexpected Error", - L"Breakpoint", - L"Integer Overflow", - L"Bound Range Exceeded", - L"Invalid Opcode", - L"FPU Not Available" -}; - /* * This is the list of registered 32-bit Interrupt handlers. */ @@ -46,86 +32,10 @@ EMULATOR_INT32_PROC Int32Proc[EMULATOR_MAX_INT32_NUM] = { NULL }; /* PUBLIC FUNCTIONS ***********************************************************/ -VOID WINAPI Exception(BYTE ExceptionNumber, LPWORD Stack) -{ - WORD CodeSegment, InstructionPointer; - PBYTE Opcode; - - ASSERT(ExceptionNumber < 8); - - /* Get the CS:IP */ - InstructionPointer = Stack[STACK_IP]; - CodeSegment = Stack[STACK_CS]; - Opcode = (PBYTE)SEG_OFF_TO_PTR(CodeSegment, InstructionPointer); - - /* Display a message to the user */ - DisplayMessage(L"Exception: %s occured at %04X:%04X\n" - L"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", - ExceptionName[ExceptionNumber], - CodeSegment, - InstructionPointer, - Opcode[0], - Opcode[1], - Opcode[2], - Opcode[3], - Opcode[4], - Opcode[5], - Opcode[6], - Opcode[7], - Opcode[8], - Opcode[9]); - - /* Stop the VDM */ - VdmRunning = FALSE; - return; -} - -#if 0 -VOID WINAPI IrqDispatch(BYTE IrqNumber, LPWORD Stack) -{ - /* Check if this was an PIC IRQ */ - if (IntNum >= BIOS_PIC_MASTER_INT && IntNum < BIOS_PIC_MASTER_INT + 8) - { - /* It was an IRQ from the master PIC */ - BiosHandleIrq(IntNum - BIOS_PIC_MASTER_INT, Stack); - } - else if (IntNum >= BIOS_PIC_SLAVE_INT && IntNum < BIOS_PIC_SLAVE_INT + 8) - { - /* It was an IRQ from the slave PIC */ - BiosHandleIrq(IntNum - BIOS_PIC_SLAVE_INT + 8, Stack); - } - - return; -} -#endif - VOID WINAPI Int32Dispatch(LPWORD Stack) { - BYTE IntNum; - /* Get the interrupt number */ - IntNum = LOBYTE(Stack[STACK_INT_NUM]); - - /* Check if this was an exception */ - if (IntNum < 8) - { - Exception(IntNum, Stack); - return; - } - - /* Check if this was an PIC IRQ */ - if (IntNum >= BIOS_PIC_MASTER_INT && IntNum < BIOS_PIC_MASTER_INT + 8) - { - /* It was an IRQ from the master PIC */ - BiosHandleIrq(IntNum - BIOS_PIC_MASTER_INT, Stack); - return; - } - else if (IntNum >= BIOS_PIC_SLAVE_INT && IntNum < BIOS_PIC_SLAVE_INT + 8) - { - /* It was an IRQ from the slave PIC */ - BiosHandleIrq(IntNum - BIOS_PIC_SLAVE_INT + 8, Stack); - return; - } + BYTE IntNum = LOBYTE(Stack[STACK_INT_NUM]); /* Call the 32-bit Interrupt handler */ if (Int32Proc[IntNum] != NULL) diff --git a/subsystems/ntvdm/ntvdm.c b/subsystems/ntvdm/ntvdm.c index 235eaa9332c..a4d14e5c89b 100644 --- a/subsystems/ntvdm/ntvdm.c +++ b/subsystems/ntvdm/ntvdm.c @@ -55,7 +55,7 @@ BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType) case CTRL_C_EVENT: case CTRL_BREAK_EVENT: { - /* Perform interrupt 0x23 */ + /* Call INT 23h */ EmulatorInterrupt(0x23); break; } @@ -202,7 +202,7 @@ INT wmain(INT argc, WCHAR *argv[]) } /* Initialize the emulator */ - if (!EmulatorInitialize()) + if (!EmulatorInitialize(ConsoleInput, ConsoleOutput)) { wprintf(L"FATAL: Failed to initialize the emulator\n"); goto Cleanup;