File: ppc32_jit.h

package info (click to toggle)
dynamips 0.2.14-1
  • links: PTS, VCS
  • area: non-free
  • in suites: bookworm, bullseye, buster, forky, jessie, jessie-kfreebsd, sid, stretch, trixie
  • size: 5,448 kB
  • ctags: 14,852
  • sloc: ansic: 104,416; perl: 20; sh: 4; makefile: 3
file content (366 lines) | stat: -rw-r--r-- 10,628 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
/*
 * Cisco router simulation platform.
 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
 *
 * PPC32 JIT compiler.
 */

#ifndef __PPC32_JIT_H__
#define __PPC32_JIT_H__

#include "utils.h"
#include "sbox.h"

/* Size of executable page area (in Mb) */
#ifndef __CYGWIN__
#define PPC_EXEC_AREA_SIZE  64
#else
#define PPC_EXEC_AREA_SIZE  16
#endif

/* Buffer size for JIT code generation */
#define PPC_JIT_BUFSIZE     32768

/* Maximum number of X86 chunks */
#define PPC_JIT_MAX_CHUNKS  64

/* Size of hash for IA lookup */
#define PPC_JIT_IA_HASH_BITS    17
#define PPC_JIT_IA_HASH_MASK    ((1 << PPC_JIT_IA_HASH_BITS) - 1)
#define PPC_JIT_IA_HASH_SIZE    (1 << PPC_JIT_IA_HASH_BITS)

/* Size of hash for physical lookup */
#define PPC_JIT_PHYS_HASH_BITS  16
#define PPC_JIT_PHYS_HASH_MASK  ((1 << PPC_JIT_PHYS_HASH_BITS) - 1)
#define PPC_JIT_PHYS_HASH_SIZE  (1 << PPC_JIT_PHYS_HASH_BITS)

#define PPC_JIT_TARGET_BITMAP_INDEX(x) (((x) >> 7) & 0x1F)
#define PPC_JIT_TARGET_BITMAP_POS(x)   (((x) >> 2) & 0x1F)

/* Instruction jump patch */
struct ppc32_insn_patch {
   struct ppc32_insn_patch *next;
   u_char *jit_insn;
   m_uint32_t ppc_ia;
};

/* Instruction patch table */
#define PPC32_INSN_PATCH_TABLE_SIZE  32

struct ppc32_jit_patch_table {   
   struct ppc32_jit_patch_table *next;
   struct ppc32_insn_patch patches[PPC32_INSN_PATCH_TABLE_SIZE];
   u_int cur_patch;
};

#define PPC32_JIT_TCB_FLAG_NO_FLUSH  0x2   /* No flushing */

/* PPC32 translated code block */
struct ppc32_jit_tcb {
   u_int flags;
   m_uint32_t start_ia;
   u_char **jit_insn_ptr;
   m_uint64_t acc_count;
   ppc_insn_t *ppc_code;
   u_int ppc_trans_pos;
   u_int jit_chunk_pos;
   u_char *jit_ptr;
   insn_exec_page_t *jit_buffer;
   insn_exec_page_t *jit_chunks[PPC_JIT_MAX_CHUNKS];
   struct ppc32_jit_patch_table *patch_table;
   ppc32_jit_tcb_t *prev,*next;

   m_uint32_t phys_page;
   m_uint32_t phys_hash;
   ppc32_jit_tcb_t **phys_pprev,*phys_next;
   
   /* 1024 instructions per page, one bit per instruction */
   m_uint32_t target_bitmap[32];
   m_uint32_t target_undef_cnt;

#if DEBUG_BLOCK_TIMESTAMP
   m_uint64_t tm_first_use,tm_last_use;
#endif
};

/* PPC instruction recognition */
struct ppc32_insn_tag {
   int (*emit)(cpu_ppc_t *cpu,ppc32_jit_tcb_t *,ppc_insn_t);
   m_uint32_t mask,value;
};

/* Mark the specified IA as a target for further recompiling */
static inline void 
ppc32_jit_tcb_set_target_bit(ppc32_jit_tcb_t *b,m_uint32_t ia)
{
   int index,pos;

   index = PPC_JIT_TARGET_BITMAP_INDEX(ia);
   pos   = PPC_JIT_TARGET_BITMAP_POS(ia);

   b->target_bitmap[index] |= 1 << pos;
}

/* Returns TRUE if the specified IA is in the target bitmap */
static inline int
ppc32_jit_tcb_get_target_bit(ppc32_jit_tcb_t *b,m_uint32_t ia)
{
   int index,pos;

   index = PPC_JIT_TARGET_BITMAP_INDEX(ia);
   pos   = PPC_JIT_TARGET_BITMAP_POS(ia);

   return(b->target_bitmap[index] & (1 << pos));
}

/* Get the JIT instruction pointer in a translated block */
static forced_inline 
u_char *ppc32_jit_tcb_get_host_ptr(ppc32_jit_tcb_t *b,m_uint32_t vaddr)
{
   m_uint32_t offset;

   offset = (vaddr & PPC32_MIN_PAGE_IMASK) >> 2;
   return(b->jit_insn_ptr[offset]);
}

/* Check if the specified address belongs to the specified block */
static forced_inline 
int ppc32_jit_tcb_local_addr(ppc32_jit_tcb_t *block,m_uint32_t vaddr,
                             u_char **jit_addr)
{
   if ((vaddr & PPC32_MIN_PAGE_MASK) == block->start_ia) {
      *jit_addr = ppc32_jit_tcb_get_host_ptr(block,vaddr);
      return(1);
   }

   return(0);
}

/* Check if PC register matches the compiled block virtual address */
static forced_inline 
int ppc32_jit_tcb_match(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block)
{
   m_uint32_t vpage;

   vpage = cpu->ia & ~PPC32_MIN_PAGE_IMASK;
   return(block->start_ia == vpage);
}

/* Compute the hash index for the specified IA value */
static forced_inline m_uint32_t ppc32_jit_get_ia_hash(m_uint32_t ia)
{
   m_uint32_t page_hash;

   page_hash = sbox_u32(ia >> PPC32_MIN_PAGE_SHIFT);
   return((page_hash ^ (page_hash >> 14)) & PPC_JIT_IA_HASH_MASK);
}

/* Compute the hash index for the specified physical page */
static forced_inline m_uint32_t ppc32_jit_get_phys_hash(m_uint32_t phys_page)
{
   m_uint32_t page_hash;

   page_hash = sbox_u32(phys_page);
   return((page_hash ^ (page_hash >> 12)) & PPC_JIT_PHYS_HASH_MASK);
}

/* Find the JIT block matching a physical page */
static inline ppc32_jit_tcb_t *
ppc32_jit_find_by_phys_page(cpu_ppc_t *cpu,m_uint32_t phys_page)
{
   m_uint32_t page_hash =  ppc32_jit_get_phys_hash(phys_page);
   ppc32_jit_tcb_t *block;
   
   for(block=cpu->exec_phys_map[page_hash];block;block=block->phys_next)
      if (block->phys_page == phys_page)
         return block;

   return NULL;
}

/* ======================================================================== */
/* JIT emit operations (generic).                                           */
/* ======================================================================== */

/* Indicate registers modified by ppc32_update_cr() functions */
extern void ppc32_update_cr_set_altered_hreg(cpu_ppc_t *cpu);

/* Set opcode */
static inline void ppc32_op_set(cpu_ppc_t *cpu,jit_op_t *op)
{
   cpu_gen_t *c = cpu->gen;
   *c->jit_op_current = op;
   c->jit_op_current = &op->next;
}

/* EMIT_BASIC_OPCODE */
static inline void ppc32_op_emit_basic_opcode(cpu_ppc_t *cpu,u_int opcode)
{
   jit_op_t *op = jit_op_get(cpu->gen,0,opcode);
   ppc32_op_set(cpu,op);
}

/* Trash the specified host register */
static inline void ppc32_op_emit_alter_host_reg(cpu_ppc_t *cpu,int host_reg)
{
   jit_op_t *op = jit_op_get(cpu->gen,0,JIT_OP_ALTER_HOST_REG);
   op->param[0] = host_reg;
   ppc32_op_set(cpu,op);
}

/* EMIT_INSN_OUTPUT */
static inline jit_op_t *
ppc32_op_emit_insn_output(cpu_ppc_t *cpu,u_int size_index,char *insn_name)
{
   jit_op_t *op = jit_op_get(cpu->gen,size_index,JIT_OP_INSN_OUTPUT);
   op->arg_ptr = NULL;
   op->insn_name = insn_name;
   ppc32_op_set(cpu,op);
   return op;
}

/* EMIT_LOAD_GPR */
static inline 
void ppc32_op_emit_load_gpr(cpu_ppc_t *cpu,int host_reg,int ppc_reg)
{
   jit_op_t *op = jit_op_get(cpu->gen,0,JIT_OP_LOAD_GPR);
   op->param[0] = host_reg;
   op->param[1] = ppc_reg;
   op->param[2] = host_reg;
   ppc32_op_set(cpu,op);
}

/* EMIT_STORE_GPR */
static inline 
void ppc32_op_emit_store_gpr(cpu_ppc_t *cpu,int ppc_reg,int host_reg)
{
   jit_op_t *op = jit_op_get(cpu->gen,0,JIT_OP_STORE_GPR);
   op->param[0] = host_reg;
   op->param[1] = ppc_reg;
   op->param[2] = host_reg;
   ppc32_op_set(cpu,op);
}

/* EMIT_UPDATE_FLAGS */
static inline 
void ppc32_op_emit_update_flags(cpu_ppc_t *cpu,int field,int is_signed)
{
   jit_op_t *op = jit_op_get(cpu->gen,0,JIT_OP_UPDATE_FLAGS);

   op->param[0] = field;
   op->param[1] = is_signed;

   ppc32_op_set(cpu,op);
   ppc32_update_cr_set_altered_hreg(cpu);
}

/* EMIT_REQUIRE_FLAGS */
static inline void ppc32_op_emit_require_flags(cpu_ppc_t *cpu,int field)
{
   jit_op_t *op = jit_op_get(cpu->gen,0,JIT_OP_REQUIRE_FLAGS);
   op->param[0] = field;
   ppc32_op_set(cpu,op);
}

/* EMIT_BRANCH_TARGET */
static inline void ppc32_op_emit_branch_target(cpu_ppc_t *cpu,
                                               ppc32_jit_tcb_t *b,
                                               m_uint32_t ia)
{
   if ((ia & PPC32_MIN_PAGE_MASK) == b->start_ia) {
      cpu_gen_t *c = cpu->gen;
      jit_op_t *op = jit_op_get(c,0,JIT_OP_BRANCH_TARGET);
      u_int pos = (ia & PPC32_MIN_PAGE_IMASK) >> 2;

      /* Insert in head */
      op->next = c->jit_op_array[pos];
      c->jit_op_array[pos] = op;
   }
}

/* EMIT_SET_HOST_REG_IMM32 */
static inline void 
ppc32_op_emit_set_host_reg_imm32(cpu_ppc_t *cpu,int reg,m_uint32_t val)
{
   jit_op_t *op = jit_op_get(cpu->gen,0,JIT_OP_SET_HOST_REG_IMM32);
   op->param[0] = reg;
   op->param[1] = val;
   ppc32_op_set(cpu,op);
}

/* ======================================================================== */
/* JIT operations with implementations specific to target CPU */
void ppc32_op_insn_output(ppc32_jit_tcb_t *b,jit_op_t *op);
void ppc32_op_load_gpr(ppc32_jit_tcb_t *b,jit_op_t *op);
void ppc32_op_store_gpr(ppc32_jit_tcb_t *b,jit_op_t *op);
void ppc32_op_update_flags(ppc32_jit_tcb_t *b,jit_op_t *op);
void ppc32_op_move_host_reg(ppc32_jit_tcb_t *b,jit_op_t *op);
void ppc32_op_set_host_reg_imm32(ppc32_jit_tcb_t *b,jit_op_t *op);

/* Set the Instruction Address (IA) register */
void ppc32_set_ia(u_char **ptr,m_uint32_t new_ia);

/* Jump to the next page */
void ppc32_set_page_jump(cpu_ppc_t *cpu,ppc32_jit_tcb_t *b);

/* Increment the number of executed instructions (performance debugging) */
void ppc32_inc_perf_counter(cpu_ppc_t *cpu);

/* ======================================================================== */

/* Virtual Breakpoint */
void ppc32_emit_breakpoint(cpu_ppc_t *cpu,ppc32_jit_tcb_t *b);

/* Initialize instruction lookup table */
void ppc32_jit_create_ilt(void);

/* Initialize the JIT structure */
int ppc32_jit_init(cpu_ppc_t *cpu);

/* Flush the JIT */
u_int ppc32_jit_flush(cpu_ppc_t *cpu,u_int threshold);

/* Shutdown the JIT */
void ppc32_jit_shutdown(cpu_ppc_t *cpu);

/* Fetch a PowerPC instruction and emit corresponding translated code */
struct ppc32_insn_tag *ppc32_jit_fetch_and_emit(cpu_ppc_t *cpu,
                                                ppc32_jit_tcb_t *block);

/* Record a patch to apply in a compiled block */
int ppc32_jit_tcb_record_patch(ppc32_jit_tcb_t *block,jit_op_t *iop,
                               u_char *jit_ptr,m_uint32_t vaddr);

/* Free an instruction block */
void ppc32_jit_tcb_free(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block,
                        int list_removal);

/* Check if the specified address belongs to the specified block */
int ppc32_jit_tcb_local_addr(ppc32_jit_tcb_t *block,m_uint32_t vaddr,
                             u_char **jit_addr);

/* Recompile a page */
int ppc32_jit_tcb_recompile(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block);

/* Execute compiled PowerPC code */
void *ppc32_jit_run_cpu(cpu_gen_t *gen);

/* Start register allocation sequence */
void ppc32_jit_start_hreg_seq(cpu_ppc_t *cpu,char *insn);

/* Close register allocation sequence */
void ppc32_jit_close_hreg_seq(cpu_ppc_t *cpu);

/* Insert a reg map as head of list (as MRU element) */
void ppc32_jit_insert_hreg_mru(cpu_ppc_t *cpu,struct hreg_map *map);

/* Allocate an host register */
int ppc32_jit_alloc_hreg(cpu_ppc_t *cpu,int ppc_reg);

/* Force allocation of an host register */
int ppc32_jit_alloc_hreg_forced(cpu_ppc_t *cpu,int hreg);

/* Initialize register mapping */
void ppc32_jit_init_hreg_mapping(cpu_ppc_t *cpu);

#endif