Added some new dosmod communication possibilities, including

activating a dosmod-specific setitimer(), and the capture of some
common signals, which is returned to Wine (previously a SIGILL
would just cause a "dosmod sync lost" without explanation, now it
invokes the Wine debugger). Invokes int 08 upon receipt of dosmod
SIGALRM, thus simulating the DOS timer. Made DOS interrupt calls
be reported by -debugmsg +relay instead of -debugmsg +int. And
fixed non-i386 compilation of dosmod. (Anything else?!)
This commit is contained in:
Ove Kaaven 1998-12-24 16:23:01 +00:00 committed by Alexandre Julliard
parent a844189d1a
commit b8e7a833c7
4 changed files with 170 additions and 28 deletions

View File

@ -4,7 +4,7 @@
* Copyright 1998 Ove Kåven
*/
#ifdef linux
#if defined(linux) && defined(__i386__)
/* apparently ELF images are usually loaded high anyway */
#ifndef __ELF__
@ -22,9 +22,11 @@ asm(".org 0x110000");
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/vm86.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "dosmod.h"
/* FIXME: hack because libc vm86 may be the old syscall version */
@ -54,11 +56,38 @@ static __inline__ int vm86plus( int func, struct vm86plus_struct *ptr )
return -1;
}
void set_timer(struct timeval*tim)
{
struct itimerval cur;
cur.it_interval=*tim;
cur.it_value=*tim;
setitimer(ITIMER_REAL,&cur,NULL);
}
volatile int sig_pend,sig_fatal=0;
void*img;
struct vm86plus_struct VM86;
void sig_handler(int sig)
{
if (sig_pend) fprintf(stderr,"DOSMOD previous signal %d lost\n",sig_pend);
sig_pend=sig;
signal(sig,sig_handler);
}
void bad_handler(int sig)
{
fprintf(stderr,"DOSMOD caught fatal signal %d\n",sig);
fprintf(stderr,"(Last known VM86 CS:IP was %04x:%04lx)\n",VM86.regs.cs,VM86.regs.eip);
sig_pend=sig; sig_fatal++;
signal(sig,bad_handler);
}
int main(int argc,char**argv)
{
int mfd=open(argv[0],O_RDWR);
void*img;
struct vm86plus_struct VM86;
struct timeval tim;
int func,ret;
off_t fofs=0;
pid_t ppid=getppid();
@ -73,8 +102,8 @@ int main(int argc,char**argv)
/* linux currently only allows mapping a process memory if it's being ptraced */
/* Linus doesn't like it, so this probably won't work in the future */
/* it doesn't even work for me right now */
ptrace(PTRACE_ATTACH,ppid,0,0);
kill(ppid,SIGSTOP);
ptrace(PTRACE_ATTACH,ppid,0,0);
waitpid(ppid,NULL,0);
}
img=mmap(NULL,0x110000,PROT_EXEC|PROT_READ|PROT_WRITE,MAP_FIXED|MAP_SHARED,mfd,fofs);
@ -87,24 +116,55 @@ int main(int argc,char**argv)
fprintf(stderr,"in attempt to map %s, offset %08lX, length 110000, to offset 0\n",argv[0],fofs);
return 1;
}
/* fprintf(stderr,"Successfully mapped DOS memory, entering vm86 loop\n"); */
signal(SIGHUP,SIG_IGN);
signal(SIGINT,SIG_IGN);
/* initialize signals and system timer */
signal(SIGHUP,sig_handler);
signal(SIGINT,sig_handler);
signal(SIGUSR1,sig_handler);
signal(SIGUSR2,sig_handler);
signal(SIGALRM,sig_handler);
signal(SIGQUIT,bad_handler);
signal(SIGILL,bad_handler);
signal(SIGBUS,bad_handler);
signal(SIGFPE,bad_handler);
signal(SIGSEGV,bad_handler);
signal(SIGTERM,bad_handler);
#if 0
tim.tv_sec=0; tim.tv_usec=54925;
set_timer(&tim);
#endif
/* report back to the main program that we're ready */
ret=0;
ret=1; /* dosmod protocol revision 1 */
write(1,&ret,sizeof(ret));
/* context exchange loop */
do {
if (read(0,&func,sizeof(func))!=sizeof(func)) return 1;
if (read(0,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1;
if (func<0) break;
ret=vm86plus(func,&VM86);
if (write(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
if (write(1,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1;
switch (func) {
case DOSMOD_SET_TIMER:
if (read(0,&tim,sizeof(tim))!=sizeof(tim)) return 1;
set_timer(&tim);
/* no response */
break;
case DOSMOD_ENTER:
default:
if (read(0,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1;
if (sig_pend) ret=DOSMOD_SIGNAL; else
ret=vm86plus(func,&VM86);
if (write(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
if (write(1,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1;
switch (ret&0xff) {
case DOSMOD_SIGNAL:
ret=sig_pend; sig_pend=0;
if (write(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
if (sig_fatal) return 1;
break;
}
}
} while (1);
return 0;
}
#else /* !linux */
#else /* !linux-i386 */
int main(void) {return 1;}
#endif

9
loader/dos/dosmod.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __WINE_DOSMOD_H
#define __WINE_DOSMOD_H
#define DOSMOD_ENTER 0x01 /* VM86_ENTER */
#define DOSMOD_SET_TIMER 0x10
#define DOSMOD_SIGNAL 0x00 /* VM86_SIGNAL */
#endif

View File

@ -28,6 +28,7 @@
#include "task.h"
#include "ldt.h"
#include "dosexe.h"
#include "dosmod.h"
void (*ctx_debug_call)(int sig,CONTEXT*ctx)=NULL;
BOOL32 (*instr_emu_call)(SIGCONTEXT*ctx)=NULL;
@ -37,7 +38,7 @@ BOOL32 (*instr_emu_call)(SIGCONTEXT*ctx)=NULL;
#include <sys/mman.h>
#include <sys/vm86.h>
static void DOSVM_Dump( LPDOSTASK lpDosTask, int fn,
static void DOSVM_Dump( LPDOSTASK lpDosTask, int fn, int sig,
struct vm86plus_struct*VM86 )
{
unsigned iofs;
@ -46,7 +47,7 @@ static void DOSVM_Dump( LPDOSTASK lpDosTask, int fn,
switch (VM86_TYPE(fn)) {
case VM86_SIGNAL:
printf("Trapped signal\n"); break;
printf("Trapped signal %d\n",sig); break;
case VM86_UNKNOWN:
printf("Trapped unhandled GPF\n"); break;
case VM86_INTx:
@ -89,13 +90,26 @@ static int DOSVM_Int( int vect, PCONTEXT context, LPDOSTASK lpDosTask )
return 0;
}
static void DOSVM_SimulateInt( int vect, PCONTEXT context, LPDOSTASK lpDosTask )
{
FARPROC16 handler=INT_GetRMHandler(vect);
WORD*stack=(WORD*)(V86BASE(context)+(((DWORD)SS_reg(context))<<4)+SP_reg(context));
*(--stack)=FL_reg(context);
*(--stack)=CS_reg(context);
*(--stack)=IP_reg(context);
SP_reg(context)-=6;
CS_reg(context)=SELECTOROF(handler);
IP_reg(context)=OFFSETOF(handler);
}
#define CV CP(eax,EAX); CP(ecx,ECX); CP(edx,EDX); CP(ebx,EBX); \
CP(esi,ESI); CP(edi,EDI); CP(esp,ESP); CP(ebp,EBP); \
CP(cs,CS); CP(ds,DS); CP(es,ES); \
CP(ss,SS); CP(fs,FS); CP(gs,GS); \
CP(eip,EIP); CP(eflags,EFL)
static int DOSVM_Process( LPDOSTASK lpDosTask, int fn,
static int DOSVM_Process( LPDOSTASK lpDosTask, int fn, int sig,
struct vm86plus_struct*VM86 )
{
SIGCONTEXT sigcontext;
@ -121,15 +135,31 @@ static int DOSVM_Process( LPDOSTASK lpDosTask, int fn,
switch (VM86_TYPE(fn)) {
case VM86_SIGNAL:
DOSVM_Dump(lpDosTask,fn,VM86);
ret=-1; break;
TRACE(int,"DOS module caught signal %d\n",sig);
if (sig==SIGALRM) {
DOSVM_SimulateInt(8,&context,lpDosTask);
} else
if (sig==SIGHUP) {
if (ctx_debug_call) ctx_debug_call(SIGTRAP,&context);
} else
if ((sig==SIGILL)||(sig==SIGSEGV)) {
if (ctx_debug_call) ctx_debug_call(SIGILL,&context);
} else {
DOSVM_Dump(lpDosTask,fn,sig,VM86);
ret=-1;
}
break;
case VM86_UNKNOWN: /* unhandled GPF */
DOSVM_Dump(lpDosTask,fn,VM86);
DOSVM_Dump(lpDosTask,fn,sig,VM86);
if (ctx_debug_call) ctx_debug_call(SIGSEGV,&context); else ret=-1;
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,lpDosTask); break;
if (TRACE_ON(relay))
DPRINTF("Call DOS int 0x%02x (EAX=%08lx) ret=%04lx:%04lx\n",VM86_ARG(fn),context.Eax,context.SegCs,context.Eip);
ret=DOSVM_Int(VM86_ARG(fn),&context,lpDosTask);
if (TRACE_ON(relay))
DPRINTF("Ret DOS int 0x%02x (EAX=%08lx) ret=%04lx:%04lx\n",VM86_ARG(fn),context.Eax,context.SegCs,context.Eip);
break;
case VM86_STI:
break;
case VM86_PICRETURN:
@ -138,7 +168,7 @@ static int DOSVM_Process( LPDOSTASK lpDosTask, int fn,
if (ctx_debug_call) ctx_debug_call(SIGTRAP,&context);
break;
default:
DOSVM_Dump(lpDosTask,fn,VM86);
DOSVM_Dump(lpDosTask,fn,sig,VM86);
ret=-1;
}
@ -154,7 +184,7 @@ int DOSVM_Enter( PCONTEXT context )
NE_MODULE *pModule = NE_GetPtr( pTask->hModule );
LPDOSTASK lpDosTask;
struct vm86plus_struct VM86;
int stat,len;
int stat,len,sig;
fd_set readfds,exceptfds;
GlobalUnlock16( GetCurrentTask() );
@ -199,6 +229,7 @@ int DOSVM_Enter( PCONTEXT context )
/* main exchange loop */
do {
stat = VM86_ENTER;
errno = 0;
/* transmit VM86 structure to dosmod task */
if (write(lpDosTask->write_pipe,&stat,sizeof(stat))!=sizeof(stat)) {
ERR(module,"dosmod sync lost, errno=%d\n",errno);
@ -241,8 +272,20 @@ int DOSVM_Enter( PCONTEXT context )
return -1;
}
} while (0);
if ((stat&0xff)==DOSMOD_SIGNAL) {
do {
if ((len=read(lpDosTask->read_pipe,&sig,sizeof(sig)))!=sizeof(sig)) {
if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) {
WARN(module,"rereading dosmod signal due to errno=%d, result=%d\n",errno,len);
continue;
}
ERR(module,"dosmod sync lost reading signal, errno=%d, result=%d\n",errno,len);
return -1;
}
} while (0);
} else sig=0;
/* got response */
} while (DOSVM_Process(lpDosTask,stat,&VM86)>=0);
} while (DOSVM_Process(lpDosTask,stat,sig,&VM86)>=0);
if (context) {
#define CP(x,y) y##_reg(context) = VM86.regs.x

View File

@ -15,6 +15,7 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "windows.h"
#include "winbase.h"
#include "module.h"
@ -26,6 +27,7 @@
#include "miscemu.h"
#include "debug.h"
#include "dosexe.h"
#include "dosmod.h"
#include "options.h"
#ifdef MZ_SUPPORTED
@ -68,6 +70,7 @@ static void MZ_InitPSP( LPVOID lpPSP, LPCSTR cmdline, WORD env )
/* FIXME: integrate the PDB stuff from Wine (loader/task.c) */
}
/* default INT 08 handler: increases timer tick counter but not much more */
static char int08[]={
0xCD,0x1C, /* int $0x1c */
0x50, /* pushw %ax */
@ -92,7 +95,10 @@ static void MZ_InitHandlers( LPDOSTASK lpDosTask )
WORD seg;
LPBYTE start=DOSMEM_GetBlock(lpDosTask->hModule,sizeof(int08),&seg);
memcpy(start,int08,sizeof(int08));
/* INT 08: point it at our tick-incrementing handler */
((SEGPTR*)(lpDosTask->img))[0x08]=PTR_SEG_OFF_TO_SEGPTR(seg,0);
/* INT 1C: just point it to IRET, we don't want to handle it ourselves */
((SEGPTR*)(lpDosTask->img))[0x1C]=PTR_SEG_OFF_TO_SEGPTR(seg,sizeof(int08)-1);
}
static char enter_xms[]={
@ -201,6 +207,7 @@ int MZ_InitMemory( LPDOSTASK lpDosTask, NE_MODULE *pModule )
/* initialize the memory */
TRACE(module,"Initializing DOS memory structures\n");
DOSMEM_Init(lpDosTask->hModule);
MZ_InitHandlers(lpDosTask);
MZ_InitXMS(lpDosTask);
MZ_InitDPMI(lpDosTask);
return lpDosTask->hModule;
@ -268,7 +275,7 @@ static int MZ_LoadImage( HFILE16 hFile, LPCSTR name, LPCSTR cmdline,
if (mz_header.e_crlc) {
/* load relocation table */
TRACE(module,"loading DOS EXE relocation table, %d entries\n",mz_header.e_lfarlc);
TRACE(module,"loading DOS EXE relocation table, %d entries\n",mz_header.e_crlc);
/* FIXME: is this too slow without read buffering? */
_llseek16(hFile,mz_header.e_lfarlc,FILE_BEGIN);
for (x=0; x<mz_header.e_crlc; x++) {
@ -308,6 +315,26 @@ LPDOSTASK MZ_AllocDPMITask( HMODULE16 hModule )
return lpDosTask;
}
static void MZ_InitTimer( LPDOSTASK lpDosTask, int ver )
{
if (ver<1) {
#if 0
/* start simulated system 55Hz timer */
lpDosTask->system_timer = CreateSystemTimer( 55, MZ_Tick );
TRACE(module,"created 55Hz timer tick, handle=%d\n",lpDosTask->system_timer);
#endif
} else {
int func;
struct timeval tim;
/* start dosmod timer at 55Hz */
func=DOSMOD_SET_TIMER;
tim.tv_sec=0; tim.tv_usec=54925;
write(lpDosTask->write_pipe,&func,sizeof(func));
write(lpDosTask->write_pipe,&tim,sizeof(tim));
}
}
int MZ_InitTask( LPDOSTASK lpDosTask )
{
int read_fd[2],write_fd[2];
@ -355,6 +382,8 @@ int MZ_InitTask( LPDOSTASK lpDosTask )
/* the child has now mmaped the temp file, it's now safe to unlink.
* do it here to avoid leaving a mess in /tmp if/when Wine crashes... */
if (lpDosTask->mm_name[0]!=0) unlink(lpDosTask->mm_name);
/* start simulated system timer */
MZ_InitTimer(lpDosTask,ret);
/* all systems are now go */
} else {
/* child process */
@ -362,6 +391,8 @@ int MZ_InitTask( LPDOSTASK lpDosTask )
/* put our pipes somewhere dosmod can find them */
dup2(write_fd[0],0); /* stdin */
dup2(read_fd[1],1); /* stdout */
/* enable signals */
SIGNAL_MaskAsyncEvents(FALSE);
/* now load dosmod */
execlp("dosmod",fname,farg,NULL);
execl("dosmod",fname,farg,NULL);
@ -377,9 +408,6 @@ int MZ_InitTask( LPDOSTASK lpDosTask )
ERR(module,"Failed to spawn dosmod, error=%s\n",strerror(errno));
exit(1);
}
/* start simulated system 55Hz timer */
lpDosTask->system_timer = CreateSystemTimer( 55, MZ_Tick );
TRACE(module,"created 55Hz timer tick, handle=%d\n",lpDosTask->system_timer);
return lpDosTask->hModule;
}
@ -447,7 +475,9 @@ HINSTANCE16 MZ_CreateProcess( LPCSTR name, LPCSTR cmdline, LPCSTR env,
void MZ_KillModule( LPDOSTASK lpDosTask )
{
TRACE(module,"killing DOS task\n");
#if 0
SYSTEM_KillSystemTimer(lpDosTask->system_timer);
#endif
if (lpDosTask->mm_name[0]!=0) {
munmap(lpDosTask->img,0x110000-START_OFFSET);
close(lpDosTask->mm_fd);