diff --git a/loader/dos/dosmod.c b/loader/dos/dosmod.c index 6514f08947f..75ac48ff587 100644 --- a/loader/dos/dosmod.c +++ b/loader/dos/dosmod.c @@ -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 #include #include +#include #include #include #include +#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 diff --git a/loader/dos/dosmod.h b/loader/dos/dosmod.h new file mode 100644 index 00000000000..65456206bd9 --- /dev/null +++ b/loader/dos/dosmod.h @@ -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 diff --git a/loader/dos/dosvm.c b/loader/dos/dosvm.c index 0ade52ae9b4..989b6a950ac 100644 --- a/loader/dos/dosvm.c +++ b/loader/dos/dosvm.c @@ -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 #include -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 diff --git a/loader/dos/module.c b/loader/dos/module.c index c0b5f47872b..df644ae4b88 100644 --- a/loader/dos/module.c +++ b/loader/dos/module.c @@ -15,6 +15,7 @@ #include #include #include +#include #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; xsystem_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);