1 /* $Id: recode-x86.h,v 1.5 2010/02/07 17:16:56 fredette Exp $ */ 2 3 /* libtme/host/recode-x86.h - recode header for x86 hosts: */ 4 5 /* 6 * Copyright (c) 2007 Matt Fredette 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Matt Fredette. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 _TME_RCSID("$Id: recode-x86.h,v 1.5 2010/02/07 17:16:56 fredette Exp $"); 37 38 /* macros: */ 39 40 /* TME_RECODE_SIZE_HOST is the log base two of the natural size of the 41 host in bits: */ 42 #ifdef __x86_64__ 43 #define TME_RECODE_SIZE_HOST (6) 44 #else /* !__x86_64__ */ 45 #define TME_RECODE_SIZE_HOST (5) 46 #endif /* !__x86_64__ */ 47 48 /* TME_RECODE_FLAG_NEED() evaluates to nonzero if the host can't 49 provide a condition at a certain size, after a recode instruction 50 of the given class and size. in this case, the guest 51 implementation needs to compute it. 52 53 for additive, logical, shift, and extension instructions, x86 54 provides N and Z codes at all sizes starting at 8 bits, and an even 55 parity code at the 8-bit size. for additive instructions only, 56 it also provides C, V, BE, and LE, and L codes at all sizes 57 starting at 8 bits: */ 58 #define TME_RECODE_FLAG_NEED(insn_class, insn_size, cond, size) \ 59 (!((((insn_class) == TME_RECODE_INSN_CLASS_ADDITIVE \ 60 || (insn_class) == TME_RECODE_INSN_CLASS_LOGICAL \ 61 || (insn_class) == TME_RECODE_INSN_CLASS_SHIFT \ 62 || (insn_class) == TME_RECODE_INSN_CLASS_EXT) \ 63 && (((size) >= TME_RECODE_SIZE_8 \ 64 && ((cond) == TME_RECODE_COND_N \ 65 || (cond) == TME_RECODE_COND_Z)) \ 66 || ((size) == TME_RECODE_SIZE_8 \ 67 && (cond) == TME_RECODE_COND_PE))) \ 68 || ((insn_class) == TME_RECODE_INSN_CLASS_ADDITIVE \ 69 && ((size) >= TME_RECODE_SIZE_8 \ 70 && ((cond) == TME_RECODE_COND_C \ 71 || (cond) == TME_RECODE_COND_V \ 72 || (cond) == TME_RECODE_COND_BE \ 73 || (cond) == TME_RECODE_COND_LE \ 74 || (cond) == TME_RECODE_COND_L))))) 75 76 /* TME_RECODE_FLAGS_COMPAT() evaluates to nonzero if two flags from 77 two different flags groups are compatible. this is used to 78 determine if two flags groups are compatible (and can use the same 79 code thunk), even though their instruction sizes are different. 80 this can happen when two groups have the same flags relative to the 81 instruction size. 82 83 for x86, the ratio between instruction size and condition code size 84 must be the same in both groups. and because double-host-size 85 condition codes need different thunk code than all others, either 86 both condition code sizes must be the double-host size, or neither 87 can be: */ 88 #define TME_RECODE_FLAGS_COMPAT(flags_group0, flag0, flags_group1, flag1)\ 89 ((((flags_group0)->tme_recode_flags_group_insn_size \ 90 - (flag0)->tme_recode_flag_size) \ 91 == ((flags_group1)->tme_recode_flags_group_insn_size \ 92 - (flag1)->tme_recode_flag_size)) \ 93 && (((flag0)->tme_recode_flag_size \ 94 <= TME_RECODE_SIZE_HOST) \ 95 == ((flag1)->tme_recode_flag_size \ 96 <= TME_RECODE_SIZE_HOST))) 97 98 /* the undefined host register number. this is also the number of 99 host registers, so this must match the number of elements in 100 tme_recode_x86_reg_from_host[]: */ 101 #if TME_RECODE_SIZE_HOST > 5 102 #define TME_RECODE_REG_HOST_UNDEF (13) 103 #else /* TME_RECODE_SIZE_HOST == 5 */ 104 #define TME_RECODE_REG_HOST_UNDEF (5) 105 #endif /* TME_RECODE_SIZE_HOST == 5 */ 106 107 /* the alignment of a thunk, in bytes: */ 108 #define TME_RECODE_HOST_THUNK_ALIGN (16) 109 110 /* the overhead of a instructions thunk, in bytes: */ 111 /* on x86, this is the maximum size of the chain in plus chain out: */ 112 #define TME_RECODE_X86_CHAIN_IN_SIZE_MAX (48) 113 #define TME_RECODE_X86_CHAIN_OUT_SIZE_MAX (32) 114 #define TME_RECODE_HOST_INSN_THUNK_OVERHEAD \ 115 (TME_RECODE_X86_CHAIN_IN_SIZE_MAX \ 116 + TME_RECODE_X86_CHAIN_OUT_SIZE_MAX) 117 118 /* the maximum size of a single recoded insn, in bytes: */ 119 #if TME_RECODE_SIZE_HOST > 5 120 #define TME_RECODE_HOST_INSN_SIZE_MAX (384) 121 #else /* TME_RECODE_SIZE_HOST == 5 */ 122 #define TME_RECODE_HOST_INSN_SIZE_MAX (256) 123 #endif /* TME_RECODE_SIZE_HOST == 5 */ 124 125 /* these are the host-specific members added to struct 126 tme_recode_flags_thunk: */ 127 #define TME_RECODE_HOST_FLAGS_THUNK \ 128 \ 129 /* the size-specific flags subs: */ \ 130 struct { \ 131 \ 132 /* the integer-opcode-specific flags subs: */ \ 133 tme_recode_thunk_off_t tme_recode_x86_flags_thunk_size_subs[TME_RECODE_OPCODES_INTEGER];\ 134 \ 135 /* the zero- and sign-extension subs are kept in this separate \ 136 list, because their different source and destination operand \ 137 sizes require multiple subs: */ \ 138 tme_recode_thunk_off_t tme_recode_x86_flags_thunk_size_subs_ext \ 139 [TME_RECODE_SIZE_GUEST_MAX - TME_RECODE_SIZE_8][2]; \ 140 \ 141 /* the test flags subs, chained to by the flags subs for the \ 142 logical, shift, and extension opcodes: */ \ 143 tme_recode_thunk_off_t tme_recode_x86_flags_thunk_size_subs_test; \ 144 \ 145 } tme_recode_x86_flags_thunk_sizes[TME_RECODE_SIZE_GUEST_MAX + 1 - TME_RECODE_SIZE_8];\ 146 \ 147 /* this is the main flags subs, eventually chained to by all of the \ 148 above subs: */ \ 149 tme_recode_thunk_off_t tme_recode_x86_flags_thunk_subs_main; \ 150 \ 151 /* this is nonzero if the flags thunk calls a guest function: */ \ 152 unsigned int tme_recode_x86_flags_thunk_has_guest_func; \ 153 \ 154 /* if there is a guest function, this is any amount of stack padding \ 155 the subs need to do to satisfy the host ABI: */ \ 156 int tme_recode_x86_flags_thunk_stack_padding 157 158 /* these are the host-specific members added to struct 159 tme_recode_conds_thunk: */ 160 #define TME_RECODE_HOST_CONDS_THUNK \ 161 \ 162 /* the conditions subs: */ \ 163 tme_recode_thunk_off_t tme_recode_x86_conds_thunk_subs; \ 164 \ 165 /* the size of the part of the guest flags register tested by this \ 166 thunk: */ \ 167 tme_uint8_t tme_recode_x86_conds_thunk_flags_size; \ 168 \ 169 /* the struct tme_ic offset of the part of the guest flags register \ 170 tested by this thunk: */ \ 171 tme_uint32_t tme_recode_x86_conds_thunk_flags_offset; \ 172 \ 173 /* the simple condition information. the exact size of this array \ 174 is determined by the guest: */ \ 175 tme_uint32_t tme_recode_x86_conds_thunk_simple[1] 176 177 /* these are the host-specific members added to struct 178 tme_recode_rw_thunk: */ 179 #define TME_RECODE_HOST_RW_THUNK \ 180 \ 181 /* the read or write subs: */ \ 182 tme_recode_thunk_off_t tme_recode_x86_rw_thunk_subs; \ 183 \ 184 /* any sign- or zero-extension instruction and its size: */ \ 185 tme_uint32_t tme_recode_x86_rw_thunk_extend; \ 186 tme_uint32_t tme_recode_x86_rw_thunk_extend_size 187 188 /* these are the host-specific members added to struct 189 tme_recode_chain_thunk: */ 190 #define TME_RECODE_HOST_CHAIN_THUNK \ 191 \ 192 /* the chain subs: */ \ 193 tme_recode_thunk_off_t tme_recode_x86_chain_thunk_subs[8 + 4]; \ 194 \ 195 /* the chain prologue: */ \ 196 void (*tme_recode_x86_chain_thunk_prologue) _TME_P((struct tme_ic *, tme_recode_thunk_off_t)) 197 198 /* these are the x86-specific members added to struct tme_recode_ic. 199 this macro is added to TME_RECODE_HOST_IC at configure time: */ 200 #define TME_RECODE_X86_IC \ 201 \ 202 /* the thunk offset of the chain epilogue: */ \ 203 tme_recode_thunk_off_t tme_recode_x86_ic_chain_epilogue; \ 204 \ 205 /* the chain fixup targets: */ \ 206 tme_recode_thunk_off_t tme_recode_x86_ic_chain_fixup_target[4 + 2]; \ 207 \ 208 /* the thunk offsets of the shift insn subs: */ \ 209 tme_recode_thunk_off_t tme_recode_x86_ic_subs_shift \ 210 [TME_RECODE_SIZE_GUEST_MAX + 1 - TME_RECODE_SIZE_8][3]; \ 211 \ 212 /* if not TME_RECODE_REG_GUEST_WINDOW_UNDEF, the c register \ 213 still holds the base offset of that guest window: */ \ 214 unsigned int tme_recode_x86_ic_thunks_reg_guest_window_c; \ 215 \ 216 /* if not TME_RECODE_REG_GUEST_WINDOW_UNDEF, the c register still \ 217 held the base offset of that guest window at the time of the \ 218 previous if jump: */ \ 219 unsigned int tme_recode_x86_ic_thunks_reg_guest_window_c_if_jmp; \ 220 \ 221 /* the position of an active if in the thunks build memory: */ \ 222 tme_recode_host_insn_t *tme_recode_x86_ic_thunks_build_if; \ 223 \ 224 /* the position of an active else in the thunks build memory: */ \ 225 tme_recode_host_insn_t *tme_recode_x86_ic_thunks_build_else 226 227 /* this runs an instruction thunk: */ 228 #define tme_recode_insns_thunk_run(ic, chain_thunk, insns_thunk) \ 229 ((*((chain_thunk)->tme_recode_x86_chain_thunk_prologue))((ic), (insns_thunk))) 230 231 /* TLB flags: */ 232 #define TME_RECODE_TLB_FLAG_CONTEXT_MISMATCH(ic) (((tme_uint32_t) 1) << (31 + (0 && ic))) 233 #define TME_RECODE_TLB_FLAG(ic, x) (((tme_uint32_t) 1) << (30 - (x) + (0 && (ic)))) 234 #define TME_RECODE_X86_TLB_FLAG_INVALID(ic) ((ic)->tme_recode_ic_tlb_page_size) 235 #define TME_RECODE_TLB_FLAGS_MASK(ic) (0 - (tme_uint32_t) (TME_RECODE_X86_TLB_FLAG_INVALID(ic) * 3)) 236 237 /* types: */ 238 239 /* a host instruction: */ 240 typedef tme_uint8_t tme_recode_host_insn_t; 241 242 /* a thunk offset: */ 243 typedef tme_int32_t tme_recode_thunk_off_t; 244 245 /* a return address stack entry: */ 246 typedef tme_uint32_t tme_recode_ras_entry_t; 247