Use WOWCallback16Ex to switch to vm86 mode so that we can setup a
proper exception handler and handle instruction emulation.
This commit is contained in:
parent
f5cb3dde17
commit
add0c5850b
@ -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 )
|
|||||||
* 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 )
|
|||||||
}
|
}
|
||||||
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 )
|
|||||||
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 )
|
|||||||
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 )
|
|||||||
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 )
|
|||||||
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 )
|
|||||||
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 )
|
|||||||
}
|
}
|
||||||
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 )
|
|||||||
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 )
|
|||||||
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 )
|
|||||||
{
|
{
|
||||||
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 )
|
|||||||
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 )
|
|||||||
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 )
|
|||||||
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 )
|
|||||||
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 )
|
|||||||
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 )
|
|||||||
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
|
|||||||
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
|
|||||||
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,
|
|||||||
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 @@
|
|||||||
#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 )
|
|||||||
|
|
||||||
__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 */
|
|||||||
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 );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user