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