[NTVDM]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Thu, 24 Oct 2013 01:01:49 +0000 (01:01 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Thu, 24 Oct 2013 01:01:49 +0000 (01:01 +0000)
Remove the code that performs waiting in 32-bit mode since that blocks the emulator
and prevents interrupts from working.
Implement a 16-bit waiting system in the interrupt handlers.
Fix the PS/2 interrupt code.

svn path=/branches/ntvdm/; revision=60739

subsystems/ntvdm/bios.c
subsystems/ntvdm/dos.c
subsystems/ntvdm/emulator.c
subsystems/ntvdm/emulator.h
subsystems/ntvdm/ps2.c

index 0cb767d..0005b65 100644 (file)
@@ -267,14 +267,14 @@ static LPBYTE VideoModes[] =
 
 static BOOLEAN BiosKbdBufferPush(WORD Data)
 {
-    /* Get the location of the element after the head */
-    WORD NextElement = Bda->KeybdBufferHead + 2;
+    /* Get the location of the element after the tail */
+    WORD NextElement = Bda->KeybdBufferTail + 2;
 
     /* 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->KeybdBufferTail) return FALSE;
+    if (NextElement == Bda->KeybdBufferHead) return FALSE;
 
     /* Put the value in the queue */
     *((LPWORD)((ULONG_PTR)Bda + Bda->KeybdBufferTail)) = Data;
@@ -468,18 +468,33 @@ BOOLEAN BiosInitialize(VOID)
         IntVecTable[i * 2] = Offset;
         IntVecTable[i * 2 + 1] = BIOS_SEGMENT;
 
-        BiosCode[Offset++] = 0xFA; // cli
+        BiosCode[Offset++] = 0xFB; // sti
 
         BiosCode[Offset++] = 0x6A; // push i
         BiosCode[Offset++] = (BYTE)i;
 
+        BiosCode[Offset++] = 0x6A; // push 0
+        BiosCode[Offset++] = 0x00;
+
+        BiosCode[Offset++] = 0xF8; // clc
+
         BiosCode[Offset++] = LOBYTE(EMULATOR_BOP); // BOP sequence
         BiosCode[Offset++] = HIBYTE(EMULATOR_BOP);
         BiosCode[Offset++] = LOBYTE(EMULATOR_INT_BOP);
         BiosCode[Offset++] = HIBYTE(EMULATOR_INT_BOP);
 
-        BiosCode[Offset++] = 0x44; // inc sp
-        BiosCode[Offset++] = 0x44; // inc sp
+        BiosCode[Offset++] = 0x73; // jnc +3
+        BiosCode[Offset++] = 0x03;
+
+        // HACK: The following instruction should be HLT!
+        BiosCode[Offset++] = 0x90; // nop
+
+        BiosCode[Offset++] = 0xEB; // jmp -10
+        BiosCode[Offset++] = 0xF6;
+
+        BiosCode[Offset++] = 0x83; // add sp, 4
+        BiosCode[Offset++] = 0xC4;
+        BiosCode[Offset++] = 0x04;
 
         BiosCode[Offset++] = 0xCF; // iret
     }
@@ -590,9 +605,7 @@ WORD BiosPeekCharacter(VOID)
 
 WORD BiosGetCharacter(VOID)
 {
-    WORD CharacterData;
-    INPUT_RECORD InputRecord;
-    DWORD Count;
+    WORD CharacterData = 0;
 
     /* Check if there is a key available */
     if (Bda->KeybdBufferHead != Bda->KeybdBufferTail)
@@ -603,24 +616,8 @@ WORD BiosGetCharacter(VOID)
     }
     else
     {
-        VgaRefreshDisplay(); // HACK: Waiting here blocks the emulator!!!
-
-        while (TRUE)
-        {
-            /* Wait for a console event */
-            WaitForSingleObject(BiosConsoleInput, INFINITE);
-    
-            /* Read the event, and make sure it's a keypress */
-            if (!ReadConsoleInput(BiosConsoleInput, &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;
-        }
+        /* Set the handler CF to repeat the BOP */
+        EmulatorSetFlag(EMULATOR_FLAG_CF);
     }
 
     return CharacterData;
index 837ae25..c2d863d 100644 (file)
@@ -684,30 +684,17 @@ WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead)
     WORD Result = ERROR_SUCCESS;
     DWORD BytesRead32 = 0;
     HANDLE Handle = DosGetRealHandle(FileHandle);
-    WORD i;
 
     DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
 
     /* Make sure the handle is valid */
     if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
 
-    if (IsConsoleHandle(Handle))
-    {
-        for (i = 0; i < Count; i++)
-        {
-            /* Call the BIOS function to read the character */
-            ((LPBYTE)Buffer)[i] = LOBYTE(BiosGetCharacter());
-            BytesRead32++;
-        }
-    }
-    else
+    /* Read the file */
+    if (!ReadFile(Handle, Buffer, Count, &BytesRead32, NULL))
     {
-        /* Read the file */
-        if (!ReadFile(Handle, Buffer, Count, &BytesRead32, NULL))
-        {
-            /* Store the error code */
-            Result = (WORD)GetLastError();
-        }
+        /* Store the error code */
+        Result = (WORD)GetLastError();
     }
 
     /* The number of bytes read is always 16-bit */
@@ -1283,8 +1270,16 @@ CHAR DosReadCharacter(VOID)
     CHAR Character = '\0';
     WORD BytesRead;
 
-    /* Use the file reading function */
-    DosReadFile(DOS_INPUT_HANDLE, &Character, sizeof(CHAR), &BytesRead);
+    if (IsConsoleHandle(DosGetRealHandle(DOS_INPUT_HANDLE)))
+    {
+        /* Call the BIOS */
+        Character = LOBYTE(BiosGetCharacter());
+    }
+    else
+    {
+        /* Use the file reading function */
+        DosReadFile(DOS_INPUT_HANDLE, &Character, sizeof(CHAR), &BytesRead);
+    }
 
     return Character;
 }
@@ -1381,7 +1376,12 @@ VOID DosInt21h(LPWORD Stack)
         {
             Character = DosReadCharacter();
             DosPrintCharacter(Character);
-            EmulatorSetRegister(EMULATOR_REG_AX, (Eax & 0xFFFFFF00) | Character);
+
+            if (!EmulatorGetFlag(EMULATOR_FLAG_CF))
+            {
+                EmulatorSetRegister(EMULATOR_REG_AX, (Eax & 0xFFFFFF00) | Character);
+            }
+
             break;
         }
 
@@ -1396,8 +1396,13 @@ VOID DosInt21h(LPWORD Stack)
         case 0x07:
         case 0x08:
         {
-            EmulatorSetRegister(EMULATOR_REG_AX,
-                               (Eax & 0xFFFFFF00) | DosReadCharacter());
+            Character = DosReadCharacter();
+
+            if (!EmulatorGetFlag(EMULATOR_FLAG_CF))
+            {
+                EmulatorSetRegister(EMULATOR_REG_AX, (Eax & 0xFFFFFF00) | Character);
+            }
+
             break;
         }
 
@@ -1419,6 +1424,8 @@ VOID DosInt21h(LPWORD Stack)
         /* Read Buffered Input */
         case 0x0A:
         {
+            DPRINT1("FIXME: This function is still not adapted to the new system!\n");
+
             InputBuffer = (PDOS_INPUT_BUFFER)((ULONG_PTR)BaseAddress
                                               + TO_LINEAR(DataSegment,
                                                           LOWORD(Edx)));
@@ -1725,23 +1732,45 @@ VOID DosInt21h(LPWORD Stack)
         /* Read File */
         case 0x3F:
         {
+            WORD Handle = LOWORD(Ebx);
+            LPBYTE Buffer = (LPBYTE)((ULONG_PTR)BaseAddress + TO_LINEAR(DataSegment, LOWORD(Edx)));
+            WORD Count = LOWORD(Ecx);
             WORD BytesRead = 0;
-            WORD ErrorCode = DosReadFile(LOWORD(Ebx),
-                                         (LPVOID)((ULONG_PTR)BaseAddress
-                                         + TO_LINEAR(DataSegment, LOWORD(Edx))),
-                                         LOWORD(Ecx),
-                                         &BytesRead);
+            WORD ErrorCode = ERROR_SUCCESS;
 
-            if (ErrorCode == 0)
+            if (IsConsoleHandle(DosGetRealHandle(Handle)))
             {
-                /* Clear CF */
-                Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+                while (Stack[STACK_COUNTER] < Count)
+                {
+                    /* Read a character from the BIOS */
+                    Buffer[Stack[STACK_COUNTER]] = LOBYTE(BiosGetCharacter()); // FIXME: Security checks!
 
-                /* Return the number of bytes read in AX */
-                EmulatorSetRegister(EMULATOR_REG_AX,
-                                    (Eax & 0xFFFF0000) | BytesRead);
+                    /* Stop if the BOP needs to be repeated */
+                    if (EmulatorGetFlag(EMULATOR_FLAG_CF)) break;
+
+                    /* Increment the counter */
+                    Stack[STACK_COUNTER]++;
+                }
+
+                if (Stack[STACK_COUNTER] < Count) ErrorCode = ERROR_NOT_READY;
+                else BytesRead = Count;
             }
             else
+            {
+                /* Use the file reading function */
+                ErrorCode = DosReadFile(Handle, Buffer, Count, &BytesRead);
+            }
+
+            if (ErrorCode == 0)
+            {
+                    /* Clear CF */
+                    Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+    
+                    /* Return the number of bytes read in AX */
+                    EmulatorSetRegister(EMULATOR_REG_AX,
+                                        (Eax & 0xFFFF0000) | BytesRead);
+            }
+            else if (ErrorCode != ERROR_NOT_READY)
             {
                 /* Set CF */
                 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
index 42d709f..861d260 100644 (file)
@@ -590,9 +590,6 @@ VOID EmulatorStep(VOID)
         /* Skip the opcodes */
         EmulatorContext.state->reg_ip += 4;
 
-        // HACK: Refresh the display because the called function may wait.
-        VgaRefreshDisplay();
-
         /* Call the BOP handler */
         EmulatorBop(Instruction[1]);
     }
index 5b6ec6b..62895c4 100644 (file)
 /* Common definitions */
 #define EMULATOR_BOP 0xC4C4
 #define EMULATOR_INT_BOP 0xBEEF
-#define STACK_INT_NUM 0
-#define STACK_IP 1
-#define STACK_CS 2
-#define STACK_FLAGS 3
+#define STACK_COUNTER 0
+#define STACK_INT_NUM 1
+#define STACK_IP 2
+#define STACK_CS 3
+#define STACK_FLAGS 4
 
 enum
 {
index f5cbef6..276cce7 100644 (file)
@@ -271,6 +271,7 @@ VOID CheckForInputEvents()
     HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
     DWORD i, j, Count, TotalEvents;
     BYTE ScanCode;
+    BOOLEAN Interrupt = FALSE;
 
     /* Get the number of input events */
     if (!GetNumberOfConsoleInputEvents(ConsoleInput, &Count)) return;
@@ -300,13 +301,11 @@ VOID CheckForInputEvents()
             KeyboardQueuePush(ScanCode);
         }
 
-        /* Yes, IRQ 1 */
-        PicInterruptRequest(1);
-
-        /* Stop the loop */
-        break;
+        Interrupt = TRUE;
     }
 
+    if (Interrupt) PicInterruptRequest(1);
+
 Cleanup:
     HeapFree(GetProcessHeap(), 0, Buffer);
 }