Extended __wine_enter_vm86 to handle pending interrupts.
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 39a41c4..91cf202 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c
@@ -774,6 +774,62 @@ /********************************************************************** + * set_vm86_pend + * + * Handler for SIGUSR2, which we use to set the vm86 pending flag. + */ +static void set_vm86_pend( CONTEXT *context ) +{ + EXCEPTION_RECORD rec; + TEB *teb = NtCurrentTeb(); + + rec.ExceptionCode = EXCEPTION_VM86_STI; + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionRecord = NULL; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = 0; + + /* __wine_enter_vm86() merges the vm86_pending flag in safely */ + teb->vm86_pending |= VIP_MASK; + /* see if we were in VM86 mode */ + if (context->EFlags & 0x00020000) + { + /* seems so, also set flag in signal context */ + if (context->EFlags & VIP_MASK) return; + context->EFlags |= VIP_MASK; + if (context->EFlags & VIF_MASK) { + /* VIF is set, throw exception */ + teb->vm86_pending = 0; + rec.ExceptionAddress = (LPVOID)context->Eip; + EXC_RtlRaiseException( &rec, context ); + } + } +#ifdef linux + else if (teb->vm86_ptr) + { + /* not in VM86, but possibly setting up for it */ + struct vm86plus_struct *vm86 = (struct vm86plus_struct*)(teb->vm86_ptr); + if (vm86->regs.eflags & VIP_MASK) return; + vm86->regs.eflags |= VIP_MASK; + if (vm86->regs.eflags & VIF_MASK) { + /* VIF is set, throw exception */ + CONTEXT vcontext; + teb->vm86_pending = 0; + save_vm86_context( &vcontext, vm86 ); + rec.ExceptionAddress = (LPVOID)vcontext.Eip; + EXC_RtlRaiseException( &rec, &vcontext ); + restore_vm86_context( &vcontext, vm86 ); + if (teb->vm86_ctx) { + /* must also save here */ + *(CONTEXT*)(teb->vm86_ctx) = vcontext; + } + } + } +#endif /* linux */ +} + + +/********************************************************************** * segv_handler * * Handler for SIGSEGV and related errors. @@ -839,6 +895,41 @@ } +/********************************************************************** + * alrm_handler + * + * Handler for SIGALRM. + * Increases the alarm counter and sets the vm86 pending flag. + */ +static HANDLER_DEF(alrm_handler) +{ + CONTEXT context; + + save_context( &context, HANDLER_CONTEXT ); + NtCurrentTeb()->alarms++; + set_vm86_pend( &context ); + restore_context( &context, HANDLER_CONTEXT ); +} + + +/********************************************************************** + * usr2_handler + * + * Handler for SIGUSR2. + * We use it to signal that the running __wine_enter_vm86() should + * immediately set VIP_MASK, causing pending events to be handled + * as early as possible. + */ +static HANDLER_DEF(usr2_handler) +{ + CONTEXT context; + + save_context( &context, HANDLER_CONTEXT ); + set_vm86_pend( &context ); + restore_context( &context, HANDLER_CONTEXT ); +} + + /*********************************************************************** * set_handler * @@ -919,6 +1010,8 @@ #ifdef SIGTRAP if (set_handler( SIGTRAP, have_sigaltstack, (void (*)())trap_handler ) == -1) goto error; #endif + if (set_handler( SIGALRM, have_sigaltstack, (void (*)())alrm_handler ) == -1) goto error; + if (set_handler( SIGUSR2, have_sigaltstack, (void (*)())usr2_handler ) == -1) goto error; return TRUE; error: @@ -936,6 +1029,7 @@ void __wine_enter_vm86( CONTEXT *context ) { EXCEPTION_RECORD rec; + TEB *teb = NtCurrentTeb(); int res; struct vm86plus_struct vm86; @@ -943,6 +1037,22 @@ for (;;) { restore_vm86_context( context, &vm86 ); + /* Linux doesn't preserve pending flag (VIP_MASK) on return, + * so save it on entry, just in case */ + teb->vm86_pending |= (context->EFlags & VIP_MASK); + /* Work around race conditions with signal handler + * (avoiding sigprocmask for performance reasons) */ + teb->vm86_ptr = &vm86; + vm86.regs.eflags |= teb->vm86_pending; + /* Check for VIF|VIP here, since vm86_enter doesn't */ + if ((vm86.regs.eflags & (VIF_MASK|VIP_MASK)) == (VIF_MASK|VIP_MASK)) { + teb->vm86_ptr = NULL; + teb->vm86_pending = 0; + context->EFlags |= VIP_MASK; + rec.ExceptionCode = EXCEPTION_VM86_STI; + rec.ExceptionInformation[0] = 0; + goto cancel_vm86; + } do { @@ -954,7 +1064,11 @@ } } while (VM86_TYPE(res) == VM86_SIGNAL); + teb->vm86_ctx = context; save_vm86_context( context, &vm86 ); + teb->vm86_ptr = NULL; + teb->vm86_ctx = NULL; + context->EFlags |= teb->vm86_pending; switch(VM86_TYPE(res)) { @@ -962,12 +1076,13 @@ do_segv( context, T_PROTFLT, 0, 0 ); continue; case VM86_TRAP: /* return due to DOS-debugger request */ - do_trap( context, VM86_ARG(res) ); + do_trap( context, VM86_ARG(res) ); continue; case VM86_INTx: /* int3/int x instruction (ARG = x) */ rec.ExceptionCode = EXCEPTION_VM86_INTx; break; case VM86_STI: /* sti/popf/iret instruction enabled virtual interrupts */ + teb->vm86_pending = 0; rec.ExceptionCode = EXCEPTION_VM86_STI; break; case VM86_PICRETURN: /* return due to pending PIC request */ @@ -977,11 +1092,12 @@ ERR( "unhandled result from vm86 mode %x\n", res ); continue; } + rec.ExceptionInformation[0] = VM86_ARG(res); +cancel_vm86: rec.ExceptionFlags = EXCEPTION_CONTINUABLE; rec.ExceptionRecord = NULL; rec.ExceptionAddress = (LPVOID)context->Eip; rec.NumberParameters = 1; - rec.ExceptionInformation[0] = VM86_ARG(res); EXC_RtlRaiseException( &rec, context ); } }
diff --git a/include/thread.h b/include/thread.h index 03c4ba7..d132ea9 100644 --- a/include/thread.h +++ b/include/thread.h
@@ -102,10 +102,14 @@ void *pthread_data; /* --3 220 Data for pthread emulation */ struct async_private *pending_list; /* --3 224 list of pending async operations */ void *driver_data; /* --3 228 Graphics driver private data */ + DWORD alarms; /* --3 22c Data for vm86 mode */ + DWORD vm86_pending; /* --3 230 Data for vm86 mode */ + void *vm86_ptr; /* --3 234 Data for vm86 mode */ + void *vm86_ctx; /* --3 238 Data for vm86 mode */ /* here is plenty space for wine specific fields (don't forget to change pad6!!) */ /* the following are nt specific fields */ - DWORD pad6[627]; /* --n 22c */ + DWORD pad6[623]; /* --n 23c */ UNICODE_STRING StaticUnicodeString; /* -2- bf8 used by advapi32 */ USHORT StaticUnicodeBuffer[261]; /* -2- c00 used by advapi32 */ DWORD pad7; /* --n e0c */