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"
33 #include "wine/exception.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(int31
);
37 static void* lastvalloced
= NULL
;
39 /**********************************************************************
41 * special virtualalloc, allocates linearly monoton growing memory.
42 * (the usual VirtualAlloc does not satisfy that restriction)
44 static LPVOID
DPMI_xalloc( DWORD len
)
47 LPVOID oldlastv
= lastvalloced
;
56 ret
= VirtualAlloc( lastvalloced
, len
,
57 MEM_COMMIT
|MEM_RESERVE
, PAGE_EXECUTE_READWRITE
);
59 lastvalloced
= (char *) lastvalloced
+ 0x10000;
61 /* we failed to allocate one in the first round.
64 if (!xflag
&& (lastvalloced
<oldlastv
))
67 FIXME( "failed to allocate linearly growing memory (%u bytes), "
68 "using non-linear growing...\n", len
);
72 /* if we even fail to allocate something in the next
75 if ((xflag
==1) && (lastvalloced
>= oldlastv
))
78 if ((xflag
==2) && (lastvalloced
< oldlastv
)) {
79 FIXME( "failed to allocate any memory of %u bytes!\n", len
);
86 ret
= VirtualAlloc( NULL
, len
,
87 MEM_COMMIT
|MEM_RESERVE
, PAGE_EXECUTE_READWRITE
);
90 lastvalloced
= (LPVOID
)(((DWORD
)ret
+len
+0xffff)&~0xffff);
94 /**********************************************************************
97 static void DPMI_xfree( LPVOID ptr
)
99 VirtualFree( ptr
, 0, MEM_RELEASE
);
102 /**********************************************************************
105 * FIXME: perhaps we could grow this mapped area...
107 static LPVOID
DPMI_xrealloc( LPVOID ptr
, DWORD newsize
)
109 MEMORY_BASIC_INFORMATION mbi
;
115 if (!VirtualQuery(ptr
,&mbi
,sizeof(mbi
)))
117 FIXME( "realloc of DPMI_xallocd region %p?\n", ptr
);
121 if (mbi
.State
== MEM_FREE
)
123 FIXME( "realloc of DPMI_xallocd region %p?\n", ptr
);
127 /* We do not shrink allocated memory. most reallocs
128 * only do grows anyway
130 if (newsize
<= mbi
.RegionSize
)
133 newptr
= DPMI_xalloc( newsize
);
137 memcpy( newptr
, ptr
, mbi
.RegionSize
);
143 return DPMI_xalloc( newsize
);
147 /**********************************************************************
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
) );
164 SET_AX( context
, 0x8011 ); /* descriptor unavailable */
165 SET_CFLAG( context
);
169 TRACE( "success, array starts at 0x%04x\n", sel
);
170 SET_AX( context
, sel
);
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
);
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;
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 */
209 FIXME("Real mode segment (%x) to descriptor: no longer supported\n",
211 SET_CFLAG( context
);
216 FARPROC16 proc
= GetProcAddress16( GetModuleHandle16( "KERNEL" ),
217 (LPCSTR
)(ULONG_PTR
)entryPoint
);
218 SET_AX( context
, LOWORD(proc
) );
223 case 0x0003: /* Get next selector increment */
224 TRACE("get selector increment (__AHINCR)\n");
225 context
->Eax
= __AHINCR
;
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? */
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? */
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 */
247 void *base
= ldt_get_base( BX_reg(context
) );
248 SET_CX( context
, HIWORD(base
) );
249 SET_DX( context
, LOWORD(base
) );
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
);
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
);
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
) );
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 */
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
,
296 ldt_get_entry( BX_reg(context
), entry
);
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
,
305 if (!ldt_is_system( BX_reg(context
) )) ldt_set_entry( BX_reg(context
), *entry
);
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
);
315 case 0x000e: /* Get Multiple Descriptors (1.0) */
316 FIXME( "get multiple descriptors - unimplemented\n" );
319 case 0x000f: /* Set Multiple Descriptors (1.0) */
320 FIXME( "set multiple descriptors - unimplemented\n" );
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 );
328 SET_AX( context
, HIWORD(dw
) );
329 SET_DX( context
, LOWORD(dw
) );
331 SET_AX( context
, 0x0008 ); /* insufficient memory */
332 SET_BX( context
, DOSMEM_Available() >> 4 );
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
) );
343 SET_AX( context
, 0x0009 ); /* memory block address invalid */
344 SET_CFLAG( context
);
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
) );
354 case 0x0200: /* get real mode interrupt vector */
355 TRACE( "get realmode interrupt vector (0x%02x) - not supported\n",
357 SET_CX( context
, 0 );
358 SET_DX( context
, 0 );
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
) );
366 case 0x0202: /* Get Processor Exception Handler Vector */
367 FIXME( "Get Processor Exception Handler Vector (0x%02x)\n",
369 SET_CX( context
, 0 );
370 SET_DX( context
, 0 );
373 case 0x0203: /* Set Processor Exception Handler Vector */
374 FIXME( "Set Processor Exception Handler Vector (0x%02x)\n",
378 case 0x0204: /* Get protected mode interrupt vector */
379 TRACE("get protected mode interrupt handler (0x%02x)\n",
382 FARPROC16 handler
= DOSVM_GetPMHandler16( BL_reg(context
) );
383 SET_CX( context
, SELECTOROF(handler
) );
384 SET_DX( context
, OFFSETOF(handler
) );
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
);
393 handler
= (FARPROC16
)MAKESEGPTR( CX_reg(context
), DX_reg(context
));
394 DOSVM_SetPMHandler16( BL_reg(context
), handler
);
398 case 0x0300: /* Simulate real mode interrupt */
399 TRACE( "Simulate real mode interrupt %02x - not supported\n", BL_reg(context
));
402 case 0x0301: /* Call real mode procedure with far return */
403 TRACE( "Call real mode procedure with far return - not supported\n" );
406 case 0x0302: /* Call real mode procedure with interrupt return */
407 TRACE( "Call real mode procedure with interrupt return - not supported\n" );
410 case 0x0303: /* Allocate Real Mode Callback Address */
411 TRACE( "Allocate real mode callback address - not supported\n" );
414 case 0x0304: /* Free Real Mode Callback Address */
415 TRACE( "Free real mode callback address - not supported\n" );
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 );
423 SET_BX( context
, 0 );
424 SET_CX( context
, 0 );
426 SET_SI( context
, 0 );
430 case 0x0306: /* Get Raw Mode Switch Addresses */
431 TRACE("get raw mode switch addresses - no longer supported\n");
433 SET_BX( context
, 0 );
434 SET_CX( context
, 0 );
436 SET_SI( context
, 0 );
440 case 0x0400: /* Get DPMI version */
441 TRACE("get DPMI version\n");
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 ); /* Interrupt controller base */
453 case 0x0401: /* Get DPMI Capabilities (1.0) */
454 FIXME( "get dpmi capabilities - unimplemented\n");
457 case 0x0500: /* Get free memory information */
458 TRACE("get free memory information\n");
461 SYSTEM_BASIC_INFORMATION sbi
;
463 /* the layout is just the same as MEMMANINFO, but without
468 DWORD dwLargestFreeBlock
;
469 DWORD dwMaxPagesAvailable
;
470 DWORD dwMaxPagesLockable
;
471 DWORD dwTotalLinearSpace
;
472 DWORD dwTotalUnlockedPages
;
475 DWORD dwFreeLinearSpace
;
476 DWORD dwSwapFilePages
;
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
;
496 case 0x0501: /* Allocate memory block */
498 DWORD size
= MAKELONG( CX_reg(context
), BX_reg(context
) );
501 TRACE( "allocate memory block (%u bytes)\n", size
);
503 ptr
= DPMI_xalloc( size
);
506 SET_AX( context
, 0x8012 ); /* linear memory not available */
511 SET_BX( context
, HIWORD(ptr
) );
512 SET_CX( context
, LOWORD(ptr
) );
513 SET_SI( context
, HIWORD(ptr
) );
514 SET_DI( context
, LOWORD(ptr
) );
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
);
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
) );
533 TRACE( "resize memory block (0x%08x, %u bytes)\n", handle
, size
);
535 ptr
= DPMI_xrealloc( (void *)handle
, size
);
538 SET_AX( context
, 0x8012 ); /* linear memory not available */
541 SET_BX( context
, HIWORD(ptr
) );
542 SET_CX( context
, LOWORD(ptr
) );
543 SET_SI( context
, HIWORD(ptr
) );
544 SET_DI( context
, LOWORD(ptr
) );
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" );
557 case 0x0601: /* Unlock linear region */
558 TRACE( "unlock linear region - ignored (no paging)\n" );
561 case 0x0602: /* Mark real mode region as pageable */
562 TRACE( "mark real mode region as pageable - ignored (no paging)\n" );
565 case 0x0603: /* Relock real mode region */
566 TRACE( "relock real mode region - ignored (no paging)\n" );
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
) );
578 case 0x0700: /* Mark pages as paging candidates */
579 TRACE( "mark pages as paging candidates - ignored (no paging)\n" );
582 case 0x0701: /* Discard pages */
583 TRACE( "discard pages - ignored (no paging)\n" );
586 case 0x0702: /* Mark page as demand-paging candidate */
587 TRACE( "mark page as demand-paging candidate - ignored (no paging)\n" );
590 case 0x0703: /* Discard page contents */
591 TRACE( "discard page contents - ignored (no paging)\n" );
594 case 0x0800: /* Physical address mapping */
595 FIXME( "physical address mapping (0x%08x) - unimplemented\n",
596 MAKELONG(CX_reg(context
),BX_reg(context
)) );
599 case 0x0900: /* Get and Disable Virtual Interrupt State */
600 TRACE( "Get and Disable Virtual Interrupt State - not supported\n" );
603 case 0x0901: /* Get and Enable Virtual Interrupt State */
604 TRACE( "Get and Enable Virtual Interrupt State - not supported\n" );
607 case 0x0902: /* Get Virtual Interrupt State */
608 TRACE( "Get Virtual Interrupt State - not supported\n" );
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
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 */
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",
647 TRACE( "Set Coprocessor Emulation - ignored\n" );
651 INT_BARF( context
, 0x31 );
652 SET_AX( context
, 0x8001 ); /* unsupported function */