LoadModule32/WinExec32 should return 16-bit hInstance/hTask.
[wine] / msdos / int2f.c
1 /*
2  * DOS interrupt 2fh handler
3  */
4
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8
9 #include "ldt.h"
10 #include "drive.h"
11 #include "msdos.h"
12 #include "miscemu.h"
13 #include "module.h"
14 #include "task.h"
15 #include "dosexe.h"
16 /* #define DEBUG_INT */
17 #include "debug.h"
18
19   /* base WPROCS.DLL ordinal number for VxDs */
20 #define VXD_BASE 400
21
22 static void do_int2f_16( CONTEXT *context );
23
24 /**********************************************************************
25  *          INT_Int2fHandler
26  *
27  * Handler for int 2fh (multiplex).
28  */
29 void WINAPI INT_Int2fHandler( CONTEXT *context )
30 {
31     TRACE(int,"Subfunction 0x%X\n", AH_reg(context));
32
33     switch(AH_reg(context))
34     {
35     case 0x10:
36         AL_reg(context) = 0xff; /* share is installed */
37         break;
38
39     case 0x11:  /* Network Redirector / IFSFUNC */
40         switch (AL_reg(context))
41         {
42         case 0x00:  /* Install check */
43             /* not installed */
44             break;
45         case 0x80:  /* Enhanced services - Install check */
46             /* not installed */
47             break;
48         default:
49             INT_BARF( context, 0x2f );
50             break;
51         }
52         break;
53
54     case 0x12:
55         switch (AL_reg(context))
56         {
57         case 0x2e: /* get or set DOS error table address */
58             switch (DL_reg(context))
59             {
60             /* Four tables: even commands are 'get', odd are 'set' */
61             /* DOS 5.0+ ignores "set" commands */
62             case 0x01:
63             case 0x03:
64             case 0x05:
65             case 0x07:
66             case 0x09:
67                 break; 
68             /* Instead of having a message table in DOS-space, */
69             /* we can use a special case for MS-DOS to force   */
70             /* the secondary interface.                        */
71             case 0x00:
72             case 0x02:
73             case 0x04:
74             case 0x06: 
75                 ES_reg(context) = 0x0001;
76                 DI_reg(context) = 0x0000;
77                 break;
78             case 0x08:
79                 FIXME(int, "No real-mode handler for errors yet! (bye!)");
80                 break;
81             default:
82                 INT_BARF(context, 0x2f);
83             }
84             break;
85         default:
86            INT_BARF(context, 0x2f);
87         }  
88         break;
89    
90     case 0x15: /* mscdex */
91         do_mscdex(context);
92         break;
93
94     case 0x16:
95         do_int2f_16( context );
96         break;
97
98     case 0x1a: /* ANSI.SYS / AVATAR.SYS Install Check */
99         /* Not supported yet, do nothing */
100         break;
101
102     case 0x43:
103 #if 1
104         switch (AL_reg(context))
105         {
106         case 0x00:   /* XMS v2+ installation check */
107             WARN(int,"XMS is not fully implemented\n");
108             AL_reg(context) = 0x80;
109             break;
110         case 0x10:   /* XMS v2+ get driver address */
111         {
112             TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
113             NE_MODULE *pModule = pTask ? NE_GetPtr( pTask->hModule ) : NULL;
114             GlobalUnlock16( GetCurrentTask() );
115 #ifdef MZ_SUPPORTED
116             if (pModule && pModule->lpDosTask)
117                 ES_reg(context) = pModule->lpDosTask->xms_seg;
118             else
119 #endif
120                 ES_reg(context) = 0;
121             BX_reg(context) = 0;
122             break;
123         }
124         default:
125             INT_BARF( context, 0x2f );
126         }
127 #else
128         FIXME(int,"check for XMS (not supported)\n");
129         AL_reg(context) = 0x42; /* != 0x80 */
130 #endif
131         break;
132
133     case 0x45:
134        switch (AL_reg(context)) 
135        {
136        case 0x00:
137        case 0x01:
138        case 0x02:
139        case 0x03:
140        case 0x04:
141        case 0x05:
142        case 0x06:
143        case 0x07:
144        case 0x08:
145            /* Microsoft Profiler - not installed */
146            break;
147        default:
148             INT_BARF( context, 0x2f );
149        }
150        break;
151
152     case 0x4a:
153         switch(AL_reg(context))
154         {
155         case 0x10:  /* smartdrv */
156             break;  /* not installed */
157         case 0x11:  /* dblspace */
158             break;  /* not installed */
159         case 0x12:  /* realtime compression interface */
160             break;  /* not installed */
161         case 0x32:  /* patch IO.SYS (???) */
162             break;  /* we have no IO.SYS, so we can't patch it :-/ */
163         default:
164             INT_BARF( context, 0x2f );
165         }
166         break;
167     case 0x56:  /* INTERLNK */
168         switch(AL_reg(context))
169         {
170         case 0x01:  /* check if redirected drive */
171             AL_reg(context) = 0; /* not redirected */
172             break;
173         default:
174             INT_BARF( context, 0x2f );
175         }
176         break;
177     case 0x7a:  /* NOVELL NetWare */
178         switch (AL_reg(context))
179         {
180         case 0x20:  /* Get VLM Call Address */
181             /* return nothing -> NetWare not installed */
182             break;
183         default:
184             INT_BARF( context, 0x2f );
185             break;
186         }
187         break;
188     case 0xb7:  /* append */
189         AL_reg(context) = 0; /* not installed */
190         break;
191     case 0xb8:  /* network */
192         switch (AL_reg(context))
193         {
194         case 0x00:  /* Install check */
195             /* not installed */
196             break;
197         default:
198             INT_BARF( context, 0x2f );
199             break;
200         }
201         break;
202     case 0xbd:  /* some Novell network install check ??? */
203         AX_reg(context) = 0xa5a5; /* pretend to have Novell IPX installed */
204         break;
205     case 0xbf:  /* REDIRIFS.EXE */
206         switch (AL_reg(context))
207         {
208         case 0x00:  /* Install check */
209             /* not installed */
210             break;
211         default:
212             INT_BARF( context, 0x2f );
213             break;
214         }
215         break;
216     case 0xd7:  /* Banyan Vines */
217         switch (AL_reg(context))
218         {
219         case 0x01:  /* Install check - Get Int Number */
220             /* not installed */
221             break;
222         default:
223             INT_BARF( context, 0x2f );
224             break;
225         }
226         break;
227     case 0xfa:  /* Watcom debugger check, returns 0x666 if installed */
228         break;
229     default:
230         INT_BARF( context, 0x2f );
231         break;
232     }
233 }
234
235
236 /**********************************************************************
237  *          do_int2f_16
238  */
239 static void do_int2f_16( CONTEXT *context )
240 {
241     DWORD addr;
242
243     switch(AL_reg(context))
244     {
245     case 0x00:  /* Windows enhanced mode installation check */
246         AX_reg(context) = (GetWinFlags() & WF_ENHANCED) ?
247                                                   LOWORD(GetVersion16()) : 0;
248         break;
249         
250     case 0x0a:  /* Get Windows version and type */
251         AX_reg(context) = 0;
252         BX_reg(context) = (LOWORD(GetVersion16()) << 8) |
253                           (LOWORD(GetVersion16()) >> 8);
254         CX_reg(context) = (GetWinFlags() & WF_ENHANCED) ? 3 : 2;
255         break;
256
257     case 0x0b:  /* Identify Windows-aware TSRs */
258         /* we don't have any pre-Windows TSRs */
259         break;
260
261     case 0x11:  /* Get Shell Parameters - (SHELL= in CONFIG.SYS) */
262         /* We can mock this up. But not today... */ 
263         FIXME(int, "Get Shell Parameters\n");       
264         break;
265
266     case 0x80:  /* Release time-slice */
267         AL_reg(context) = 0;
268         /* FIXME: We need to do something that lets some other process run
269            here.  */
270         sleep(0);
271         break;
272
273     case 0x81: /* Begin critical section.  */
274         /* FIXME? */
275         break;
276
277     case 0x82: /* End critical section.  */
278         /* FIXME? */
279         break;
280
281     case 0x83:  /* Return Current Virtual Machine ID */
282         /* Virtual Machines are usually created/destroyed when Windows runs
283          * DOS programs. Since we never do, we are always in the System VM.
284          * According to Ralf Brown's Interrupt List, never return 0. But it
285          * seems to work okay (returning 0), just to be sure we return 1.
286          */
287         BX_reg(context) = 1; /* VM 1 is probably the System VM */
288         break;
289
290     case 0x84:  /* Get device API entry point */
291         addr = (DWORD)NE_GetEntryPoint( GetModuleHandle16("WPROCS"),
292                                         VXD_BASE + BX_reg(context) );
293         if (!addr)  /* not supported */
294         {
295             ERR(int,"Accessing unknown VxD %04x - Expect a failure now.\n",
296                      BX_reg(context) );
297         }
298         ES_reg(context) = SELECTOROF(addr);
299         DI_reg(context) = OFFSETOF(addr);
300         break;
301
302     case 0x86:  /* DPMI detect mode */
303         AX_reg(context) = 0;  /* Running under DPMI */
304         break;
305
306     case 0x87: /* DPMI installation check */
307 #if 1   /* DPMI still breaks pkunzip */
308         if (ISV86(context)) break; /* so bail out for now if in v86 mode */
309 #endif
310         {
311             TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
312             NE_MODULE *pModule = pTask ? NE_GetPtr( pTask->hModule ) : NULL;
313             SYSTEM_INFO si;
314
315             GlobalUnlock16( GetCurrentTask() );
316             GetSystemInfo(&si);
317             AX_reg(context) = 0x0000; /* DPMI Installed */
318             BX_reg(context) = 0x0001; /* 32bits available */
319             CL_reg(context) = si.wProcessorLevel;
320             DX_reg(context) = 0x005a; /* DPMI major/minor 0.90 */
321             SI_reg(context) = 0;      /* # of para. of DOS extended private data */
322 #ifdef MZ_SUPPORTED                   /* ES:DI is DPMI switch entry point */
323             if (pModule && pModule->lpDosTask)
324                 ES_reg(context) = pModule->lpDosTask->dpmi_seg;
325             else
326 #endif
327                 ES_reg(context) = 0;
328             DI_reg(context) = 0;
329             break;
330         }
331     case 0x8a:  /* DPMI get vendor-specific API entry point. */
332         /* The 1.0 specs say this should work with all 0.9 hosts.  */
333         break;
334
335     default:
336         INT_BARF( context, 0x2f );
337     }
338 }
339
340 void do_mscdex( CONTEXT *context )
341 {
342     int drive, count;
343     char *p;
344
345     switch(AL_reg(context))
346     {
347         case 0x00: /* Installation check */
348             /* Count the number of contiguous CDROM drives
349              */
350             for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
351             {
352                 if (DRIVE_GetType(drive) == TYPE_CDROM)
353                 {
354                     while (DRIVE_GetType(drive + count) == TYPE_CDROM) count++;
355                     break;
356                 }
357             }
358
359             BX_reg(context) = count;
360             CX_reg(context) = (drive < MAX_DOS_DRIVES) ? drive : 0;
361             break;
362
363         case 0x0B: /* drive check */
364             AX_reg(context) = (DRIVE_GetType(CX_reg(context)) == TYPE_CDROM);
365             BX_reg(context) = 0xADAD;
366             break;
367
368         case 0x0C: /* get version */
369             BX_reg(context) = 0x020a;
370             break;
371
372         case 0x0D: /* get drive letters */
373             p = CTX_SEG_OFF_TO_LIN(context, ES_reg(context), EBX_reg(context));
374             memset( p, 0, MAX_DOS_DRIVES );
375             for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
376             {
377                 if (DRIVE_GetType(drive) == TYPE_CDROM) *p++ = drive;
378             }
379             break;
380
381 #ifdef linux
382         /* FIXME: why a new linux-only CDROM drive access, for crying out loud?
383          * There are pretty complete routines in multimedia/mcicda.c already! */
384         case 0x10: /* direct driver acces */
385             FIXME(cdaudio,"mscdex should use multimedia/mcicda.c");
386             do_mscdex_dd(context,ISV86(context));
387             break;
388
389 #endif
390
391         default:
392             FIXME(int, "Unimplemented MSCDEX function 0x%02X.\n", AL_reg(context));
393             break;
394     }
395 }