Paolo Bonzini
2009-Jul-24 16:27 UTC
[Xen-devel] [PATCH] handle x87 opcodes in TLS segment fixups
This patch adds support to the TLS fixup code for x87 opcodes. These can be treated like 2-byte opcodes with a weird encoding. The patch includes some extra changes because, now that we have >2 opcode tables and 9 different lead bytes in a two-byte opcode, a simple boolean code will not be enough to differentiate one- and two-byte opcodes. Besides this, the patch is trivial since the segment fixup code cares about the operands of the instruction, not about its semantics. --- arch/x86/x86_32/seg_fixup.c | 58 ++++++++++++++++++++++++++++++++++++------ 1 files changed, 49 insertions(+), 9 deletions(-) diff --git a/xen/arch/x86/x86_32/seg_fixup.c b/xen/arch/x86/x86_32/seg_fixup.c --- a/xen/arch/x86/x86_32/seg_fixup.c +++ b/xen/arch/x86/x86_32/seg_fixup.c @@ -42,7 +42,7 @@ #define O OPCODE_BYTE #define M HAS_MODRM -static const unsigned char insn_decode[256] = { +static const u8 insn_decode[256] = { /* 0x00 - 0x0F */ O|M, O|M, O|M, O|M, X, X, X, X, O|M, O|M, O|M, O|M, X, X, X, X, @@ -93,7 +93,18 @@ X, X, X, X, X, X, O|M, O|M }; -static const unsigned char twobyte_decode[256] = { +static const u8 float_decode[64] = { + O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M, /* 0xD8 */ + O|M, X, O|M, O|M, O|M, O|M, O|M, O|M, /* 0xD9 */ + O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M, /* 0xDA */ + O|M, X, O|M, O|M, X, O|M, X, O|M, /* 0xDB */ + O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M, /* 0xDC */ + O|M, O|M, O|M, O|M, O|M, X, O|M, O|M, /* 0xDD */ + O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M, /* 0xDE */ + O|M, X, O|M, O|M, O|M, O|M, O|M, O|M, /* 0xDF */ +}; + +static const u8 twobyte_decode[256] = { /* 0x00 - 0x0F */ X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, @@ -321,7 +332,9 @@ s32 disp32 = 0; u8 *eip; /* ptr to instruction start */ u8 *pb, b; /* ptr into instr. / current instr. byte */ - int gs_override = 0, scale = 0, twobyte = 0; + int opcode = -1; + int gs_override = 0, scale = 0; + const u8 *table = insn_decode; /* WARNING: We only work for ring-3 segments. */ if ( unlikely(vm86_mode(regs)) || unlikely(!ring_3(regs)) ) @@ -352,8 +365,11 @@ goto fail; } - if ( twobyte ) - break; + if (opcode != -1) + { + opcode = (opcode << 8) | b; + break; + } switch ( b ) { @@ -374,8 +390,29 @@ gs_override = 1; break; case 0x0f: /* Not really a prefix byte */ - twobyte = 1; + table = twobyte_decode; + opcode = b; break; + case 0xd8: /* Math coprocessor instructions. */ + case 0xd9: + case 0xda: + case 0xdb: + case 0xdc: + case 0xdd: + case 0xde: + case 0xdf: + /* Float opcodes have a secondary opcode in the modrm byte. */ + table = float_decode; + if ( get_user(modrm, pb + 1) ) + { + dprintk(XENLOG_DEBUG, "Fault while extracting modrm byte\n"); + goto page_fault; + } + + opcode = (b << 8) | modrm; + b = ((b & 7) << 3) + ((modrm >> 3) & 7); + goto done_prefix; + default: /* Not a prefix byte */ goto done_prefix; } @@ -388,13 +425,16 @@ goto fail; } - decode = (!twobyte ? insn_decode : twobyte_decode)[b]; + decode = table[b]; pb++; if ( !(decode & OPCODE_BYTE) ) { - dprintk(XENLOG_DEBUG, "Unsupported %sopcode %02x\n", - twobyte ? "two byte " : "", b); + if (opcode == -1) + dprintk(XENLOG_DEBUG, "Unsupported opcode %02x\n", b); + else + dprintk(XENLOG_DEBUG, "Unsupported opcode %02x %02x\n", + opcode >> 8, opcode & 255); goto fail; } _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel