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 init_cs,init_ip,init_ss,init_sp;
|
||||||
WORD xms_seg;
|
WORD xms_seg;
|
||||||
WORD dpmi_seg,dpmi_sel,dpmi_flag;
|
WORD dpmi_seg,dpmi_sel,dpmi_flag;
|
||||||
|
DWORD wrap_ofs,call_ofs;
|
||||||
HMODULE16 hModule;
|
HMODULE16 hModule;
|
||||||
char mm_name[128];
|
char mm_name[128];
|
||||||
int mm_fd;
|
int mm_fd;
|
||||||
|
@ -35,6 +36,7 @@ struct _NE_MODULE;
|
||||||
extern int MZ_InitTask( LPDOSTASK lpDosTask );
|
extern int MZ_InitTask( LPDOSTASK lpDosTask );
|
||||||
extern int MZ_InitMemory( LPDOSTASK lpDosTask, struct _NE_MODULE *pModule );
|
extern int MZ_InitMemory( LPDOSTASK lpDosTask, struct _NE_MODULE *pModule );
|
||||||
extern void MZ_KillModule( LPDOSTASK lpDosTask );
|
extern void MZ_KillModule( LPDOSTASK lpDosTask );
|
||||||
|
extern LPDOSTASK MZ_AllocDPMITask( HMODULE16 hModule );
|
||||||
|
|
||||||
#endif /* linux */
|
#endif /* linux */
|
||||||
|
|
||||||
|
|
|
@ -71,9 +71,17 @@ static void DOSVM_Dump( LPDOSTASK lpDosTask, int fn,
|
||||||
exit(0);
|
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);
|
INT_RealModeInterrupt(vect,context);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +113,7 @@ static int DOSVM_Process( LPDOSTASK lpDosTask, int fn,
|
||||||
break;
|
break;
|
||||||
case VM86_INTx:
|
case VM86_INTx:
|
||||||
TRACE(int,"DOS EXE calls INT %02x with AX=%04lx\n",VM86_ARG(fn),context.Eax);
|
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:
|
case VM86_STI:
|
||||||
break;
|
break;
|
||||||
case VM86_PICRETURN:
|
case VM86_PICRETURN:
|
||||||
|
|
|
@ -68,13 +68,13 @@ static void MZ_InitPSP( LPVOID lpPSP, LPCSTR cmdline, WORD env )
|
||||||
|
|
||||||
static char enter_xms[]={
|
static char enter_xms[]={
|
||||||
/* XMS hookable entry point */
|
/* XMS hookable entry point */
|
||||||
0xEB,0x03, /* jmp entry */
|
0xEB,0x03, /* jmp entry */
|
||||||
0x90,0x90,0x90, /* nop;nop;nop */
|
0x90,0x90,0x90, /* nop;nop;nop */
|
||||||
/* entry: */
|
/* entry: */
|
||||||
/* real entry point */
|
/* real entry point */
|
||||||
/* for simplicity, we'll just use the same hook as DPMI below */
|
/* for simplicity, we'll just use the same hook as DPMI below */
|
||||||
0xCD,0x31, /* int 0x31 */
|
0xCD,0x31, /* int $0x31 */
|
||||||
0xCB /* retf */
|
0xCB /* lret */
|
||||||
};
|
};
|
||||||
|
|
||||||
static void MZ_InitXMS( LPDOSTASK lpDosTask )
|
static void MZ_InitXMS( LPDOSTASK lpDosTask )
|
||||||
|
@ -92,7 +92,7 @@ static char enter_pm[]={
|
||||||
0x8B,0x56,0x08, /* movw 8(%bp),%dx */
|
0x8B,0x56,0x08, /* movw 8(%bp),%dx */
|
||||||
/* just call int 31 here to get into protected mode... */
|
/* just call int 31 here to get into protected mode... */
|
||||||
/* it'll check whether it was called from dpmi_seg... */
|
/* 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 */
|
/* we are now in the context of a 16-bit relay call */
|
||||||
/* need to fixup our stack;
|
/* need to fixup our stack;
|
||||||
* 16-bit relay return address will be lost, but we won't worry quite yet */
|
* 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 */
|
0x5D, /* popw %bp */
|
||||||
0x5A, /* popw %dx */
|
0x5A, /* popw %dx */
|
||||||
0x58, /* popw %ax */
|
0x58, /* popw %ax */
|
||||||
0xCB /* retf */
|
0xCB /* lret */
|
||||||
|
};
|
||||||
|
|
||||||
|
static char wrap_rm[]={
|
||||||
|
0xCD,0x31, /* int $0x31 */
|
||||||
|
0xCB /* lret */
|
||||||
};
|
};
|
||||||
|
|
||||||
static void MZ_InitDPMI( LPDOSTASK lpDosTask )
|
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));
|
memcpy(start,enter_pm,sizeof(enter_pm));
|
||||||
}
|
}
|
||||||
|
@ -258,12 +266,33 @@ static int MZ_LoadImage( HFILE16 hFile, LPCSTR name, LPCSTR cmdline,
|
||||||
return 32;
|
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 MZ_InitTask( LPDOSTASK lpDosTask )
|
||||||
{
|
{
|
||||||
int read_fd[2],write_fd[2];
|
int read_fd[2],write_fd[2];
|
||||||
pid_t child;
|
pid_t child;
|
||||||
char *fname,*farg,arg[16],fproc[64],path[256],*fpath;
|
char *fname,*farg,arg[16],fproc[64],path[256],*fpath;
|
||||||
|
|
||||||
|
if (!lpDosTask) return 0;
|
||||||
/* create read pipe */
|
/* create read pipe */
|
||||||
if (pipe(read_fd)<0) return 0;
|
if (pipe(read_fd)<0) return 0;
|
||||||
if (pipe(write_fd)<0) {
|
if (pipe(write_fd)<0) {
|
||||||
|
|
127
msdos/dpmi.c
127
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
|
* INT_DoRealModeInt
|
||||||
*/
|
*/
|
||||||
static void INT_DoRealModeInt( CONTEXT *context )
|
static void INT_DoRealModeInt( CONTEXT *context )
|
||||||
{
|
{
|
||||||
CONTEXT realmode_ctx;
|
CONTEXT realmode_ctx;
|
||||||
|
FARPROC16 rm_int = INT_GetRMHandler( BL_reg(context) );
|
||||||
REALMODECALL *call = (REALMODECALL *)PTR_SEG_OFF_TO_LIN( ES_reg(context),
|
REALMODECALL *call = (REALMODECALL *)PTR_SEG_OFF_TO_LIN( ES_reg(context),
|
||||||
DI_reg(context) );
|
DI_reg(context) );
|
||||||
INT_GetRealModeContext( call, &realmode_ctx );
|
INT_GetRealModeContext( call, &realmode_ctx );
|
||||||
|
|
||||||
RESET_CFLAG(context);
|
#ifdef MZ_SUPPORTED
|
||||||
if (INT_RealModeInterrupt( BL_reg(context), &realmode_ctx ))
|
/* we need to check if a real-mode program has hooked the interrupt */
|
||||||
SET_CFLAG(context);
|
if (HIWORD(rm_int)!=0xF000) {
|
||||||
if (EFL_reg(context)&1) {
|
/* yup, which means we need to switch to real mode... */
|
||||||
FIXME(int31,"%02x: EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n",
|
CS_reg(&realmode_ctx) = HIWORD(rm_int);
|
||||||
BL_reg(context), EAX_reg(&realmode_ctx), EBX_reg(&realmode_ctx),
|
EIP_reg(&realmode_ctx) = LOWORD(rm_int);
|
||||||
ECX_reg(&realmode_ctx), EDX_reg(&realmode_ctx));
|
if (DPMI_CallRMProc( &realmode_ctx, NULL, 0, TRUE))
|
||||||
FIXME(int31," ESI=%08lx EDI=%08lx DS=%04lx ES=%04lx\n",
|
SET_CFLAG(context);
|
||||||
ESI_reg(&realmode_ctx), EDI_reg(&realmode_ctx),
|
} else
|
||||||
DS_reg(&realmode_ctx), ES_reg(&realmode_ctx) );
|
#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 );
|
INT_SetRealModeContext( call, &realmode_ctx );
|
||||||
}
|
}
|
||||||
|
@ -227,6 +329,7 @@ static void CallRMProcFar( CONTEXT *context )
|
||||||
}
|
}
|
||||||
INT_GetRealModeContext(p, &context16);
|
INT_GetRealModeContext(p, &context16);
|
||||||
|
|
||||||
|
#if 0
|
||||||
addr = DOSMEM_MapRealToLinear(MAKELONG(p->ip, p->cs));
|
addr = DOSMEM_MapRealToLinear(MAKELONG(p->ip, p->cs));
|
||||||
sel = SELECTOR_AllocBlock( addr, 0x10000, SEGMENT_CODE, FALSE, FALSE );
|
sel = SELECTOR_AllocBlock( addr, 0x10000, SEGMENT_CODE, FALSE, FALSE );
|
||||||
seg_addr = PTR_SEG_OFF_TO_SEGPTR( sel, 0 );
|
seg_addr = PTR_SEG_OFF_TO_SEGPTR( sel, 0 );
|
||||||
|
@ -243,6 +346,10 @@ static void CallRMProcFar( CONTEXT *context )
|
||||||
Callbacks->CallRegisterShortProc(&context16, argsize);
|
Callbacks->CallRegisterShortProc(&context16, argsize);
|
||||||
|
|
||||||
UnMapLS(seg_addr);
|
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);
|
INT_SetRealModeContext(p, &context16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue