winedos: Merge a number of tiny source files into interrupts.c.
[wine/dibdrv.git] / dlls / winedos / interrupts.c
blob37d7a4ba80597f085ffdba30bbed307635a25e4b
1 /*
2 * Interrupt emulation
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
21 #include "config.h"
23 #include <stdio.h>
25 #include "dosexe.h"
26 #include "wine/debug.h"
27 #include "wine/winbase16.h"
29 #include "thread.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*);
49 static FARPROC16 DOSVM_Vectors16[256];
50 static FARPROC48 DOSVM_Vectors48[256];
51 static const INTPROC DOSVM_VectorsBuiltin[] =
53 /* 00 */ 0, 0, 0, 0,
54 /* 04 */ 0, 0, 0, 0,
55 /* 08 */ DOSVM_Int08Handler, DOSVM_Int09Handler, 0, 0,
56 /* 0C */ 0, 0, 0, 0,
57 /* 10 */ DOSVM_Int10Handler, DOSVM_Int11Handler, DOSVM_Int12Handler, DOSVM_Int13Handler,
58 /* 14 */ 0, DOSVM_Int15Handler, DOSVM_Int16Handler, DOSVM_Int17Handler,
59 /* 18 */ 0, DOSVM_Int19Handler, DOSVM_Int1aHandler, 0,
60 /* 1C */ 0, 0, 0, 0,
61 /* 20 */ DOSVM_Int20Handler, DOSVM_Int21Handler, 0, 0,
62 /* 24 */ 0, DOSVM_Int25Handler, DOSVM_Int26Handler, 0,
63 /* 28 */ 0, DOSVM_Int29Handler, DOSVM_Int2aHandler, 0,
64 /* 2C */ 0, 0, 0, DOSVM_Int2fHandler,
65 /* 30 */ 0, DOSVM_Int31Handler, 0, DOSVM_Int33Handler,
66 /* 34 */ DOSVM_Int34Handler, DOSVM_Int35Handler, DOSVM_Int36Handler, DOSVM_Int37Handler,
67 /* 38 */ DOSVM_Int38Handler, DOSVM_Int39Handler, DOSVM_Int3aHandler, DOSVM_Int3bHandler,
68 /* 3C */ DOSVM_Int3cHandler, DOSVM_Int3dHandler, DOSVM_Int3eHandler, 0,
69 /* 40 */ 0, DOSVM_Int41Handler, 0, 0,
70 /* 44 */ 0, 0, 0, 0,
71 /* 48 */ 0, 0, 0, DOSVM_Int4bHandler,
72 /* 4C */ 0, 0, 0, 0,
73 /* 50 */ 0, 0, 0, 0,
74 /* 54 */ 0, 0, 0, 0,
75 /* 58 */ 0, 0, 0, 0,
76 /* 5C */ DOSVM_Int5cHandler, 0, 0, 0,
77 /* 60 */ 0, 0, 0, 0,
78 /* 64 */ 0, 0, 0, DOSVM_Int67Handler
83 * Sizes of real mode and protected mode interrupt stubs.
85 #define DOSVM_STUB_RM 4
86 #define DOSVM_STUB_PM16 5
87 #define DOSVM_STUB_PM48 6
90 /**********************************************************************
91 * DOSVM_GetRMVector
93 * Return pointer to real mode interrupt vector. These are not at fixed
94 * location because those Win16 programs that do not use any real mode
95 * code have protected NULL pointer catching block at low linear memory
96 * and interrupt vectors have been moved to another location.
98 static FARPROC16* DOSVM_GetRMVector( BYTE intnum )
100 LDT_ENTRY entry;
101 FARPROC16 proc;
103 proc = GetProcAddress16( GetModuleHandle16( "KERNEL" ),
104 (LPCSTR)(ULONG_PTR)183 );
105 wine_ldt_get_entry( LOWORD(proc), &entry );
107 return (FARPROC16*)wine_ldt_get_base( &entry ) + intnum;
111 /**********************************************************************
112 * DOSVM_IsIRQ
114 * Return TRUE if interrupt is an IRQ.
116 static BOOL DOSVM_IsIRQ( BYTE intnum )
118 if (intnum >= 0x08 && intnum <= 0x0f)
119 return TRUE;
121 if (intnum >= 0x70 && intnum <= 0x77)
122 return TRUE;
124 return FALSE;
128 /**********************************************************************
129 * DOSVM_DefaultHandler
131 * Default interrupt handler. This will be used to emulate all
132 * interrupts that don't have their own interrupt handler.
134 static void WINAPI DOSVM_DefaultHandler( CONTEXT86 *context )
139 /**********************************************************************
140 * DOSVM_GetBuiltinHandler
142 * Return Wine interrupt handler procedure for a given interrupt.
144 static INTPROC DOSVM_GetBuiltinHandler( BYTE intnum )
146 if (intnum < sizeof(DOSVM_VectorsBuiltin)/sizeof(INTPROC)) {
147 INTPROC proc = DOSVM_VectorsBuiltin[intnum];
148 if (proc)
149 return proc;
152 WARN("int%x not implemented, returning dummy handler\n", intnum );
154 if (DOSVM_IsIRQ(intnum))
155 return DOSVM_AcknowledgeIRQ;
157 return DOSVM_DefaultHandler;
161 /**********************************************************************
162 * DOSVM_IntProcRelay
164 * Simple DOSRELAY that interprets its argument as INTPROC and calls it.
166 static void DOSVM_IntProcRelay( CONTEXT86 *context, LPVOID data )
168 INTPROC proc = (INTPROC)data;
169 proc(context);
173 /**********************************************************************
174 * DOSVM_PrepareIRQ
177 static void DOSVM_PrepareIRQ( CONTEXT86 *context, BOOL isbuiltin )
179 /* Disable virtual interrupts. */
180 NtCurrentTeb()->dpmi_vif = 0;
182 if (!isbuiltin)
184 DWORD *stack = CTX_SEG_OFF_TO_LIN(context,
185 context->SegSs,
186 context->Esp);
188 /* Push return address to stack. */
189 *(--stack) = context->SegCs;
190 *(--stack) = context->Eip;
191 context->Esp += -8;
193 /* Jump to enable interrupts stub. */
194 context->SegCs = DOSVM_dpmi_segments->relay_code_sel;
195 context->Eip = 5;
200 /**********************************************************************
201 * DOSVM_PushFlags
203 * This routine is used to make default int25 and int26 handlers leave the
204 * original eflags into stack. In order to do this, stack is manipulated
205 * so that it actually contains two copies of eflags, one of which is
206 * popped during return from interrupt handler.
208 static void DOSVM_PushFlags( CONTEXT86 *context, BOOL islong, BOOL isstub )
210 if (islong)
212 DWORD *stack = CTX_SEG_OFF_TO_LIN(context,
213 context->SegSs,
214 context->Esp);
215 context->Esp += -4; /* One item will be added to stack. */
217 if (isstub)
219 DWORD ip = stack[0];
220 DWORD cs = stack[1];
221 stack += 2; /* Pop ip and cs. */
222 *(--stack) = context->EFlags;
223 *(--stack) = cs;
224 *(--stack) = ip;
226 else
227 *(--stack) = context->EFlags;
229 else
231 WORD *stack = CTX_SEG_OFF_TO_LIN(context,
232 context->SegSs,
233 context->Esp);
234 ADD_LOWORD( context->Esp, -2 ); /* One item will be added to stack. */
236 if (isstub)
238 WORD ip = stack[0];
239 WORD cs = stack[1];
240 stack += 2; /* Pop ip and cs. */
241 *(--stack) = LOWORD(context->EFlags);
242 *(--stack) = cs;
243 *(--stack) = ip;
245 else
246 *(--stack) = LOWORD(context->EFlags);
251 /**********************************************************************
252 * DOSVM_EmulateInterruptPM
254 * Emulate software interrupt in 16-bit or 32-bit protected mode.
255 * Called from signal handler when intXX opcode is executed.
257 * Pushes interrupt frame to stack and changes instruction
258 * pointer to interrupt handler.
260 void WINAPI DOSVM_EmulateInterruptPM( CONTEXT86 *context, BYTE intnum )
262 TRACE_(relay)("Call DOS int 0x%02x ret=%04x:%08x\n"
263 " eax=%08x ebx=%08x ecx=%08x edx=%08x\n"
264 " esi=%08x edi=%08x ebp=%08x esp=%08x \n"
265 " ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x\n",
266 intnum, context->SegCs, context->Eip,
267 context->Eax, context->Ebx, context->Ecx, context->Edx,
268 context->Esi, context->Edi, context->Ebp, context->Esp,
269 context->SegDs, context->SegEs, context->SegFs, context->SegGs,
270 context->SegSs, context->EFlags );
272 if (context->SegCs == DOSVM_dpmi_segments->dpmi_sel)
274 DOSVM_BuildCallFrame( context,
275 DOSVM_IntProcRelay,
276 DOSVM_RawModeSwitchHandler );
278 else if (context->SegCs == DOSVM_dpmi_segments->relay_code_sel)
281 * This must not be called using DOSVM_BuildCallFrame.
283 DOSVM_RelayHandler( context );
285 else if (context->SegCs == DOSVM_dpmi_segments->int48_sel)
287 /* Restore original flags stored into the stack by the caller. */
288 DWORD *stack = CTX_SEG_OFF_TO_LIN(context,
289 context->SegSs, context->Esp);
290 context->EFlags = stack[2];
292 if (intnum != context->Eip / DOSVM_STUB_PM48)
293 WARN( "interrupt stub has been modified "
294 "(interrupt is %02x, interrupt stub is %02x)\n",
295 intnum, context->Eip/DOSVM_STUB_PM48 );
297 TRACE( "builtin interrupt %02x has been branched to\n", intnum );
299 if (intnum == 0x25 || intnum == 0x26)
300 DOSVM_PushFlags( context, TRUE, TRUE );
302 DOSVM_BuildCallFrame( context,
303 DOSVM_IntProcRelay,
304 DOSVM_GetBuiltinHandler(intnum) );
306 else if (context->SegCs == DOSVM_dpmi_segments->int16_sel)
308 /* Restore original flags stored into the stack by the caller. */
309 WORD *stack = CTX_SEG_OFF_TO_LIN(context,
310 context->SegSs, context->Esp);
311 context->EFlags = (DWORD)MAKELONG( stack[2], HIWORD(context->EFlags) );
313 if (intnum != context->Eip / DOSVM_STUB_PM16)
314 WARN( "interrupt stub has been modified "
315 "(interrupt is %02x, interrupt stub is %02x)\n",
316 intnum, context->Eip/DOSVM_STUB_PM16 );
318 TRACE( "builtin interrupt %02x has been branched to\n", intnum );
320 if (intnum == 0x25 || intnum == 0x26)
321 DOSVM_PushFlags( context, FALSE, TRUE );
323 DOSVM_BuildCallFrame( context,
324 DOSVM_IntProcRelay,
325 DOSVM_GetBuiltinHandler(intnum) );
327 else
329 DOSVM_HardwareInterruptPM( context, intnum );
334 /**********************************************************************
335 * DOSVM_HardwareInterruptPM
337 * Emulate call to interrupt handler in 16-bit or 32-bit protected mode.
339 * Pushes interrupt frame to stack and changes instruction
340 * pointer to interrupt handler.
342 void DOSVM_HardwareInterruptPM( CONTEXT86 *context, BYTE intnum )
344 if(DOSVM_IsDos32())
346 FARPROC48 addr = DOSVM_GetPMHandler48( intnum );
348 if (addr.selector == DOSVM_dpmi_segments->int48_sel)
350 TRACE( "builtin interrupt %02x has been invoked "
351 "(through vector %02x)\n",
352 addr.offset / DOSVM_STUB_PM48, intnum );
354 if (intnum == 0x25 || intnum == 0x26)
355 DOSVM_PushFlags( context, TRUE, FALSE );
356 else if (DOSVM_IsIRQ(intnum))
357 DOSVM_PrepareIRQ( context, TRUE );
359 DOSVM_BuildCallFrame( context,
360 DOSVM_IntProcRelay,
361 DOSVM_GetBuiltinHandler(
362 addr.offset/DOSVM_STUB_PM48 ) );
364 else
366 DWORD *stack;
368 TRACE( "invoking hooked interrupt %02x at %04x:%08x\n",
369 intnum, addr.selector, addr.offset );
371 if (DOSVM_IsIRQ(intnum))
372 DOSVM_PrepareIRQ( context, FALSE );
374 /* Push the flags and return address on the stack */
375 stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
376 *(--stack) = context->EFlags;
377 *(--stack) = context->SegCs;
378 *(--stack) = context->Eip;
379 context->Esp += -12;
381 /* Jump to the interrupt handler */
382 context->SegCs = addr.selector;
383 context->Eip = addr.offset;
386 else
388 FARPROC16 addr = DOSVM_GetPMHandler16( intnum );
390 if (SELECTOROF(addr) == DOSVM_dpmi_segments->int16_sel)
392 TRACE( "builtin interrupt %02x has been invoked "
393 "(through vector %02x)\n",
394 OFFSETOF(addr)/DOSVM_STUB_PM16, intnum );
396 if (intnum == 0x25 || intnum == 0x26)
397 DOSVM_PushFlags( context, FALSE, FALSE );
398 else if (DOSVM_IsIRQ(intnum))
399 DOSVM_PrepareIRQ( context, TRUE );
401 DOSVM_BuildCallFrame( context,
402 DOSVM_IntProcRelay,
403 DOSVM_GetBuiltinHandler(
404 OFFSETOF(addr)/DOSVM_STUB_PM16 ) );
406 else
408 TRACE( "invoking hooked interrupt %02x at %04x:%04x\n",
409 intnum, SELECTOROF(addr), OFFSETOF(addr) );
411 if (DOSVM_IsIRQ(intnum))
412 DOSVM_PrepareIRQ( context, FALSE );
414 /* Push the flags and return address on the stack */
415 PUSH_WORD16( context, LOWORD(context->EFlags) );
416 PUSH_WORD16( context, context->SegCs );
417 PUSH_WORD16( context, LOWORD(context->Eip) );
419 /* Jump to the interrupt handler */
420 context->SegCs = HIWORD(addr);
421 context->Eip = LOWORD(addr);
427 /**********************************************************************
428 * DOSVM_EmulateInterruptRM
430 * Emulate software interrupt in real mode.
431 * Called from VM86 emulation when intXX opcode is executed.
433 * Either calls directly builtin handler or pushes interrupt frame to
434 * stack and changes instruction pointer to interrupt handler.
436 * Returns FALSE if this interrupt was caused by return
437 * from real mode wrapper.
439 BOOL WINAPI DOSVM_EmulateInterruptRM( CONTEXT86 *context, BYTE intnum )
441 TRACE_(relay)("Call DOS int 0x%02x ret=%04x:%08x\n"
442 " eax=%08x ebx=%08x ecx=%08x edx=%08x\n"
443 " esi=%08x edi=%08x ebp=%08x esp=%08x \n"
444 " ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x\n",
445 intnum, context->SegCs, context->Eip,
446 context->Eax, context->Ebx, context->Ecx, context->Edx,
447 context->Esi, context->Edi, context->Ebp, context->Esp,
448 context->SegDs, context->SegEs, context->SegFs, context->SegGs,
449 context->SegSs, context->EFlags );
451 /* check for our real-mode hooks */
452 if (intnum == 0x31)
454 /* is this exit from real-mode wrapper */
455 if (context->SegCs == DOSVM_dpmi_segments->wrap_seg)
456 return FALSE;
458 if (DOSVM_CheckWrappers( context ))
459 return TRUE;
462 /* check if the call is from our fake BIOS interrupt stubs */
463 if (context->SegCs==0xf000)
465 /* Restore original flags stored into the stack by the caller. */
466 WORD *stack = CTX_SEG_OFF_TO_LIN(context,
467 context->SegSs, context->Esp);
468 context->EFlags = (DWORD)MAKELONG( stack[2], HIWORD(context->EFlags) );
470 if (intnum != context->Eip / DOSVM_STUB_RM)
471 WARN( "interrupt stub has been modified "
472 "(interrupt is %02x, interrupt stub is %02x)\n",
473 intnum, context->Eip/DOSVM_STUB_RM );
475 TRACE( "builtin interrupt %02x has been branched to\n", intnum );
477 DOSVM_CallBuiltinHandler( context, intnum );
479 /* Real mode stubs use IRET so we must put flags back into stack. */
480 stack[2] = LOWORD(context->EFlags);
482 else
484 DOSVM_HardwareInterruptRM( context, intnum );
487 return TRUE;
491 /**********************************************************************
492 * DOSVM_HardwareInterruptRM
494 * Emulate call to interrupt handler in real mode.
496 * Either calls directly builtin handler or pushes interrupt frame to
497 * stack and changes instruction pointer to interrupt handler.
499 void DOSVM_HardwareInterruptRM( CONTEXT86 *context, BYTE intnum )
501 FARPROC16 handler = DOSVM_GetRMHandler( intnum );
503 /* check if the call goes to an unhooked interrupt */
504 if (SELECTOROF(handler) == 0xf000)
506 /* if so, call it directly */
507 TRACE( "builtin interrupt %02x has been invoked "
508 "(through vector %02x)\n",
509 OFFSETOF(handler)/DOSVM_STUB_RM, intnum );
510 DOSVM_CallBuiltinHandler( context, OFFSETOF(handler)/DOSVM_STUB_RM );
512 else
514 /* the interrupt is hooked, simulate interrupt in DOS space */
515 WORD flag = LOWORD( context->EFlags );
517 TRACE( "invoking hooked interrupt %02x at %04x:%04x\n",
518 intnum, SELECTOROF(handler), OFFSETOF(handler) );
520 /* Copy virtual interrupt flag to pushed interrupt flag. */
521 if (context->EFlags & VIF_MASK)
522 flag |= IF_MASK;
523 else
524 flag &= ~IF_MASK;
526 PUSH_WORD16( context, flag );
527 PUSH_WORD16( context, context->SegCs );
528 PUSH_WORD16( context, LOWORD( context->Eip ));
530 context->SegCs = SELECTOROF( handler );
531 context->Eip = OFFSETOF( handler );
533 /* Clear virtual interrupt flag and trap flag. */
534 context->EFlags &= ~(VIF_MASK | TF_MASK);
539 /**********************************************************************
540 * DOSVM_GetRMHandler
542 * Return the real mode interrupt vector for a given interrupt.
544 FARPROC16 DOSVM_GetRMHandler( BYTE intnum )
546 return *DOSVM_GetRMVector( intnum );
550 /**********************************************************************
551 * DOSVM_SetRMHandler
553 * Set the real mode interrupt handler for a given interrupt.
555 void DOSVM_SetRMHandler( BYTE intnum, FARPROC16 handler )
557 TRACE("Set real mode interrupt vector %02x <- %04x:%04x\n",
558 intnum, HIWORD(handler), LOWORD(handler) );
559 *DOSVM_GetRMVector( intnum ) = handler;
563 /**********************************************************************
564 * DOSVM_GetPMHandler16
566 * Return the protected mode interrupt vector for a given interrupt.
568 FARPROC16 DOSVM_GetPMHandler16( BYTE intnum )
570 TDB *pTask;
571 FARPROC16 proc = 0;
573 pTask = GlobalLock16(GetCurrentTask());
574 if (pTask)
576 switch( intnum )
578 case 0x00:
579 proc = pTask->int0;
580 break;
581 case 0x02:
582 proc = pTask->int2;
583 break;
584 case 0x04:
585 proc = pTask->int4;
586 break;
587 case 0x06:
588 proc = pTask->int6;
589 break;
590 case 0x07:
591 proc = pTask->int7;
592 break;
593 case 0x3e:
594 proc = pTask->int3e;
595 break;
596 case 0x75:
597 proc = pTask->int75;
598 break;
600 if( proc )
601 return proc;
603 if (!DOSVM_Vectors16[intnum])
605 proc = (FARPROC16)MAKESEGPTR( DOSVM_dpmi_segments->int16_sel,
606 DOSVM_STUB_PM16 * intnum );
607 DOSVM_Vectors16[intnum] = proc;
609 return DOSVM_Vectors16[intnum];
613 /**********************************************************************
614 * DOSVM_SetPMHandler16
616 * Set the protected mode interrupt handler for a given interrupt.
618 void DOSVM_SetPMHandler16( BYTE intnum, FARPROC16 handler )
620 TDB *pTask;
622 TRACE("Set protected mode interrupt vector %02x <- %04x:%04x\n",
623 intnum, HIWORD(handler), LOWORD(handler) );
625 pTask = GlobalLock16(GetCurrentTask());
626 if (!pTask)
627 return;
628 switch( intnum )
630 case 0x00:
631 pTask->int0 = handler;
632 break;
633 case 0x02:
634 pTask->int2 = handler;
635 break;
636 case 0x04:
637 pTask->int4 = handler;
638 break;
639 case 0x06:
640 pTask->int6 = handler;
641 break;
642 case 0x07:
643 pTask->int7 = handler;
644 break;
645 case 0x3e:
646 pTask->int3e = handler;
647 break;
648 case 0x75:
649 pTask->int75 = handler;
650 break;
651 default:
652 DOSVM_Vectors16[intnum] = handler;
653 break;
658 /**********************************************************************
659 * DOSVM_GetPMHandler48
661 * Return the protected mode interrupt vector for a given interrupt.
662 * Used to get 48-bit pointer for 32-bit interrupt handlers in DPMI32.
664 FARPROC48 DOSVM_GetPMHandler48( BYTE intnum )
666 if (!DOSVM_Vectors48[intnum].selector)
668 DOSVM_Vectors48[intnum].selector = DOSVM_dpmi_segments->int48_sel;
669 DOSVM_Vectors48[intnum].offset = DOSVM_STUB_PM48 * intnum;
671 return DOSVM_Vectors48[intnum];
675 /**********************************************************************
676 * DOSVM_SetPMHandler48
678 * Set the protected mode interrupt handler for a given interrupt.
679 * Used to set 48-bit pointer for 32-bit interrupt handlers in DPMI32.
681 void DOSVM_SetPMHandler48( BYTE intnum, FARPROC48 handler )
683 TRACE("Set 32-bit protected mode interrupt vector %02x <- %04x:%08x\n",
684 intnum, handler.selector, handler.offset );
685 DOSVM_Vectors48[intnum] = handler;
689 /**********************************************************************
690 * DOSVM_CallBuiltinHandler
692 * Execute Wine interrupt handler procedure.
694 void WINAPI DOSVM_CallBuiltinHandler( CONTEXT86 *context, BYTE intnum )
697 * FIXME: Make all builtin interrupt calls go via this routine.
698 * FIXME: Check for PM->RM interrupt reflection.
699 * FIXME: Check for RM->PM interrupt reflection.
702 INTPROC proc = DOSVM_GetBuiltinHandler( intnum );
703 proc( context );
707 /**********************************************************************
708 * DOSVM_Int11Handler
710 * Handler for int 11h (get equipment list).
713 * Borrowed from Ralph Brown's interrupt lists:
715 * bits 15-14: number of parallel devices
716 * bit 13: [Conv] Internal modem
717 * bit 12: reserved
718 * bits 11- 9: number of serial devices
719 * bit 8: reserved
720 * bits 7- 6: number of diskette drives minus one
721 * bits 5- 4: Initial video mode:
722 * 00b = EGA,VGA,PGA
723 * 01b = 40 x 25 color
724 * 10b = 80 x 25 color
725 * 11b = 80 x 25 mono
726 * bit 3: reserved
727 * bit 2: [PS] =1 if pointing device
728 * [non-PS] reserved
729 * bit 1: =1 if math co-processor
730 * bit 0: =1 if diskette available for boot
733 * Currently the only of these bits correctly set are:
735 * bits 15-14 } Added by William Owen Smith,
736 * bits 11-9 } wos@dcs.warwick.ac.uk
737 * bits 7-6
738 * bit 2 (always set) ( bit 2 = 4 )
739 * bit 1 } Robert 'Admiral' Coeyman
740 * All *nix systems either have a math processor or
741 * emulate one.
743 static void WINAPI DOSVM_Int11Handler( CONTEXT86 *context )
745 int diskdrives = 0;
746 int parallelports = 0;
747 int serialports = 0;
748 int x;
750 if (GetDriveTypeA("A:\\") == DRIVE_REMOVABLE) diskdrives++;
751 if (GetDriveTypeA("B:\\") == DRIVE_REMOVABLE) diskdrives++;
752 if (diskdrives) diskdrives--;
754 for (x=0; x < 9; x++)
756 HANDLE handle;
757 char file[10];
759 /* serial port name */
760 sprintf( file, "\\\\.\\COM%d", x+1 );
761 handle = CreateFileA( file, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
762 if (handle != INVALID_HANDLE_VALUE)
764 CloseHandle( handle );
765 serialports++;
768 sprintf( file, "\\\\.\\LPT%d", x+1 );
769 handle = CreateFileA( file, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
770 if (handle != INVALID_HANDLE_VALUE)
772 CloseHandle( handle );
773 parallelports++;
777 if (serialports > 7) /* 3 bits -- maximum value = 7 */
778 serialports = 7;
780 if (parallelports > 3) /* 2 bits -- maximum value = 3 */
781 parallelports = 3;
783 SET_AX( context,
784 (diskdrives << 6) | (serialports << 9) | (parallelports << 14) | 0x06 );
788 /**********************************************************************
789 * DOSVM_Int12Handler
791 * Handler for int 12h (get memory size).
793 static void WINAPI DOSVM_Int12Handler( CONTEXT86 *context )
795 SET_AX( context, 640 );
799 /**********************************************************************
800 * DOSVM_Int17Handler
802 * Handler for int 17h (printer - output character).
804 static void WINAPI DOSVM_Int17Handler( CONTEXT86 *context )
806 switch( AH_reg(context) )
808 case 0x00:/* Send character*/
809 FIXME("Send character not supported yet\n");
810 SET_AH( context, 0x00 );/*Timeout*/
811 break;
812 case 0x01: /* PRINTER - INITIALIZE */
813 FIXME("Initialize Printer - Not Supported\n");
814 SET_AH( context, 0x30 ); /* selected | out of paper */
815 break;
816 case 0x02: /* PRINTER - GET STATUS */
817 FIXME("Get Printer Status - Not Supported\n");
818 break;
819 default:
820 SET_AH( context, 0 ); /* time out */
821 INT_BARF( context, 0x17 );
826 /**********************************************************************
827 * DOSVM_Int19Handler
829 * Handler for int 19h (Reboot).
831 static void WINAPI DOSVM_Int19Handler( CONTEXT86 *context )
833 TRACE( "Attempted Reboot\n" );
834 ExitProcess(0);
838 /**********************************************************************
839 * DOSVM_Int1aHandler
841 * Handler for int 1ah.
843 static void WINAPI DOSVM_Int1aHandler( CONTEXT86 *context )
845 switch(AH_reg(context))
847 case 0x00: /* GET SYSTEM TIME */
849 BIOSDATA *data = DOSVM_BiosData();
850 SET_CX( context, HIWORD(data->Ticks) );
851 SET_DX( context, LOWORD(data->Ticks) );
852 SET_AL( context, 0 ); /* FIXME: midnight flag is unsupported */
853 TRACE( "GET SYSTEM TIME - ticks=%d\n", data->Ticks );
855 break;
857 case 0x01: /* SET SYSTEM TIME */
858 FIXME( "SET SYSTEM TIME - not allowed\n" );
859 break;
861 case 0x02: /* GET REAL-TIME CLOCK TIME */
862 TRACE( "GET REAL-TIME CLOCK TIME\n" );
864 SYSTEMTIME systime;
865 GetLocalTime( &systime );
866 SET_CH( context, BIN_TO_BCD(systime.wHour) );
867 SET_CL( context, BIN_TO_BCD(systime.wMinute) );
868 SET_DH( context, BIN_TO_BCD(systime.wSecond) );
869 SET_DL( context, 0 ); /* FIXME: assume no daylight saving */
870 RESET_CFLAG(context);
872 break;
874 case 0x03: /* SET REAL-TIME CLOCK TIME */
875 FIXME( "SET REAL-TIME CLOCK TIME - not allowed\n" );
876 break;
878 case 0x04: /* GET REAL-TIME CLOCK DATE */
879 TRACE( "GET REAL-TIME CLOCK DATE\n" );
881 SYSTEMTIME systime;
882 GetLocalTime( &systime );
883 SET_CH( context, BIN_TO_BCD(systime.wYear / 100) );
884 SET_CL( context, BIN_TO_BCD(systime.wYear % 100) );
885 SET_DH( context, BIN_TO_BCD(systime.wMonth) );
886 SET_DL( context, BIN_TO_BCD(systime.wDay) );
887 RESET_CFLAG(context);
889 break;
891 case 0x05: /* SET REAL-TIME CLOCK DATE */
892 FIXME( "SET REAL-TIME CLOCK DATE - not allowed\n" );
893 break;
895 case 0x06: /* SET ALARM */
896 FIXME( "SET ALARM - unimplemented\n" );
897 break;
899 case 0x07: /* CANCEL ALARM */
900 FIXME( "CANCEL ALARM - unimplemented\n" );
901 break;
903 case 0x08: /* SET RTC ACTIVATED POWER ON MODE */
904 case 0x09: /* READ RTC ALARM TIME AND STATUS */
905 case 0x0a: /* READ SYSTEM-TIMER DAY COUNTER */
906 case 0x0b: /* SET SYSTEM-TIMER DAY COUNTER */
907 case 0x0c: /* SET RTC DATE/TIME ACTIVATED POWER-ON MODE */
908 case 0x0d: /* RESET RTC DATE/TIME ACTIVATED POWER-ON MODE */
909 case 0x0e: /* GET RTC DATE/TIME ALARM AND STATUS */
910 case 0x0f: /* INITIALIZE REAL-TIME CLOCK */
911 INT_BARF( context, 0x1a );
912 break;
914 case 0xb0:
915 if (CX_reg(context) == 0x4d52 &&
916 DX_reg(context) == 0x4349 &&
917 AL_reg(context) == 0x01)
920 * Microsoft Real-Time Compression Interface (MRCI).
921 * Ignoring this call indicates MRCI is not supported.
923 TRACE( "Microsoft Real-Time Compression Interface - not supported\n" );
925 else
927 INT_BARF(context, 0x1a);
929 break;
931 default:
932 INT_BARF( context, 0x1a );
937 /**********************************************************************
938 * DOSVM_Int20Handler
940 * Handler for int 20h.
942 static void WINAPI DOSVM_Int20Handler( CONTEXT86 *context )
944 if (DOSVM_IsWin16())
945 ExitThread( 0 );
946 else if(ISV86(context))
947 MZ_Exit( context, TRUE, 0 );
948 else
949 ERR( "Called from DOS protected mode\n" );
953 /**********************************************************************
954 * DOSVM_Int29Handler
956 * Handler for int 29h (fast console output)
958 static void WINAPI DOSVM_Int29Handler( CONTEXT86 *context )
960 /* Yes, it seems that this is really all this interrupt does. */
961 DOSVM_PutChar(AL_reg(context));
965 /**********************************************************************
966 * DOSVM_Int2aHandler
968 * Handler for int 2ah (network).
970 static void WINAPI DOSVM_Int2aHandler( CONTEXT86 *context )
972 switch(AH_reg(context))
974 case 0x00: /* NETWORK INSTALLATION CHECK */
975 break;
977 default:
978 INT_BARF( context, 0x2a );
983 /***********************************************************************
984 * DOSVM_Int41Handler
986 static void WINAPI DOSVM_Int41Handler( CONTEXT86 *context )
988 if ( ISV86(context) )
990 /* Real-mode debugger services */
991 switch ( AX_reg(context) )
993 default:
994 INT_BARF( context, 0x41 );
995 break;
998 else
1000 /* Protected-mode debugger services */
1001 switch ( AX_reg(context) )
1003 case 0x4f:
1004 case 0x50:
1005 case 0x150:
1006 case 0x51:
1007 case 0x52:
1008 case 0x152:
1009 case 0x59:
1010 case 0x5a:
1011 case 0x5b:
1012 case 0x5c:
1013 case 0x5d:
1014 /* Notifies the debugger of a lot of stuff. We simply ignore it
1015 for now, but some of the info might actually be useful ... */
1016 break;
1018 default:
1019 INT_BARF( context, 0x41 );
1020 break;
1026 /***********************************************************************
1027 * DOSVM_Int4bHandler
1030 static void WINAPI DOSVM_Int4bHandler( CONTEXT86 *context )
1032 switch(AH_reg(context))
1034 case 0x81: /* Virtual DMA Spec (IBM SCSI interface) */
1035 if(AL_reg(context) != 0x02) /* if not install check */
1037 SET_CFLAG(context);
1038 SET_AL( context, 0x0f ); /* function is not implemented */
1040 break;
1041 default:
1042 INT_BARF(context, 0x4b);
1047 /***********************************************************************
1048 * DOSVM_Int5cHandler
1050 * Called from NetBIOSCall16.
1052 static void WINAPI DOSVM_Int5cHandler( CONTEXT86 *context )
1054 BYTE* ptr;
1055 ptr = MapSL( MAKESEGPTR(context->SegEs,BX_reg(context)) );
1056 FIXME("(%p): command code %02x (ignored)\n",context, *ptr);
1057 *(ptr+0x01) = 0xFB; /* NetBIOS emulator not found */
1058 SET_AL( context, 0xFB );