Commit 28c11324 authored by Ove Kaaven's avatar Ove Kaaven Committed by Alexandre Julliard

First shot at DPMI realmode calls.

parent ebc543cd
......@@ -19,6 +19,7 @@ typedef struct _DOSTASK {
WORD init_cs,init_ip,init_ss,init_sp;
WORD xms_seg;
WORD dpmi_seg,dpmi_sel,dpmi_flag;
DWORD wrap_ofs,call_ofs;
HMODULE16 hModule;
char mm_name[128];
int mm_fd;
......@@ -35,6 +36,7 @@ struct _NE_MODULE;
extern int MZ_InitTask( LPDOSTASK lpDosTask );
extern int MZ_InitMemory( LPDOSTASK lpDosTask, struct _NE_MODULE *pModule );
extern void MZ_KillModule( LPDOSTASK lpDosTask );
extern LPDOSTASK MZ_AllocDPMITask( HMODULE16 hModule );
#endif /* linux */
......
......@@ -71,9 +71,17 @@ static void DOSVM_Dump( LPDOSTASK lpDosTask, int fn,
exit(0);
}
static int DOSVM_Int(int vect, PCONTEXT context )
static int DOSVM_Int( int vect, PCONTEXT context, LPDOSTASK lpDosTask )
{
/* moved to INT_RealModeInterrupt in msdos/interrupts.c */
if (vect==0x31) {
if (CS_reg(context)==lpDosTask->dpmi_sel) {
if (IP_reg(context)>=lpDosTask->wrap_ofs) {
/* exit from real-mode wrapper */
return -1;
}
}
/* we could probably move some other dodgy stuff here too from dpmi.c */
}
INT_RealModeInterrupt(vect,context);
return 0;
}
......@@ -105,7 +113,7 @@ static int DOSVM_Process( LPDOSTASK lpDosTask, int fn,
break;
case VM86_INTx:
TRACE(int,"DOS EXE calls INT %02x with AX=%04lx\n",VM86_ARG(fn),context.Eax);
ret=DOSVM_Int(VM86_ARG(fn),&context); break;
ret=DOSVM_Int(VM86_ARG(fn),&context,lpDosTask); break;
case VM86_STI:
break;
case VM86_PICRETURN:
......
......@@ -68,13 +68,13 @@ static void MZ_InitPSP( LPVOID lpPSP, LPCSTR cmdline, WORD env )
static char enter_xms[]={
/* XMS hookable entry point */
0xEB,0x03, /* jmp entry */
0x90,0x90,0x90, /* nop;nop;nop */
/* entry: */
0xEB,0x03, /* jmp entry */
0x90,0x90,0x90, /* nop;nop;nop */
/* entry: */
/* real entry point */
/* for simplicity, we'll just use the same hook as DPMI below */
0xCD,0x31, /* int 0x31 */
0xCB /* retf */
0xCD,0x31, /* int $0x31 */
0xCB /* lret */
};
static void MZ_InitXMS( LPDOSTASK lpDosTask )
......@@ -92,7 +92,7 @@ static char enter_pm[]={
0x8B,0x56,0x08, /* movw 8(%bp),%dx */
/* just call int 31 here to get into protected mode... */
/* it'll check whether it was called from dpmi_seg... */
0xCD,0x31, /* int 0x31 */
0xCD,0x31, /* int $0x31 */
/* we are now in the context of a 16-bit relay call */
/* need to fixup our stack;
* 16-bit relay return address will be lost, but we won't worry quite yet */
......@@ -103,14 +103,22 @@ static char enter_pm[]={
0x5D, /* popw %bp */
0x5A, /* popw %dx */
0x58, /* popw %ax */
0xCB /* retf */
0xCB /* lret */
};
static char wrap_rm[]={
0xCD,0x31, /* int $0x31 */
0xCB /* lret */
};
static void MZ_InitDPMI( LPDOSTASK lpDosTask )
{
LPBYTE start=DOSMEM_GetBlock(lpDosTask->hModule,sizeof(enter_pm),&(lpDosTask->dpmi_seg));
unsigned size=sizeof(enter_pm)+sizeof(wrap_rm);
LPBYTE start=DOSMEM_GetBlock(lpDosTask->hModule,size,&(lpDosTask->dpmi_seg));
lpDosTask->dpmi_sel = SELECTOR_AllocBlock( start, sizeof(enter_pm), SEGMENT_CODE, FALSE, FALSE );
lpDosTask->dpmi_sel = SELECTOR_AllocBlock( start, size, SEGMENT_CODE, FALSE, FALSE );
lpDosTask->wrap_ofs = size-sizeof(wrap_rm);
lpDosTask->call_ofs = size-1;
memcpy(start,enter_pm,sizeof(enter_pm));
}
......@@ -258,12 +266,33 @@ static int MZ_LoadImage( HFILE16 hFile, LPCSTR name, LPCSTR cmdline,
return 32;
}
LPDOSTASK MZ_AllocDPMITask( HMODULE16 hModule )
{
LPDOSTASK lpDosTask = calloc(1, sizeof(DOSTASK));
NE_MODULE *pModule;
if (lpDosTask) {
lpDosTask->hModule = hModule;
pModule = (NE_MODULE *)GlobalLock16(hModule);
pModule->lpDosTask = lpDosTask;
lpDosTask->img=NULL; lpDosTask->mm_name[0]=0; lpDosTask->mm_fd=-1;
MZ_InitMemory(lpDosTask, pModule);
GlobalUnlock16(hModule);
}
return lpDosTask;
}
int MZ_InitTask( LPDOSTASK lpDosTask )
{
int read_fd[2],write_fd[2];
pid_t child;
char *fname,*farg,arg[16],fproc[64],path[256],*fpath;
if (!lpDosTask) return 0;
/* create read pipe */
if (pipe(read_fd)<0) return 0;
if (pipe(write_fd)<0) {
......
......@@ -181,25 +181,127 @@ static void INT_SetRealModeContext( REALMODECALL *call, CONTEXT *context )
/**********************************************************************
* DPMI_CallRMProc
*
* This routine does the hard work of calling a real mode procedure.
*/
int DPMI_CallRMProc( CONTEXT *context, LPWORD stack, int args, int iret )
{
LPWORD stack16;
THDB *thdb = THREAD_Current();
LPVOID addr;
TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
NE_MODULE *pModule = pTask ? NE_GetPtr( pTask->hModule ) : NULL;
int alloc = 0;
GlobalUnlock16( GetCurrentTask() );
TRACE(int31, "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n",
EAX_reg(context), EBX_reg(context), ECX_reg(context), EDX_reg(context) );
TRACE(int31, "ESI=%08lx EDI=%08lx ES=%04x DS=%04x CS:IP=%04x:%04x, %d WORD arguments\n",
ESI_reg(context), EDI_reg(context), ES_reg(context), DS_reg(context),
CS_reg(context), IP_reg(context), args );
#ifdef MZ_SUPPORTED
FIXME(int31,"DPMI real-mode call using DOS VM task system, untested!\n");
if (!pModule->lpDosTask) {
TRACE(int31,"creating VM86 task\n");
if (MZ_InitTask( MZ_AllocDPMITask( pModule->self ) ) < 32) {
ERR(int31,"could not setup VM86 task\n");
return 1;
}
}
if (!SS_reg(context)) {
alloc = 1; /* allocate default stack */
stack16 = addr = DOSMEM_GetBlock( pModule->self, 64, &(SS_reg(context)) );
SP_reg(context) = 64-2;
if (!stack16) {
ERR(int31,"could not allocate default stack\n");
return 1;
}
} else {
stack16 = CTX_SEG_OFF_TO_LIN(context, SS_reg(context), SP_reg(context));
addr = NULL; /* avoid gcc warning */
}
SP_reg(context) -= args*sizeof(WORD) + (iret?1:0);
#else
stack16 = THREAD_STACK16(thdb);
#endif
stack16 -= args;
if (args) memcpy(stack16, stack, args*sizeof(WORD) );
/* push flags if iret */
if (iret) {
stack16--; args++;
*stack16 = FL_reg(context);
}
#ifdef MZ_SUPPORTED
/* push return address (return to interrupt wrapper) */
*(--stack16) = pModule->lpDosTask->dpmi_seg;
*(--stack16) = pModule->lpDosTask->wrap_ofs;
/* push call address */
*(--stack16) = CS_reg(context);
*(--stack16) = IP_reg(context);
/* adjust stack */
SP_reg(context) -= 4*sizeof(WORD);
/* set initial CS:IP to the wrapper's "lret" */
CS_reg(context) = pModule->lpDosTask->dpmi_seg;
IP_reg(context) = pModule->lpDosTask->call_ofs;
TRACE(int31,"entering real mode...\n");
DOSVM_Enter( context );
TRACE(int31,"returned from real-mode call\n");
if (alloc) DOSMEM_FreeBlock( pModule->self, addr );
#else
/* FIXME: I copied this from CallRMProcFar (below), did I do it right? */
/* Murphy's law says I didn't */
addr = CTX_SEG_OFF_TO_LIN(context, CS_reg(context), IP_reg(context));
sel = SELECTOR_AllocBlock( addr, 0x10000, SEGMENT_CODE, FALSE, FALSE );
seg_addr = PTR_SEG_OFF_TO_SEGPTR( sel, 0 );
CS_reg(context) = HIWORD(seg_addr);
IP_reg(context) = LOWORD(seg_addr);
EBP_reg(context) = OFFSETOF( thdb->cur_stack )
+ (WORD)&((STACK16FRAME*)0)->bp;
Callbacks->CallRegisterShortProc(context, args*sizeof(WORD));
UnMapLS(seg_addr);
#endif
return 0;
}
/**********************************************************************
* INT_DoRealModeInt
*/
static void INT_DoRealModeInt( CONTEXT *context )
{
CONTEXT realmode_ctx;
FARPROC16 rm_int = INT_GetRMHandler( BL_reg(context) );
REALMODECALL *call = (REALMODECALL *)PTR_SEG_OFF_TO_LIN( ES_reg(context),
DI_reg(context) );
INT_GetRealModeContext( call, &realmode_ctx );
RESET_CFLAG(context);
if (INT_RealModeInterrupt( BL_reg(context), &realmode_ctx ))
SET_CFLAG(context);
if (EFL_reg(context)&1) {
FIXME(int31,"%02x: EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n",
BL_reg(context), EAX_reg(&realmode_ctx), EBX_reg(&realmode_ctx),
ECX_reg(&realmode_ctx), EDX_reg(&realmode_ctx));
FIXME(int31," ESI=%08lx EDI=%08lx DS=%04lx ES=%04lx\n",
ESI_reg(&realmode_ctx), EDI_reg(&realmode_ctx),
DS_reg(&realmode_ctx), ES_reg(&realmode_ctx) );
#ifdef MZ_SUPPORTED
/* we need to check if a real-mode program has hooked the interrupt */
if (HIWORD(rm_int)!=0xF000) {
/* yup, which means we need to switch to real mode... */
CS_reg(&realmode_ctx) = HIWORD(rm_int);
EIP_reg(&realmode_ctx) = LOWORD(rm_int);
if (DPMI_CallRMProc( &realmode_ctx, NULL, 0, TRUE))
SET_CFLAG(context);
} else
#endif
{
RESET_CFLAG(context);
if (INT_RealModeInterrupt( BL_reg(context), &realmode_ctx ))
SET_CFLAG(context);
if (EFL_reg(context)&1) {
FIXME(int31,"%02x: EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n",
BL_reg(context), EAX_reg(&realmode_ctx), EBX_reg(&realmode_ctx),
ECX_reg(&realmode_ctx), EDX_reg(&realmode_ctx));
FIXME(int31," ESI=%08lx EDI=%08lx DS=%04lx ES=%04lx\n",
ESI_reg(&realmode_ctx), EDI_reg(&realmode_ctx),
DS_reg(&realmode_ctx), ES_reg(&realmode_ctx) );
}
}
INT_SetRealModeContext( call, &realmode_ctx );
}
......@@ -227,6 +329,7 @@ static void CallRMProcFar( CONTEXT *context )
}
INT_GetRealModeContext(p, &context16);
#if 0
addr = DOSMEM_MapRealToLinear(MAKELONG(p->ip, p->cs));
sel = SELECTOR_AllocBlock( addr, 0x10000, SEGMENT_CODE, FALSE, FALSE );
seg_addr = PTR_SEG_OFF_TO_SEGPTR( sel, 0 );
......@@ -243,6 +346,10 @@ static void CallRMProcFar( CONTEXT *context )
Callbacks->CallRegisterShortProc(&context16, argsize);
UnMapLS(seg_addr);
#else
DPMI_CallRMProc( &context16, ((LPWORD)PTR_SEG_OFF_TO_LIN(SS_reg(context), SP_reg(context)))+3,
CX_reg(context), 0 );
#endif
INT_SetRealModeContext(p, &context16);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment