From 28c11324b55113c32cc04e04e8519c123041d2ec Mon Sep 17 00:00:00 2001 From: Ove Kaaven Date: Fri, 23 Oct 1998 09:50:07 +0000 Subject: [PATCH] First shot at DPMI realmode calls. --- include/dosexe.h | 2 + loader/dos/dosvm.c | 14 +++-- loader/dos/module.c | 47 ++++++++++++---- msdos/dpmi.c | 127 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 168 insertions(+), 22 deletions(-) diff --git a/include/dosexe.h b/include/dosexe.h index 3fb33e15367..202a7b2fff0 100644 --- a/include/dosexe.h +++ b/include/dosexe.h @@ -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 */ diff --git a/loader/dos/dosvm.c b/loader/dos/dosvm.c index 093b159d08a..fc918148959 100644 --- a/loader/dos/dosvm.c +++ b/loader/dos/dosvm.c @@ -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: diff --git a/loader/dos/module.c b/loader/dos/module.c index 9573030a65b..4a7471d2acf 100644 --- a/loader/dos/module.c +++ b/loader/dos/module.c @@ -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) { diff --git a/msdos/dpmi.c b/msdos/dpmi.c index 913d832d858..ed236ba8e6f 100644 --- a/msdos/dpmi.c +++ b/msdos/dpmi.c @@ -180,26 +180,128 @@ 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); }