From: Andrew Cooper Date: Thu, 25 Jan 2018 12:16:12 +0000 (+0000) Subject: x86/emul: Optimise decode_register() somewhat X-Git-Tag: archive/raspbian/4.11.1-1+rpi1~1^2~66^2~656 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=004f98ffc7e57cac17365341c07389aa8d0418be;p=xen.git x86/emul: Optimise decode_register() somewhat The positions of GPRs inside struct cpu_user_regs doesn't follow any particular order, so as compiled, decode_register() becomes a jump table to 16 blocks which calculate the appropriate offset, at a total of 207 bytes. Instead, pre-compute the offsets at build time and use pointer arithmetic to calculate the result. By observation, most callers in x86_emulate() inline and constant-propagate the highbyte_regs value of 0. The splitting of the general and legacy byte-op cases means that we will now hit an ASSERT if any code path tries to use the legacy byte-op encoding with a REX prefix. Signed-off-by: Andrew Cooper Reviewed-by: Jan Beulich --- diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c index ff0a003902..1ffbf9c314 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -1935,36 +1935,67 @@ load_seg( return rc; } +/* Map GPRs by ModRM encoding to their offset within struct cpu_user_regs. */ +static const uint8_t cpu_user_regs_gpr_offsets[] = { + offsetof(struct cpu_user_regs, r(ax)), + offsetof(struct cpu_user_regs, r(cx)), + offsetof(struct cpu_user_regs, r(dx)), + offsetof(struct cpu_user_regs, r(bx)), + offsetof(struct cpu_user_regs, r(sp)), + offsetof(struct cpu_user_regs, r(bp)), + offsetof(struct cpu_user_regs, r(si)), + offsetof(struct cpu_user_regs, r(di)), +#ifdef __x86_64__ + offsetof(struct cpu_user_regs, r8), + offsetof(struct cpu_user_regs, r9), + offsetof(struct cpu_user_regs, r10), + offsetof(struct cpu_user_regs, r11), + offsetof(struct cpu_user_regs, r12), + offsetof(struct cpu_user_regs, r13), + offsetof(struct cpu_user_regs, r14), + offsetof(struct cpu_user_regs, r15), +#endif +}; + void * decode_register( uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs) { - void *p; + static const uint8_t byte_reg_offsets[] = { + offsetof(struct cpu_user_regs, al), + offsetof(struct cpu_user_regs, cl), + offsetof(struct cpu_user_regs, dl), + offsetof(struct cpu_user_regs, bl), + offsetof(struct cpu_user_regs, ah), + offsetof(struct cpu_user_regs, ch), + offsetof(struct cpu_user_regs, dh), + offsetof(struct cpu_user_regs, bh), + }; - switch ( modrm_reg ) + if ( !highbyte_regs ) { - case 0: p = ®s->r(ax); break; - case 1: p = ®s->r(cx); break; - case 2: p = ®s->r(dx); break; - case 3: p = ®s->r(bx); break; - case 4: p = (highbyte_regs ? ®s->ah : (void *)®s->r(sp)); break; - case 5: p = (highbyte_regs ? ®s->ch : (void *)®s->r(bp)); break; - case 6: p = (highbyte_regs ? ®s->dh : (void *)®s->r(si)); break; - case 7: p = (highbyte_regs ? ®s->bh : (void *)®s->r(di)); break; -#if defined(__x86_64__) - case 8: p = ®s->r8; break; - case 9: p = ®s->r9; break; - case 10: p = ®s->r10; break; - case 11: p = ®s->r11; break; - case 12: p = ®s->r12; break; - case 13: p = ®s->r13; break; - case 14: p = ®s->r14; break; - case 15: p = ®s->r15; break; -#endif - default: BUG(); p = NULL; break; + /* Check that the array is a power of two. */ + BUILD_BUG_ON(ARRAY_SIZE(cpu_user_regs_gpr_offsets) & + (ARRAY_SIZE(cpu_user_regs_gpr_offsets) - 1)); + + ASSERT(modrm_reg < ARRAY_SIZE(cpu_user_regs_gpr_offsets)); + + /* For safety in release builds. Debug builds will hit the ASSERT() */ + modrm_reg &= ARRAY_SIZE(cpu_user_regs_gpr_offsets) - 1; + + return (void *)regs + cpu_user_regs_gpr_offsets[modrm_reg]; } - return p; + /* Check that the array is a power of two. */ + BUILD_BUG_ON(ARRAY_SIZE(byte_reg_offsets) & + (ARRAY_SIZE(byte_reg_offsets) - 1)); + + ASSERT(modrm_reg < ARRAY_SIZE(byte_reg_offsets)); + + /* For safety in release builds. Debug builds will hit the ASSERT() */ + modrm_reg &= ARRAY_SIZE(byte_reg_offsets) - 1; + + return (void *)regs + byte_reg_offsets[modrm_reg]; } static void *decode_vex_gpr(unsigned int vex_reg, struct cpu_user_regs *regs,