mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-31 12:19:49 +00:00
Various DPMI fixes and preliminary DPMI raw mode switch handler.
This commit is contained in:
parent
fe0a5e8895
commit
e78e1af43e
3 changed files with 176 additions and 30 deletions
|
@ -389,6 +389,8 @@ int DOSVM_Enter( PCONTEXT context )
|
|||
#define CP(x,y) VM86.regs.x = y##_reg(context)
|
||||
CV;
|
||||
#undef CP
|
||||
if (VM86.regs.eflags & IF_MASK)
|
||||
VM86.regs.eflags |= VIF_MASK;
|
||||
} else {
|
||||
/* initial setup */
|
||||
/* allocate standard DOS handles */
|
||||
|
|
|
@ -537,9 +537,9 @@ void MZ_KillModule( LPDOSTASK lpDosTask )
|
|||
#undef DFREE
|
||||
|
||||
#if 0
|
||||
/* FIXME: this seems to crash */
|
||||
if (lpDosTask->dpmi_sel)
|
||||
UnMapLS(PTR_SEG_OFF_TO_SEGPTR(lpDosTask->dpmi_sel,0));
|
||||
/* FIXME: this seems to crash */
|
||||
if (lpDosTask->dpmi_sel)
|
||||
SELECTOR_FreeBlock(lpDosTask->dpmi_sel, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
198
msdos/dpmi.c
198
msdos/dpmi.c
|
@ -243,7 +243,7 @@ static void DPMI_CallRMCBProc( CONTEXT *context, RMCB *rmcb, WORD flag )
|
|||
es = ES_reg(&ctx);
|
||||
edi = EDI_reg(&ctx);
|
||||
}
|
||||
UnMapLS(PTR_SEG_OFF_TO_SEGPTR(ss,0));
|
||||
SELECTOR_FreeBlock(ss, 1);
|
||||
INT_GetRealModeContext((REALMODECALL*)PTR_SEG_OFF_TO_LIN( es, edi ), context);
|
||||
#else
|
||||
ERR(int31,"RMCBs only implemented for i386\n");
|
||||
|
@ -391,7 +391,7 @@ callrmproc_again:
|
|||
EBP_reg(context) = OFFSETOF( thdb->cur_stack )
|
||||
+ (WORD)&((STACK16FRAME*)0)->bp;
|
||||
Callbacks->CallRegisterShortProc(context, args*sizeof(WORD));
|
||||
UnMapLS(seg_addr);
|
||||
SELECTOR_FreeBlock(sel, 1);
|
||||
#endif
|
||||
}
|
||||
if (alloc) DOSMEM_FreeBlock( pModule->self, addr );
|
||||
|
@ -596,14 +596,28 @@ static void StartPM( CONTEXT *context, LPDOSTASK lpDosTask )
|
|||
char *base = DOSMEM_MemoryBase(0);
|
||||
UINT16 cs, ss, ds, es;
|
||||
CONTEXT pm_ctx;
|
||||
DWORD psp_ofs = (DWORD)(lpDosTask->psp_seg<<4);
|
||||
PDB16 *psp = (PDB16 *)(base + psp_ofs);
|
||||
HANDLE16 env_seg = psp->environment;
|
||||
int is32;
|
||||
|
||||
RESET_CFLAG(context);
|
||||
lpDosTask->dpmi_flag = AX_reg(context);
|
||||
is32 = lpDosTask->dpmi_flag & 1;
|
||||
/* our mode switch wrapper have placed the desired CS into DX */
|
||||
cs = SELECTOR_AllocBlock( base + (DWORD)(DX_reg(context)<<4), 0x10000, SEGMENT_CODE, FALSE, FALSE );
|
||||
ss = SELECTOR_AllocBlock( base + (DWORD)(SS_reg(context)<<4), 0x10000, SEGMENT_DATA, FALSE, FALSE );
|
||||
ds = SELECTOR_AllocBlock( base + (DWORD)(DS_reg(context)<<4), 0x10000, SEGMENT_DATA, FALSE, FALSE );
|
||||
es = SELECTOR_AllocBlock( base + (DWORD)(lpDosTask->psp_seg<<4), 0x100, SEGMENT_DATA, FALSE, FALSE );
|
||||
/* due to a flaw in some CPUs (at least mine), it is best to mark stack segments as 32-bit if they
|
||||
can be used in 32-bit code. Otherwise, these CPUs may not set the high word of esp during a
|
||||
ring transition (from kernel code) to the 16-bit stack, and this causes trouble if executing
|
||||
32-bit code using this stack. */
|
||||
ss = SELECTOR_AllocBlock( base + (DWORD)(SS_reg(context)<<4), 0x10000, SEGMENT_DATA, is32, FALSE );
|
||||
/* do the same for the data segments, just in case */
|
||||
if (DS_reg(context) == SS_reg(context)) ds = ss;
|
||||
else ds = SELECTOR_AllocBlock( base + (DWORD)(DS_reg(context)<<4), 0x10000, SEGMENT_DATA, is32, FALSE );
|
||||
es = SELECTOR_AllocBlock( base + psp_ofs, 0x100, SEGMENT_DATA, is32, FALSE );
|
||||
/* convert environment pointer, as the spec says, but we're a bit lazy about the size here... */
|
||||
psp->environment = SELECTOR_AllocBlock( base + (DWORD)(env_seg<<4),
|
||||
0x10000, SEGMENT_DATA, FALSE, FALSE );
|
||||
|
||||
pm_ctx = *context;
|
||||
CS_reg(&pm_ctx) = lpDosTask->dpmi_sel;
|
||||
|
@ -619,14 +633,90 @@ static void StartPM( CONTEXT *context, LPDOSTASK lpDosTask )
|
|||
Callbacks->CallRegisterShortProc(&pm_ctx, 0);
|
||||
|
||||
/* in the current state of affairs, we won't ever actually return here... */
|
||||
/* we should have int21/ah=4c do it someday, though... */
|
||||
|
||||
UnMapLS(PTR_SEG_OFF_TO_SEGPTR(es,0));
|
||||
UnMapLS(PTR_SEG_OFF_TO_SEGPTR(ds,0));
|
||||
UnMapLS(PTR_SEG_OFF_TO_SEGPTR(ss,0));
|
||||
UnMapLS(PTR_SEG_OFF_TO_SEGPTR(cs,0));
|
||||
SELECTOR_FreeBlock(psp->environment, 1);
|
||||
psp->environment = env_seg;
|
||||
SELECTOR_FreeBlock(es, 1);
|
||||
if (ds != ss) SELECTOR_FreeBlock(ds, 1);
|
||||
SELECTOR_FreeBlock(ss, 1);
|
||||
SELECTOR_FreeBlock(cs, 1);
|
||||
}
|
||||
|
||||
/* DPMI Raw Mode Switch handler */
|
||||
|
||||
void WINAPI DPMI_RawModeSwitch( SIGCONTEXT *context )
|
||||
{
|
||||
LPDOSTASK lpDosTask = MZ_Current();
|
||||
CONTEXT rm_ctx;
|
||||
int ret;
|
||||
|
||||
if (!lpDosTask) {
|
||||
/* we could probably start a DPMI-only dosmod task here, but I doubt
|
||||
anything other than real DOS apps want to call raw mode switch */
|
||||
ERR(int31,"attempting raw mode switch without DOS task!\n");
|
||||
ExitProcess(1);
|
||||
}
|
||||
/* initialize real-mode context as per spec */
|
||||
memset(&rm_ctx, 0, sizeof(rm_ctx));
|
||||
DS_reg(&rm_ctx) = AX_sig(context);
|
||||
ES_reg(&rm_ctx) = CX_sig(context);
|
||||
SS_reg(&rm_ctx) = DX_sig(context);
|
||||
ESP_reg(&rm_ctx) = EBX_sig(context);
|
||||
CS_reg(&rm_ctx) = SI_sig(context);
|
||||
EIP_reg(&rm_ctx) = EDI_sig(context);
|
||||
EBP_reg(&rm_ctx) = EBP_sig(context);
|
||||
FS_reg(&rm_ctx) = 0;
|
||||
GS_reg(&rm_ctx) = 0;
|
||||
EFL_reg(&rm_ctx) = EFL_sig(context); /* at least we need the IF flag */
|
||||
|
||||
/* enter real mode again */
|
||||
TRACE(int31,"re-entering real mode at %04lx:%04lx\n",
|
||||
CS_reg(&rm_ctx),EIP_reg(&rm_ctx));
|
||||
ret = DOSVM_Enter( &rm_ctx );
|
||||
/* when the real-mode stuff call its mode switch address,
|
||||
DOSVM_Enter will return and we will continue here */
|
||||
|
||||
if (ret<0) {
|
||||
/* if the sync was lost, there's no way to recover */
|
||||
ExitProcess(1);
|
||||
}
|
||||
|
||||
/* alter protected-mode context as per spec */
|
||||
DS_sig(context) = AX_reg(&rm_ctx);
|
||||
ES_sig(context) = CX_reg(&rm_ctx);
|
||||
SS_sig(context) = DX_reg(&rm_ctx);
|
||||
ESP_sig(context) = EBX_reg(&rm_ctx);
|
||||
CS_sig(context) = SI_reg(&rm_ctx);
|
||||
EIP_sig(context) = EDI_reg(&rm_ctx);
|
||||
EBP_sig(context) = EBP_reg(&rm_ctx);
|
||||
FS_sig(context) = 0;
|
||||
GS_sig(context) = 0;
|
||||
|
||||
/* Return to new address and hope that we didn't mess up */
|
||||
TRACE(int31,"re-entering protected mode at %04x:%08lx\n",
|
||||
CS_sig(context), EIP_sig(context));
|
||||
}
|
||||
|
||||
#else
|
||||
void WINAPI DPMI_RawModeSwitch( SIGCONTEXT *context )
|
||||
{
|
||||
ERR(int31,"don't even think about DPMI raw mode switch without DOS support!\n");
|
||||
ExitProcess(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DOS_APP_ISDOS(addr,base) ((addr) < 0x110000)
|
||||
#define DOS_WINE_ISDOS(addr,base) (((addr) >= (base)) && ((addr) < (base) + 0x110000))
|
||||
#define DOS_UC_APPTOWINE(addr,base) ((addr) + (base))
|
||||
#define DOS_UC_WINETOAPP(addr,base) ((addr) - (base))
|
||||
#define DOS_APPTOWINE(addr,base) (DOS_APP_ISDOS(addr,base) ? DOS_UC_APPTOWINE(addr,base) : (addr))
|
||||
#define DOS_WINETOAPP(addr,base) (DOS_WINE_ISDOS(addr,base) ? DOS_UC_WINETOAPP(addr,base) : (addr))
|
||||
#define DOS_BADLIMIT(addr,base,limit) \
|
||||
((limit == 0xffffffff) || /* disallow "fat DS" for now */ \
|
||||
(DOS_WINE_ISDOS(addr,base) && \
|
||||
((addr) + (limit) > (base) + 0x110000)))
|
||||
|
||||
/**********************************************************************
|
||||
* INT_Int31Handler
|
||||
*
|
||||
|
@ -645,21 +735,18 @@ void WINAPI INT_Int31Handler( CONTEXT *context )
|
|||
DWORD dw;
|
||||
BYTE *ptr;
|
||||
|
||||
TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
|
||||
NE_MODULE *pModule = pTask ? NE_GetPtr( pTask->hModule ) : NULL;
|
||||
|
||||
GlobalUnlock16( GetCurrentTask() );
|
||||
LPDOSTASK lpDosTask = MZ_Current();
|
||||
|
||||
#ifdef MZ_SUPPORTED
|
||||
if (ISV86(context) && pModule && pModule->lpDosTask) {
|
||||
if (ISV86(context) && lpDosTask) {
|
||||
/* Called from real mode, check if it's our wrapper */
|
||||
TRACE(int31,"called from real mode\n");
|
||||
if (CS_reg(context)==pModule->lpDosTask->dpmi_seg) {
|
||||
if (CS_reg(context)==lpDosTask->dpmi_seg) {
|
||||
/* This is the protected mode switch */
|
||||
StartPM(context,pModule->lpDosTask);
|
||||
StartPM(context,lpDosTask);
|
||||
return;
|
||||
} else
|
||||
if (CS_reg(context)==pModule->lpDosTask->xms_seg) {
|
||||
if (CS_reg(context)==lpDosTask->xms_seg) {
|
||||
/* This is the XMS driver entry point */
|
||||
XMS_Handler(context);
|
||||
return;
|
||||
|
@ -673,7 +760,7 @@ void WINAPI INT_Int31Handler( CONTEXT *context )
|
|||
|
||||
if (CurrRMCB) {
|
||||
/* RMCB call, propagate to protected-mode handler */
|
||||
DPMI_CallRMCBProc(context, CurrRMCB, pModule->lpDosTask->dpmi_flag);
|
||||
DPMI_CallRMCBProc(context, CurrRMCB, lpDosTask->dpmi_flag);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -763,9 +850,9 @@ void WINAPI INT_Int31Handler( CONTEXT *context )
|
|||
else
|
||||
{
|
||||
#ifdef MZ_SUPPORTED
|
||||
if (pModule && pModule->lpDosTask) {
|
||||
DWORD base = (DWORD)DOSMEM_MemoryBase(pModule->self);
|
||||
if ((dw >= base) && (dw < base + 0x110000)) dw -= base;
|
||||
if (lpDosTask) {
|
||||
DWORD base = (DWORD)DOSMEM_MemoryBase(lpDosTask->hModule);
|
||||
dw = DOS_WINETOAPP(dw, base);
|
||||
}
|
||||
#endif
|
||||
CX_reg(context) = HIWORD(W32S_WINE2APP(dw, offset));
|
||||
|
@ -779,9 +866,9 @@ void WINAPI INT_Int31Handler( CONTEXT *context )
|
|||
W32S_APP2WINE(MAKELONG(DX_reg(context),CX_reg(context)), offset));
|
||||
dw = W32S_APP2WINE(MAKELONG(DX_reg(context), CX_reg(context)), offset);
|
||||
#ifdef MZ_SUPPORTED
|
||||
/* well, what else could we possibly do? */
|
||||
if (pModule && pModule->lpDosTask) {
|
||||
if (dw < 0x110000) dw += (DWORD)DOSMEM_MemoryBase(pModule->self);
|
||||
if (lpDosTask) {
|
||||
DWORD base = (DWORD)DOSMEM_MemoryBase(lpDosTask->hModule);
|
||||
dw = DOS_APPTOWINE(dw, base);
|
||||
}
|
||||
#endif
|
||||
SetSelectorBase(BX_reg(context), dw);
|
||||
|
@ -791,9 +878,21 @@ void WINAPI INT_Int31Handler( CONTEXT *context )
|
|||
TRACE(int31,"set selector limit (0x%04x,0x%08lx)\n",BX_reg(context),MAKELONG(DX_reg(context),CX_reg(context)));
|
||||
dw = MAKELONG( DX_reg(context), CX_reg(context) );
|
||||
#ifdef MZ_SUPPORTED
|
||||
if (pModule && pModule->lpDosTask) {
|
||||
DWORD base = GetSelectorBase( BX_reg(context) );
|
||||
if ((dw == 0xffffffff) || ((base < 0x110000) && (base + dw > 0x110000))) {
|
||||
if (lpDosTask) {
|
||||
DWORD base = (DWORD)DOSMEM_MemoryBase(lpDosTask->hModule);
|
||||
DWORD sbase = GetSelectorBase( BX_reg(context) );
|
||||
if (!sbase) {
|
||||
/* the app has set the limit without setting the base,
|
||||
* it must be relying on that the default should be DOS space;
|
||||
* so set the base address now */
|
||||
SetSelectorBase( BX_reg(context), sbase = base );
|
||||
if (dw == 0xffffffff) {
|
||||
/* djgpp does this without checking (in _dos_ds setup, crt1.c),
|
||||
* so we have to override the limit here */
|
||||
dw = 0x110000;
|
||||
}
|
||||
}
|
||||
if (DOS_BADLIMIT(sbase, base, dw)) {
|
||||
AX_reg(context) = 0x8021; /* invalid value */
|
||||
SET_CFLAG(context);
|
||||
break;
|
||||
|
@ -822,6 +921,12 @@ void WINAPI INT_Int31Handler( CONTEXT *context )
|
|||
{
|
||||
ldt_entry entry;
|
||||
LDT_GetEntry( SELECTOR_TO_ENTRY( BX_reg(context) ), &entry );
|
||||
#ifdef MZ_SUPPORTED
|
||||
if (lpDosTask) {
|
||||
DWORD base = (DWORD)DOSMEM_MemoryBase(lpDosTask->hModule);
|
||||
entry.base = DOS_WINETOAPP(entry.base, base);
|
||||
}
|
||||
#endif
|
||||
entry.base = W32S_WINE2APP(entry.base, offset);
|
||||
|
||||
/* FIXME: should use ES:EDI for 32-bit clients */
|
||||
|
@ -837,6 +942,17 @@ void WINAPI INT_Int31Handler( CONTEXT *context )
|
|||
LDT_BytesToEntry( PTR_SEG_OFF_TO_LIN( ES_reg(context),
|
||||
DI_reg(context) ), &entry );
|
||||
entry.base = W32S_APP2WINE(entry.base, offset);
|
||||
#ifdef MZ_SUPPORTED
|
||||
if (lpDosTask) {
|
||||
DWORD base = (DWORD)DOSMEM_MemoryBase(lpDosTask->hModule);
|
||||
entry.base = DOS_APPTOWINE(entry.base, base);
|
||||
if (DOS_BADLIMIT(entry.base, base, entry.limit)) {
|
||||
AX_reg(context) = 0x8021; /* invalid value */
|
||||
SET_CFLAG(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
LDT_SetEntry( SELECTOR_TO_ENTRY( BX_reg(context) ), &entry );
|
||||
}
|
||||
|
@ -911,6 +1027,34 @@ void WINAPI INT_Int31Handler( CONTEXT *context )
|
|||
FreeRMCB( context );
|
||||
break;
|
||||
|
||||
case 0x0305: /* Get State Save/Restore Addresses */
|
||||
TRACE(int31,"get state save/restore addresses\n");
|
||||
/* we probably won't need this kind of state saving */
|
||||
AX_reg(context) = 0;
|
||||
/* real mode: just point to the lret */
|
||||
BX_reg(context) = DPMI_wrap_seg;
|
||||
ECX_reg(context) = 2;
|
||||
/* protected mode: don't have any handler yet... */
|
||||
FIXME(int31,"no protected-mode dummy state save/restore handler yet\n");
|
||||
SI_reg(context) = 0;
|
||||
EDI_reg(context) = 0;
|
||||
break;
|
||||
|
||||
case 0x0306: /* Get Raw Mode Switch Addresses */
|
||||
TRACE(int31,"get raw mode switch addresses\n");
|
||||
if (lpDosTask) {
|
||||
/* real mode, point to standard DPMI return wrapper */
|
||||
BX_reg(context) = DPMI_wrap_seg;
|
||||
ECX_reg(context) = 0;
|
||||
/* protected mode, point to DPMI call wrapper */
|
||||
SI_reg(context) = lpDosTask->dpmi_sel;
|
||||
EDI_reg(context) = 8; /* offset of the INT 0x31 call */
|
||||
} else {
|
||||
ERR(int31,"win app attempting to get raw mode switch!\n");
|
||||
AX_reg(context) = 0x8001; /* unsupported function */
|
||||
SET_CFLAG(context);
|
||||
}
|
||||
break;
|
||||
case 0x0400: /* Get DPMI version */
|
||||
TRACE(int31,"get DPMI version\n");
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue