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
|
/*
* Cisco router simulation platform.
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
*
* MIPS64 JIT compiler.
*/
#ifndef __MIPS64_JIT_H__
#define __MIPS64_JIT_H__
#include "utils.h"
#include "sbox.h"
/* Size of executable page area (in Mb) */
#ifndef __CYGWIN__
#define MIPS_EXEC_AREA_SIZE 64
#else
#define MIPS_EXEC_AREA_SIZE 16
#endif
/* Buffer size for JIT code generation */
#define MIPS_JIT_BUFSIZE 32768
/* Maximum number of X86 chunks */
#define MIPS_JIT_MAX_CHUNKS 32
/* Size of hash for PC lookup */
#define MIPS_JIT_PC_HASH_BITS 16
#define MIPS_JIT_PC_HASH_MASK ((1 << MIPS_JIT_PC_HASH_BITS) - 1)
#define MIPS_JIT_PC_HASH_SIZE (1 << MIPS_JIT_PC_HASH_BITS)
/* Instruction jump patch */
struct mips64_insn_patch {
u_char *jit_insn;
m_uint64_t mips_pc;
};
/* Instruction patch table */
#define MIPS64_INSN_PATCH_TABLE_SIZE 32
struct mips64_jit_patch_table {
struct mips64_insn_patch patches[MIPS64_INSN_PATCH_TABLE_SIZE];
u_int cur_patch;
struct mips64_jit_patch_table *next;
};
/* MIPS64 translated code block */
struct mips64_jit_tcb {
m_uint64_t start_pc;
u_char **jit_insn_ptr;
m_uint64_t acc_count;
mips_insn_t *mips_code;
u_int mips_trans_pos;
u_int jit_chunk_pos;
u_char *jit_ptr;
insn_exec_page_t *jit_buffer;
insn_exec_page_t *jit_chunks[MIPS_JIT_MAX_CHUNKS];
struct mips64_jit_patch_table *patch_table;
mips64_jit_tcb_t *prev,*next;
#if DEBUG_BLOCK_TIMESTAMP
m_uint64_t tm_first_use,tm_last_use;
#endif
};
/* MIPS instruction recognition */
struct mips64_insn_tag {
int (*emit)(cpu_mips_t *cpu,mips64_jit_tcb_t *,mips_insn_t);
m_uint32_t mask,value;
int delay_slot;
};
/* MIPS jump instruction (for block scan) */
struct mips64_insn_jump {
char *name;
m_uint32_t mask,value;
int offset_bits;
int relative;
};
/* Get the JIT instruction pointer in a translated block */
static forced_inline
u_char *mips64_jit_tcb_get_host_ptr(mips64_jit_tcb_t *b,m_uint64_t vaddr)
{
m_uint32_t offset;
offset = ((m_uint32_t)vaddr & MIPS_MIN_PAGE_IMASK) >> 2;
return(b->jit_insn_ptr[offset]);
}
/* Check if the specified address belongs to the specified block */
static forced_inline
int mips64_jit_tcb_local_addr(mips64_jit_tcb_t *block,m_uint64_t vaddr,
u_char **jit_addr)
{
if ((vaddr & MIPS_MIN_PAGE_MASK) == block->start_pc) {
*jit_addr = mips64_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 mips64_jit_tcb_match(cpu_mips_t *cpu,mips64_jit_tcb_t *block)
{
m_uint64_t vpage;
vpage = cpu->pc & ~(m_uint64_t)MIPS_MIN_PAGE_IMASK;
return(block->start_pc == vpage);
}
/* Compute the hash index for the specified PC value */
static forced_inline m_uint32_t mips64_jit_get_pc_hash(m_uint64_t pc)
{
m_uint32_t page_hash;
page_hash = sbox_u32(pc >> MIPS_MIN_PAGE_SHIFT);
return((page_hash ^ (page_hash >> 12)) & MIPS_JIT_PC_HASH_MASK);
}
/* Check if there are pending IRQ */
extern void mips64_check_pending_irq(mips64_jit_tcb_t *b);
/* Initialize instruction lookup table */
void mips64_jit_create_ilt(void);
/* Initialize the JIT structure */
int mips64_jit_init(cpu_mips_t *cpu);
/* Flush the JIT */
u_int mips64_jit_flush(cpu_mips_t *cpu,u_int threshold);
/* Shutdown the JIT */
void mips64_jit_shutdown(cpu_mips_t *cpu);
/* Check if an instruction is in a delay slot or not */
int mips64_jit_is_delay_slot(mips64_jit_tcb_t *b,m_uint64_t pc);
/* Fetch a MIPS instruction and emit corresponding x86 translated code */
struct mips64_insn_tag *mips64_jit_fetch_and_emit(cpu_mips_t *cpu,
mips64_jit_tcb_t *block,
int delay_slot);
/* Record a patch to apply in a compiled block */
int mips64_jit_tcb_record_patch(mips64_jit_tcb_t *block,u_char *x86_ptr,
m_uint64_t vaddr);
/* Free an instruction block */
void mips64_jit_tcb_free(cpu_mips_t *cpu,mips64_jit_tcb_t *block,
int list_removal);
/* Execute compiled MIPS code */
void *mips64_jit_run_cpu(cpu_gen_t *cpu);
/* Set the Pointer Counter (PC) register */
void mips64_set_pc(mips64_jit_tcb_t *b,m_uint64_t new_pc);
/* Set the Return Address (RA) register */
void mips64_set_ra(mips64_jit_tcb_t *b,m_uint64_t ret_pc);
/* Single-step operation */
void mips64_emit_single_step(mips64_jit_tcb_t *b,mips_insn_t insn);
/* Virtual Breakpoint */
void mips64_emit_breakpoint(mips64_jit_tcb_t *b);
/* Emit unhandled instruction code */
int mips64_emit_invalid_delay_slot(mips64_jit_tcb_t *b);
/*
* Increment count register and trigger the timer IRQ if value in compare
* register is the same.
*/
void mips64_inc_cp0_count_reg(mips64_jit_tcb_t *b);
/* Increment the number of executed instructions (performance debugging) */
void mips64_inc_perf_counter(mips64_jit_tcb_t *b);
#endif
|