Modify winedos interrupt handlers so that they work with PM
[wine] / dlls / winedos / interrupts.c
1 /*
2  * Interrupt emulation
3  *
4  * Copyright 2002 Jukka Heinonen
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "dosexe.h"
22 #include "wine/debug.h"
23 #include "wine/winbase16.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(int);
26
27 /*
28  * FIXME: Interrupt handlers for interrupts implemented in other DLLs.
29  *        These functions should be removed when the interrupt handlers have
30  *        been moved to winedos.
31  */
32 void WINAPI DOSVM_Int11Handler( CONTEXT86 *context ) { INT_Int11Handler(context); }
33 void WINAPI DOSVM_Int12Handler( CONTEXT86 *context ) { INT_Int12Handler(context); }
34 void WINAPI DOSVM_Int13Handler( CONTEXT86 *context ) { INT_Int13Handler(context); }
35 void WINAPI DOSVM_Int15Handler( CONTEXT86 *context ) { INT_Int15Handler(context); }
36 void WINAPI DOSVM_Int1aHandler( CONTEXT86 *context ) { INT_Int1aHandler(context); }
37 void WINAPI DOSVM_Int25Handler( CONTEXT86 *context ) { INT_Int25Handler(context); }
38 void WINAPI DOSVM_Int26Handler( CONTEXT86 *context ) { INT_Int26Handler(context); }
39 void WINAPI DOSVM_Int2aHandler( CONTEXT86 *context ) { INT_Int2aHandler(context); }
40 void WINAPI DOSVM_Int2fHandler( CONTEXT86 *context ) { INT_Int2fHandler(context); }
41 void WINAPI DOSVM_Int34Handler( CONTEXT86 *context ) { INT_Int34Handler(context); }
42 void WINAPI DOSVM_Int35Handler( CONTEXT86 *context ) { INT_Int35Handler(context); }
43 void WINAPI DOSVM_Int36Handler( CONTEXT86 *context ) { INT_Int36Handler(context); }
44 void WINAPI DOSVM_Int37Handler( CONTEXT86 *context ) { INT_Int37Handler(context); }
45 void WINAPI DOSVM_Int38Handler( CONTEXT86 *context ) { INT_Int38Handler(context); }
46 void WINAPI DOSVM_Int39Handler( CONTEXT86 *context ) { INT_Int39Handler(context); }
47 void WINAPI DOSVM_Int3aHandler( CONTEXT86 *context ) { INT_Int3aHandler(context); }
48 void WINAPI DOSVM_Int3bHandler( CONTEXT86 *context ) { INT_Int3bHandler(context); }
49 void WINAPI DOSVM_Int3cHandler( CONTEXT86 *context ) { INT_Int3cHandler(context); }
50 void WINAPI DOSVM_Int3dHandler( CONTEXT86 *context ) { INT_Int3dHandler(context); }
51 void WINAPI DOSVM_Int3eHandler( CONTEXT86 *context ) { INT_Int3eHandler(context); }
52 void WINAPI DOSVM_Int41Handler( CONTEXT86 *context ) { INT_Int41Handler(context); }
53 void WINAPI DOSVM_Int4bHandler( CONTEXT86 *context ) { INT_Int4bHandler(context); }
54 void WINAPI DOSVM_Int5cHandler( CONTEXT86 *context ) { NetBIOSCall16(context); }
55
56 static FARPROC16     DOSVM_Vectors16[256];
57 static FARPROC48     DOSVM_Vectors48[256];
58 static const INTPROC DOSVM_VectorsBuiltin[] =
59 {
60   /* 00 */ 0,                  0,                  0,                  0,
61   /* 04 */ 0,                  0,                  0,                  0,
62   /* 08 */ 0,                  DOSVM_Int09Handler, 0,                  0,
63   /* 0C */ 0,                  0,                  0,                  0,
64   /* 10 */ DOSVM_Int10Handler, DOSVM_Int11Handler, DOSVM_Int12Handler, DOSVM_Int13Handler,
65   /* 14 */ 0,                  DOSVM_Int15Handler, DOSVM_Int16Handler, DOSVM_Int17Handler,
66   /* 18 */ 0,                  0,                  DOSVM_Int1aHandler, 0,
67   /* 1C */ 0,                  0,                  0,                  0,
68   /* 20 */ DOSVM_Int20Handler, DOSVM_Int21Handler, 0,                  0,
69   /* 24 */ 0,                  DOSVM_Int25Handler, DOSVM_Int26Handler, 0,
70   /* 28 */ 0,                  DOSVM_Int29Handler, DOSVM_Int2aHandler, 0,
71   /* 2C */ 0,                  0,                  0,                  DOSVM_Int2fHandler,
72   /* 30 */ 0,                  DOSVM_Int31Handler, 0,                  DOSVM_Int33Handler,
73   /* 34 */ DOSVM_Int34Handler, DOSVM_Int35Handler, DOSVM_Int36Handler, DOSVM_Int37Handler,
74   /* 38 */ DOSVM_Int38Handler, DOSVM_Int39Handler, DOSVM_Int3aHandler, DOSVM_Int3bHandler,
75   /* 3C */ DOSVM_Int3cHandler, DOSVM_Int3dHandler, DOSVM_Int3eHandler, 0,
76   /* 40 */ 0,                  DOSVM_Int41Handler, 0,                  0,
77   /* 44 */ 0,                  0,                  0,                  0,
78   /* 48 */ 0,                  0,                  0,                  DOSVM_Int4bHandler,
79   /* 4C */ 0,                  0,                  0,                  0,
80   /* 50 */ 0,                  0,                  0,                  0,
81   /* 54 */ 0,                  0,                  0,                  0,
82   /* 58 */ 0,                  0,                  0,                  0,
83   /* 5C */ DOSVM_Int5cHandler, 0,                  0,                  0,
84   /* 60 */ 0,                  0,                  0,                  0,
85   /* 64 */ 0,                  0,                  0,                  DOSVM_Int67Handler
86 };
87
88 /* Ordinal number for interrupt 0 handler in winedos16.dll */
89 #define FIRST_INTERRUPT 100
90
91 /**********************************************************************
92  *         DOSVM_DefaultHandler
93  *
94  * Default interrupt handler. This will be used to emulate all
95  * interrupts that don't have their own interrupt handler.
96  */
97 void WINAPI DOSVM_DefaultHandler( CONTEXT86 *context )
98 {
99 }
100
101 /**********************************************************************
102  *         DOSVM_EmulateInterruptPM
103  *
104  * Emulate software interrupt in 16-bit or 32-bit protected mode.
105  * Called from signal handler when intXX opcode is executed. 
106  *
107  * Pushes interrupt frame to stack and changes instruction 
108  * pointer to interrupt handler.
109  */
110 void WINAPI DOSVM_EmulateInterruptPM( CONTEXT86 *context, BYTE intnum ) 
111 {
112   BOOL islong;
113
114   if(context->SegCs == DOSVM_dpmi_segments->int48_sel) 
115     islong = FALSE;
116   else if(DOSVM_IsDos32())
117     islong = TRUE;
118   else if(IS_SELECTOR_32BIT(context->SegCs)) {
119     WARN("Interrupt in 32-bit code and mode is not DPMI32\n");
120     islong = TRUE;
121   } else
122     islong = FALSE;
123
124   if(islong)
125   {
126     FARPROC48 addr = DOSVM_GetPMHandler48( intnum );
127     DWORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
128     /* Push the flags and return address on the stack */
129     *(--stack) = context->EFlags;
130     *(--stack) = context->SegCs;
131     *(--stack) = context->Eip;
132     /* Jump to the interrupt handler */
133     context->SegCs  = addr.selector;
134     context->Eip = addr.offset;
135   }
136   else
137   {
138     FARPROC16 addr = INT_GetPMHandler( intnum ); /* FIXME: DOSVM_GetPMHandler16 */
139     WORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
140     /* Push the flags and return address on the stack */
141     *(--stack) = LOWORD(context->EFlags);
142     *(--stack) = context->SegCs;
143     *(--stack) = LOWORD(context->Eip);
144     /* Jump to the interrupt handler */
145     context->SegCs  = HIWORD(addr);
146     context->Eip = LOWORD(addr);
147   }
148
149   if (IS_SELECTOR_32BIT(context->SegSs))
150     context->Esp += islong ? -12 : -6;
151   else
152     ADD_LOWORD( context->Esp, islong ? -12 : -6 );
153 }
154
155 /**********************************************************************
156  *          DOSVM_GetRMHandler
157  *
158  * Return the real mode interrupt vector for a given interrupt.
159  */
160 FARPROC16 DOSVM_GetRMHandler( BYTE intnum )
161 {
162   return ((FARPROC16*)0)[intnum];
163 }
164
165 /**********************************************************************
166  *          DOSVM_SetRMHandler
167  *
168  * Set the real mode interrupt handler for a given interrupt.
169  */
170 void DOSVM_SetRMHandler( BYTE intnum, FARPROC16 handler )
171 {
172   TRACE("Set real mode interrupt vector %02x <- %04x:%04x\n",
173        intnum, HIWORD(handler), LOWORD(handler) );
174   ((FARPROC16*)0)[intnum] = handler;
175 }
176
177 /**********************************************************************
178  *          DOSVM_GetPMHandler16
179  *
180  * Return the protected mode interrupt vector for a given interrupt.
181  */
182 FARPROC16 DOSVM_GetPMHandler16( BYTE intnum )
183 {
184   static HMODULE16 procs;
185   FARPROC16 handler = DOSVM_Vectors16[intnum];
186
187   if (!handler)
188   {
189     if (!procs &&
190         (procs = GetModuleHandle16( "winedos16" )) < 32 &&
191         (procs = LoadLibrary16( "winedos16" )) < 32)
192     {
193       ERR("could not load winedos16.dll\n");
194       procs = 0;
195       return 0;
196     }
197
198     handler = GetProcAddress16( procs, (LPCSTR)(FIRST_INTERRUPT + intnum));
199     if (!handler) 
200     {
201       WARN("int%x not implemented, returning dummy handler\n", intnum );
202       handler = GetProcAddress16( procs, (LPCSTR)(FIRST_INTERRUPT + 256));
203     }
204
205     DOSVM_Vectors16[intnum] = handler;
206   }
207
208   return handler;
209 }
210
211
212 /**********************************************************************
213  *          DOSVM_SetPMHandler16
214  *
215  * Set the protected mode interrupt handler for a given interrupt.
216  */
217 void DOSVM_SetPMHandler16( BYTE intnum, FARPROC16 handler )
218 {
219   TRACE("Set protected mode interrupt vector %02x <- %04x:%04x\n",
220        intnum, HIWORD(handler), LOWORD(handler) );
221   DOSVM_Vectors16[intnum] = handler;
222 }
223
224 /**********************************************************************
225  *         DOSVM_GetPMHandler48
226  *
227  * Return the protected mode interrupt vector for a given interrupt.
228  * Used to get 48-bit pointer for 32-bit interrupt handlers in DPMI32.
229  */
230 FARPROC48 DOSVM_GetPMHandler48( BYTE intnum )
231 {
232   if (!DOSVM_Vectors48[intnum].selector)
233   {
234     DOSVM_Vectors48[intnum].selector = DOSVM_dpmi_segments->int48_sel;
235     DOSVM_Vectors48[intnum].offset = 4 * intnum;
236   }
237   return DOSVM_Vectors48[intnum];
238 }
239
240 /**********************************************************************
241  *         DOSVM_SetPMHandler48
242  *
243  * Set the protected mode interrupt handler for a given interrupt.
244  * Used to set 48-bit pointer for 32-bit interrupt handlers in DPMI32.
245  */
246 void DOSVM_SetPMHandler48( BYTE intnum, FARPROC48 handler )
247 {
248   TRACE("Set 32-bit protected mode interrupt vector %02x <- %04x:%08lx\n",
249        intnum, handler.selector, handler.offset );
250   DOSVM_Vectors48[intnum] = handler;
251 }
252
253 /**********************************************************************
254  *         DOSVM_GetBuiltinHandler
255  *
256  * Return Wine interrupt handler procedure for a given interrupt.
257  */
258 INTPROC DOSVM_GetBuiltinHandler( BYTE intnum )
259 {
260   if (intnum < sizeof(DOSVM_VectorsBuiltin)/sizeof(INTPROC)) {
261     INTPROC proc = DOSVM_VectorsBuiltin[intnum];
262     if(proc)
263       return proc;
264   }
265
266   WARN("int%x not implemented, returning dummy handler\n", intnum );
267   return DOSVM_DefaultHandler;
268 }