2014-11-12 16:34:48 -08:00
|
|
|
From 7cb209e122fc503190dcad411483147ebc6d6cb4 Mon Sep 17 00:00:00 2001
|
2014-11-10 18:28:23 -08:00
|
|
|
From: Sebastian Lackner <sebastian@fds-team.de>
|
|
|
|
Date: Tue, 11 Nov 2014 03:11:33 +0100
|
2014-11-10 23:06:52 -08:00
|
|
|
Subject: ntdll: Implement emulation of SIDT instruction when using Exagear.
|
2014-11-10 18:28:23 -08:00
|
|
|
|
|
|
|
---
|
|
|
|
configure.ac | 8 ++
|
|
|
|
dlls/ntdll/signal_i386.c | 224 +++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
2 files changed, 232 insertions(+)
|
|
|
|
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
|
|
index 92d78a2..c88a139 100644
|
|
|
|
--- a/configure.ac
|
|
|
|
+++ b/configure.ac
|
|
|
|
@@ -32,6 +32,7 @@ AC_ARG_ENABLE(win16, AS_HELP_STRING([--disable-win16],[do not include Win16 supp
|
|
|
|
AC_ARG_ENABLE(win64, AS_HELP_STRING([--enable-win64],[build a Win64 emulator on AMD64 (won't run Win32 binaries)]))
|
|
|
|
AC_ARG_ENABLE(tests, AS_HELP_STRING([--disable-tests],[do not build the regression tests]))
|
|
|
|
AC_ARG_ENABLE(maintainer-mode, AS_HELP_STRING([--enable-maintainer-mode],[enable maintainer-specific build rules]))
|
|
|
|
+AC_ARG_ENABLE(exagear-compat, AS_HELP_STRING([--enable-exagear-compat],[use workarounds for known problems in the Exagear emulator]))
|
|
|
|
|
|
|
|
AC_ARG_WITH(alsa, AS_HELP_STRING([--without-alsa],[do not use the Alsa sound support]),
|
|
|
|
[if test "x$withval" = "xno"; then ac_cv_header_sys_asoundlib_h=no; ac_cv_header_alsa_asoundlib_h=no; fi])
|
|
|
|
@@ -367,6 +368,13 @@ fi
|
|
|
|
WINE_WARNING_WITH(gettext,[test "$MSGFMT" = false],
|
|
|
|
[gettext tools not found (or too old), translations won't be built.])
|
|
|
|
|
|
|
|
+dnl **** Enable Exagear workarounds ****
|
|
|
|
+
|
|
|
|
+if test "x$enable_exagear_compat" = "xyes"
|
|
|
|
+then
|
|
|
|
+ AC_DEFINE(EXAGEAR_COMPAT, 1, [Define if you want to enable Exagear emulator workarounds])
|
|
|
|
+fi
|
|
|
|
+
|
|
|
|
dnl **** Check for some libraries ****
|
|
|
|
|
|
|
|
dnl Check for -li386 for NetBSD and OpenBSD
|
|
|
|
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
|
2014-11-12 16:34:48 -08:00
|
|
|
index 13df4bb..edf5ea8 100644
|
2014-11-10 18:28:23 -08:00
|
|
|
--- a/dlls/ntdll/signal_i386.c
|
|
|
|
+++ b/dlls/ntdll/signal_i386.c
|
|
|
|
@@ -96,6 +96,14 @@ typedef struct
|
|
|
|
BYTE Reserved4[96];
|
|
|
|
} XMM_SAVE_AREA32;
|
|
|
|
|
|
|
|
+#include "pshpack1.h"
|
|
|
|
+struct idtr
|
|
|
|
+{
|
|
|
|
+ WORD limit;
|
|
|
|
+ BYTE *base;
|
|
|
|
+};
|
|
|
|
+#include "poppack.h"
|
|
|
|
+
|
|
|
|
/***********************************************************************
|
|
|
|
* signal context platform-specific definitions
|
|
|
|
*/
|
|
|
|
@@ -1573,6 +1581,214 @@ static inline DWORD is_privileged_instr( CONTEXT *context )
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+#ifdef EXAGEAR_COMPAT
|
|
|
|
+
|
|
|
|
+/***********************************************************************
|
|
|
|
+ * INSTR_GetOperandAddr
|
|
|
|
+ *
|
|
|
|
+ * Return the address of an instruction operand (from the mod/rm byte).
|
|
|
|
+ */
|
|
|
|
+static BYTE *INSTR_GetOperandAddr( CONTEXT *context, const BYTE *instr,
|
|
|
|
+ int long_addr, int segprefix, int *len )
|
|
|
|
+{
|
|
|
|
+ int mod, rm, base = 0, index = 0, ss = 0, off;
|
|
|
|
+
|
|
|
|
+#define GET_VAL(val,type) \
|
|
|
|
+ { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
|
|
|
|
+
|
|
|
|
+ *len = 0;
|
|
|
|
+ GET_VAL( &mod, BYTE );
|
|
|
|
+ rm = mod & 7;
|
|
|
|
+ mod >>= 6;
|
|
|
|
+
|
|
|
|
+ if (mod == 3)
|
|
|
|
+ {
|
|
|
|
+ switch(rm)
|
|
|
|
+ {
|
|
|
|
+ case 0: return (BYTE *)&context->Eax;
|
|
|
|
+ case 1: return (BYTE *)&context->Ecx;
|
|
|
|
+ case 2: return (BYTE *)&context->Edx;
|
|
|
|
+ case 3: return (BYTE *)&context->Ebx;
|
|
|
|
+ case 4: return (BYTE *)&context->Esp;
|
|
|
|
+ case 5: return (BYTE *)&context->Ebp;
|
|
|
|
+ case 6: return (BYTE *)&context->Esi;
|
|
|
|
+ case 7: return (BYTE *)&context->Edi;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (long_addr)
|
|
|
|
+ {
|
|
|
|
+ if (rm == 4)
|
|
|
|
+ {
|
|
|
|
+ BYTE sib;
|
|
|
|
+ GET_VAL( &sib, BYTE );
|
|
|
|
+ rm = sib & 7;
|
|
|
|
+ ss = sib >> 6;
|
|
|
|
+ switch((sib >> 3) & 7)
|
|
|
|
+ {
|
|
|
|
+ case 0: index = context->Eax; break;
|
|
|
|
+ case 1: index = context->Ecx; break;
|
|
|
|
+ case 2: index = context->Edx; break;
|
|
|
|
+ case 3: index = context->Ebx; break;
|
|
|
|
+ case 4: index = 0; break;
|
|
|
|
+ case 5: index = context->Ebp; break;
|
|
|
|
+ case 6: index = context->Esi; break;
|
|
|
|
+ case 7: index = context->Edi; break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ switch(rm)
|
|
|
|
+ {
|
|
|
|
+ case 0: base = context->Eax; break;
|
|
|
|
+ case 1: base = context->Ecx; break;
|
|
|
|
+ case 2: base = context->Edx; break;
|
|
|
|
+ case 3: base = context->Ebx; break;
|
|
|
|
+ case 4: base = context->Esp; break;
|
|
|
|
+ case 5: base = context->Ebp; break;
|
|
|
|
+ case 6: base = context->Esi; break;
|
|
|
|
+ case 7: base = context->Edi; break;
|
|
|
|
+ }
|
|
|
|
+ switch (mod)
|
|
|
|
+ {
|
|
|
|
+ case 0:
|
|
|
|
+ if (rm == 5) /* special case: ds:(disp32) */
|
|
|
|
+ {
|
|
|
|
+ GET_VAL( &base, DWORD );
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 1: /* 8-bit disp */
|
|
|
|
+ GET_VAL( &off, BYTE );
|
|
|
|
+ base += (signed char)off;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 2: /* 32-bit disp */
|
|
|
|
+ GET_VAL( &off, DWORD );
|
|
|
|
+ base += (signed long)off;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else /* short address */
|
|
|
|
+ {
|
|
|
|
+ switch(rm)
|
|
|
|
+ {
|
|
|
|
+ case 0: /* ds:(bx,si) */
|
|
|
|
+ base = LOWORD(context->Ebx) + LOWORD(context->Esi);
|
|
|
|
+ break;
|
|
|
|
+ case 1: /* ds:(bx,di) */
|
|
|
|
+ base = LOWORD(context->Ebx) + LOWORD(context->Edi);
|
|
|
|
+ break;
|
|
|
|
+ case 2: /* ss:(bp,si) */
|
|
|
|
+ base = LOWORD(context->Ebp) + LOWORD(context->Esi);
|
|
|
|
+ break;
|
|
|
|
+ case 3: /* ss:(bp,di) */
|
|
|
|
+ base = LOWORD(context->Ebp) + LOWORD(context->Edi);
|
|
|
|
+ break;
|
|
|
|
+ case 4: /* ds:(si) */
|
|
|
|
+ base = LOWORD(context->Esi);
|
|
|
|
+ break;
|
|
|
|
+ case 5: /* ds:(di) */
|
|
|
|
+ base = LOWORD(context->Edi);
|
|
|
|
+ break;
|
|
|
|
+ case 6: /* ss:(bp) */
|
|
|
|
+ base = LOWORD(context->Ebp);
|
|
|
|
+ break;
|
|
|
|
+ case 7: /* ds:(bx) */
|
|
|
|
+ base = LOWORD(context->Ebx);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ switch(mod)
|
|
|
|
+ {
|
|
|
|
+ case 0:
|
|
|
|
+ if (rm == 6) /* special case: ds:(disp16) */
|
|
|
|
+ {
|
|
|
|
+ GET_VAL( &base, WORD );
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 1: /* 8-bit disp */
|
|
|
|
+ GET_VAL( &off, BYTE );
|
|
|
|
+ base += (signed char)off;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 2: /* 16-bit disp */
|
|
|
|
+ GET_VAL( &off, WORD );
|
|
|
|
+ base += (signed short)off;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ base &= 0xffff;
|
|
|
|
+ }
|
|
|
|
+ /* FIXME: we assume that all segments have a base of 0 */
|
|
|
|
+ return (BYTE *)(base + (index << ss));
|
|
|
|
+#undef GET_VAL
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/***********************************************************************
|
|
|
|
+ * check_invalid_instr
|
|
|
|
+ *
|
|
|
|
+ * Support for instructions not implemented by Exagear.
|
|
|
|
+ */
|
|
|
|
+static inline BOOL check_invalid_instr( CONTEXT *context )
|
|
|
|
+{
|
|
|
|
+ const BYTE *instr;
|
|
|
|
+ unsigned int prefix_count = 0;
|
|
|
|
+ int len, long_addr = 1;
|
|
|
|
+
|
|
|
|
+ if (!wine_ldt_is_system( context->SegCs )) return FALSE;
|
|
|
|
+ instr = (BYTE *)context->Eip;
|
|
|
|
+
|
|
|
|
+ for (;;) switch (*instr)
|
|
|
|
+ {
|
|
|
|
+ /* instruction prefixes */
|
|
|
|
+ case 0x2e: /* %cs: */
|
|
|
|
+ case 0x36: /* %ss: */
|
|
|
|
+ case 0x3e: /* %ds: */
|
|
|
|
+ case 0x26: /* %es: */
|
|
|
|
+ case 0x64: /* %fs: */
|
|
|
|
+ case 0x65: /* %gs: */
|
|
|
|
+ case 0x66: /* opcode size */
|
|
|
|
+ case 0x67: /* addr size */
|
|
|
|
+ case 0xf0: /* lock */
|
|
|
|
+ case 0xf2: /* repne */
|
|
|
|
+ case 0xf3: /* repe */
|
|
|
|
+ if (++prefix_count >= 15) return FALSE;
|
|
|
|
+ if (*instr == 0x67) long_addr = !long_addr; /* addr size */
|
|
|
|
+ instr++;
|
|
|
|
+ continue;
|
|
|
|
+ case 0x0f: /* extended instruction */
|
|
|
|
+ switch (instr[1])
|
|
|
|
+ {
|
|
|
|
+ case 0x01:
|
|
|
|
+ if (((instr[2] >> 3) & 7) == 1) /* sidt m */
|
|
|
|
+ {
|
|
|
|
+ struct idtr ret;
|
|
|
|
+ BYTE *addr;
|
|
|
|
+
|
2014-11-12 16:34:48 -08:00
|
|
|
+ if ((instr[2] >> 6) == 3) return FALSE; /* loading to register not allowed */
|
2014-11-10 18:28:23 -08:00
|
|
|
+ addr = INSTR_GetOperandAddr( context, instr + 2, long_addr, 0, &len );
|
|
|
|
+
|
|
|
|
+ /* fake IDT structure */
|
|
|
|
+ ret.limit = 0xfff;
|
|
|
|
+ ret.base = (void *)0xff000000;
|
|
|
|
+ memcpy(addr, &ret, sizeof(ret));
|
|
|
|
+
|
|
|
|
+ context->Eip += prefix_count + len + 2;
|
|
|
|
+ return TRUE;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ return FALSE;
|
|
|
|
+ default:
|
|
|
|
+ return FALSE;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#endif /* EXAGEAR_COMPAT */
|
|
|
|
+
|
|
|
|
+
|
|
|
|
/***********************************************************************
|
|
|
|
* check_invalid_gs
|
|
|
|
*
|
|
|
|
@@ -1902,6 +2118,14 @@ static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context
|
|
|
|
|
|
|
|
switch(rec->ExceptionCode)
|
|
|
|
{
|
|
|
|
+#ifdef EXAGEAR_COMPAT
|
|
|
|
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
|
|
|
|
+ {
|
|
|
|
+ if (check_invalid_instr( context ))
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+#endif
|
|
|
|
case EXCEPTION_ACCESS_VIOLATION:
|
|
|
|
if (rec->NumberParameters == 2)
|
|
|
|
{
|
|
|
|
--
|
|
|
|
2.1.3
|
|
|
|
|