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
26 #include "wine/winbase16.h"
28 #include "kernel16_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(int31
);
36 static void* lastvalloced
= NULL
;
38 /**********************************************************************
40 * special virtualalloc, allocates linearly monoton growing memory.
41 * (the usual VirtualAlloc does not satisfy that restriction)
43 static LPVOID
DPMI_xalloc( DWORD len
)
46 LPVOID oldlastv
= lastvalloced
;
55 ret
= VirtualAlloc( lastvalloced
, len
,
56 MEM_COMMIT
|MEM_RESERVE
, PAGE_EXECUTE_READWRITE
);
58 lastvalloced
= (char *) lastvalloced
+ 0x10000;
60 /* we failed to allocate one in the first round.
63 if (!xflag
&& (lastvalloced
<oldlastv
))
66 FIXME( "failed to allocate linearly growing memory (%lu bytes), "
67 "using non-linear growing...\n", len
);
71 /* if we even fail to allocate something in the next
74 if ((xflag
==1) && (lastvalloced
>= oldlastv
))
77 if ((xflag
==2) && (lastvalloced
< oldlastv
)) {
78 FIXME( "failed to allocate any memory of %lu bytes!\n", len
);
85 ret
= VirtualAlloc( NULL
, len
,
86 MEM_COMMIT
|MEM_RESERVE
, PAGE_EXECUTE_READWRITE
);
89 lastvalloced
= (LPVOID
)(((DWORD
)ret
+len
+0xffff)&~0xffff);
93 /**********************************************************************
96 static void DPMI_xfree( LPVOID ptr
)
98 VirtualFree( ptr
, 0, MEM_RELEASE
);
101 /**********************************************************************
104 * FIXME: perhaps we could grow this mapped area...
106 static LPVOID
DPMI_xrealloc( LPVOID ptr
, DWORD newsize
)
108 MEMORY_BASIC_INFORMATION mbi
;
114 if (!VirtualQuery(ptr
,&mbi
,sizeof(mbi
)))
116 FIXME( "realloc of DPMI_xallocd region %p?\n", ptr
);
120 if (mbi
.State
== MEM_FREE
)
122 FIXME( "realloc of DPMI_xallocd region %p?\n", ptr
);
126 /* We do not shrink allocated memory. most reallocs
127 * only do grows anyway
129 if (newsize
<= mbi
.RegionSize
)
132 newptr
= DPMI_xalloc( newsize
);
136 memcpy( newptr
, ptr
, mbi
.RegionSize
);
142 return DPMI_xalloc( newsize
);
146 /**********************************************************************
149 * Handler for int 31h (DPMI).
151 void WINAPI
DOSVM_Int31Handler( CONTEXT
*context
)
153 RESET_CFLAG(context
);
154 switch(AX_reg(context
))
156 case 0x0000: /* Allocate LDT descriptors */
157 TRACE( "allocate LDT descriptors (%d)\n", CX_reg(context
) );
159 WORD sel
= AllocSelectorArray16( CX_reg(context
) );
163 SET_AX( context
, 0x8011 ); /* descriptor unavailable */
164 SET_CFLAG( context
);
168 TRACE( "success, array starts at 0x%04x\n", sel
);
169 SET_AX( context
, sel
);
174 case 0x0001: /* Free LDT descriptor */
175 TRACE( "free LDT descriptor (0x%04x)\n", BX_reg(context
) );
176 if (FreeSelector16( BX_reg(context
) ))
178 SET_AX( context
, 0x8022 ); /* invalid selector */
179 SET_CFLAG( context
);
183 /* If a segment register contains the selector being freed, */
184 /* set it to zero. */
185 if (!((context
->SegDs
^BX_reg(context
)) & ~3)) context
->SegDs
= 0;
186 if (!((context
->SegEs
^BX_reg(context
)) & ~3)) context
->SegEs
= 0;
187 if (!((context
->SegFs
^BX_reg(context
)) & ~3)) context
->SegFs
= 0;
188 if (!((context
->SegGs
^BX_reg(context
)) & ~3)) context
->SegGs
= 0;
192 case 0x0002: /* Real mode segment to descriptor */
193 TRACE( "real mode segment to descriptor (0x%04x)\n", BX_reg(context
) );
195 WORD entryPoint
= 0; /* KERNEL entry point for descriptor */
196 switch(BX_reg(context
))
198 case 0x0000: entryPoint
= 183; break; /* __0000H */
199 case 0x0040: entryPoint
= 193; break; /* __0040H */
200 case 0xa000: entryPoint
= 174; break; /* __A000H */
201 case 0xb000: entryPoint
= 181; break; /* __B000H */
202 case 0xb800: entryPoint
= 182; break; /* __B800H */
203 case 0xc000: entryPoint
= 195; break; /* __C000H */
204 case 0xd000: entryPoint
= 179; break; /* __D000H */
205 case 0xe000: entryPoint
= 190; break; /* __E000H */
206 case 0xf000: entryPoint
= 194; break; /* __F000H */
208 FIXME("Real mode segment (%x) to descriptor: no longer supported\n",
210 SET_CFLAG( context
);
215 FARPROC16 proc
= GetProcAddress16( GetModuleHandle16( "KERNEL" ),
216 (LPCSTR
)(ULONG_PTR
)entryPoint
);
217 SET_AX( context
, LOWORD(proc
) );
222 case 0x0003: /* Get next selector increment */
223 TRACE("get selector increment (__AHINCR)\n");
224 context
->Eax
= __AHINCR
;
227 case 0x0004: /* Lock selector (not supported) */
228 FIXME("lock selector not supported\n");
229 context
->Eax
= 0; /* FIXME: is this a correct return value? */
232 case 0x0005: /* Unlock selector (not supported) */
233 FIXME("unlock selector not supported\n");
234 context
->Eax
= 0; /* FIXME: is this a correct return value? */
237 case 0x0006: /* Get selector base address */
238 TRACE( "get selector base address (0x%04x)\n", BX_reg(context
) );
239 if (!ldt_is_valid( BX_reg(context
) ))
241 context
->Eax
= 0x8022; /* invalid selector */
246 void *base
= ldt_get_base( BX_reg(context
) );
247 SET_CX( context
, HIWORD(base
) );
248 SET_DX( context
, LOWORD(base
) );
252 case 0x0007: /* Set selector base address */
254 DWORD base
= MAKELONG( DX_reg(context
), CX_reg(context
) );
255 WORD sel
= BX_reg(context
);
256 TRACE( "set selector base address (0x%04x,0x%08lx)\n", sel
, base
);
258 /* check if Win16 app wants to access lower 64K of DOS memory */
259 if (base
< 0x10000) DOSMEM_MapDosLayout();
261 SetSelectorBase( sel
, base
);
265 case 0x0008: /* Set selector limit */
267 DWORD limit
= MAKELONG( DX_reg(context
), CX_reg(context
) );
268 TRACE( "set selector limit (0x%04x,0x%08lx)\n",
269 BX_reg(context
), limit
);
270 SetSelectorLimit16( BX_reg(context
), limit
);
274 case 0x0009: /* Set selector access rights */
275 TRACE( "set selector access rights(0x%04x,0x%04x)\n",
276 BX_reg(context
), CX_reg(context
) );
277 SelectorAccessRights16( BX_reg(context
), 1, CX_reg(context
) );
280 case 0x000a: /* Allocate selector alias */
281 TRACE( "allocate selector alias (0x%04x)\n", BX_reg(context
) );
282 SET_AX( context
, AllocCStoDSAlias16( BX_reg(context
) ) );
283 if (!AX_reg(context
))
285 SET_AX( context
, 0x8011 ); /* descriptor unavailable */
290 case 0x000b: /* Get descriptor */
291 TRACE( "get descriptor (0x%04x)\n", BX_reg(context
) );
293 LDT_ENTRY
*entry
= CTX_SEG_OFF_TO_LIN( context
, context
->SegEs
,
295 ldt_get_entry( BX_reg(context
), entry
);
299 case 0x000c: /* Set descriptor */
300 TRACE( "set descriptor (0x%04x)\n", BX_reg(context
) );
302 LDT_ENTRY
*entry
= CTX_SEG_OFF_TO_LIN( context
, context
->SegEs
,
304 if (!ldt_is_system( BX_reg(context
) )) ldt_set_entry( BX_reg(context
), *entry
);
308 case 0x000d: /* Allocate specific LDT descriptor */
309 FIXME( "allocate descriptor (0x%04x), stub!\n", BX_reg(context
) );
310 SET_AX( context
, 0x8011 ); /* descriptor unavailable */
311 SET_CFLAG( context
);
314 case 0x000e: /* Get Multiple Descriptors (1.0) */
315 FIXME( "get multiple descriptors - unimplemented\n" );
318 case 0x000f: /* Set Multiple Descriptors (1.0) */
319 FIXME( "set multiple descriptors - unimplemented\n" );
322 case 0x0100: /* Allocate DOS memory block */
323 TRACE( "allocate DOS memory block (0x%x paragraphs)\n", BX_reg(context
) );
325 DWORD dw
= GlobalDOSAlloc16( (DWORD
)BX_reg(context
) << 4 );
327 SET_AX( context
, HIWORD(dw
) );
328 SET_DX( context
, LOWORD(dw
) );
330 SET_AX( context
, 0x0008 ); /* insufficient memory */
331 SET_BX( context
, DOSMEM_Available() >> 4 );
337 case 0x0101: /* Free DOS memory block */
338 TRACE( "free DOS memory block (0x%04x)\n", DX_reg(context
) );
340 WORD error
= GlobalDOSFree16( DX_reg(context
) );
342 SET_AX( context
, 0x0009 ); /* memory block address invalid */
343 SET_CFLAG( context
);
348 case 0x0102: /* Resize DOS Memory Block */
349 FIXME( "resize DOS memory block (0x%04x, 0x%x paragraphs) - unimplemented\n",
350 DX_reg(context
), BX_reg(context
) );
353 case 0x0200: /* get real mode interrupt vector */
354 TRACE( "get realmode interrupt vector (0x%02x) - not supported\n",
356 SET_CX( context
, 0 );
357 SET_DX( context
, 0 );
360 case 0x0201: /* set real mode interrupt vector */
361 TRACE( "set realmode interrupt vector (0x%02x, 0x%04x:0x%04x) - not supported\n",
362 BL_reg(context
), CX_reg(context
), DX_reg(context
) );
365 case 0x0202: /* Get Processor Exception Handler Vector */
366 FIXME( "Get Processor Exception Handler Vector (0x%02x)\n",
368 SET_CX( context
, 0 );
369 SET_DX( context
, 0 );
372 case 0x0203: /* Set Processor Exception Handler Vector */
373 FIXME( "Set Processor Exception Handler Vector (0x%02x)\n",
377 case 0x0204: /* Get protected mode interrupt vector */
378 TRACE("get protected mode interrupt handler (0x%02x)\n",
381 FARPROC16 handler
= DOSVM_GetPMHandler16( BL_reg(context
) );
382 SET_CX( context
, SELECTOROF(handler
) );
383 SET_DX( context
, OFFSETOF(handler
) );
387 case 0x0205: /* Set protected mode interrupt vector */
388 TRACE("set protected mode interrupt handler (0x%02x,0x%04x:0x%08lx)\n",
389 BL_reg(context
), CX_reg(context
), context
->Edx
);
392 handler
= (FARPROC16
)MAKESEGPTR( CX_reg(context
), DX_reg(context
));
393 DOSVM_SetPMHandler16( BL_reg(context
), handler
);
397 case 0x0300: /* Simulate real mode interrupt */
398 TRACE( "Simulate real mode interrupt %02x - not supported\n", BL_reg(context
));
401 case 0x0301: /* Call real mode procedure with far return */
402 TRACE( "Call real mode procedure with far return - not supported\n" );
405 case 0x0302: /* Call real mode procedure with interrupt return */
406 TRACE( "Call real mode procedure with interrupt return - not supported\n" );
409 case 0x0303: /* Allocate Real Mode Callback Address */
410 TRACE( "Allocate real mode callback address - not supported\n" );
413 case 0x0304: /* Free Real Mode Callback Address */
414 TRACE( "Free real mode callback address - not supported\n" );
417 case 0x0305: /* Get State Save/Restore Addresses */
418 TRACE("get state save/restore addresses - no longer supported\n");
419 /* we probably won't need this kind of state saving */
420 SET_AX( context
, 0 );
422 SET_BX( context
, 0 );
423 SET_CX( context
, 0 );
425 SET_SI( context
, 0 );
429 case 0x0306: /* Get Raw Mode Switch Addresses */
430 TRACE("get raw mode switch addresses - no longer supported\n");
432 SET_BX( context
, 0 );
433 SET_CX( context
, 0 );
435 SET_SI( context
, 0 );
439 case 0x0400: /* Get DPMI version */
440 TRACE("get DPMI version\n");
445 SET_AX( context
, 0x005a ); /* DPMI version 0.90 */
446 SET_BX( context
, 0x0005 ); /* Flags: 32-bit, virtual memory */
447 SET_CL( context
, si
.wProcessorLevel
);
448 SET_DX( context
, 0x0870 ); /* Interrupt controller base */
452 case 0x0401: /* Get DPMI Capabilities (1.0) */
453 FIXME( "get dpmi capabilities - unimplemented\n");
456 case 0x0500: /* Get free memory information */
457 TRACE("get free memory information\n");
460 SYSTEM_BASIC_INFORMATION sbi
;
462 /* the layout is just the same as MEMMANINFO, but without
467 DWORD dwLargestFreeBlock
;
468 DWORD dwMaxPagesAvailable
;
469 DWORD dwMaxPagesLockable
;
470 DWORD dwTotalLinearSpace
;
471 DWORD dwTotalUnlockedPages
;
474 DWORD dwFreeLinearSpace
;
475 DWORD dwSwapFilePages
;
477 } *info
= CTX_SEG_OFF_TO_LIN( context
, context
->SegEs
, context
->Edi
);
479 GlobalMemoryStatus( &status
);
480 NtQuerySystemInformation( SystemBasicInformation
, &sbi
, sizeof(sbi
), NULL
);
482 info
->wPageSize
= sbi
.PageSize
;
483 info
->dwLargestFreeBlock
= status
.dwAvailVirtual
;
484 info
->dwMaxPagesAvailable
= info
->dwLargestFreeBlock
/ info
->wPageSize
;
485 info
->dwMaxPagesLockable
= info
->dwMaxPagesAvailable
;
486 info
->dwTotalLinearSpace
= status
.dwTotalVirtual
/ info
->wPageSize
;
487 info
->dwTotalUnlockedPages
= info
->dwTotalLinearSpace
;
488 info
->dwFreePages
= info
->dwMaxPagesAvailable
;
489 info
->dwTotalPages
= info
->dwTotalLinearSpace
;
490 info
->dwFreeLinearSpace
= info
->dwMaxPagesAvailable
;
491 info
->dwSwapFilePages
= status
.dwTotalPageFile
/ info
->wPageSize
;
495 case 0x0501: /* Allocate memory block */
497 DWORD size
= MAKELONG( CX_reg(context
), BX_reg(context
) );
500 TRACE( "allocate memory block (%lu bytes)\n", size
);
502 ptr
= DPMI_xalloc( size
);
505 SET_AX( context
, 0x8012 ); /* linear memory not available */
510 SET_BX( context
, HIWORD(ptr
) );
511 SET_CX( context
, LOWORD(ptr
) );
512 SET_SI( context
, HIWORD(ptr
) );
513 SET_DI( context
, LOWORD(ptr
) );
518 case 0x0502: /* Free memory block */
520 DWORD handle
= MAKELONG( DI_reg(context
), SI_reg(context
) );
521 TRACE( "free memory block (0x%08lx)\n", handle
);
522 DPMI_xfree( (void *)handle
);
526 case 0x0503: /* Resize memory block */
528 DWORD size
= MAKELONG( CX_reg(context
), BX_reg(context
) );
529 DWORD handle
= MAKELONG( DI_reg(context
), SI_reg(context
) );
532 TRACE( "resize memory block (0x%08lx, %lu bytes)\n", handle
, size
);
534 ptr
= DPMI_xrealloc( (void *)handle
, size
);
537 SET_AX( context
, 0x8012 ); /* linear memory not available */
540 SET_BX( context
, HIWORD(ptr
) );
541 SET_CX( context
, LOWORD(ptr
) );
542 SET_SI( context
, HIWORD(ptr
) );
543 SET_DI( context
, LOWORD(ptr
) );
548 case 0x0507: /* Set page attributes (1.0) */
549 FIXME( "set page attributes - unimplemented\n" );
550 break; /* Just ignore it */
552 case 0x0600: /* Lock linear region */
553 TRACE( "lock linear region - ignored (no paging)\n" );
556 case 0x0601: /* Unlock linear region */
557 TRACE( "unlock linear region - ignored (no paging)\n" );
560 case 0x0602: /* Mark real mode region as pageable */
561 TRACE( "mark real mode region as pageable - ignored (no paging)\n" );
564 case 0x0603: /* Relock real mode region */
565 TRACE( "relock real mode region - ignored (no paging)\n" );
568 case 0x0604: /* Get page size */
570 SYSTEM_BASIC_INFORMATION info
;
571 TRACE("get pagesize\n");
572 NtQuerySystemInformation( SystemBasicInformation
, &info
, sizeof(info
), NULL
);
573 SET_BX( context
, HIWORD(info
.PageSize
) );
574 SET_CX( context
, LOWORD(info
.PageSize
) );
577 case 0x0700: /* Mark pages as paging candidates */
578 TRACE( "mark pages as paging candidates - ignored (no paging)\n" );
581 case 0x0701: /* Discard pages */
582 TRACE( "discard pages - ignored (no paging)\n" );
585 case 0x0702: /* Mark page as demand-paging candidate */
586 TRACE( "mark page as demand-paging candidate - ignored (no paging)\n" );
589 case 0x0703: /* Discard page contents */
590 TRACE( "discard page contents - ignored (no paging)\n" );
593 case 0x0800: /* Physical address mapping */
594 FIXME( "physical address mapping (0x%08lx) - unimplemented\n",
595 MAKELONG(CX_reg(context
),BX_reg(context
)) );
598 case 0x0900: /* Get and Disable Virtual Interrupt State */
599 TRACE( "Get and Disable Virtual Interrupt State - not supported\n" );
602 case 0x0901: /* Get and Enable Virtual Interrupt State */
603 TRACE( "Get and Enable Virtual Interrupt State - not supported\n" );
606 case 0x0902: /* Get Virtual Interrupt State */
607 TRACE( "Get Virtual Interrupt State - not supported\n" );
610 case 0x0e00: /* Get Coprocessor Status (1.0) */
612 * Return status in AX bits:
613 * B0 - MPv (MP bit in the virtual MSW/CR0)
614 * 0 = numeric coprocessor is disabled for this client
615 * 1 = numeric coprocessor is enabled for this client
616 * B1 - EMv (EM bit in the virtual MSW/CR0)
617 * 0 = client is not emulating coprocessor instructions
618 * 1 = client is emulating coprocessor instructions
619 * B2 - MPr (MP bit from the actual MSW/CR0)
620 * 0 = numeric coprocessor is not present
621 * 1 = numeric coprocessor is present
622 * B3 - EMr (EM bit from the actual MSW/CR0)
623 * 0 = host is not emulating coprocessor instructions
624 * 1 = host is emulating coprocessor instructions
625 * B4-B7 - coprocessor type
626 * 00H = no coprocessor
629 * 04H = 80486 with numeric coprocessor
630 * 05H-0FH = reserved for future numeric processors
632 TRACE( "Get Coprocessor Status\n" );
633 SET_AX( context
, 69 ); /* 486, coprocessor present and enabled */
636 case 0x0e01: /* Set Coprocessor Emulation (1.0) */
638 * See function 0x0e00.
639 * BX bit B0 is new value for MPv.
640 * BX bit B1 is new value for EMv.
642 if (BX_reg(context
) != 1)
643 FIXME( "Set Coprocessor Emulation to %d - unimplemented\n",
646 TRACE( "Set Coprocessor Emulation - ignored\n" );
650 INT_BARF( context
, 0x31 );
651 SET_AX( context
, 0x8001 ); /* unsupported function */