|
From: <sv...@va...> - 2010-06-07 16:30:42
|
Author: sewardj Date: 2010-06-07 17:22:22 +0100 (Mon, 07 Jun 2010) New Revision: 1982 Log: 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 Modified: trunk/priv/guest_amd64_defs.h trunk/priv/guest_amd64_helpers.c trunk/priv/guest_amd64_toIR.c trunk/priv/guest_x86_defs.h trunk/priv/guest_x86_helpers.c trunk/priv/guest_x86_toIR.c Modified: trunk/priv/guest_amd64_defs.h =================================================================== --- trunk/priv/guest_amd64_defs.h 2010-05-10 20:51:22 UTC (rev 1981) +++ trunk/priv/guest_amd64_defs.h 2010-06-07 16:22:22 UTC (rev 1982) @@ -153,6 +153,9 @@ 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* ); Modified: trunk/priv/guest_amd64_helpers.c =================================================================== --- trunk/priv/guest_amd64_helpers.c 2010-05-10 20:51:22 UTC (rev 1981) +++ trunk/priv/guest_amd64_helpers.c 2010-06-07 16:22:22 UTC (rev 1982) @@ -2218,6 +2218,31 @@ # 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. ---*/ Modified: trunk/priv/guest_amd64_toIR.c =================================================================== --- trunk/priv/guest_amd64_toIR.c 2010-05-10 20:51:22 UTC (rev 1981) +++ trunk/priv/guest_amd64_toIR.c 2010-06-07 16:22:22 UTC (rev 1982) @@ -17260,6 +17260,41 @@ 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: Modified: trunk/priv/guest_x86_defs.h =================================================================== --- trunk/priv/guest_x86_defs.h 2010-05-10 20:51:22 UTC (rev 1981) +++ trunk/priv/guest_x86_defs.h 2010-06-07 16:22:22 UTC (rev 1982) @@ -153,6 +153,9 @@ 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 ); Modified: trunk/priv/guest_x86_helpers.c =================================================================== --- trunk/priv/guest_x86_helpers.c 2010-05-10 20:51:22 UTC (rev 1981) +++ trunk/priv/guest_x86_helpers.c 2010-06-07 16:22:22 UTC (rev 1982) @@ -2353,6 +2353,30 @@ # 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. ---*/ Modified: trunk/priv/guest_x86_toIR.c =================================================================== --- trunk/priv/guest_x86_toIR.c 2010-05-10 20:51:22 UTC (rev 1981) +++ trunk/priv/guest_x86_toIR.c 2010-06-07 16:22:22 UTC (rev 1982) @@ -14790,6 +14790,41 @@ 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: |