4 * Copyright 1995 Alexandre Julliard
19 #include "selectors.h"
22 #include "stackframe.h"
25 #define DOS_GET_DRIVE(reg) ((reg) ? (reg) - 1 : DRIVE_GetCurrentDrive())
27 void CreateBPB(int drive
, BYTE
*data
, BOOL16 limited
); /* defined in int21.c */
29 static void* lastvalloced
= NULL
;
31 /* Structure for real-mode callbacks */
55 typedef struct tagRMCB
{
61 static RMCB
*FirstRMCB
= NULL
;
63 /**********************************************************************
65 * special virtualalloc, allocates lineary monoton growing memory.
66 * (the usual VirtualAlloc does not satisfy that restriction)
69 DPMI_xalloc(int len
) {
71 LPVOID oldlastv
= lastvalloced
;
77 ret
=VirtualAlloc(lastvalloced
,len
,MEM_COMMIT
|MEM_RESERVE
,PAGE_EXECUTE_READWRITE
);
79 lastvalloced
+=0x10000;
80 /* we failed to allocate one in the first round.
83 if (!xflag
&& (lastvalloced
<oldlastv
)) { /* wrapped */
84 FIXME(int31
,"failed to allocate lineary growing memory (%d bytes), using non-linear growing...\n",len
);
87 /* if we even fail to allocate something in the next
90 if ((xflag
==1) && (lastvalloced
>= oldlastv
))
92 if ((xflag
==2) && (lastvalloced
< oldlastv
)) {
93 FIXME(int31
,"failed to allocate any memory of %d bytes!\n",len
);
98 ret
=VirtualAlloc(NULL
,len
,MEM_COMMIT
|MEM_RESERVE
,PAGE_EXECUTE_READWRITE
);
99 lastvalloced
= (LPVOID
)(((DWORD
)ret
+len
+0xffff)&~0xffff);
104 DPMI_xfree(LPVOID ptr
) {
105 VirtualFree(ptr
,0,MEM_RELEASE
);
108 /* FIXME: perhaps we could grow this mapped area... */
110 DPMI_xrealloc(LPVOID ptr
,int newsize
) {
111 MEMORY_BASIC_INFORMATION mbi
;
114 newptr
= DPMI_xalloc(newsize
);
116 if (!VirtualQuery(ptr
,&mbi
,sizeof(mbi
))) {
117 FIXME(int31
,"realloc of DPMI_xallocd region %p?\n",ptr
);
120 if (mbi
.State
== MEM_FREE
) {
121 FIXME(int31
,"realloc of DPMI_xallocd region %p?\n",ptr
);
124 /* We do not shrink allocated memory. most reallocs
125 * only do grows anyway
127 if (newsize
<=mbi
.RegionSize
)
129 memcpy(newptr
,ptr
,mbi
.RegionSize
);
134 /**********************************************************************
135 * INT_GetRealModeContext
137 static void INT_GetRealModeContext( REALMODECALL
*call
, CONTEXT
*context
)
139 EAX_reg(context
) = call
->eax
;
140 EBX_reg(context
) = call
->ebx
;
141 ECX_reg(context
) = call
->ecx
;
142 EDX_reg(context
) = call
->edx
;
143 ESI_reg(context
) = call
->esi
;
144 EDI_reg(context
) = call
->edi
;
145 EBP_reg(context
) = call
->ebp
;
146 EFL_reg(context
) = call
->fl
| 0x00020000; /* V86 */
147 EIP_reg(context
) = call
->ip
;
148 ESP_reg(context
) = call
->sp
;
149 CS_reg(context
) = call
->cs
;
150 DS_reg(context
) = call
->ds
;
151 ES_reg(context
) = call
->es
;
152 FS_reg(context
) = call
->fs
;
153 GS_reg(context
) = call
->gs
;
154 (char*)V86BASE(context
) = DOSMEM_MemoryBase(0);
158 /**********************************************************************
159 * INT_SetRealModeContext
161 static void INT_SetRealModeContext( REALMODECALL
*call
, CONTEXT
*context
)
163 call
->eax
= EAX_reg(context
);
164 call
->ebx
= EBX_reg(context
);
165 call
->ecx
= ECX_reg(context
);
166 call
->edx
= EDX_reg(context
);
167 call
->esi
= ESI_reg(context
);
168 call
->edi
= EDI_reg(context
);
169 call
->ebp
= EBP_reg(context
);
170 call
->fl
= FL_reg(context
);
171 call
->ip
= IP_reg(context
);
172 call
->sp
= SP_reg(context
);
173 call
->cs
= CS_reg(context
);
174 call
->ds
= DS_reg(context
);
175 call
->es
= ES_reg(context
);
176 call
->fs
= FS_reg(context
);
177 call
->gs
= GS_reg(context
);
181 /**********************************************************************
184 static void INT_DoRealModeInt( CONTEXT
*context
)
186 CONTEXT realmode_ctx
;
187 REALMODECALL
*call
= (REALMODECALL
*)PTR_SEG_OFF_TO_LIN( ES_reg(context
),
189 INT_GetRealModeContext( call
, &realmode_ctx
);
191 RESET_CFLAG(context
);
192 if (INT_RealModeInterrupt( BL_reg(context
), context
))
194 if (EFL_reg(context
)&1) {
195 FIXME(int31
,"%02x: EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n",
196 BL_reg(context
), EAX_reg(&realmode_ctx
), EBX_reg(&realmode_ctx
),
197 ECX_reg(&realmode_ctx
), EDX_reg(&realmode_ctx
));
198 FIXME(int31
," ESI=%08lx EDI=%08lx DS=%04lx ES=%04lx\n",
199 ESI_reg(&realmode_ctx
), EDI_reg(&realmode_ctx
),
200 DS_reg(&realmode_ctx
), ES_reg(&realmode_ctx
) );
202 INT_SetRealModeContext( call
, &realmode_ctx
);
206 static void CallRMProcFar( CONTEXT
*context
)
208 REALMODECALL
*p
= (REALMODECALL
*)PTR_SEG_OFF_TO_LIN( ES_reg(context
), DI_reg(context
) );
210 THDB
*thdb
= THREAD_Current();
215 TRACE(int31
, "RealModeCall: EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n",
216 p
->eax
, p
->ebx
, p
->ecx
, p
->edx
);
217 TRACE(int31
, " ESI=%08lx EDI=%08lx ES=%04x DS=%04x CS:IP=%04x:%04x, %d WORD arguments\n",
218 p
->esi
, p
->edi
, p
->es
, p
->ds
, p
->cs
, p
->ip
, CX_reg(context
) );
220 if (!(p
->cs
) && !(p
->ip
)) { /* remove this check
221 if Int21/6501 case map function
222 has been implemented */
226 INT_GetRealModeContext(p
, &context16
);
228 addr
= DOSMEM_MapRealToLinear(MAKELONG(p
->ip
, p
->cs
));
229 sel
= SELECTOR_AllocBlock( addr
, 0x10000, SEGMENT_CODE
, FALSE
, FALSE
);
230 seg_addr
= PTR_SEG_OFF_TO_SEGPTR( sel
, 0 );
232 CS_reg(&context16
) = HIWORD(seg_addr
);
233 IP_reg(&context16
) = LOWORD(seg_addr
);
234 EBP_reg(&context16
) = OFFSETOF( thdb
->cur_stack
)
235 + (WORD
)&((STACK16FRAME
*)0)->bp
;
237 argsize
= CX_reg(context
)*sizeof(WORD
);
238 memcpy( ((LPBYTE
)THREAD_STACK16(thdb
))-argsize
,
239 (LPBYTE
)PTR_SEG_OFF_TO_LIN(SS_reg(context
), SP_reg(context
))+6, argsize
);
241 Callbacks
->CallRegisterShortProc(&context16
, argsize
);
244 INT_SetRealModeContext(p
, &context16
);
248 void WINAPI
RMCallbackProc( FARPROC16 pmProc
, REALMODECALL
*rmc
)
251 INT_GetRealModeContext(rmc
, &ctx
);
252 Callbacks
->CallRegisterShortProc(&ctx
, 0);
256 static void AllocRMCB( CONTEXT
*context
)
258 RMCB
*NewRMCB
= HeapAlloc(GetProcessHeap(), 0, sizeof(RMCB
));
259 REALMODECALL
*p
= (REALMODECALL
*)PTR_SEG_OFF_TO_LIN( ES_reg(context
), DI_reg(context
) );
262 FIXME(int31
, "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n", p
->eax
, p
->ebx
, p
->ecx
, p
->edx
);
263 FIXME(int31
, " ESI=%08lx EDI=%08lx ES=%04x DS=%04x CS:IP=%04x:%04x\n", p
->esi
, p
->edi
, p
->es
, p
->ds
, p
->cs
, p
->ip
);
264 FIXME(int31
, " Function to call: %04x:%04x\n",
265 (WORD
)DS_reg(context
), SI_reg(context
) );
269 LPVOID RMCBmem
= DOSMEM_GetBlock(0, 20, &uParagraph
);
272 *p
++ = 0x68; /* pushl */
274 PTR_SEG_OFF_TO_LIN(ES_reg(context
), SI_reg(context
)); /* pmode proc to call */
276 *p
++ = 0x68; /* pushl */
278 PTR_SEG_OFF_TO_LIN(ES_reg(context
), DI_reg(context
));
280 *p
++ = 0x9a; /* lcall */
281 *(FARPROC16
*)p
= (FARPROC16
)RMCallbackProc
; /* FIXME ? */
285 *p
++=0xc3; /* retf */
286 NewRMCB
->address
= MAKELONG(0, uParagraph
);
287 NewRMCB
->next
= FirstRMCB
;
289 CX_reg(context
) = uParagraph
;
294 AX_reg(context
) = 0x8015; /* callback unavailable */
300 static void FreeRMCB( CONTEXT
*context
)
302 RMCB
*CurrRMCB
= FirstRMCB
;
303 RMCB
*PrevRMCB
= NULL
;
305 FIXME(int31
, "callback address: %04x:%04x\n",
306 CX_reg(context
), DX_reg(context
));
308 while (CurrRMCB
&& (CurrRMCB
->address
!= MAKELONG(DX_reg(context
), CX_reg(context
))))
311 CurrRMCB
= CurrRMCB
->next
;
316 PrevRMCB
->next
= CurrRMCB
->next
;
318 FirstRMCB
= CurrRMCB
->next
;
319 DOSMEM_FreeBlock(0, DOSMEM_MapRealToLinear(CurrRMCB
->address
));
320 HeapFree(GetProcessHeap(), 0, CurrRMCB
);
324 AX_reg(context
) = 0x8024; /* invalid callback address */
330 /**********************************************************************
333 * Handler for int 31h (DPMI).
336 void WINAPI
INT_Int31Handler( CONTEXT
*context
)
339 * Note: For Win32s processes, the whole linear address space is
340 * shifted by 0x10000 relative to the OS linear address space.
341 * See the comment in msdos/vxd.c.
343 DWORD offset
= PROCESS_Current()->flags
& PDB32_WIN32S_PROC
? 0x10000 : 0;
344 #define AppToWine(addr) ((addr)? ((DWORD)(addr)) + offset : 0)
345 #define WineToApp(addr) ((addr)? ((DWORD)(addr)) - offset : 0)
350 RESET_CFLAG(context
);
351 switch(AX_reg(context
))
353 case 0x0000: /* Allocate LDT descriptors */
354 TRACE(int31
,"allocate LDT descriptors (%d)\n",CX_reg(context
));
355 if (!(AX_reg(context
) = AllocSelectorArray( CX_reg(context
) )))
357 TRACE(int31
,"failed\n");
358 AX_reg(context
) = 0x8011; /* descriptor unavailable */
361 TRACE(int31
,"success, array starts at 0x%04x\n",AX_reg(context
));
364 case 0x0001: /* Free LDT descriptor */
365 TRACE(int31
,"free LDT descriptor (0x%04x)\n",BX_reg(context
));
366 if (FreeSelector( BX_reg(context
) ))
368 AX_reg(context
) = 0x8022; /* invalid selector */
373 /* If a segment register contains the selector being freed, */
374 /* set it to zero. */
375 if (!((DS_reg(context
)^BX_reg(context
)) & ~3)) DS_reg(context
) = 0;
376 if (!((ES_reg(context
)^BX_reg(context
)) & ~3)) ES_reg(context
) = 0;
377 if (!((FS_reg(context
)^BX_reg(context
)) & ~3)) FS_reg(context
) = 0;
378 if (!((GS_reg(context
)^BX_reg(context
)) & ~3)) GS_reg(context
) = 0;
382 case 0x0002: /* Real mode segment to descriptor */
383 TRACE(int31
,"real mode segment to descriptor (0x%04x)\n",BX_reg(context
));
385 WORD entryPoint
= 0; /* KERNEL entry point for descriptor */
386 switch(BX_reg(context
))
388 case 0x0000: entryPoint
= 183; break; /* __0000H */
389 case 0x0040: entryPoint
= 193; break; /* __0040H */
390 case 0xa000: entryPoint
= 174; break; /* __A000H */
391 case 0xb000: entryPoint
= 181; break; /* __B000H */
392 case 0xb800: entryPoint
= 182; break; /* __B800H */
393 case 0xc000: entryPoint
= 195; break; /* __C000H */
394 case 0xd000: entryPoint
= 179; break; /* __D000H */
395 case 0xe000: entryPoint
= 190; break; /* __E000H */
396 case 0xf000: entryPoint
= 194; break; /* __F000H */
398 AX_reg(context
) = DOSMEM_AllocSelector(BX_reg(context
));
402 AX_reg(context
) = LOWORD(NE_GetEntryPoint(
403 GetModuleHandle16( "KERNEL" ),
408 case 0x0003: /* Get next selector increment */
409 TRACE(int31
,"get selector increment (__AHINCR)\n");
410 AX_reg(context
) = __AHINCR
;
413 case 0x0004: /* Lock selector (not supported) */
414 FIXME(int31
,"lock selector not supported\n");
415 AX_reg(context
) = 0; /* FIXME: is this a correct return value? */
418 case 0x0005: /* Unlock selector (not supported) */
419 FIXME(int31
,"unlock selector not supported\n");
420 AX_reg(context
) = 0; /* FIXME: is this a correct return value? */
423 case 0x0006: /* Get selector base address */
424 TRACE(int31
,"get selector base address (0x%04x)\n",BX_reg(context
));
425 if (!(dw
= GetSelectorBase( BX_reg(context
) )))
427 AX_reg(context
) = 0x8022; /* invalid selector */
432 CX_reg(context
) = HIWORD(WineToApp(dw
));
433 DX_reg(context
) = LOWORD(WineToApp(dw
));
437 case 0x0007: /* Set selector base address */
438 TRACE(int31
, "set selector base address (0x%04x,0x%08lx)\n",
440 AppToWine(MAKELONG(DX_reg(context
),CX_reg(context
))));
441 SetSelectorBase(BX_reg(context
),
442 AppToWine(MAKELONG(DX_reg(context
), CX_reg(context
))));
445 case 0x0008: /* Set selector limit */
446 TRACE(int31
,"set selector limit (0x%04x,0x%08lx)\n",BX_reg(context
),MAKELONG(DX_reg(context
),CX_reg(context
)));
447 SetSelectorLimit( BX_reg(context
),
448 MAKELONG( DX_reg(context
), CX_reg(context
) ) );
451 case 0x0009: /* Set selector access rights */
452 TRACE(int31
,"set selector access rights(0x%04x,0x%04x)\n",BX_reg(context
),CX_reg(context
));
453 SelectorAccessRights( BX_reg(context
), 1, CX_reg(context
) );
456 case 0x000a: /* Allocate selector alias */
457 TRACE(int31
,"allocate selector alias (0x%04x)\n",BX_reg(context
));
458 if (!(AX_reg(context
) = AllocCStoDSAlias( BX_reg(context
) )))
460 AX_reg(context
) = 0x8011; /* descriptor unavailable */
465 case 0x000b: /* Get descriptor */
466 TRACE(int31
,"get descriptor (0x%04x)\n",BX_reg(context
));
469 LDT_GetEntry( SELECTOR_TO_ENTRY( BX_reg(context
) ), &entry
);
470 entry
.base
= WineToApp(entry
.base
);
472 /* FIXME: should use ES:EDI for 32-bit clients */
473 LDT_EntryToBytes( PTR_SEG_OFF_TO_LIN( ES_reg(context
),
474 DI_reg(context
) ), &entry
);
478 case 0x000c: /* Set descriptor */
479 TRACE(int31
,"set descriptor (0x%04x)\n",BX_reg(context
));
482 LDT_BytesToEntry( PTR_SEG_OFF_TO_LIN( ES_reg(context
),
483 DI_reg(context
) ), &entry
);
484 entry
.base
= AppToWine(entry
.base
);
486 LDT_SetEntry( SELECTOR_TO_ENTRY( BX_reg(context
) ), &entry
);
490 case 0x000d: /* Allocate specific LDT descriptor */
491 FIXME(int31
,"allocate descriptor (0x%04x), stub!\n",BX_reg(context
));
492 AX_reg(context
) = 0x8011; /* descriptor unavailable */
495 case 0x0200: /* get real mode interrupt vector */
496 FIXME(int31
,"get realmode interupt vector(0x%02x) unimplemented.\n",
500 case 0x0201: /* set real mode interrupt vector */
501 FIXME(int31
, "set realmode interupt vector(0x%02x,0x%04x:0x%04x) unimplemented\n", BL_reg(context
),CX_reg(context
),DX_reg(context
));
504 case 0x0204: /* Get protected mode interrupt vector */
505 TRACE(int31
,"get protected mode interrupt handler (0x%02x), stub!\n",BL_reg(context
));
506 dw
= (DWORD
)INT_GetHandler( BL_reg(context
) );
507 CX_reg(context
) = HIWORD(dw
);
508 DX_reg(context
) = LOWORD(dw
);
511 case 0x0205: /* Set protected mode interrupt vector */
512 TRACE(int31
,"set protected mode interrupt handler (0x%02x,%p), stub!\n",
513 BL_reg(context
),PTR_SEG_OFF_TO_LIN(CX_reg(context
),DX_reg(context
)));
514 INT_SetHandler( BL_reg(context
),
515 (FARPROC16
)PTR_SEG_OFF_TO_SEGPTR( CX_reg(context
),
519 case 0x0300: /* Simulate real mode interrupt */
520 INT_DoRealModeInt( context
);
523 case 0x0301: /* Call real mode procedure with far return */
524 CallRMProcFar( context
);
527 case 0x0302: /* Call real mode procedure with interrupt return */
529 REALMODECALL
*p
= (REALMODECALL
*)PTR_SEG_OFF_TO_LIN( ES_reg(context
), DI_reg(context
) );
530 FIXME(int31
, "RealModeCallIret: EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n", p
->eax
, p
->ebx
, p
->ecx
, p
->edx
);
531 FIXME(int31
, " ESI=%08lx EDI=%08lx ES=%04x DS=%04x CS:IP=%04x:%04x\n", p
->esi
, p
->edi
, p
->es
, p
->ds
, p
->cs
, p
->ip
);
536 case 0x0303: /* Allocate Real Mode Callback Address */
537 AllocRMCB( context
);
540 case 0x0304: /* Free Real Mode Callback Address */
544 case 0x0400: /* Get DPMI version */
545 TRACE(int31
,"get DPMI version\n");
550 AX_reg(context
) = 0x005a; /* DPMI version 0.90 */
551 BX_reg(context
) = 0x0005; /* Flags: 32-bit, virtual memory */
552 CL_reg(context
) = si
.wProcessorLevel
;
553 DX_reg(context
) = 0x0102; /* Master/slave interrupt controller base*/
556 case 0x0500: /* Get free memory information */
557 TRACE(int31
,"get free memory information\n");
561 mmi
.dwSize
= sizeof(mmi
);
563 ptr
= (BYTE
*)PTR_SEG_OFF_TO_LIN(ES_reg(context
),DI_reg(context
));
564 /* the layout is just the same as MEMMANINFO, but without
567 memcpy(ptr
,((char*)&mmi
)+4,sizeof(mmi
)-4);
570 case 0x0501: /* Allocate memory block */
571 TRACE(int31
,"allocate memory block (%ld)\n",MAKELONG(CX_reg(context
),BX_reg(context
)));
572 if (!(ptr
= (BYTE
*)DPMI_xalloc(MAKELONG(CX_reg(context
), BX_reg(context
)))))
574 AX_reg(context
) = 0x8012; /* linear memory not available */
577 BX_reg(context
) = SI_reg(context
) = HIWORD(WineToApp(ptr
));
578 CX_reg(context
) = DI_reg(context
) = LOWORD(WineToApp(ptr
));
582 case 0x0502: /* Free memory block */
583 TRACE(int31
, "free memory block (0x%08lx)\n",
584 AppToWine(MAKELONG(DI_reg(context
),SI_reg(context
))));
585 DPMI_xfree( (void *)AppToWine(MAKELONG(DI_reg(context
),
589 case 0x0503: /* Resize memory block */
590 TRACE(int31
, "resize memory block (0x%08lx,%ld)\n",
591 AppToWine(MAKELONG(DI_reg(context
),SI_reg(context
))),
592 MAKELONG(CX_reg(context
),BX_reg(context
)));
593 if (!(ptr
= (BYTE
*)DPMI_xrealloc(
594 (void *)AppToWine(MAKELONG(DI_reg(context
),SI_reg(context
))),
595 MAKELONG(CX_reg(context
),BX_reg(context
)))))
597 AX_reg(context
) = 0x8012; /* linear memory not available */
600 BX_reg(context
) = SI_reg(context
) = HIWORD(WineToApp(ptr
));
601 CX_reg(context
) = DI_reg(context
) = LOWORD(WineToApp(ptr
));
605 case 0x0600: /* Lock linear region */
606 FIXME(int31
,"lock linear region unimplemented\n");
607 break; /* Just ignore it */
609 case 0x0601: /* Unlock linear region */
610 FIXME(int31
,"unlock linear region unimplemented\n");
611 break; /* Just ignore it */
613 case 0x0602: /* Unlock real-mode region */
614 FIXME(int31
,"unlock realmode region unimplemented\n");
615 break; /* Just ignore it */
617 case 0x0603: /* Lock real-mode region */
618 FIXME(int31
,"lock realmode region unimplemented\n");
619 break; /* Just ignore it */
621 case 0x0604: /* Get page size */
622 TRACE(int31
,"get pagesize\n");
624 CX_reg(context
) = VIRTUAL_GetPageSize();
627 case 0x0702: /* Mark page as demand-paging candidate */
628 FIXME(int31
,"mark page as demand-paging candidate\n");
629 break; /* Just ignore it */
631 case 0x0703: /* Discard page contents */
632 FIXME(int31
,"discard page contents\n");
633 break; /* Just ignore it */
635 case 0x0800: /* Physical address mapping */
636 FIXME(int31
,"map real to linear (0x%08lx)\n",MAKELONG(CX_reg(context
),BX_reg(context
)));
637 if(!(ptr
=DOSMEM_MapRealToLinear(MAKELONG(CX_reg(context
),BX_reg(context
)))))
639 AX_reg(context
) = 0x8021;
644 BX_reg(context
) = HIWORD(WineToApp(ptr
));
645 CX_reg(context
) = LOWORD(WineToApp(ptr
));
646 RESET_CFLAG(context
);
651 INT_BARF( context
, 0x31 );
652 AX_reg(context
) = 0x8001; /* unsupported function */