From: Julian Seward Date: Mon, 7 Jun 2010 16:22:22 +0000 (+0000) Subject: Implement SIDT and SGDT as pass-throughs to the host. It's a pretty X-Git-Tag: svn/VALGRIND_3_6_1^2~88 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0ffb684d82720ba0ac89b2f5dd510626375a5e30;p=thirdparty%2Fvalgrind.git Implement SIDT and SGDT as pass-throughs to the host. It's a pretty bad thing to do, but I can't think of a way to virtualise these properly. Patch from Alexander Potapenko. See https://bugs.kde.org/show_bug.cgi?id=205241#c38 git-svn-id: svn://svn.valgrind.org/vex/trunk@1982 --- diff --git a/VEX/priv/guest_amd64_defs.h b/VEX/priv/guest_amd64_defs.h index 40ed37f143..ea3a4c9d6b 100644 --- a/VEX/priv/guest_amd64_defs.h +++ b/VEX/priv/guest_amd64_defs.h @@ -153,6 +153,9 @@ extern ULong amd64g_dirtyhelper_IN ( ULong portno, ULong sz/*1,2 or 4*/ ); extern void amd64g_dirtyhelper_OUT ( ULong portno, ULong data, ULong sz/*1,2 or 4*/ ); +extern void amd64g_dirtyhelper_SxDT ( void* address, + ULong op /* 0 or 1 */ ); + //extern void amd64g_dirtyhelper_CPUID_sse0 ( VexGuestAMD64State* ); //extern void amd64g_dirtyhelper_CPUID_sse1 ( VexGuestAMD64State* ); //extern void amd64g_dirtyhelper_CPUID_sse2 ( VexGuestAMD64State* ); diff --git a/VEX/priv/guest_amd64_helpers.c b/VEX/priv/guest_amd64_helpers.c index 74e1b5ea5e..fe1ac0c193 100644 --- a/VEX/priv/guest_amd64_helpers.c +++ b/VEX/priv/guest_amd64_helpers.c @@ -2218,6 +2218,31 @@ void amd64g_dirtyhelper_OUT ( ULong portno, ULong data, ULong sz/*1,2 or 4*/ ) # endif } +/* CALLED FROM GENERATED CODE */ +/* DIRTY HELPER (non-referentially-transparent) */ +/* Horrible hack. On non-amd64 platforms, do nothing. */ +/* op = 0: call the native SGDT instruction. + op = 1: call the native SIDT instruction. +*/ +void amd64g_dirtyhelper_SxDT ( void *address, ULong op ) { +# if defined(__x86_64__) + switch (op) { + case 0: + __asm__ __volatile__("sgdt (%0)" : : "r" (address) : "memory"); + break; + case 1: + __asm__ __volatile__("sidt (%0)" : : "r" (address) : "memory"); + break; + default: + vpanic("amd64g_dirtyhelper_SxDT"); + } +# else + /* do nothing */ + UChar* p = (UChar*)address; + p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = 0; + p[6] = p[7] = p[8] = p[9] = 0; +# endif +} /*---------------------------------------------------------------*/ /*--- Helpers for MMX/SSE/SSE2. ---*/ diff --git a/VEX/priv/guest_amd64_toIR.c b/VEX/priv/guest_amd64_toIR.c index 5fcdf3854c..a526cc7ba9 100644 --- a/VEX/priv/guest_amd64_toIR.c +++ b/VEX/priv/guest_amd64_toIR.c @@ -17260,6 +17260,41 @@ DisResult disInstr_AMD64_WRK ( DIP("{f}emms\n"); break; + /* =-=-=-=-=-=-=-=-=- SGDT and SIDT =-=-=-=-=-=-=-=-=-=-= */ + case 0x01: /* 0F 01 /0 -- SGDT */ + /* 0F 01 /1 -- SIDT */ + { + /* This is really revolting, but ... since each processor + (core) only has one IDT and one GDT, just let the guest + see it (pass-through semantics). I can't see any way to + construct a faked-up value, so don't bother to try. */ + modrm = getUChar(delta); + addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 ); + delta += alen; + if (epartIsReg(modrm)) goto decode_failure; + if (gregLO3ofRM(modrm) != 0 && gregLO3ofRM(modrm) != 1) + goto decode_failure; + switch (gregLO3ofRM(modrm)) { + case 0: DIP("sgdt %s\n", dis_buf); break; + case 1: DIP("sidt %s\n", dis_buf); break; + default: vassert(0); /*NOTREACHED*/ + } + + IRDirty* d = unsafeIRDirty_0_N ( + 0/*regparms*/, + "amd64g_dirtyhelper_SxDT", + &amd64g_dirtyhelper_SxDT, + mkIRExprVec_2( mkexpr(addr), + mkU64(gregLO3ofRM(modrm)) ) + ); + /* declare we're writing memory */ + d->mFx = Ifx_Write; + d->mAddr = mkexpr(addr); + d->mSize = 6; + stmt( IRStmt_Dirty(d) ); + break; + } + /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */ default: diff --git a/VEX/priv/guest_x86_defs.h b/VEX/priv/guest_x86_defs.h index a6953c8815..4a5bf3731a 100644 --- a/VEX/priv/guest_x86_defs.h +++ b/VEX/priv/guest_x86_defs.h @@ -153,6 +153,9 @@ extern UInt x86g_dirtyhelper_IN ( UInt portno, UInt sz/*1,2 or 4*/ ); extern void x86g_dirtyhelper_OUT ( UInt portno, UInt data, UInt sz/*1,2 or 4*/ ); +extern void x86g_dirtyhelper_SxDT ( void* address, + UInt op /* 0 or 1 */ ); + extern VexEmWarn x86g_dirtyhelper_FXRSTOR ( VexGuestX86State*, HWord ); diff --git a/VEX/priv/guest_x86_helpers.c b/VEX/priv/guest_x86_helpers.c index 8178842ad7..95bae8a19e 100644 --- a/VEX/priv/guest_x86_helpers.c +++ b/VEX/priv/guest_x86_helpers.c @@ -2353,6 +2353,30 @@ void x86g_dirtyhelper_OUT ( UInt portno, UInt data, UInt sz/*1,2 or 4*/ ) # endif } +/* CALLED FROM GENERATED CODE */ +/* DIRTY HELPER (non-referentially-transparent) */ +/* Horrible hack. On non-x86 platforms, do nothing. */ +/* op = 0: call the native SGDT instruction. + op = 1: call the native SIDT instruction. +*/ +void x86g_dirtyhelper_SxDT ( void *address, UInt op ) { +# if defined(__i386__) + switch (op) { + case 0: + __asm__ __volatile__("sgdt (%0)" : : "r" (address) : "memory"); + break; + case 1: + __asm__ __volatile__("sidt (%0)" : : "r" (address) : "memory"); + break; + default: + vpanic("x86g_dirtyhelper_SxDT"); + } +# else + /* do nothing */ + UChar* p = (UChar*)address; + p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = 0; +# endif +} /*---------------------------------------------------------------*/ /*--- Helpers for MMX/SSE/SSE2. ---*/ diff --git a/VEX/priv/guest_x86_toIR.c b/VEX/priv/guest_x86_toIR.c index 7abfc6cff3..1dcdf627b3 100644 --- a/VEX/priv/guest_x86_toIR.c +++ b/VEX/priv/guest_x86_toIR.c @@ -14790,6 +14790,41 @@ DisResult disInstr_X86_WRK ( DIP("emms\n"); break; + /* =-=-=-=-=-=-=-=-=- SGDT and SIDT =-=-=-=-=-=-=-=-=-=-= */ + case 0x01: /* 0F 01 /0 -- SGDT */ + /* 0F 01 /1 -- SIDT */ + { + /* This is really revolting, but ... since each processor + (core) only has one IDT and one GDT, just let the guest + see it (pass-through semantics). I can't see any way to + construct a faked-up value, so don't bother to try. */ + modrm = getUChar(delta); + addr = disAMode ( &alen, sorb, delta, dis_buf ); + delta += alen; + if (epartIsReg(modrm)) goto decode_failure; + if (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1) + goto decode_failure; + switch (gregOfRM(modrm)) { + case 0: DIP("sgdt %s\n", dis_buf); break; + case 1: DIP("sidt %s\n", dis_buf); break; + default: vassert(0); /*NOTREACHED*/ + } + + IRDirty* d = unsafeIRDirty_0_N ( + 0/*regparms*/, + "x86g_dirtyhelper_SxDT", + &x86g_dirtyhelper_SxDT, + mkIRExprVec_2( mkexpr(addr), + mkU32(gregOfRM(modrm)) ) + ); + /* declare we're writing memory */ + d->mFx = Ifx_Write; + d->mAddr = mkexpr(addr); + d->mSize = 6; + stmt( IRStmt_Dirty(d) ); + break; + } + /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */ default: