Commit add0c585 authored by Alexandre Julliard's avatar Alexandre Julliard

Use WOWCallback16Ex to switch to vm86 mode so that we can setup a

proper exception handler and handle instruction emulation.
parent f5cb3dde
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "winbase.h" #include "winbase.h"
#include "wingdi.h" #include "wingdi.h"
#include "wine/winuser16.h" #include "wine/winuser16.h"
#include "excpt.h"
#include "module.h" #include "module.h"
#include "miscemu.h" #include "miscemu.h"
#include "selectors.h" #include "selectors.h"
...@@ -392,17 +393,16 @@ static void INSTR_outport( WORD port, int size, DWORD val, CONTEXT86 *context ) ...@@ -392,17 +393,16 @@ static void INSTR_outport( WORD port, int size, DWORD val, CONTEXT86 *context )
* INSTR_EmulateInstruction * INSTR_EmulateInstruction
* *
* Emulate a privileged instruction. * Emulate a privileged instruction.
* Returns exception code, or 0 if emulation successful. * Returns exception continuation status.
*/ */
DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) DWORD INSTR_EmulateInstruction( EXCEPTION_RECORD *rec, CONTEXT86 *context )
{ {
int prefix, segprefix, prefixlen, len, repX, long_op, long_addr; int prefix, segprefix, prefixlen, len, repX, long_op, long_addr;
BYTE *instr; BYTE *instr;
DWORD ret = EXCEPTION_PRIV_INSTRUCTION;
long_op = long_addr = (!ISV86(context) && IS_SELECTOR_32BIT(context->SegCs)); long_op = long_addr = (!ISV86(context) && IS_SELECTOR_32BIT(context->SegCs));
instr = make_ptr( context, context->SegCs, context->Eip, TRUE ); instr = make_ptr( context, context->SegCs, context->Eip, TRUE );
if (!instr) return ret; if (!instr) return ExceptionContinueSearch;
/* First handle any possible prefix */ /* First handle any possible prefix */
...@@ -476,7 +476,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -476,7 +476,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
} }
add_stack(context, long_op ? 4 : 2); add_stack(context, long_op ? 4 : 2);
context->Eip += prefixlen + 1; context->Eip += prefixlen + 1;
return 0; return ExceptionContinueExecution;
} }
} }
break; /* Unable to emulate it */ break; /* Unable to emulate it */
...@@ -491,7 +491,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -491,7 +491,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
ERR("mov eax,cr0 at 0x%08lx, EAX=0x%08lx\n", ERR("mov eax,cr0 at 0x%08lx, EAX=0x%08lx\n",
context->Eip,context->Eax ); context->Eip,context->Eax );
context->Eip += prefixlen+3; context->Eip += prefixlen+3;
return 0; return ExceptionContinueExecution;
default: default:
break; /*fallthrough to bad instruction handling */ break; /*fallthrough to bad instruction handling */
} }
...@@ -514,12 +514,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -514,12 +514,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
ERR("mov cr4,eax at 0x%08lx\n",context->Eip); ERR("mov cr4,eax at 0x%08lx\n",context->Eip);
context->Eax = 0; context->Eax = 0;
context->Eip += prefixlen+3; context->Eip += prefixlen+3;
return 0; return ExceptionContinueExecution;
case 0xc0: /* mov cr0, eax */ case 0xc0: /* mov cr0, eax */
ERR("mov cr0,eax at 0x%08lx\n",context->Eip); ERR("mov cr0,eax at 0x%08lx\n",context->Eip);
context->Eax = 0x10; /* FIXME: set more bits ? */ context->Eax = 0x10; /* FIXME: set more bits ? */
context->Eip += prefixlen+3; context->Eip += prefixlen+3;
return 0; return ExceptionContinueExecution;
default: /* fallthrough to illegal instruction */ default: /* fallthrough to illegal instruction */
break; break;
} }
...@@ -533,7 +533,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -533,7 +533,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
context->SegFs = seg; context->SegFs = seg;
add_stack(context, long_op ? 4 : 2); add_stack(context, long_op ? 4 : 2);
context->Eip += prefixlen + 2; context->Eip += prefixlen + 2;
return 0; return ExceptionContinueExecution;
} }
} }
break; break;
...@@ -545,7 +545,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -545,7 +545,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
context->SegGs = seg; context->SegGs = seg;
add_stack(context, long_op ? 4 : 2); add_stack(context, long_op ? 4 : 2);
context->Eip += prefixlen + 2; context->Eip += prefixlen + 2;
return 0; return ExceptionContinueExecution;
} }
} }
break; break;
...@@ -556,7 +556,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -556,7 +556,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
long_addr, segprefix, &len )) long_addr, segprefix, &len ))
{ {
context->Eip += prefixlen + len; context->Eip += prefixlen + len;
return 0; return ExceptionContinueExecution;
} }
break; break;
} }
...@@ -629,7 +629,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -629,7 +629,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
} }
context->Eip += prefixlen + 1; context->Eip += prefixlen + 1;
} }
return 0; return ExceptionContinueExecution;
case 0x8e: /* mov XX,segment_reg */ case 0x8e: /* mov XX,segment_reg */
{ {
...@@ -647,25 +647,25 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -647,25 +647,25 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
case 0: case 0:
context->SegEs = seg; context->SegEs = seg;
context->Eip += prefixlen + len + 1; context->Eip += prefixlen + len + 1;
return 0; return ExceptionContinueExecution;
case 1: /* cs */ case 1: /* cs */
break; break;
case 2: case 2:
context->SegSs = seg; context->SegSs = seg;
context->Eip += prefixlen + len + 1; context->Eip += prefixlen + len + 1;
return 0; return ExceptionContinueExecution;
case 3: case 3:
context->SegDs = seg; context->SegDs = seg;
context->Eip += prefixlen + len + 1; context->Eip += prefixlen + len + 1;
return 0; return ExceptionContinueExecution;
case 4: case 4:
context->SegFs = seg; context->SegFs = seg;
context->Eip += prefixlen + len + 1; context->Eip += prefixlen + len + 1;
return 0; return ExceptionContinueExecution;
case 5: case 5:
context->SegGs = seg; context->SegGs = seg;
context->Eip += prefixlen + len + 1; context->Eip += prefixlen + len + 1;
return 0; return ExceptionContinueExecution;
case 6: /* unused */ case 6: /* unused */
case 7: /* unused */ case 7: /* unused */
break; break;
...@@ -679,7 +679,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -679,7 +679,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
long_addr, segprefix, &len )) long_addr, segprefix, &len ))
{ {
context->Eip += prefixlen + len; context->Eip += prefixlen + len;
return 0; return ExceptionContinueExecution;
} }
break; /* Unable to emulate it */ break; /* Unable to emulate it */
...@@ -692,7 +692,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -692,7 +692,7 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
{ {
context->Eip += prefixlen + 2; context->Eip += prefixlen + 2;
Dosvm.EmulateInterruptPM( context, instr[1] ); Dosvm.EmulateInterruptPM( context, instr[1] );
return 0; return ExceptionContinueExecution;
} }
break; /* Unable to emulate it */ break; /* Unable to emulate it */
...@@ -713,12 +713,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -713,12 +713,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
SET_LOWORD(context->EFlags,*stack); SET_LOWORD(context->EFlags,*stack);
add_stack(context, 3*sizeof(WORD)); /* Pop the return address and flags */ add_stack(context, 3*sizeof(WORD)); /* Pop the return address and flags */
} }
return 0; return ExceptionContinueExecution;
case 0xe4: /* inb al,XX */ case 0xe4: /* inb al,XX */
SET_LOBYTE(context->Eax,INSTR_inport( instr[1], 1, context )); SET_LOBYTE(context->Eax,INSTR_inport( instr[1], 1, context ));
context->Eip += prefixlen + 2; context->Eip += prefixlen + 2;
return 0; return ExceptionContinueExecution;
case 0xe5: /* in (e)ax,XX */ case 0xe5: /* in (e)ax,XX */
if (long_op) if (long_op)
...@@ -726,12 +726,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -726,12 +726,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
else else
SET_LOWORD(context->Eax, INSTR_inport( instr[1], 2, context )); SET_LOWORD(context->Eax, INSTR_inport( instr[1], 2, context ));
context->Eip += prefixlen + 2; context->Eip += prefixlen + 2;
return 0; return ExceptionContinueExecution;
case 0xe6: /* outb XX,al */ case 0xe6: /* outb XX,al */
INSTR_outport( instr[1], 1, LOBYTE(context->Eax), context ); INSTR_outport( instr[1], 1, LOBYTE(context->Eax), context );
context->Eip += prefixlen + 2; context->Eip += prefixlen + 2;
return 0; return ExceptionContinueExecution;
case 0xe7: /* out XX,(e)ax */ case 0xe7: /* out XX,(e)ax */
if (long_op) if (long_op)
...@@ -739,12 +739,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -739,12 +739,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
else else
INSTR_outport( instr[1], 2, LOWORD(context->Eax), context ); INSTR_outport( instr[1], 2, LOWORD(context->Eax), context );
context->Eip += prefixlen + 2; context->Eip += prefixlen + 2;
return 0; return ExceptionContinueExecution;
case 0xec: /* inb al,dx */ case 0xec: /* inb al,dx */
SET_LOBYTE(context->Eax, INSTR_inport( LOWORD(context->Edx), 1, context ) ); SET_LOBYTE(context->Eax, INSTR_inport( LOWORD(context->Edx), 1, context ) );
context->Eip += prefixlen + 1; context->Eip += prefixlen + 1;
return 0; return ExceptionContinueExecution;
case 0xed: /* in (e)ax,dx */ case 0xed: /* in (e)ax,dx */
if (long_op) if (long_op)
...@@ -752,12 +752,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -752,12 +752,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
else else
SET_LOWORD(context->Eax, INSTR_inport( LOWORD(context->Edx), 2, context )); SET_LOWORD(context->Eax, INSTR_inport( LOWORD(context->Edx), 2, context ));
context->Eip += prefixlen + 1; context->Eip += prefixlen + 1;
return 0; return ExceptionContinueExecution;
case 0xee: /* outb dx,al */ case 0xee: /* outb dx,al */
INSTR_outport( LOWORD(context->Edx), 1, LOBYTE(context->Eax), context ); INSTR_outport( LOWORD(context->Edx), 1, LOBYTE(context->Eax), context );
context->Eip += prefixlen + 1; context->Eip += prefixlen + 1;
return 0; return ExceptionContinueExecution;
case 0xef: /* out dx,(e)ax */ case 0xef: /* out dx,(e)ax */
if (long_op) if (long_op)
...@@ -765,12 +765,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -765,12 +765,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
else else
INSTR_outport( LOWORD(context->Edx), 2, LOWORD(context->Eax), context ); INSTR_outport( LOWORD(context->Edx), 2, LOWORD(context->Eax), context );
context->Eip += prefixlen + 1; context->Eip += prefixlen + 1;
return 0; return ExceptionContinueExecution;
case 0xfa: /* cli */ case 0xfa: /* cli */
NtCurrentTeb()->dpmi_vif = 0; NtCurrentTeb()->dpmi_vif = 0;
context->Eip += prefixlen + 1; context->Eip += prefixlen + 1;
return 0; return ExceptionContinueExecution;
case 0xfb: /* sti */ case 0xfb: /* sti */
NtCurrentTeb()->dpmi_vif = 1; NtCurrentTeb()->dpmi_vif = 1;
...@@ -778,11 +778,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) ...@@ -778,11 +778,12 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
if (NtCurrentTeb()->vm86_pending) if (NtCurrentTeb()->vm86_pending)
{ {
NtCurrentTeb()->vm86_pending = 0; NtCurrentTeb()->vm86_pending = 0;
return EXCEPTION_VM86_STI; rec->ExceptionCode = EXCEPTION_VM86_STI;
return ExceptionContinueSearch;
} }
return 0; return ExceptionContinueExecution;
} }
return ret; /* Unable to emulate it */ return ExceptionContinueSearch; /* Unable to emulate it */
} }
#endif /* __i386__ */ #endif /* __i386__ */
...@@ -180,8 +180,9 @@ static DWORD call16_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RE ...@@ -180,8 +180,9 @@ static DWORD call16_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RE
else else
{ {
SEGPTR gpHandler; SEGPTR gpHandler;
DWORD ret = INSTR_EmulateInstruction( record, context );
if (!INSTR_EmulateInstruction( context )) return ExceptionContinueExecution; if (ret != ExceptionContinueSearch) return ret;
/* check for Win16 __GP handler */ /* check for Win16 __GP handler */
if ((gpHandler = HasGPHandler16( MAKESEGPTR( context->SegCs, context->Eip ) ))) if ((gpHandler = HasGPHandler16( MAKESEGPTR( context->SegCs, context->Eip ) )))
...@@ -205,6 +206,28 @@ static DWORD call16_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RE ...@@ -205,6 +206,28 @@ static DWORD call16_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RE
return ExceptionContinueSearch; return ExceptionContinueSearch;
} }
/*************************************************************
* vm86_handler
*
* Handler for exceptions occurring in vm86 code.
*/
static DWORD vm86_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RECORD *frame,
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **pdispatcher )
{
if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
return ExceptionContinueSearch;
if (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION)
{
return INSTR_EmulateInstruction( record, context );
}
return ExceptionContinueSearch;
}
#else /* __i386__ */ #else /* __i386__ */
BOOL WOWTHUNK_Init(void) BOOL WOWTHUNK_Init(void)
...@@ -470,22 +493,33 @@ BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags, ...@@ -470,22 +493,33 @@ BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags,
SYSLEVEL_CheckNotLevel( 2 ); SYSLEVEL_CheckNotLevel( 2 );
} }
/* push return address */ if (ISV86(context))
if (dwFlags & WCB16_REGS_LONG)
{ {
*((DWORD *)stack - 1) = HIWORD(call16_ret_addr); EXCEPTION_REGISTRATION_RECORD frame;
*((DWORD *)stack - 2) = LOWORD(call16_ret_addr); frame.Handler = vm86_handler;
cbArgs += 2 * sizeof(DWORD); __wine_push_frame( &frame );
__wine_enter_vm86( context );
__wine_pop_frame( &frame );
} }
else else
{ {
*((SEGPTR *)stack - 1) = call16_ret_addr; /* push return address */
cbArgs += sizeof(SEGPTR); if (dwFlags & WCB16_REGS_LONG)
} {
*((DWORD *)stack - 1) = HIWORD(call16_ret_addr);
*((DWORD *)stack - 2) = LOWORD(call16_ret_addr);
cbArgs += 2 * sizeof(DWORD);
}
else
{
*((SEGPTR *)stack - 1) = call16_ret_addr;
cbArgs += sizeof(SEGPTR);
}
_EnterWin16Lock(); _EnterWin16Lock();
wine_call_to_16_regs( context, cbArgs, call16_handler ); wine_call_to_16_regs( context, cbArgs, call16_handler );
_LeaveWin16Lock(); _LeaveWin16Lock();
}
if (TRACE_ON(relay)) if (TRACE_ON(relay))
{ {
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include "winbase.h" #include "winbase.h"
#include "wingdi.h" #include "wingdi.h"
#include "winuser.h" #include "winuser.h"
#include "wownt32.h"
#include "winnt.h" #include "winnt.h"
#include "wincon.h" #include "wincon.h"
...@@ -583,8 +584,8 @@ int WINAPI DOSVM_Enter( CONTEXT86 *context ) ...@@ -583,8 +584,8 @@ int WINAPI DOSVM_Enter( CONTEXT86 *context )
__TRY __TRY
{ {
__wine_enter_vm86( context ); WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)context );
TRACE_(module)( "vm86 returned: %s\n", strerror(errno) ); TRACE_(module)( "vm86 returned: %s\n", strerror(errno) );
} }
__EXCEPT(exception_handler) __EXCEPT(exception_handler)
{ {
......
...@@ -105,7 +105,7 @@ extern LPVOID DOSMEM_MapDosToLinear(UINT); /* linear DOS to Wine */ ...@@ -105,7 +105,7 @@ extern LPVOID DOSMEM_MapDosToLinear(UINT); /* linear DOS to Wine */
extern UINT DOSMEM_MapLinearToDos(LPVOID); /* linear Wine to DOS */ extern UINT DOSMEM_MapLinearToDos(LPVOID); /* linear Wine to DOS */
/* memory/instr.c */ /* memory/instr.c */
extern DWORD INSTR_EmulateInstruction( CONTEXT86 *context ); extern DWORD INSTR_EmulateInstruction( EXCEPTION_RECORD *rec, CONTEXT86 *context );
/* msdos/ioports.c */ /* msdos/ioports.c */
extern DWORD IO_inport( int port, int count ); extern DWORD IO_inport( int port, int count );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment