1 |
/* |
2 |
* Cisco router simulation platform. |
3 |
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) |
4 |
* |
5 |
* PPC32 JIT compiler. |
6 |
*/ |
7 |
|
8 |
#ifndef __PPC32_JIT_H__ |
9 |
#define __PPC32_JIT_H__ |
10 |
|
11 |
#include "utils.h" |
12 |
#include "sbox.h" |
13 |
|
14 |
/* Size of executable page area (in Mb) */ |
15 |
#ifndef __CYGWIN__ |
16 |
#define PPC_EXEC_AREA_SIZE 64 |
17 |
#else |
18 |
#define PPC_EXEC_AREA_SIZE 16 |
19 |
#endif |
20 |
|
21 |
/* Buffer size for JIT code generation */ |
22 |
#define PPC_JIT_BUFSIZE 32768 |
23 |
|
24 |
/* Maximum number of X86 chunks */ |
25 |
#define PPC_JIT_MAX_CHUNKS 64 |
26 |
|
27 |
/* Size of hash for IA lookup */ |
28 |
#define PPC_JIT_IA_HASH_BITS 17 |
29 |
#define PPC_JIT_IA_HASH_MASK ((1 << PPC_JIT_IA_HASH_BITS) - 1) |
30 |
#define PPC_JIT_IA_HASH_SIZE (1 << PPC_JIT_IA_HASH_BITS) |
31 |
|
32 |
/* Size of hash for physical lookup */ |
33 |
#define PPC_JIT_PHYS_HASH_BITS 16 |
34 |
#define PPC_JIT_PHYS_HASH_MASK ((1 << PPC_JIT_PHYS_HASH_BITS) - 1) |
35 |
#define PPC_JIT_PHYS_HASH_SIZE (1 << PPC_JIT_PHYS_HASH_BITS) |
36 |
|
37 |
#define PPC_JIT_TARGET_BITMAP_INDEX(x) (((x) >> 7) & 0x1F) |
38 |
#define PPC_JIT_TARGET_BITMAP_POS(x) (((x) >> 2) & 0x1F) |
39 |
|
40 |
/* Instruction jump patch */ |
41 |
struct ppc32_insn_patch { |
42 |
struct ppc32_insn_patch *next; |
43 |
u_char *jit_insn; |
44 |
m_uint32_t ppc_ia; |
45 |
}; |
46 |
|
47 |
/* Instruction patch table */ |
48 |
#define PPC32_INSN_PATCH_TABLE_SIZE 32 |
49 |
|
50 |
struct ppc32_jit_patch_table { |
51 |
struct ppc32_jit_patch_table *next; |
52 |
struct ppc32_insn_patch patches[PPC32_INSN_PATCH_TABLE_SIZE]; |
53 |
u_int cur_patch; |
54 |
}; |
55 |
|
56 |
/* PPC32 translated code block */ |
57 |
struct ppc32_jit_tcb { |
58 |
m_uint32_t start_ia; |
59 |
u_char **jit_insn_ptr; |
60 |
m_uint64_t acc_count; |
61 |
ppc_insn_t *ppc_code; |
62 |
u_int ppc_trans_pos; |
63 |
u_int jit_chunk_pos; |
64 |
u_char *jit_ptr; |
65 |
insn_exec_page_t *jit_buffer; |
66 |
insn_exec_page_t *jit_chunks[PPC_JIT_MAX_CHUNKS]; |
67 |
struct ppc32_jit_patch_table *patch_table; |
68 |
ppc32_jit_tcb_t *prev,*next; |
69 |
|
70 |
m_uint32_t phys_page; |
71 |
m_uint32_t phys_hash; |
72 |
ppc32_jit_tcb_t **phys_pprev,*phys_next; |
73 |
|
74 |
/* 1024 instructions per page, one bit per instruction */ |
75 |
m_uint32_t target_bitmap[32]; |
76 |
m_uint32_t target_undef_cnt; |
77 |
|
78 |
#if DEBUG_BLOCK_TIMESTAMP |
79 |
m_uint64_t tm_first_use,tm_last_use; |
80 |
#endif |
81 |
}; |
82 |
|
83 |
/* PPC instruction recognition */ |
84 |
struct ppc32_insn_tag { |
85 |
int (*emit)(cpu_ppc_t *cpu,ppc32_jit_tcb_t *,ppc_insn_t); |
86 |
m_uint32_t mask,value; |
87 |
}; |
88 |
|
89 |
/* Mark the specified IA as a target for further recompiling */ |
90 |
static inline void |
91 |
ppc32_jit_tcb_set_target_bit(ppc32_jit_tcb_t *b,m_uint32_t ia) |
92 |
{ |
93 |
int index,pos; |
94 |
|
95 |
index = PPC_JIT_TARGET_BITMAP_INDEX(ia); |
96 |
pos = PPC_JIT_TARGET_BITMAP_POS(ia); |
97 |
|
98 |
b->target_bitmap[index] |= 1 << pos; |
99 |
} |
100 |
|
101 |
/* Returns TRUE if the specified IA is in the target bitmap */ |
102 |
static inline int |
103 |
ppc32_jit_tcb_get_target_bit(ppc32_jit_tcb_t *b,m_uint32_t ia) |
104 |
{ |
105 |
int index,pos; |
106 |
|
107 |
index = PPC_JIT_TARGET_BITMAP_INDEX(ia); |
108 |
pos = PPC_JIT_TARGET_BITMAP_POS(ia); |
109 |
|
110 |
return(b->target_bitmap[index] & (1 << pos)); |
111 |
} |
112 |
|
113 |
/* Get the JIT instruction pointer in a translated block */ |
114 |
static forced_inline |
115 |
u_char *ppc32_jit_tcb_get_host_ptr(ppc32_jit_tcb_t *b,m_uint32_t vaddr) |
116 |
{ |
117 |
m_uint32_t offset; |
118 |
|
119 |
offset = (vaddr & PPC32_MIN_PAGE_IMASK) >> 2; |
120 |
return(b->jit_insn_ptr[offset]); |
121 |
} |
122 |
|
123 |
/* Check if the specified address belongs to the specified block */ |
124 |
static forced_inline |
125 |
int ppc32_jit_tcb_local_addr(ppc32_jit_tcb_t *block,m_uint32_t vaddr, |
126 |
u_char **jit_addr) |
127 |
{ |
128 |
if ((vaddr & PPC32_MIN_PAGE_MASK) == block->start_ia) { |
129 |
*jit_addr = ppc32_jit_tcb_get_host_ptr(block,vaddr); |
130 |
return(1); |
131 |
} |
132 |
|
133 |
return(0); |
134 |
} |
135 |
|
136 |
/* Check if PC register matches the compiled block virtual address */ |
137 |
static forced_inline |
138 |
int ppc32_jit_tcb_match(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block) |
139 |
{ |
140 |
m_uint32_t vpage; |
141 |
|
142 |
vpage = cpu->ia & ~PPC32_MIN_PAGE_IMASK; |
143 |
return(block->start_ia == vpage); |
144 |
} |
145 |
|
146 |
/* Compute the hash index for the specified IA value */ |
147 |
static forced_inline m_uint32_t ppc32_jit_get_ia_hash(m_uint32_t ia) |
148 |
{ |
149 |
m_uint32_t page_hash; |
150 |
|
151 |
page_hash = sbox_u32(ia >> PPC32_MIN_PAGE_SHIFT); |
152 |
return((page_hash ^ (page_hash >> 14)) & PPC_JIT_IA_HASH_MASK); |
153 |
} |
154 |
|
155 |
/* Compute the hash index for the specified physical page */ |
156 |
static forced_inline m_uint32_t ppc32_jit_get_phys_hash(m_uint32_t phys_page) |
157 |
{ |
158 |
m_uint32_t page_hash; |
159 |
|
160 |
page_hash = sbox_u32(phys_page); |
161 |
return((page_hash ^ (page_hash >> 12)) & PPC_JIT_PHYS_HASH_MASK); |
162 |
} |
163 |
|
164 |
/* Find the JIT block matching a physical page */ |
165 |
static inline ppc32_jit_tcb_t * |
166 |
ppc32_jit_find_by_phys_page(cpu_ppc_t *cpu,m_uint32_t phys_page) |
167 |
{ |
168 |
m_uint32_t page_hash = ppc32_jit_get_phys_hash(phys_page); |
169 |
ppc32_jit_tcb_t *block; |
170 |
|
171 |
for(block=cpu->exec_phys_map[page_hash];block;block=block->phys_next) |
172 |
if (block->phys_page == phys_page) |
173 |
return block; |
174 |
|
175 |
return NULL; |
176 |
} |
177 |
|
178 |
/* ======================================================================== */ |
179 |
/* JIT emit operations (generic). */ |
180 |
/* ======================================================================== */ |
181 |
|
182 |
/* Indicate registers modified by ppc32_update_cr() functions */ |
183 |
extern void ppc32_update_cr_set_altered_hreg(cpu_ppc_t *cpu); |
184 |
|
185 |
/* Set opcode */ |
186 |
static inline void ppc32_op_set(cpu_ppc_t *cpu,jit_op_t *op) |
187 |
{ |
188 |
cpu_gen_t *c = cpu->gen; |
189 |
*c->jit_op_current = op; |
190 |
c->jit_op_current = &op->next; |
191 |
} |
192 |
|
193 |
/* EMIT_BASIC_OPCODE */ |
194 |
static inline void ppc32_op_emit_basic_opcode(cpu_ppc_t *cpu,u_int opcode) |
195 |
{ |
196 |
jit_op_t *op = jit_op_get(cpu->gen,0,opcode); |
197 |
ppc32_op_set(cpu,op); |
198 |
} |
199 |
|
200 |
/* Trash the specified host register */ |
201 |
static inline void ppc32_op_emit_alter_host_reg(cpu_ppc_t *cpu,int host_reg) |
202 |
{ |
203 |
jit_op_t *op = jit_op_get(cpu->gen,0,JIT_OP_ALTER_HOST_REG); |
204 |
op->param[0] = host_reg; |
205 |
ppc32_op_set(cpu,op); |
206 |
} |
207 |
|
208 |
/* EMIT_INSN_OUTPUT */ |
209 |
static inline jit_op_t * |
210 |
ppc32_op_emit_insn_output(cpu_ppc_t *cpu,u_int size_index,char *insn_name) |
211 |
{ |
212 |
jit_op_t *op = jit_op_get(cpu->gen,size_index,JIT_OP_INSN_OUTPUT); |
213 |
op->arg_ptr = NULL; |
214 |
op->insn_name = insn_name; |
215 |
ppc32_op_set(cpu,op); |
216 |
return op; |
217 |
} |
218 |
|
219 |
/* EMIT_LOAD_GPR */ |
220 |
static inline |
221 |
void ppc32_op_emit_load_gpr(cpu_ppc_t *cpu,int host_reg,int ppc_reg) |
222 |
{ |
223 |
jit_op_t *op = jit_op_get(cpu->gen,0,JIT_OP_LOAD_GPR); |
224 |
op->param[0] = host_reg; |
225 |
op->param[1] = ppc_reg; |
226 |
op->param[2] = host_reg; |
227 |
ppc32_op_set(cpu,op); |
228 |
} |
229 |
|
230 |
/* EMIT_STORE_GPR */ |
231 |
static inline |
232 |
void ppc32_op_emit_store_gpr(cpu_ppc_t *cpu,int ppc_reg,int host_reg) |
233 |
{ |
234 |
jit_op_t *op = jit_op_get(cpu->gen,0,JIT_OP_STORE_GPR); |
235 |
op->param[0] = host_reg; |
236 |
op->param[1] = ppc_reg; |
237 |
op->param[2] = host_reg; |
238 |
ppc32_op_set(cpu,op); |
239 |
} |
240 |
|
241 |
/* EMIT_UPDATE_FLAGS */ |
242 |
static inline |
243 |
void ppc32_op_emit_update_flags(cpu_ppc_t *cpu,int field,int is_signed) |
244 |
{ |
245 |
jit_op_t *op = jit_op_get(cpu->gen,0,JIT_OP_UPDATE_FLAGS); |
246 |
|
247 |
op->param[0] = field; |
248 |
op->param[1] = is_signed; |
249 |
|
250 |
ppc32_op_set(cpu,op); |
251 |
ppc32_update_cr_set_altered_hreg(cpu); |
252 |
} |
253 |
|
254 |
/* EMIT_REQUIRE_FLAGS */ |
255 |
static inline void ppc32_op_emit_require_flags(cpu_ppc_t *cpu,int field) |
256 |
{ |
257 |
jit_op_t *op = jit_op_get(cpu->gen,0,JIT_OP_REQUIRE_FLAGS); |
258 |
op->param[0] = field; |
259 |
ppc32_op_set(cpu,op); |
260 |
} |
261 |
|
262 |
/* EMIT_BRANCH_TARGET */ |
263 |
static inline void ppc32_op_emit_branch_target(cpu_ppc_t *cpu, |
264 |
ppc32_jit_tcb_t *b, |
265 |
m_uint32_t ia) |
266 |
{ |
267 |
cpu_gen_t *c = cpu->gen; |
268 |
jit_op_t *op = jit_op_get(c,0,JIT_OP_BRANCH_TARGET); |
269 |
u_int pos; |
270 |
|
271 |
if ((ia & PPC32_MIN_PAGE_MASK) == b->start_ia) { |
272 |
pos = (ia & PPC32_MIN_PAGE_IMASK) >> 2; |
273 |
|
274 |
/* Insert in head */ |
275 |
op->next = c->jit_op_array[pos]; |
276 |
c->jit_op_array[pos] = op; |
277 |
} |
278 |
} |
279 |
|
280 |
/* EMIT_SET_HOST_REG_IMM32 */ |
281 |
static inline void |
282 |
ppc32_op_emit_set_host_reg_imm32(cpu_ppc_t *cpu,int reg,m_uint32_t val) |
283 |
{ |
284 |
jit_op_t *op = jit_op_get(cpu->gen,0,JIT_OP_SET_HOST_REG_IMM32); |
285 |
op->param[0] = reg; |
286 |
op->param[1] = val; |
287 |
ppc32_op_set(cpu,op); |
288 |
} |
289 |
|
290 |
/* ======================================================================== */ |
291 |
/* JIT operations with implementations specific to target CPU */ |
292 |
void ppc32_op_insn_output(ppc32_jit_tcb_t *b,jit_op_t *op); |
293 |
void ppc32_op_load_gpr(ppc32_jit_tcb_t *b,jit_op_t *op); |
294 |
void ppc32_op_store_gpr(ppc32_jit_tcb_t *b,jit_op_t *op); |
295 |
void ppc32_op_update_flags(ppc32_jit_tcb_t *b,jit_op_t *op); |
296 |
void ppc32_op_move_host_reg(ppc32_jit_tcb_t *b,jit_op_t *op); |
297 |
void ppc32_op_set_host_reg_imm32(ppc32_jit_tcb_t *b,jit_op_t *op); |
298 |
|
299 |
/* Set the Instruction Address (IA) register */ |
300 |
void ppc32_set_ia(u_char **ptr,m_uint32_t new_ia); |
301 |
|
302 |
/* Jump to the next page */ |
303 |
void ppc32_set_page_jump(cpu_ppc_t *cpu,ppc32_jit_tcb_t *b); |
304 |
|
305 |
/* Increment the number of executed instructions (performance debugging) */ |
306 |
void ppc32_inc_perf_counter(ppc32_jit_tcb_t *b); |
307 |
|
308 |
/* ======================================================================== */ |
309 |
|
310 |
/* Virtual Breakpoint */ |
311 |
void ppc32_emit_breakpoint(cpu_ppc_t *cpu,ppc32_jit_tcb_t *b); |
312 |
|
313 |
/* Initialize instruction lookup table */ |
314 |
void ppc32_jit_create_ilt(void); |
315 |
|
316 |
/* Initialize the JIT structure */ |
317 |
int ppc32_jit_init(cpu_ppc_t *cpu); |
318 |
|
319 |
/* Flush the JIT */ |
320 |
u_int ppc32_jit_flush(cpu_ppc_t *cpu,u_int threshold); |
321 |
|
322 |
/* Shutdown the JIT */ |
323 |
void ppc32_jit_shutdown(cpu_ppc_t *cpu); |
324 |
|
325 |
/* Fetch a PowerPC instruction and emit corresponding translated code */ |
326 |
struct ppc32_insn_tag *ppc32_jit_fetch_and_emit(cpu_ppc_t *cpu, |
327 |
ppc32_jit_tcb_t *block); |
328 |
|
329 |
/* Record a patch to apply in a compiled block */ |
330 |
int ppc32_jit_tcb_record_patch(ppc32_jit_tcb_t *block,jit_op_t *iop, |
331 |
u_char *jit_ptr,m_uint32_t vaddr); |
332 |
|
333 |
/* Free an instruction block */ |
334 |
void ppc32_jit_tcb_free(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block, |
335 |
int list_removal); |
336 |
|
337 |
/* Check if the specified address belongs to the specified block */ |
338 |
int ppc32_jit_tcb_local_addr(ppc32_jit_tcb_t *block,m_uint32_t vaddr, |
339 |
u_char **jit_addr); |
340 |
|
341 |
/* Recompile a page */ |
342 |
int ppc32_jit_tcb_recompile(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block); |
343 |
|
344 |
/* Execute compiled PowerPC code */ |
345 |
void *ppc32_jit_run_cpu(cpu_gen_t *gen); |
346 |
|
347 |
/* Start register allocation sequence */ |
348 |
void ppc32_jit_start_hreg_seq(cpu_ppc_t *cpu,char *insn); |
349 |
|
350 |
/* Close register allocation sequence */ |
351 |
void ppc32_jit_close_hreg_seq(cpu_ppc_t *cpu); |
352 |
|
353 |
/* Insert a reg map as head of list (as MRU element) */ |
354 |
void ppc32_jit_insert_hreg_mru(cpu_ppc_t *cpu,struct hreg_map *map); |
355 |
|
356 |
/* Allocate an host register */ |
357 |
int ppc32_jit_alloc_hreg(cpu_ppc_t *cpu,int ppc_reg); |
358 |
|
359 |
/* Force allocation of an host register */ |
360 |
int ppc32_jit_alloc_hreg_forced(cpu_ppc_t *cpu,int hreg); |
361 |
|
362 |
/* Initialize register mapping */ |
363 |
void ppc32_jit_init_hreg_mapping(cpu_ppc_t *cpu); |
364 |
|
365 |
#endif |