4 * Copyright 2002 Jukka Heinonen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/debug.h"
27 #include "wine/winbase16.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(int);
32 WINE_DECLARE_DEBUG_CHANNEL(relay
);
34 #define BCD_TO_BIN(x) ((x&15) + (x>>4)*10)
35 #define BIN_TO_BCD(x) ((x%10) + ((x/10)<<4))
37 static void WINAPI
DOSVM_Int11Handler(CONTEXT86
*);
38 static void WINAPI
DOSVM_Int12Handler(CONTEXT86
*);
39 static void WINAPI
DOSVM_Int17Handler(CONTEXT86
*);
40 static void WINAPI
DOSVM_Int19Handler(CONTEXT86
*);
41 static void WINAPI
DOSVM_Int1aHandler(CONTEXT86
*);
42 static void WINAPI
DOSVM_Int20Handler(CONTEXT86
*);
43 static void WINAPI
DOSVM_Int29Handler(CONTEXT86
*);
44 static void WINAPI
DOSVM_Int2aHandler(CONTEXT86
*);
45 static void WINAPI
DOSVM_Int41Handler(CONTEXT86
*);
46 static void WINAPI
DOSVM_Int4bHandler(CONTEXT86
*);
47 static void WINAPI
DOSVM_Int5cHandler(CONTEXT86
*);
48 static void WINAPI
DOSVM_DefaultHandler(CONTEXT86
*);
50 static FARPROC16 DOSVM_Vectors16
[256];
51 static FARPROC48 DOSVM_Vectors48
[256];
52 static const INTPROC DOSVM_VectorsBuiltin
[] =
56 /* 08 */ DOSVM_Int08Handler
, DOSVM_Int09Handler
, 0, 0,
58 /* 10 */ DOSVM_Int10Handler
, DOSVM_Int11Handler
, DOSVM_Int12Handler
, DOSVM_Int13Handler
,
59 /* 14 */ 0, DOSVM_Int15Handler
, DOSVM_Int16Handler
, DOSVM_Int17Handler
,
60 /* 18 */ 0, DOSVM_Int19Handler
, DOSVM_Int1aHandler
, 0,
62 /* 20 */ DOSVM_Int20Handler
, DOSVM_Int21Handler
, 0, 0,
63 /* 24 */ 0, DOSVM_Int25Handler
, DOSVM_Int26Handler
, 0,
64 /* 28 */ 0, DOSVM_Int29Handler
, DOSVM_Int2aHandler
, 0,
65 /* 2C */ 0, 0, 0, DOSVM_Int2fHandler
,
66 /* 30 */ 0, DOSVM_Int31Handler
, 0, DOSVM_Int33Handler
,
67 /* 34 */ DOSVM_Int34Handler
, DOSVM_Int35Handler
, DOSVM_Int36Handler
, DOSVM_Int37Handler
,
68 /* 38 */ DOSVM_Int38Handler
, DOSVM_Int39Handler
, DOSVM_Int3aHandler
, DOSVM_Int3bHandler
,
69 /* 3C */ DOSVM_Int3cHandler
, DOSVM_Int3dHandler
, DOSVM_Int3eHandler
, 0,
70 /* 40 */ 0, DOSVM_Int41Handler
, 0, 0,
72 /* 48 */ 0, 0, 0, DOSVM_Int4bHandler
,
77 /* 5C */ DOSVM_Int5cHandler
, 0, 0, 0,
79 /* 64 */ 0, 0, 0, DOSVM_Int67Handler
,
80 /* 68 */ DOSVM_DefaultHandler
85 * Sizes of real mode and protected mode interrupt stubs.
87 #define DOSVM_STUB_RM 4
88 #define DOSVM_STUB_PM16 5
89 #define DOSVM_STUB_PM48 6
92 /**********************************************************************
95 * Return pointer to real mode interrupt vector. These are not at fixed
96 * location because those Win16 programs that do not use any real mode
97 * code have protected NULL pointer catching block at low linear memory
98 * and interrupt vectors have been moved to another location.
100 static FARPROC16
* DOSVM_GetRMVector( BYTE intnum
)
105 proc
= GetProcAddress16( GetModuleHandle16( "KERNEL" ),
106 (LPCSTR
)(ULONG_PTR
)183 );
107 wine_ldt_get_entry( LOWORD(proc
), &entry
);
109 return (FARPROC16
*)wine_ldt_get_base( &entry
) + intnum
;
113 /**********************************************************************
116 * Return TRUE if interrupt is an IRQ.
118 static BOOL
DOSVM_IsIRQ( BYTE intnum
)
120 if (intnum
>= 0x08 && intnum
<= 0x0f)
123 if (intnum
>= 0x70 && intnum
<= 0x77)
130 /**********************************************************************
131 * DOSVM_DefaultHandler
133 * Default interrupt handler. This will be used to emulate all
134 * interrupts that don't have their own interrupt handler.
136 static void WINAPI
DOSVM_DefaultHandler( CONTEXT86
*context
)
141 /**********************************************************************
142 * DOSVM_GetBuiltinHandler
144 * Return Wine interrupt handler procedure for a given interrupt.
146 static INTPROC
DOSVM_GetBuiltinHandler( BYTE intnum
)
148 if (intnum
< sizeof(DOSVM_VectorsBuiltin
)/sizeof(INTPROC
)) {
149 INTPROC proc
= DOSVM_VectorsBuiltin
[intnum
];
154 WARN("int%x not implemented, returning dummy handler\n", intnum
);
156 if (DOSVM_IsIRQ(intnum
))
157 return DOSVM_AcknowledgeIRQ
;
159 return DOSVM_DefaultHandler
;
163 /**********************************************************************
166 * Simple DOSRELAY that interprets its argument as INTPROC and calls it.
168 static void DOSVM_IntProcRelay( CONTEXT86
*context
, LPVOID data
)
170 INTPROC proc
= (INTPROC
)data
;
175 /**********************************************************************
179 static void DOSVM_PrepareIRQ( CONTEXT86
*context
, BOOL isbuiltin
)
181 /* Disable virtual interrupts. */
182 NtCurrentTeb()->dpmi_vif
= 0;
186 DWORD
*stack
= CTX_SEG_OFF_TO_LIN(context
,
190 /* Push return address to stack. */
191 *(--stack
) = context
->SegCs
;
192 *(--stack
) = context
->Eip
;
195 /* Jump to enable interrupts stub. */
196 context
->SegCs
= DOSVM_dpmi_segments
->relay_code_sel
;
202 /**********************************************************************
205 * This routine is used to make default int25 and int26 handlers leave the
206 * original eflags into stack. In order to do this, stack is manipulated
207 * so that it actually contains two copies of eflags, one of which is
208 * popped during return from interrupt handler.
210 static void DOSVM_PushFlags( CONTEXT86
*context
, BOOL islong
, BOOL isstub
)
214 DWORD
*stack
= CTX_SEG_OFF_TO_LIN(context
,
217 context
->Esp
+= -4; /* One item will be added to stack. */
223 stack
+= 2; /* Pop ip and cs. */
224 *(--stack
) = context
->EFlags
;
229 *(--stack
) = context
->EFlags
;
233 WORD
*stack
= CTX_SEG_OFF_TO_LIN(context
,
236 ADD_LOWORD( context
->Esp
, -2 ); /* One item will be added to stack. */
242 stack
+= 2; /* Pop ip and cs. */
243 *(--stack
) = LOWORD(context
->EFlags
);
248 *(--stack
) = LOWORD(context
->EFlags
);
253 /**********************************************************************
254 * DOSVM_EmulateInterruptPM
256 * Emulate software interrupt in 16-bit or 32-bit protected mode.
257 * Called from signal handler when intXX opcode is executed.
259 * Pushes interrupt frame to stack and changes instruction
260 * pointer to interrupt handler.
262 BOOL WINAPI
DOSVM_EmulateInterruptPM( CONTEXT86
*context
, BYTE intnum
)
264 TRACE_(relay
)("Call DOS int 0x%02x ret=%04x:%08x\n"
265 " eax=%08x ebx=%08x ecx=%08x edx=%08x\n"
266 " esi=%08x edi=%08x ebp=%08x esp=%08x \n"
267 " ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x\n",
268 intnum
, context
->SegCs
, context
->Eip
,
269 context
->Eax
, context
->Ebx
, context
->Ecx
, context
->Edx
,
270 context
->Esi
, context
->Edi
, context
->Ebp
, context
->Esp
,
271 context
->SegDs
, context
->SegEs
, context
->SegFs
, context
->SegGs
,
272 context
->SegSs
, context
->EFlags
);
274 if (context
->SegCs
== DOSVM_dpmi_segments
->dpmi_sel
)
276 DOSVM_BuildCallFrame( context
,
278 DOSVM_RawModeSwitchHandler
);
280 else if (context
->SegCs
== DOSVM_dpmi_segments
->relay_code_sel
)
283 * This must not be called using DOSVM_BuildCallFrame.
285 DOSVM_RelayHandler( context
);
287 else if (context
->SegCs
== DOSVM_dpmi_segments
->int48_sel
)
289 /* Restore original flags stored into the stack by the caller. */
290 DWORD
*stack
= CTX_SEG_OFF_TO_LIN(context
,
291 context
->SegSs
, context
->Esp
);
292 context
->EFlags
= stack
[2];
294 if (intnum
!= context
->Eip
/ DOSVM_STUB_PM48
)
295 WARN( "interrupt stub has been modified "
296 "(interrupt is %02x, interrupt stub is %02x)\n",
297 intnum
, context
->Eip
/DOSVM_STUB_PM48
);
299 TRACE( "builtin interrupt %02x has been branched to\n", intnum
);
301 if (intnum
== 0x25 || intnum
== 0x26)
302 DOSVM_PushFlags( context
, TRUE
, TRUE
);
304 DOSVM_BuildCallFrame( context
,
306 DOSVM_GetBuiltinHandler(intnum
) );
308 else if (context
->SegCs
== DOSVM_dpmi_segments
->int16_sel
)
310 /* Restore original flags stored into the stack by the caller. */
311 WORD
*stack
= CTX_SEG_OFF_TO_LIN(context
,
312 context
->SegSs
, context
->Esp
);
313 context
->EFlags
= (DWORD
)MAKELONG( stack
[2], HIWORD(context
->EFlags
) );
315 if (intnum
!= context
->Eip
/ DOSVM_STUB_PM16
)
316 WARN( "interrupt stub has been modified "
317 "(interrupt is %02x, interrupt stub is %02x)\n",
318 intnum
, context
->Eip
/DOSVM_STUB_PM16
);
320 TRACE( "builtin interrupt %02x has been branched to\n", intnum
);
322 if (intnum
== 0x25 || intnum
== 0x26)
323 DOSVM_PushFlags( context
, FALSE
, TRUE
);
325 DOSVM_BuildCallFrame( context
,
327 DOSVM_GetBuiltinHandler(intnum
) );
329 else if (wine_ldt_is_system(context
->SegCs
))
332 if (intnum
>= sizeof(DOSVM_VectorsBuiltin
)/sizeof(INTPROC
)) return FALSE
;
333 if (!(proc
= DOSVM_VectorsBuiltin
[intnum
])) return FALSE
;
338 DOSVM_HardwareInterruptPM( context
, intnum
);
344 /**********************************************************************
345 * DOSVM_HardwareInterruptPM
347 * Emulate call to interrupt handler in 16-bit or 32-bit protected mode.
349 * Pushes interrupt frame to stack and changes instruction
350 * pointer to interrupt handler.
352 void DOSVM_HardwareInterruptPM( CONTEXT86
*context
, BYTE intnum
)
356 FARPROC48 addr
= DOSVM_GetPMHandler48( intnum
);
358 if (addr
.selector
== DOSVM_dpmi_segments
->int48_sel
)
360 TRACE( "builtin interrupt %02x has been invoked "
361 "(through vector %02x)\n",
362 addr
.offset
/ DOSVM_STUB_PM48
, intnum
);
364 if (intnum
== 0x25 || intnum
== 0x26)
365 DOSVM_PushFlags( context
, TRUE
, FALSE
);
366 else if (DOSVM_IsIRQ(intnum
))
367 DOSVM_PrepareIRQ( context
, TRUE
);
369 DOSVM_BuildCallFrame( context
,
371 DOSVM_GetBuiltinHandler(
372 addr
.offset
/DOSVM_STUB_PM48
) );
378 TRACE( "invoking hooked interrupt %02x at %04x:%08x\n",
379 intnum
, addr
.selector
, addr
.offset
);
381 if (DOSVM_IsIRQ(intnum
))
382 DOSVM_PrepareIRQ( context
, FALSE
);
384 /* Push the flags and return address on the stack */
385 stack
= CTX_SEG_OFF_TO_LIN(context
, context
->SegSs
, context
->Esp
);
386 *(--stack
) = context
->EFlags
;
387 *(--stack
) = context
->SegCs
;
388 *(--stack
) = context
->Eip
;
391 /* Jump to the interrupt handler */
392 context
->SegCs
= addr
.selector
;
393 context
->Eip
= addr
.offset
;
398 FARPROC16 addr
= DOSVM_GetPMHandler16( intnum
);
400 if (SELECTOROF(addr
) == DOSVM_dpmi_segments
->int16_sel
)
402 TRACE( "builtin interrupt %02x has been invoked "
403 "(through vector %02x)\n",
404 OFFSETOF(addr
)/DOSVM_STUB_PM16
, intnum
);
406 if (intnum
== 0x25 || intnum
== 0x26)
407 DOSVM_PushFlags( context
, FALSE
, FALSE
);
408 else if (DOSVM_IsIRQ(intnum
))
409 DOSVM_PrepareIRQ( context
, TRUE
);
411 DOSVM_BuildCallFrame( context
,
413 DOSVM_GetBuiltinHandler(
414 OFFSETOF(addr
)/DOSVM_STUB_PM16
) );
418 TRACE( "invoking hooked interrupt %02x at %04x:%04x\n",
419 intnum
, SELECTOROF(addr
), OFFSETOF(addr
) );
421 if (DOSVM_IsIRQ(intnum
))
422 DOSVM_PrepareIRQ( context
, FALSE
);
424 /* Push the flags and return address on the stack */
425 PUSH_WORD16( context
, LOWORD(context
->EFlags
) );
426 PUSH_WORD16( context
, context
->SegCs
);
427 PUSH_WORD16( context
, LOWORD(context
->Eip
) );
429 /* Jump to the interrupt handler */
430 context
->SegCs
= HIWORD(addr
);
431 context
->Eip
= LOWORD(addr
);
437 /**********************************************************************
438 * DOSVM_EmulateInterruptRM
440 * Emulate software interrupt in real mode.
441 * Called from VM86 emulation when intXX opcode is executed.
443 * Either calls directly builtin handler or pushes interrupt frame to
444 * stack and changes instruction pointer to interrupt handler.
446 * Returns FALSE if this interrupt was caused by return
447 * from real mode wrapper.
449 BOOL WINAPI
DOSVM_EmulateInterruptRM( CONTEXT86
*context
, BYTE intnum
)
451 TRACE_(relay
)("Call DOS int 0x%02x ret=%04x:%08x\n"
452 " eax=%08x ebx=%08x ecx=%08x edx=%08x\n"
453 " esi=%08x edi=%08x ebp=%08x esp=%08x \n"
454 " ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x\n",
455 intnum
, context
->SegCs
, context
->Eip
,
456 context
->Eax
, context
->Ebx
, context
->Ecx
, context
->Edx
,
457 context
->Esi
, context
->Edi
, context
->Ebp
, context
->Esp
,
458 context
->SegDs
, context
->SegEs
, context
->SegFs
, context
->SegGs
,
459 context
->SegSs
, context
->EFlags
);
461 /* check for our real-mode hooks */
464 /* is this exit from real-mode wrapper */
465 if (context
->SegCs
== DOSVM_dpmi_segments
->wrap_seg
)
468 if (DOSVM_CheckWrappers( context
))
472 /* check if the call is from our fake BIOS interrupt stubs */
473 if (context
->SegCs
==0xf000)
475 /* Restore original flags stored into the stack by the caller. */
476 WORD
*stack
= CTX_SEG_OFF_TO_LIN(context
,
477 context
->SegSs
, context
->Esp
);
478 context
->EFlags
= (DWORD
)MAKELONG( stack
[2], HIWORD(context
->EFlags
) );
480 if (intnum
!= context
->Eip
/ DOSVM_STUB_RM
)
481 WARN( "interrupt stub has been modified "
482 "(interrupt is %02x, interrupt stub is %02x)\n",
483 intnum
, context
->Eip
/DOSVM_STUB_RM
);
485 TRACE( "builtin interrupt %02x has been branched to\n", intnum
);
487 DOSVM_CallBuiltinHandler( context
, intnum
);
489 /* Real mode stubs use IRET so we must put flags back into stack. */
490 stack
[2] = LOWORD(context
->EFlags
);
494 DOSVM_HardwareInterruptRM( context
, intnum
);
501 /**********************************************************************
502 * DOSVM_HardwareInterruptRM
504 * Emulate call to interrupt handler in real mode.
506 * Either calls directly builtin handler or pushes interrupt frame to
507 * stack and changes instruction pointer to interrupt handler.
509 void DOSVM_HardwareInterruptRM( CONTEXT86
*context
, BYTE intnum
)
511 FARPROC16 handler
= DOSVM_GetRMHandler( intnum
);
513 /* check if the call goes to an unhooked interrupt */
514 if (SELECTOROF(handler
) == 0xf000)
516 /* if so, call it directly */
517 TRACE( "builtin interrupt %02x has been invoked "
518 "(through vector %02x)\n",
519 OFFSETOF(handler
)/DOSVM_STUB_RM
, intnum
);
520 DOSVM_CallBuiltinHandler( context
, OFFSETOF(handler
)/DOSVM_STUB_RM
);
524 /* the interrupt is hooked, simulate interrupt in DOS space */
525 WORD flag
= LOWORD( context
->EFlags
);
527 TRACE( "invoking hooked interrupt %02x at %04x:%04x\n",
528 intnum
, SELECTOROF(handler
), OFFSETOF(handler
) );
530 /* Copy virtual interrupt flag to pushed interrupt flag. */
531 if (context
->EFlags
& VIF_MASK
)
536 PUSH_WORD16( context
, flag
);
537 PUSH_WORD16( context
, context
->SegCs
);
538 PUSH_WORD16( context
, LOWORD( context
->Eip
));
540 context
->SegCs
= SELECTOROF( handler
);
541 context
->Eip
= OFFSETOF( handler
);
543 /* Clear virtual interrupt flag and trap flag. */
544 context
->EFlags
&= ~(VIF_MASK
| TF_MASK
);
549 /**********************************************************************
552 * Return the real mode interrupt vector for a given interrupt.
554 FARPROC16
DOSVM_GetRMHandler( BYTE intnum
)
556 return *DOSVM_GetRMVector( intnum
);
560 /**********************************************************************
563 * Set the real mode interrupt handler for a given interrupt.
565 void DOSVM_SetRMHandler( BYTE intnum
, FARPROC16 handler
)
567 TRACE("Set real mode interrupt vector %02x <- %04x:%04x\n",
568 intnum
, HIWORD(handler
), LOWORD(handler
) );
569 *DOSVM_GetRMVector( intnum
) = handler
;
573 /**********************************************************************
574 * DOSVM_GetPMHandler16
576 * Return the protected mode interrupt vector for a given interrupt.
578 FARPROC16
DOSVM_GetPMHandler16( BYTE intnum
)
583 pTask
= GlobalLock16(GetCurrentTask());
613 if (!DOSVM_Vectors16
[intnum
])
615 proc
= (FARPROC16
)MAKESEGPTR( DOSVM_dpmi_segments
->int16_sel
,
616 DOSVM_STUB_PM16
* intnum
);
617 DOSVM_Vectors16
[intnum
] = proc
;
619 return DOSVM_Vectors16
[intnum
];
623 /**********************************************************************
624 * DOSVM_SetPMHandler16
626 * Set the protected mode interrupt handler for a given interrupt.
628 void DOSVM_SetPMHandler16( BYTE intnum
, FARPROC16 handler
)
632 TRACE("Set protected mode interrupt vector %02x <- %04x:%04x\n",
633 intnum
, HIWORD(handler
), LOWORD(handler
) );
635 pTask
= GlobalLock16(GetCurrentTask());
641 pTask
->int0
= handler
;
644 pTask
->int2
= handler
;
647 pTask
->int4
= handler
;
650 pTask
->int6
= handler
;
653 pTask
->int7
= handler
;
656 pTask
->int3e
= handler
;
659 pTask
->int75
= handler
;
662 DOSVM_Vectors16
[intnum
] = handler
;
668 /**********************************************************************
669 * DOSVM_GetPMHandler48
671 * Return the protected mode interrupt vector for a given interrupt.
672 * Used to get 48-bit pointer for 32-bit interrupt handlers in DPMI32.
674 FARPROC48
DOSVM_GetPMHandler48( BYTE intnum
)
676 if (!DOSVM_Vectors48
[intnum
].selector
)
678 DOSVM_Vectors48
[intnum
].selector
= DOSVM_dpmi_segments
->int48_sel
;
679 DOSVM_Vectors48
[intnum
].offset
= DOSVM_STUB_PM48
* intnum
;
681 return DOSVM_Vectors48
[intnum
];
685 /**********************************************************************
686 * DOSVM_SetPMHandler48
688 * Set the protected mode interrupt handler for a given interrupt.
689 * Used to set 48-bit pointer for 32-bit interrupt handlers in DPMI32.
691 void DOSVM_SetPMHandler48( BYTE intnum
, FARPROC48 handler
)
693 TRACE("Set 32-bit protected mode interrupt vector %02x <- %04x:%08x\n",
694 intnum
, handler
.selector
, handler
.offset
);
695 DOSVM_Vectors48
[intnum
] = handler
;
699 /**********************************************************************
700 * DOSVM_CallBuiltinHandler
702 * Execute Wine interrupt handler procedure.
704 void WINAPI
DOSVM_CallBuiltinHandler( CONTEXT86
*context
, BYTE intnum
)
707 * FIXME: Make all builtin interrupt calls go via this routine.
708 * FIXME: Check for PM->RM interrupt reflection.
709 * FIXME: Check for RM->PM interrupt reflection.
712 INTPROC proc
= DOSVM_GetBuiltinHandler( intnum
);
717 /**********************************************************************
720 * Handler for int 11h (get equipment list).
723 * Borrowed from Ralph Brown's interrupt lists:
725 * bits 15-14: number of parallel devices
726 * bit 13: [Conv] Internal modem
728 * bits 11- 9: number of serial devices
730 * bits 7- 6: number of diskette drives minus one
731 * bits 5- 4: Initial video mode:
733 * 01b = 40 x 25 color
734 * 10b = 80 x 25 color
737 * bit 2: [PS] =1 if pointing device
739 * bit 1: =1 if math co-processor
740 * bit 0: =1 if diskette available for boot
743 * Currently the only of these bits correctly set are:
745 * bits 15-14 } Added by William Owen Smith,
746 * bits 11-9 } wos@dcs.warwick.ac.uk
748 * bit 2 (always set) ( bit 2 = 4 )
749 * bit 1 } Robert 'Admiral' Coeyman
750 * All *nix systems either have a math processor or
753 static void WINAPI
DOSVM_Int11Handler( CONTEXT86
*context
)
756 int parallelports
= 0;
760 if (GetDriveTypeA("A:\\") == DRIVE_REMOVABLE
) diskdrives
++;
761 if (GetDriveTypeA("B:\\") == DRIVE_REMOVABLE
) diskdrives
++;
762 if (diskdrives
) diskdrives
--;
764 for (x
=0; x
< 9; x
++)
769 /* serial port name */
770 sprintf( file
, "\\\\.\\COM%d", x
+1 );
771 handle
= CreateFileA( file
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, 0 );
772 if (handle
!= INVALID_HANDLE_VALUE
)
774 CloseHandle( handle
);
778 sprintf( file
, "\\\\.\\LPT%d", x
+1 );
779 handle
= CreateFileA( file
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, 0 );
780 if (handle
!= INVALID_HANDLE_VALUE
)
782 CloseHandle( handle
);
787 if (serialports
> 7) /* 3 bits -- maximum value = 7 */
790 if (parallelports
> 3) /* 2 bits -- maximum value = 3 */
794 (diskdrives
<< 6) | (serialports
<< 9) | (parallelports
<< 14) | 0x06 );
798 /**********************************************************************
801 * Handler for int 12h (get memory size).
803 static void WINAPI
DOSVM_Int12Handler( CONTEXT86
*context
)
805 SET_AX( context
, 640 );
809 /**********************************************************************
812 * Handler for int 17h (printer - output character).
814 static void WINAPI
DOSVM_Int17Handler( CONTEXT86
*context
)
816 switch( AH_reg(context
) )
818 case 0x00:/* Send character*/
819 FIXME("Send character not supported yet\n");
820 SET_AH( context
, 0x00 );/*Timeout*/
822 case 0x01: /* PRINTER - INITIALIZE */
823 FIXME("Initialize Printer - Not Supported\n");
824 SET_AH( context
, 0x30 ); /* selected | out of paper */
826 case 0x02: /* PRINTER - GET STATUS */
827 FIXME("Get Printer Status - Not Supported\n");
830 SET_AH( context
, 0 ); /* time out */
831 INT_BARF( context
, 0x17 );
836 /**********************************************************************
839 * Handler for int 19h (Reboot).
841 static void WINAPI
DOSVM_Int19Handler( CONTEXT86
*context
)
843 TRACE( "Attempted Reboot\n" );
848 /**********************************************************************
851 * Handler for int 1ah.
853 static void WINAPI
DOSVM_Int1aHandler( CONTEXT86
*context
)
855 switch(AH_reg(context
))
857 case 0x00: /* GET SYSTEM TIME */
859 BIOSDATA
*data
= DOSVM_BiosData();
860 SET_CX( context
, HIWORD(data
->Ticks
) );
861 SET_DX( context
, LOWORD(data
->Ticks
) );
862 SET_AL( context
, 0 ); /* FIXME: midnight flag is unsupported */
863 TRACE( "GET SYSTEM TIME - ticks=%d\n", data
->Ticks
);
867 case 0x01: /* SET SYSTEM TIME */
868 FIXME( "SET SYSTEM TIME - not allowed\n" );
871 case 0x02: /* GET REAL-TIME CLOCK TIME */
872 TRACE( "GET REAL-TIME CLOCK TIME\n" );
875 GetLocalTime( &systime
);
876 SET_CH( context
, BIN_TO_BCD(systime
.wHour
) );
877 SET_CL( context
, BIN_TO_BCD(systime
.wMinute
) );
878 SET_DH( context
, BIN_TO_BCD(systime
.wSecond
) );
879 SET_DL( context
, 0 ); /* FIXME: assume no daylight saving */
880 RESET_CFLAG(context
);
884 case 0x03: /* SET REAL-TIME CLOCK TIME */
885 FIXME( "SET REAL-TIME CLOCK TIME - not allowed\n" );
888 case 0x04: /* GET REAL-TIME CLOCK DATE */
889 TRACE( "GET REAL-TIME CLOCK DATE\n" );
892 GetLocalTime( &systime
);
893 SET_CH( context
, BIN_TO_BCD(systime
.wYear
/ 100) );
894 SET_CL( context
, BIN_TO_BCD(systime
.wYear
% 100) );
895 SET_DH( context
, BIN_TO_BCD(systime
.wMonth
) );
896 SET_DL( context
, BIN_TO_BCD(systime
.wDay
) );
897 RESET_CFLAG(context
);
901 case 0x05: /* SET REAL-TIME CLOCK DATE */
902 FIXME( "SET REAL-TIME CLOCK DATE - not allowed\n" );
905 case 0x06: /* SET ALARM */
906 FIXME( "SET ALARM - unimplemented\n" );
909 case 0x07: /* CANCEL ALARM */
910 FIXME( "CANCEL ALARM - unimplemented\n" );
913 case 0x08: /* SET RTC ACTIVATED POWER ON MODE */
914 case 0x09: /* READ RTC ALARM TIME AND STATUS */
915 case 0x0a: /* READ SYSTEM-TIMER DAY COUNTER */
916 case 0x0b: /* SET SYSTEM-TIMER DAY COUNTER */
917 case 0x0c: /* SET RTC DATE/TIME ACTIVATED POWER-ON MODE */
918 case 0x0d: /* RESET RTC DATE/TIME ACTIVATED POWER-ON MODE */
919 case 0x0e: /* GET RTC DATE/TIME ALARM AND STATUS */
920 case 0x0f: /* INITIALIZE REAL-TIME CLOCK */
921 INT_BARF( context
, 0x1a );
925 if (CX_reg(context
) == 0x4d52 &&
926 DX_reg(context
) == 0x4349 &&
927 AL_reg(context
) == 0x01)
930 * Microsoft Real-Time Compression Interface (MRCI).
931 * Ignoring this call indicates MRCI is not supported.
933 TRACE( "Microsoft Real-Time Compression Interface - not supported\n" );
937 INT_BARF(context
, 0x1a);
942 INT_BARF( context
, 0x1a );
947 /**********************************************************************
950 * Handler for int 20h.
952 static void WINAPI
DOSVM_Int20Handler( CONTEXT86
*context
)
956 else if(ISV86(context
))
957 MZ_Exit( context
, TRUE
, 0 );
959 ERR( "Called from DOS protected mode\n" );
963 /**********************************************************************
966 * Handler for int 29h (fast console output)
968 static void WINAPI
DOSVM_Int29Handler( CONTEXT86
*context
)
970 /* Yes, it seems that this is really all this interrupt does. */
971 DOSVM_PutChar(AL_reg(context
));
975 /**********************************************************************
978 * Handler for int 2ah (network).
980 static void WINAPI
DOSVM_Int2aHandler( CONTEXT86
*context
)
982 switch(AH_reg(context
))
984 case 0x00: /* NETWORK INSTALLATION CHECK */
988 INT_BARF( context
, 0x2a );
993 /***********************************************************************
996 static void WINAPI
DOSVM_Int41Handler( CONTEXT86
*context
)
998 if ( ISV86(context
) )
1000 /* Real-mode debugger services */
1001 switch ( AX_reg(context
) )
1004 INT_BARF( context
, 0x41 );
1010 /* Protected-mode debugger services */
1011 switch ( AX_reg(context
) )
1024 /* Notifies the debugger of a lot of stuff. We simply ignore it
1025 for now, but some of the info might actually be useful ... */
1029 INT_BARF( context
, 0x41 );
1036 /***********************************************************************
1037 * DOSVM_Int4bHandler
1040 static void WINAPI
DOSVM_Int4bHandler( CONTEXT86
*context
)
1042 switch(AH_reg(context
))
1044 case 0x81: /* Virtual DMA Spec (IBM SCSI interface) */
1045 if(AL_reg(context
) != 0x02) /* if not install check */
1048 SET_AL( context
, 0x0f ); /* function is not implemented */
1052 INT_BARF(context
, 0x4b);
1057 /***********************************************************************
1058 * DOSVM_Int5cHandler
1060 * Called from NetBIOSCall16.
1062 static void WINAPI
DOSVM_Int5cHandler( CONTEXT86
*context
)
1065 ptr
= MapSL( MAKESEGPTR(context
->SegEs
,BX_reg(context
)) );
1066 FIXME("(%p): command code %02x (ignored)\n",context
, *ptr
);
1067 *(ptr
+0x01) = 0xFB; /* NetBIOS emulator not found */
1068 SET_AL( context
, 0xFB );