First shot at DPMI realmode calls.
This commit is contained in:
parent
ebc543cdb0
commit
28c11324b5
|
@ -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:
|
||||
|
|
|
@ -73,8 +73,8 @@ static char enter_xms[]={
|
|||
/* 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) {
|
||||
|
|
107
msdos/dpmi.c
107
msdos/dpmi.c
|
@ -180,16 +180,117 @@ 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 );
|
||||
|
||||
#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);
|
||||
|
@ -201,6 +302,7 @@ static void INT_DoRealModeInt( CONTEXT *context )
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue