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
22 #include "wine/port.h"
29 #include "wine/winbase16.h"
31 #include "kernel16_private.h"
35 #include "wine/debug.h"
36 #include "wine/exception.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(int31
);
40 static void* lastvalloced
= NULL
;
42 /**********************************************************************
44 * special virtualalloc, allocates linearly monoton growing memory.
45 * (the usual VirtualAlloc does not satisfy that restriction)
47 static LPVOID
DPMI_xalloc( DWORD len
)
50 LPVOID oldlastv
= lastvalloced
;
59 ret
= VirtualAlloc( lastvalloced
, len
,
60 MEM_COMMIT
|MEM_RESERVE
, PAGE_EXECUTE_READWRITE
);
62 lastvalloced
= (char *) lastvalloced
+ 0x10000;
64 /* we failed to allocate one in the first round.
67 if (!xflag
&& (lastvalloced
<oldlastv
))
70 FIXME( "failed to allocate linearly growing memory (%u bytes), "
71 "using non-linear growing...\n", len
);
75 /* if we even fail to allocate something in the next
78 if ((xflag
==1) && (lastvalloced
>= oldlastv
))
81 if ((xflag
==2) && (lastvalloced
< oldlastv
)) {
82 FIXME( "failed to allocate any memory of %u bytes!\n", len
);
89 ret
= VirtualAlloc( NULL
, len
,
90 MEM_COMMIT
|MEM_RESERVE
, PAGE_EXECUTE_READWRITE
);
93 lastvalloced
= (LPVOID
)(((DWORD
)ret
+len
+0xffff)&~0xffff);
97 /**********************************************************************
100 static void DPMI_xfree( LPVOID ptr
)
102 VirtualFree( ptr
, 0, MEM_RELEASE
);
105 /**********************************************************************
108 * FIXME: perhaps we could grow this mapped area...
110 static LPVOID
DPMI_xrealloc( LPVOID ptr
, DWORD newsize
)
112 MEMORY_BASIC_INFORMATION mbi
;
118 if (!VirtualQuery(ptr
,&mbi
,sizeof(mbi
)))
120 FIXME( "realloc of DPMI_xallocd region %p?\n", ptr
);
124 if (mbi
.State
== MEM_FREE
)
126 FIXME( "realloc of DPMI_xallocd region %p?\n", ptr
);
130 /* We do not shrink allocated memory. most reallocs
131 * only do grows anyway
133 if (newsize
<= mbi
.RegionSize
)
136 newptr
= DPMI_xalloc( newsize
);
140 memcpy( newptr
, ptr
, mbi
.RegionSize
);
146 return DPMI_xalloc( newsize
);
150 /**********************************************************************
153 * Handler for int 31h (DPMI).
155 void WINAPI
DOSVM_Int31Handler( CONTEXT
*context
)
157 RESET_CFLAG(context
);
158 switch(AX_reg(context
))
160 case 0x0000: /* Allocate LDT descriptors */
161 TRACE( "allocate LDT descriptors (%d)\n", CX_reg(context
) );
163 WORD sel
= AllocSelectorArray16( CX_reg(context
) );
167 SET_AX( context
, 0x8011 ); /* descriptor unavailable */
168 SET_CFLAG( context
);
172 TRACE( "success, array starts at 0x%04x\n", sel
);
173 SET_AX( context
, sel
);
178 case 0x0001: /* Free LDT descriptor */
179 TRACE( "free LDT descriptor (0x%04x)\n", BX_reg(context
) );
180 if (FreeSelector16( BX_reg(context
) ))
182 SET_AX( context
, 0x8022 ); /* invalid selector */
183 SET_CFLAG( context
);
187 /* If a segment register contains the selector being freed, */
188 /* set it to zero. */
189 if (!((context
->SegDs
^BX_reg(context
)) & ~3)) context
->SegDs
= 0;
190 if (!((context
->SegEs
^BX_reg(context
)) & ~3)) context
->SegEs
= 0;
191 if (!((context
->SegFs
^BX_reg(context
)) & ~3)) context
->SegFs
= 0;
192 if (!((context
->SegGs
^BX_reg(context
)) & ~3)) context
->SegGs
= 0;
196 case 0x0002: /* Real mode segment to descriptor */
197 TRACE( "real mode segment to descriptor (0x%04x)\n", BX_reg(context
) );
199 WORD entryPoint
= 0; /* KERNEL entry point for descriptor */
200 switch(BX_reg(context
))
202 case 0x0000: entryPoint
= 183; break; /* __0000H */
203 case 0x0040: entryPoint
= 193; break; /* __0040H */
204 case 0xa000: entryPoint
= 174; break; /* __A000H */
205 case 0xb000: entryPoint
= 181; break; /* __B000H */
206 case 0xb800: entryPoint
= 182; break; /* __B800H */
207 case 0xc000: entryPoint
= 195; break; /* __C000H */
208 case 0xd000: entryPoint
= 179; break; /* __D000H */
209 case 0xe000: entryPoint
= 190; break; /* __E000H */
210 case 0xf000: entryPoint
= 194; break; /* __F000H */
212 FIXME("Real mode segment (%x) to descriptor: no longer supported\n",
214 SET_CFLAG( context
);
219 FARPROC16 proc
= GetProcAddress16( GetModuleHandle16( "KERNEL" ),
220 (LPCSTR
)(ULONG_PTR
)entryPoint
);
221 SET_AX( context
, LOWORD(proc
) );
226 case 0x0003: /* Get next selector increment */
227 TRACE("get selector increment (__AHINCR)\n");
228 context
->Eax
= __AHINCR
;
231 case 0x0004: /* Lock selector (not supported) */
232 FIXME("lock selector not supported\n");
233 context
->Eax
= 0; /* FIXME: is this a correct return value? */
236 case 0x0005: /* Unlock selector (not supported) */
237 FIXME("unlock selector not supported\n");
238 context
->Eax
= 0; /* FIXME: is this a correct return value? */
241 case 0x0006: /* Get selector base address */
242 TRACE( "get selector base address (0x%04x)\n", BX_reg(context
) );
245 WORD sel
= BX_reg(context
);
246 wine_ldt_get_entry( sel
, &entry
);
247 if (wine_ldt_is_empty(&entry
))
249 context
->Eax
= 0x8022; /* invalid selector */
254 void *base
= wine_ldt_get_base(&entry
);
255 SET_CX( context
, HIWORD(base
) );
256 SET_DX( context
, LOWORD(base
) );
261 case 0x0007: /* Set selector base address */
263 DWORD base
= MAKELONG( DX_reg(context
), CX_reg(context
) );
264 WORD sel
= BX_reg(context
);
265 TRACE( "set selector base address (0x%04x,0x%08x)\n", sel
, base
);
267 /* check if Win16 app wants to access lower 64K of DOS memory */
268 if (base
< 0x10000) DOSMEM_MapDosLayout();
270 SetSelectorBase( sel
, base
);
274 case 0x0008: /* Set selector limit */
276 DWORD limit
= MAKELONG( DX_reg(context
), CX_reg(context
) );
277 TRACE( "set selector limit (0x%04x,0x%08x)\n",
278 BX_reg(context
), limit
);
279 SetSelectorLimit16( BX_reg(context
), limit
);
283 case 0x0009: /* Set selector access rights */
284 TRACE( "set selector access rights(0x%04x,0x%04x)\n",
285 BX_reg(context
), CX_reg(context
) );
286 SelectorAccessRights16( BX_reg(context
), 1, CX_reg(context
) );
289 case 0x000a: /* Allocate selector alias */
290 TRACE( "allocate selector alias (0x%04x)\n", BX_reg(context
) );
291 SET_AX( context
, AllocCStoDSAlias16( BX_reg(context
) ) );
292 if (!AX_reg(context
))
294 SET_AX( context
, 0x8011 ); /* descriptor unavailable */
299 case 0x000b: /* Get descriptor */
300 TRACE( "get descriptor (0x%04x)\n", BX_reg(context
) );
302 LDT_ENTRY
*entry
= CTX_SEG_OFF_TO_LIN( context
, context
->SegEs
,
304 wine_ldt_get_entry( BX_reg(context
), entry
);
308 case 0x000c: /* Set descriptor */
309 TRACE( "set descriptor (0x%04x)\n", BX_reg(context
) );
311 LDT_ENTRY
*entry
= CTX_SEG_OFF_TO_LIN( context
, context
->SegEs
,
313 wine_ldt_set_entry( BX_reg(context
), entry
);
317 case 0x000d: /* Allocate specific LDT descriptor */
318 FIXME( "allocate descriptor (0x%04x), stub!\n", BX_reg(context
) );
319 SET_AX( context
, 0x8011 ); /* descriptor unavailable */
320 SET_CFLAG( context
);
323 case 0x000e: /* Get Multiple Descriptors (1.0) */
324 FIXME( "get multiple descriptors - unimplemented\n" );
327 case 0x000f: /* Set Multiple Descriptors (1.0) */
328 FIXME( "set multiple descriptors - unimplemented\n" );
331 case 0x0100: /* Allocate DOS memory block */
332 TRACE( "allocate DOS memory block (0x%x paragraphs)\n", BX_reg(context
) );
334 DWORD dw
= GlobalDOSAlloc16( (DWORD
)BX_reg(context
) << 4 );
336 SET_AX( context
, HIWORD(dw
) );
337 SET_DX( context
, LOWORD(dw
) );
339 SET_AX( context
, 0x0008 ); /* insufficient memory */
340 SET_BX( context
, DOSMEM_Available() >> 4 );
346 case 0x0101: /* Free DOS memory block */
347 TRACE( "free DOS memory block (0x%04x)\n", DX_reg(context
) );
349 WORD error
= GlobalDOSFree16( DX_reg(context
) );
351 SET_AX( context
, 0x0009 ); /* memory block address invalid */
352 SET_CFLAG( context
);
357 case 0x0102: /* Resize DOS Memory Block */
358 FIXME( "resize DOS memory block (0x%04x, 0x%x paragraphs) - unimplemented\n",
359 DX_reg(context
), BX_reg(context
) );
362 case 0x0200: /* get real mode interrupt vector */
363 TRACE( "get realmode interrupt vector (0x%02x) - not supported\n",
365 SET_CX( context
, 0 );
366 SET_DX( context
, 0 );
369 case 0x0201: /* set real mode interrupt vector */
370 TRACE( "set realmode interrupt vector (0x%02x, 0x%04x:0x%04x) - not supported\n",
371 BL_reg(context
), CX_reg(context
), DX_reg(context
) );
374 case 0x0202: /* Get Processor Exception Handler Vector */
375 FIXME( "Get Processor Exception Handler Vector (0x%02x)\n",
377 SET_CX( context
, 0 );
378 SET_DX( context
, 0 );
381 case 0x0203: /* Set Processor Exception Handler Vector */
382 FIXME( "Set Processor Exception Handler Vector (0x%02x)\n",
386 case 0x0204: /* Get protected mode interrupt vector */
387 TRACE("get protected mode interrupt handler (0x%02x)\n",
390 FARPROC16 handler
= DOSVM_GetPMHandler16( BL_reg(context
) );
391 SET_CX( context
, SELECTOROF(handler
) );
392 SET_DX( context
, OFFSETOF(handler
) );
396 case 0x0205: /* Set protected mode interrupt vector */
397 TRACE("set protected mode interrupt handler (0x%02x,0x%04x:0x%08x)\n",
398 BL_reg(context
), CX_reg(context
), context
->Edx
);
401 handler
= (FARPROC16
)MAKESEGPTR( CX_reg(context
), DX_reg(context
));
402 DOSVM_SetPMHandler16( BL_reg(context
), handler
);
406 case 0x0300: /* Simulate real mode interrupt */
407 TRACE( "Simulate real mode interrupt %02x - not supported\n", BL_reg(context
));
410 case 0x0301: /* Call real mode procedure with far return */
411 TRACE( "Call real mode procedure with far return - not supported\n" );
414 case 0x0302: /* Call real mode procedure with interrupt return */
415 TRACE( "Call real mode procedure with interrupt return - not supported\n" );
418 case 0x0303: /* Allocate Real Mode Callback Address */
419 TRACE( "Allocate real mode callback address - not supported\n" );
422 case 0x0304: /* Free Real Mode Callback Address */
423 TRACE( "Free real mode callback address - not supported\n" );
426 case 0x0305: /* Get State Save/Restore Addresses */
427 TRACE("get state save/restore addresses - no longer supported\n");
428 /* we probably won't need this kind of state saving */
429 SET_AX( context
, 0 );
431 SET_BX( context
, 0 );
432 SET_CX( context
, 0 );
434 SET_SI( context
, 0 );
438 case 0x0306: /* Get Raw Mode Switch Addresses */
439 TRACE("get raw mode switch addresses - no longer supported\n");
441 SET_BX( context
, 0 );
442 SET_CX( context
, 0 );
444 SET_SI( context
, 0 );
448 case 0x0400: /* Get DPMI version */
449 TRACE("get DPMI version\n");
454 SET_AX( context
, 0x005a ); /* DPMI version 0.90 */
455 SET_BX( context
, 0x0005 ); /* Flags: 32-bit, virtual memory */
456 SET_CL( context
, si
.wProcessorLevel
);
457 SET_DX( context
, 0x0870 ); /* Master/slave interrupt controller base */
461 case 0x0401: /* Get DPMI Capabilities (1.0) */
462 FIXME( "get dpmi capabilities - unimplemented\n");
465 case 0x0500: /* Get free memory information */
466 TRACE("get free memory information\n");
469 SYSTEM_BASIC_INFORMATION sbi
;
471 /* the layout is just the same as MEMMANINFO, but without
476 DWORD dwLargestFreeBlock
;
477 DWORD dwMaxPagesAvailable
;
478 DWORD dwMaxPagesLockable
;
479 DWORD dwTotalLinearSpace
;
480 DWORD dwTotalUnlockedPages
;
483 DWORD dwFreeLinearSpace
;
484 DWORD dwSwapFilePages
;
486 } *info
= CTX_SEG_OFF_TO_LIN( context
, context
->SegEs
, context
->Edi
);
488 GlobalMemoryStatus( &status
);
489 NtQuerySystemInformation( SystemBasicInformation
, &sbi
, sizeof(sbi
), NULL
);
491 info
->wPageSize
= sbi
.PageSize
;
492 info
->dwLargestFreeBlock
= status
.dwAvailVirtual
;
493 info
->dwMaxPagesAvailable
= info
->dwLargestFreeBlock
/ info
->wPageSize
;
494 info
->dwMaxPagesLockable
= info
->dwMaxPagesAvailable
;
495 info
->dwTotalLinearSpace
= status
.dwTotalVirtual
/ info
->wPageSize
;
496 info
->dwTotalUnlockedPages
= info
->dwTotalLinearSpace
;
497 info
->dwFreePages
= info
->dwMaxPagesAvailable
;
498 info
->dwTotalPages
= info
->dwTotalLinearSpace
;
499 info
->dwFreeLinearSpace
= info
->dwMaxPagesAvailable
;
500 info
->dwSwapFilePages
= status
.dwTotalPageFile
/ info
->wPageSize
;
504 case 0x0501: /* Allocate memory block */
506 DWORD size
= MAKELONG( CX_reg(context
), BX_reg(context
) );
509 TRACE( "allocate memory block (%u bytes)\n", size
);
511 ptr
= DPMI_xalloc( size
);
514 SET_AX( context
, 0x8012 ); /* linear memory not available */
519 SET_BX( context
, HIWORD(ptr
) );
520 SET_CX( context
, LOWORD(ptr
) );
521 SET_SI( context
, HIWORD(ptr
) );
522 SET_DI( context
, LOWORD(ptr
) );
527 case 0x0502: /* Free memory block */
529 DWORD handle
= MAKELONG( DI_reg(context
), SI_reg(context
) );
530 TRACE( "free memory block (0x%08x)\n", handle
);
531 DPMI_xfree( (void *)handle
);
535 case 0x0503: /* Resize memory block */
537 DWORD size
= MAKELONG( CX_reg(context
), BX_reg(context
) );
538 DWORD handle
= MAKELONG( DI_reg(context
), SI_reg(context
) );
541 TRACE( "resize memory block (0x%08x, %u bytes)\n", handle
, size
);
543 ptr
= DPMI_xrealloc( (void *)handle
, size
);
546 SET_AX( context
, 0x8012 ); /* linear memory not available */
549 SET_BX( context
, HIWORD(ptr
) );
550 SET_CX( context
, LOWORD(ptr
) );
551 SET_SI( context
, HIWORD(ptr
) );
552 SET_DI( context
, LOWORD(ptr
) );
557 case 0x0507: /* Set page attributes (1.0) */
558 FIXME( "set page attributes - unimplemented\n" );
559 break; /* Just ignore it */
561 case 0x0600: /* Lock linear region */
562 TRACE( "lock linear region - ignored (no paging)\n" );
565 case 0x0601: /* Unlock linear region */
566 TRACE( "unlock linear region - ignored (no paging)\n" );
569 case 0x0602: /* Mark real mode region as pageable */
570 TRACE( "mark real mode region as pageable - ignored (no paging)\n" );
573 case 0x0603: /* Relock real mode region */
574 TRACE( "relock real mode region - ignored (no paging)\n" );
577 case 0x0604: /* Get page size */
579 SYSTEM_BASIC_INFORMATION info
;
580 TRACE("get pagesize\n");
581 NtQuerySystemInformation( SystemBasicInformation
, &info
, sizeof(info
), NULL
);
582 SET_BX( context
, HIWORD(info
.PageSize
) );
583 SET_CX( context
, LOWORD(info
.PageSize
) );
586 case 0x0700: /* Mark pages as paging candidates */
587 TRACE( "mark pages as paging candidates - ignored (no paging)\n" );
590 case 0x0701: /* Discard pages */
591 TRACE( "discard pages - ignored (no paging)\n" );
594 case 0x0702: /* Mark page as demand-paging candidate */
595 TRACE( "mark page as demand-paging candidate - ignored (no paging)\n" );
598 case 0x0703: /* Discard page contents */
599 TRACE( "discard page contents - ignored (no paging)\n" );
602 case 0x0800: /* Physical address mapping */
603 FIXME( "physical address mapping (0x%08x) - unimplemented\n",
604 MAKELONG(CX_reg(context
),BX_reg(context
)) );
607 case 0x0900: /* Get and Disable Virtual Interrupt State */
608 TRACE( "Get and Disable Virtual Interrupt State - not supported\n" );
611 case 0x0901: /* Get and Enable Virtual Interrupt State */
612 TRACE( "Get and Enable Virtual Interrupt State - not supported\n" );
615 case 0x0902: /* Get Virtual Interrupt State */
616 TRACE( "Get Virtual Interrupt State - not supported\n" );
619 case 0x0e00: /* Get Coprocessor Status (1.0) */
621 * Return status in AX bits:
622 * B0 - MPv (MP bit in the virtual MSW/CR0)
623 * 0 = numeric coprocessor is disabled for this client
624 * 1 = numeric coprocessor is enabled for this client
625 * B1 - EMv (EM bit in the virtual MSW/CR0)
626 * 0 = client is not emulating coprocessor instructions
627 * 1 = client is emulating coprocessor instructions
628 * B2 - MPr (MP bit from the actual MSW/CR0)
629 * 0 = numeric coprocessor is not present
630 * 1 = numeric coprocessor is present
631 * B3 - EMr (EM bit from the actual MSW/CR0)
632 * 0 = host is not emulating coprocessor instructions
633 * 1 = host is emulating coprocessor instructions
634 * B4-B7 - coprocessor type
635 * 00H = no coprocessor
638 * 04H = 80486 with numeric coprocessor
639 * 05H-0FH = reserved for future numeric processors
641 TRACE( "Get Coprocessor Status\n" );
642 SET_AX( context
, 69 ); /* 486, coprocessor present and enabled */
645 case 0x0e01: /* Set Coprocessor Emulation (1.0) */
647 * See function 0x0e00.
648 * BX bit B0 is new value for MPv.
649 * BX bit B1 is new value for EMv.
651 if (BX_reg(context
) != 1)
652 FIXME( "Set Coprocessor Emulation to %d - unimplemented\n",
655 TRACE( "Set Coprocessor Emulation - ignored\n" );
659 INT_BARF( context
, 0x31 );
660 SET_AX( context
, 0x8001 ); /* unsupported function */