user32: Move *RegisterDeviceNotification*() to input.c.
[wine.git] / dlls / krnl386.exe16 / int31.c
blobd5cf02896abf9327904474bb38cba32594dc6404
1 /*
2 * DPMI 0.9 emulation
4 * Copyright 1995 Alexandre Julliard
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 <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winternl.h"
26 #include "wine/winbase16.h"
27 #include "wownt32.h"
28 #include "kernel16_private.h"
29 #include "dosexe.h"
31 #include "excpt.h"
32 #include "wine/debug.h"
33 #include "wine/exception.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(int31);
37 static void* lastvalloced = NULL;
39 /**********************************************************************
40 * DPMI_xalloc
41 * special virtualalloc, allocates linearly monoton growing memory.
42 * (the usual VirtualAlloc does not satisfy that restriction)
44 static LPVOID DPMI_xalloc( DWORD len )
46 LPVOID ret;
47 LPVOID oldlastv = lastvalloced;
49 if (lastvalloced)
51 int xflag = 0;
53 ret = NULL;
54 while (!ret)
56 ret = VirtualAlloc( lastvalloced, len,
57 MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE );
58 if (!ret)
59 lastvalloced = (char *) lastvalloced + 0x10000;
61 /* we failed to allocate one in the first round.
62 * try non-linear
64 if (!xflag && (lastvalloced<oldlastv))
66 /* wrapped */
67 FIXME( "failed to allocate linearly growing memory (%u bytes), "
68 "using non-linear growing...\n", len );
69 xflag++;
72 /* if we even fail to allocate something in the next
73 * round, return NULL
75 if ((xflag==1) && (lastvalloced >= oldlastv))
76 xflag++;
78 if ((xflag==2) && (lastvalloced < oldlastv)) {
79 FIXME( "failed to allocate any memory of %u bytes!\n", len );
80 return NULL;
84 else
86 ret = VirtualAlloc( NULL, len,
87 MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE );
90 lastvalloced = (LPVOID)(((DWORD)ret+len+0xffff)&~0xffff);
91 return ret;
94 /**********************************************************************
95 * DPMI_xfree
97 static void DPMI_xfree( LPVOID ptr )
99 VirtualFree( ptr, 0, MEM_RELEASE );
102 /**********************************************************************
103 * DPMI_xrealloc
105 * FIXME: perhaps we could grow this mapped area...
107 static LPVOID DPMI_xrealloc( LPVOID ptr, DWORD newsize )
109 MEMORY_BASIC_INFORMATION mbi;
111 if (ptr)
113 LPVOID newptr;
115 if (!VirtualQuery(ptr,&mbi,sizeof(mbi)))
117 FIXME( "realloc of DPMI_xallocd region %p?\n", ptr );
118 return NULL;
121 if (mbi.State == MEM_FREE)
123 FIXME( "realloc of DPMI_xallocd region %p?\n", ptr );
124 return NULL;
127 /* We do not shrink allocated memory. most reallocs
128 * only do grows anyway
130 if (newsize <= mbi.RegionSize)
131 return ptr;
133 newptr = DPMI_xalloc( newsize );
134 if (!newptr)
135 return NULL;
137 memcpy( newptr, ptr, mbi.RegionSize );
138 DPMI_xfree( ptr );
140 return newptr;
143 return DPMI_xalloc( newsize );
147 /**********************************************************************
148 * DOSVM_Int31Handler
150 * Handler for int 31h (DPMI).
152 void WINAPI DOSVM_Int31Handler( CONTEXT *context )
154 RESET_CFLAG(context);
155 switch(AX_reg(context))
157 case 0x0000: /* Allocate LDT descriptors */
158 TRACE( "allocate LDT descriptors (%d)\n", CX_reg(context) );
160 WORD sel = AllocSelectorArray16( CX_reg(context) );
161 if(!sel)
163 TRACE( "failed\n" );
164 SET_AX( context, 0x8011 ); /* descriptor unavailable */
165 SET_CFLAG( context );
167 else
169 TRACE( "success, array starts at 0x%04x\n", sel );
170 SET_AX( context, sel );
173 break;
175 case 0x0001: /* Free LDT descriptor */
176 TRACE( "free LDT descriptor (0x%04x)\n", BX_reg(context) );
177 if (FreeSelector16( BX_reg(context) ))
179 SET_AX( context, 0x8022 ); /* invalid selector */
180 SET_CFLAG( context );
182 else
184 /* If a segment register contains the selector being freed, */
185 /* set it to zero. */
186 if (!((context->SegDs^BX_reg(context)) & ~3)) context->SegDs = 0;
187 if (!((context->SegEs^BX_reg(context)) & ~3)) context->SegEs = 0;
188 if (!((context->SegFs^BX_reg(context)) & ~3)) context->SegFs = 0;
189 if (!((context->SegGs^BX_reg(context)) & ~3)) context->SegGs = 0;
191 break;
193 case 0x0002: /* Real mode segment to descriptor */
194 TRACE( "real mode segment to descriptor (0x%04x)\n", BX_reg(context) );
196 WORD entryPoint = 0; /* KERNEL entry point for descriptor */
197 switch(BX_reg(context))
199 case 0x0000: entryPoint = 183; break; /* __0000H */
200 case 0x0040: entryPoint = 193; break; /* __0040H */
201 case 0xa000: entryPoint = 174; break; /* __A000H */
202 case 0xb000: entryPoint = 181; break; /* __B000H */
203 case 0xb800: entryPoint = 182; break; /* __B800H */
204 case 0xc000: entryPoint = 195; break; /* __C000H */
205 case 0xd000: entryPoint = 179; break; /* __D000H */
206 case 0xe000: entryPoint = 190; break; /* __E000H */
207 case 0xf000: entryPoint = 194; break; /* __F000H */
208 default:
209 FIXME("Real mode segment (%x) to descriptor: no longer supported\n",
210 BX_reg(context));
211 SET_CFLAG( context );
212 break;
214 if (entryPoint)
216 FARPROC16 proc = GetProcAddress16( GetModuleHandle16( "KERNEL" ),
217 (LPCSTR)(ULONG_PTR)entryPoint );
218 SET_AX( context, LOWORD(proc) );
221 break;
223 case 0x0003: /* Get next selector increment */
224 TRACE("get selector increment (__AHINCR)\n");
225 context->Eax = __AHINCR;
226 break;
228 case 0x0004: /* Lock selector (not supported) */
229 FIXME("lock selector not supported\n");
230 context->Eax = 0; /* FIXME: is this a correct return value? */
231 break;
233 case 0x0005: /* Unlock selector (not supported) */
234 FIXME("unlock selector not supported\n");
235 context->Eax = 0; /* FIXME: is this a correct return value? */
236 break;
238 case 0x0006: /* Get selector base address */
239 TRACE( "get selector base address (0x%04x)\n", BX_reg(context) );
240 if (!ldt_is_valid( BX_reg(context) ))
242 context->Eax = 0x8022; /* invalid selector */
243 SET_CFLAG(context);
245 else
247 void *base = ldt_get_base( BX_reg(context) );
248 SET_CX( context, HIWORD(base) );
249 SET_DX( context, LOWORD(base) );
251 break;
253 case 0x0007: /* Set selector base address */
255 DWORD base = MAKELONG( DX_reg(context), CX_reg(context) );
256 WORD sel = BX_reg(context);
257 TRACE( "set selector base address (0x%04x,0x%08x)\n", sel, base );
259 /* check if Win16 app wants to access lower 64K of DOS memory */
260 if (base < 0x10000) DOSMEM_MapDosLayout();
262 SetSelectorBase( sel, base );
264 break;
266 case 0x0008: /* Set selector limit */
268 DWORD limit = MAKELONG( DX_reg(context), CX_reg(context) );
269 TRACE( "set selector limit (0x%04x,0x%08x)\n",
270 BX_reg(context), limit );
271 SetSelectorLimit16( BX_reg(context), limit );
273 break;
275 case 0x0009: /* Set selector access rights */
276 TRACE( "set selector access rights(0x%04x,0x%04x)\n",
277 BX_reg(context), CX_reg(context) );
278 SelectorAccessRights16( BX_reg(context), 1, CX_reg(context) );
279 break;
281 case 0x000a: /* Allocate selector alias */
282 TRACE( "allocate selector alias (0x%04x)\n", BX_reg(context) );
283 SET_AX( context, AllocCStoDSAlias16( BX_reg(context) ) );
284 if (!AX_reg(context))
286 SET_AX( context, 0x8011 ); /* descriptor unavailable */
287 SET_CFLAG(context);
289 break;
291 case 0x000b: /* Get descriptor */
292 TRACE( "get descriptor (0x%04x)\n", BX_reg(context) );
294 LDT_ENTRY *entry = CTX_SEG_OFF_TO_LIN( context, context->SegEs,
295 context->Edi );
296 ldt_get_entry( BX_reg(context), entry );
298 break;
300 case 0x000c: /* Set descriptor */
301 TRACE( "set descriptor (0x%04x)\n", BX_reg(context) );
303 LDT_ENTRY *entry = CTX_SEG_OFF_TO_LIN( context, context->SegEs,
304 context->Edi );
305 if (!ldt_is_system( BX_reg(context) )) ldt_set_entry( BX_reg(context), *entry );
307 break;
309 case 0x000d: /* Allocate specific LDT descriptor */
310 FIXME( "allocate descriptor (0x%04x), stub!\n", BX_reg(context) );
311 SET_AX( context, 0x8011 ); /* descriptor unavailable */
312 SET_CFLAG( context );
313 break;
315 case 0x000e: /* Get Multiple Descriptors (1.0) */
316 FIXME( "get multiple descriptors - unimplemented\n" );
317 break;
319 case 0x000f: /* Set Multiple Descriptors (1.0) */
320 FIXME( "set multiple descriptors - unimplemented\n" );
321 break;
323 case 0x0100: /* Allocate DOS memory block */
324 TRACE( "allocate DOS memory block (0x%x paragraphs)\n", BX_reg(context) );
326 DWORD dw = GlobalDOSAlloc16( (DWORD)BX_reg(context) << 4 );
327 if (dw) {
328 SET_AX( context, HIWORD(dw) );
329 SET_DX( context, LOWORD(dw) );
330 } else {
331 SET_AX( context, 0x0008 ); /* insufficient memory */
332 SET_BX( context, DOSMEM_Available() >> 4 );
333 SET_CFLAG(context);
335 break;
338 case 0x0101: /* Free DOS memory block */
339 TRACE( "free DOS memory block (0x%04x)\n", DX_reg(context) );
341 WORD error = GlobalDOSFree16( DX_reg(context) );
342 if (error) {
343 SET_AX( context, 0x0009 ); /* memory block address invalid */
344 SET_CFLAG( context );
347 break;
349 case 0x0102: /* Resize DOS Memory Block */
350 FIXME( "resize DOS memory block (0x%04x, 0x%x paragraphs) - unimplemented\n",
351 DX_reg(context), BX_reg(context) );
352 break;
354 case 0x0200: /* get real mode interrupt vector */
355 TRACE( "get realmode interrupt vector (0x%02x) - not supported\n",
356 BL_reg(context) );
357 SET_CX( context, 0 );
358 SET_DX( context, 0 );
359 break;
361 case 0x0201: /* set real mode interrupt vector */
362 TRACE( "set realmode interrupt vector (0x%02x, 0x%04x:0x%04x) - not supported\n",
363 BL_reg(context), CX_reg(context), DX_reg(context) );
364 break;
366 case 0x0202: /* Get Processor Exception Handler Vector */
367 FIXME( "Get Processor Exception Handler Vector (0x%02x)\n",
368 BL_reg(context) );
369 SET_CX( context, 0 );
370 SET_DX( context, 0 );
371 break;
373 case 0x0203: /* Set Processor Exception Handler Vector */
374 FIXME( "Set Processor Exception Handler Vector (0x%02x)\n",
375 BL_reg(context) );
376 break;
378 case 0x0204: /* Get protected mode interrupt vector */
379 TRACE("get protected mode interrupt handler (0x%02x)\n",
380 BL_reg(context));
382 FARPROC16 handler = DOSVM_GetPMHandler16( BL_reg(context) );
383 SET_CX( context, SELECTOROF(handler) );
384 SET_DX( context, OFFSETOF(handler) );
386 break;
388 case 0x0205: /* Set protected mode interrupt vector */
389 TRACE("set protected mode interrupt handler (0x%02x,0x%04x:0x%08x)\n",
390 BL_reg(context), CX_reg(context), context->Edx);
392 FARPROC16 handler;
393 handler = (FARPROC16)MAKESEGPTR( CX_reg(context), DX_reg(context));
394 DOSVM_SetPMHandler16( BL_reg(context), handler );
396 break;
398 case 0x0300: /* Simulate real mode interrupt */
399 TRACE( "Simulate real mode interrupt %02x - not supported\n", BL_reg(context));
400 break;
402 case 0x0301: /* Call real mode procedure with far return */
403 TRACE( "Call real mode procedure with far return - not supported\n" );
404 break;
406 case 0x0302: /* Call real mode procedure with interrupt return */
407 TRACE( "Call real mode procedure with interrupt return - not supported\n" );
408 break;
410 case 0x0303: /* Allocate Real Mode Callback Address */
411 TRACE( "Allocate real mode callback address - not supported\n" );
412 break;
414 case 0x0304: /* Free Real Mode Callback Address */
415 TRACE( "Free real mode callback address - not supported\n" );
416 break;
418 case 0x0305: /* Get State Save/Restore Addresses */
419 TRACE("get state save/restore addresses - no longer supported\n");
420 /* we probably won't need this kind of state saving */
421 SET_AX( context, 0 );
422 /* real mode */
423 SET_BX( context, 0 );
424 SET_CX( context, 0 );
425 /* protected mode */
426 SET_SI( context, 0 );
427 context->Edi = 0;
428 break;
430 case 0x0306: /* Get Raw Mode Switch Addresses */
431 TRACE("get raw mode switch addresses - no longer supported\n");
432 /* real mode */
433 SET_BX( context, 0 );
434 SET_CX( context, 0 );
435 /* protected mode */
436 SET_SI( context, 0 );
437 context->Edi = 0;
438 break;
440 case 0x0400: /* Get DPMI version */
441 TRACE("get DPMI version\n");
443 SYSTEM_INFO si;
445 GetSystemInfo(&si);
446 SET_AX( context, 0x005a ); /* DPMI version 0.90 */
447 SET_BX( context, 0x0005 ); /* Flags: 32-bit, virtual memory */
448 SET_CL( context, si.wProcessorLevel );
449 SET_DX( context, 0x0870 ); /* Master/slave interrupt controller base */
451 break;
453 case 0x0401: /* Get DPMI Capabilities (1.0) */
454 FIXME( "get dpmi capabilities - unimplemented\n");
455 break;
457 case 0x0500: /* Get free memory information */
458 TRACE("get free memory information\n");
460 MEMORYSTATUS status;
461 SYSTEM_BASIC_INFORMATION sbi;
463 /* the layout is just the same as MEMMANINFO, but without
464 * the dwSize entry.
466 struct
468 DWORD dwLargestFreeBlock;
469 DWORD dwMaxPagesAvailable;
470 DWORD dwMaxPagesLockable;
471 DWORD dwTotalLinearSpace;
472 DWORD dwTotalUnlockedPages;
473 DWORD dwFreePages;
474 DWORD dwTotalPages;
475 DWORD dwFreeLinearSpace;
476 DWORD dwSwapFilePages;
477 WORD wPageSize;
478 } *info = CTX_SEG_OFF_TO_LIN( context, context->SegEs, context->Edi );
480 GlobalMemoryStatus( &status );
481 NtQuerySystemInformation( SystemBasicInformation, &sbi, sizeof(sbi), NULL );
483 info->wPageSize = sbi.PageSize;
484 info->dwLargestFreeBlock = status.dwAvailVirtual;
485 info->dwMaxPagesAvailable = info->dwLargestFreeBlock / info->wPageSize;
486 info->dwMaxPagesLockable = info->dwMaxPagesAvailable;
487 info->dwTotalLinearSpace = status.dwTotalVirtual / info->wPageSize;
488 info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
489 info->dwFreePages = info->dwMaxPagesAvailable;
490 info->dwTotalPages = info->dwTotalLinearSpace;
491 info->dwFreeLinearSpace = info->dwMaxPagesAvailable;
492 info->dwSwapFilePages = status.dwTotalPageFile / info->wPageSize;
493 break;
496 case 0x0501: /* Allocate memory block */
498 DWORD size = MAKELONG( CX_reg(context), BX_reg(context) );
499 BYTE *ptr;
501 TRACE( "allocate memory block (%u bytes)\n", size );
503 ptr = DPMI_xalloc( size );
504 if (!ptr)
506 SET_AX( context, 0x8012 ); /* linear memory not available */
507 SET_CFLAG(context);
509 else
511 SET_BX( context, HIWORD(ptr) );
512 SET_CX( context, LOWORD(ptr) );
513 SET_SI( context, HIWORD(ptr) );
514 SET_DI( context, LOWORD(ptr) );
516 break;
519 case 0x0502: /* Free memory block */
521 DWORD handle = MAKELONG( DI_reg(context), SI_reg(context) );
522 TRACE( "free memory block (0x%08x)\n", handle );
523 DPMI_xfree( (void *)handle );
525 break;
527 case 0x0503: /* Resize memory block */
529 DWORD size = MAKELONG( CX_reg(context), BX_reg(context) );
530 DWORD handle = MAKELONG( DI_reg(context), SI_reg(context) );
531 BYTE *ptr;
533 TRACE( "resize memory block (0x%08x, %u bytes)\n", handle, size );
535 ptr = DPMI_xrealloc( (void *)handle, size );
536 if (!ptr)
538 SET_AX( context, 0x8012 ); /* linear memory not available */
539 SET_CFLAG(context);
540 } else {
541 SET_BX( context, HIWORD(ptr) );
542 SET_CX( context, LOWORD(ptr) );
543 SET_SI( context, HIWORD(ptr) );
544 SET_DI( context, LOWORD(ptr) );
547 break;
549 case 0x0507: /* Set page attributes (1.0) */
550 FIXME( "set page attributes - unimplemented\n" );
551 break; /* Just ignore it */
553 case 0x0600: /* Lock linear region */
554 TRACE( "lock linear region - ignored (no paging)\n" );
555 break;
557 case 0x0601: /* Unlock linear region */
558 TRACE( "unlock linear region - ignored (no paging)\n" );
559 break;
561 case 0x0602: /* Mark real mode region as pageable */
562 TRACE( "mark real mode region as pageable - ignored (no paging)\n" );
563 break;
565 case 0x0603: /* Relock real mode region */
566 TRACE( "relock real mode region - ignored (no paging)\n" );
567 break;
569 case 0x0604: /* Get page size */
571 SYSTEM_BASIC_INFORMATION info;
572 TRACE("get pagesize\n");
573 NtQuerySystemInformation( SystemBasicInformation, &info, sizeof(info), NULL );
574 SET_BX( context, HIWORD(info.PageSize) );
575 SET_CX( context, LOWORD(info.PageSize) );
576 break;
578 case 0x0700: /* Mark pages as paging candidates */
579 TRACE( "mark pages as paging candidates - ignored (no paging)\n" );
580 break;
582 case 0x0701: /* Discard pages */
583 TRACE( "discard pages - ignored (no paging)\n" );
584 break;
586 case 0x0702: /* Mark page as demand-paging candidate */
587 TRACE( "mark page as demand-paging candidate - ignored (no paging)\n" );
588 break;
590 case 0x0703: /* Discard page contents */
591 TRACE( "discard page contents - ignored (no paging)\n" );
592 break;
594 case 0x0800: /* Physical address mapping */
595 FIXME( "physical address mapping (0x%08x) - unimplemented\n",
596 MAKELONG(CX_reg(context),BX_reg(context)) );
597 break;
599 case 0x0900: /* Get and Disable Virtual Interrupt State */
600 TRACE( "Get and Disable Virtual Interrupt State - not supported\n" );
601 break;
603 case 0x0901: /* Get and Enable Virtual Interrupt State */
604 TRACE( "Get and Enable Virtual Interrupt State - not supported\n" );
605 break;
607 case 0x0902: /* Get Virtual Interrupt State */
608 TRACE( "Get Virtual Interrupt State - not supported\n" );
609 break;
611 case 0x0e00: /* Get Coprocessor Status (1.0) */
613 * Return status in AX bits:
614 * B0 - MPv (MP bit in the virtual MSW/CR0)
615 * 0 = numeric coprocessor is disabled for this client
616 * 1 = numeric coprocessor is enabled for this client
617 * B1 - EMv (EM bit in the virtual MSW/CR0)
618 * 0 = client is not emulating coprocessor instructions
619 * 1 = client is emulating coprocessor instructions
620 * B2 - MPr (MP bit from the actual MSW/CR0)
621 * 0 = numeric coprocessor is not present
622 * 1 = numeric coprocessor is present
623 * B3 - EMr (EM bit from the actual MSW/CR0)
624 * 0 = host is not emulating coprocessor instructions
625 * 1 = host is emulating coprocessor instructions
626 * B4-B7 - coprocessor type
627 * 00H = no coprocessor
628 * 02H = 80287
629 * 03H = 80387
630 * 04H = 80486 with numeric coprocessor
631 * 05H-0FH = reserved for future numeric processors
633 TRACE( "Get Coprocessor Status\n" );
634 SET_AX( context, 69 ); /* 486, coprocessor present and enabled */
635 break;
637 case 0x0e01: /* Set Coprocessor Emulation (1.0) */
639 * See function 0x0e00.
640 * BX bit B0 is new value for MPv.
641 * BX bit B1 is new value for EMv.
643 if (BX_reg(context) != 1)
644 FIXME( "Set Coprocessor Emulation to %d - unimplemented\n",
645 BX_reg(context) );
646 else
647 TRACE( "Set Coprocessor Emulation - ignored\n" );
648 break;
650 default:
651 INT_BARF( context, 0x31 );
652 SET_AX( context, 0x8001 ); /* unsupported function */
653 SET_CFLAG(context);
654 break;