1 |
/* |
/* |
2 |
* Cisco 7200 (Predator) simulation platform. |
* Cisco router simulation platform. |
3 |
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) |
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) |
4 |
*/ |
*/ |
5 |
|
|
175 |
/* TLB masks and shifts */ |
/* TLB masks and shifts */ |
176 |
#define MIPS_TLB_PAGE_MASK 0x01ffe000 |
#define MIPS_TLB_PAGE_MASK 0x01ffe000 |
177 |
#define MIPS_TLB_PAGE_SHIFT 13 |
#define MIPS_TLB_PAGE_SHIFT 13 |
178 |
#define MIPS_TLB_VPN2_MASK 0xffffffffffffe000ULL |
#define MIPS_TLB_VPN2_MASK_32 0xffffe000ULL |
179 |
|
#define MIPS_TLB_VPN2_MASK_64 0xc00000ffffffe000ULL |
180 |
#define MIPS_TLB_PFN_MASK 0x3fffffc0 |
#define MIPS_TLB_PFN_MASK 0x3fffffc0 |
181 |
#define MIPS_TLB_ASID_MASK 0x000000ff /* "asid" in EntryHi */ |
#define MIPS_TLB_ASID_MASK 0x000000ff /* "asid" in EntryHi */ |
182 |
#define MIPS_TLB_G_MASK 0x00001000 /* "Global" in EntryHi */ |
#define MIPS_TLB_G_MASK 0x00001000 /* "Global" in EntryHi */ |
196 |
#define MIPS_MIN_PAGE_SHIFT 12 |
#define MIPS_MIN_PAGE_SHIFT 12 |
197 |
#define MIPS_MIN_PAGE_SIZE (1 << MIPS_MIN_PAGE_SHIFT) |
#define MIPS_MIN_PAGE_SIZE (1 << MIPS_MIN_PAGE_SHIFT) |
198 |
#define MIPS_MIN_PAGE_IMASK (MIPS_MIN_PAGE_SIZE - 1) |
#define MIPS_MIN_PAGE_IMASK (MIPS_MIN_PAGE_SIZE - 1) |
199 |
|
#define MIPS_MIN_PAGE_MASK 0xfffffffffffff000ULL |
200 |
|
|
201 |
/* Addressing mode: Kernel, Supervisor and User */ |
/* Addressing mode: Kernel, Supervisor and User */ |
202 |
#define MIPS_MODE_KERNEL 00 |
#define MIPS_MODE_KERNEL 00 |
233 |
#define MIPS64_XKPHYS_PHYS_MASK (MIPS64_XKPHYS_PHYS_SIZE - 1) |
#define MIPS64_XKPHYS_PHYS_MASK (MIPS64_XKPHYS_PHYS_SIZE - 1) |
234 |
#define MIPS64_XKPHYS_CCA_SHIFT 59 |
#define MIPS64_XKPHYS_CCA_SHIFT 59 |
235 |
|
|
|
/* Macros for CPU structure access */ |
|
|
#define REG_OFFSET(reg) (OFFSET(cpu_mips_t,gpr[(reg)])) |
|
|
#define CP0_REG_OFFSET(c0reg) (OFFSET(cpu_mips_t,cp0.reg[(c0reg)])) |
|
|
#define MEMOP_OFFSET(op) (OFFSET(cpu_mips_t,mem_op_fn[(op)])) |
|
|
|
|
236 |
/* Initial Program Counter and Stack pointer for ROM */ |
/* Initial Program Counter and Stack pointer for ROM */ |
237 |
#define MIPS_ROM_PC 0xffffffffbfc00000ULL |
#define MIPS_ROM_PC 0xffffffffbfc00000ULL |
238 |
#define MIPS_ROM_SP 0xffffffff80004000ULL |
#define MIPS_ROM_SP 0xffffffff80004000ULL |
254 |
/* Enable the 64 TLB entries for R7000 CPU */ |
/* Enable the 64 TLB entries for R7000 CPU */ |
255 |
#define MIPS64_R7000_TLB64_ENABLE 0x20000000 |
#define MIPS64_R7000_TLB64_ENABLE 0x20000000 |
256 |
|
|
257 |
|
/* Number of instructions per page */ |
258 |
|
#define MIPS_INSN_PER_PAGE (MIPS_MIN_PAGE_SIZE/sizeof(mips_insn_t)) |
259 |
|
|
260 |
/* MIPS CPU Identifiers */ |
/* MIPS CPU Identifiers */ |
261 |
#define MIPS_PRID_R4600 0x00002012 |
#define MIPS_PRID_R4600 0x00002012 |
262 |
#define MIPS_PRID_R4700 0x00002112 |
#define MIPS_PRID_R4700 0x00002112 |
265 |
#define MIPS_PRID_R527x 0x00002812 |
#define MIPS_PRID_R527x 0x00002812 |
266 |
#define MIPS_PRID_BCM1250 0x00040102 |
#define MIPS_PRID_BCM1250 0x00040102 |
267 |
|
|
|
/* Virtual CPU states */ |
|
|
enum { |
|
|
MIPS_CPU_RUNNING = 0, |
|
|
MIPS_CPU_HALTED, |
|
|
MIPS_CPU_SUSPENDED, |
|
|
}; |
|
|
|
|
268 |
/* Memory operations */ |
/* Memory operations */ |
269 |
enum { |
enum { |
270 |
MIPS_MEMOP_LOOKUP = 0, |
MIPS_MEMOP_LOOKUP = 0, |
301 |
MIPS_MEMOP_MAX, |
MIPS_MEMOP_MAX, |
302 |
}; |
}; |
303 |
|
|
|
/* 6 bits are reserved for device ID (see the memory subsystem) */ |
|
|
#define MIPS64_DEVICE_MAX (1 << 6) |
|
|
|
|
|
/* Number of recorded memory accesses (power of two) */ |
|
|
#define MEMLOG_COUNT 16 |
|
|
|
|
304 |
/* Maximum number of breakpoints */ |
/* Maximum number of breakpoints */ |
305 |
#define MIPS64_MAX_BREAKPOINTS 8 |
#define MIPS64_MAX_BREAKPOINTS 8 |
306 |
|
|
|
typedef struct memlog_access memlog_access_t; |
|
|
struct memlog_access { |
|
|
m_uint64_t pc; |
|
|
m_uint64_t vaddr; |
|
|
m_uint64_t data; |
|
|
m_uint32_t data_valid; |
|
|
m_uint32_t op_size; |
|
|
m_uint32_t op_type; |
|
|
}; |
|
|
|
|
307 |
/* MIPS CPU type */ |
/* MIPS CPU type */ |
308 |
typedef struct cpu_mips cpu_mips_t; |
typedef struct cpu_mips cpu_mips_t; |
309 |
|
|
337 |
m_uint64_t reg[MIPS64_CP1_REG_NR]; |
m_uint64_t reg[MIPS64_CP1_REG_NR]; |
338 |
}mips_cp1_t; |
}mips_cp1_t; |
339 |
|
|
|
/* MTS64 entry */ |
|
|
typedef struct mts64_entry mts64_entry_t; |
|
|
struct mts64_entry { |
|
|
m_uint64_t start; |
|
|
m_iptr_t action; |
|
|
m_uint32_t mask; |
|
|
m_uint32_t phys_page; |
|
|
mts64_entry_t **pself; |
|
|
mts64_entry_t *next,**pprev; |
|
|
}; |
|
|
|
|
|
/* MTS64 chunk forward declaration */ |
|
|
typedef struct mts64_chunk mts64_chunk_t; |
|
|
|
|
340 |
/* MIPS CPU definition */ |
/* MIPS CPU definition */ |
341 |
struct cpu_mips { |
struct cpu_mips { |
342 |
/* MTS 1st level array */ |
/* MTS32/MTS64 caches */ |
343 |
void *mts_l1_ptr; |
union { |
344 |
|
mts32_entry_t *mts32_cache; |
345 |
/* MTS64 cache */ |
mts64_entry_t *mts64_cache; |
346 |
mts64_entry_t **mts64_cache; |
}mts_u; |
347 |
|
|
348 |
/* Virtual version of CP0 Compare Register */ |
/* Virtual version of CP0 Compare Register */ |
349 |
m_uint32_t cp0_virt_cnt_reg,cp0_virt_cmp_reg; |
m_uint32_t cp0_virt_cnt_reg,cp0_virt_cmp_reg; |
354 |
m_uint64_t lo,hi,ret_pc; |
m_uint64_t lo,hi,ret_pc; |
355 |
|
|
356 |
/* Code page translation cache */ |
/* Code page translation cache */ |
357 |
insn_block_t **exec_phys_map; |
mips64_jit_tcb_t **exec_blk_map; |
358 |
|
|
359 |
/* Virtual address to physical page translation */ |
/* Virtual address to physical page translation */ |
360 |
fastcall int (*translate)(cpu_mips_t *cpu,m_uint64_t vaddr, |
fastcall int (*translate)(cpu_mips_t *cpu,m_uint64_t vaddr, |
372 |
/* FPU (CP1) */ |
/* FPU (CP1) */ |
373 |
mips_cp1_t fpu; |
mips_cp1_t fpu; |
374 |
|
|
375 |
/* MTS32 array free list */ |
/* Address bus mask for physical addresses */ |
|
void *mts32_l2_free_list; |
|
|
|
|
|
/* Address bus mask */ |
|
376 |
m_uint64_t addr_bus_mask; |
m_uint64_t addr_bus_mask; |
377 |
|
|
378 |
/* IRQ counters and cause */ |
/* IRQ counters and cause */ |
379 |
m_uint64_t irq_count,timer_irq_count,irq_fp_count; |
m_uint64_t irq_count,timer_irq_count,irq_fp_count; |
380 |
pthread_mutex_t irq_lock; |
pthread_mutex_t irq_lock; |
381 |
|
|
382 |
/* Current and free lists of instruction blocks */ |
/* Current and free lists of translated code blocks */ |
383 |
insn_block_t *insn_block_list,*insn_block_last; |
mips64_jit_tcb_t *tcb_list,*tcb_last,*tcb_free_list; |
|
insn_block_t *insn_block_free_list; |
|
384 |
|
|
385 |
/* Executable page area */ |
/* Executable page area */ |
386 |
void *exec_page_area; |
void *exec_page_area; |
389 |
insn_exec_page_t *exec_page_free_list; |
insn_exec_page_t *exec_page_free_list; |
390 |
insn_exec_page_t *exec_page_array; |
insn_exec_page_t *exec_page_array; |
391 |
|
|
392 |
/* "Idle" loop management */ |
/* Idle PC value */ |
393 |
volatile m_uint64_t idle_pc; |
volatile m_uint64_t idle_pc; |
|
u_int idle_max,idle_sleep_time; |
|
|
pthread_mutex_t idle_mutex; |
|
|
pthread_cond_t idle_cond; |
|
|
|
|
|
/* IRQ disable flag */ |
|
|
volatile u_int irq_disable; |
|
394 |
|
|
395 |
/* Timer IRQs */ |
/* Timer IRQs */ |
396 |
volatile u_int timer_irq_pending; |
volatile u_int timer_irq_pending; |
398 |
u_int timer_irq_check_itv; |
u_int timer_irq_check_itv; |
399 |
u_int timer_drift; |
u_int timer_drift; |
400 |
|
|
401 |
|
/* IRQ disable flag */ |
402 |
|
volatile u_int irq_disable; |
403 |
|
|
404 |
/* IRQ idling preemption */ |
/* IRQ idling preemption */ |
405 |
u_int irq_idle_preempt[8]; |
u_int irq_idle_preempt[8]; |
406 |
|
|
407 |
/* CPU identifier for MP systems */ |
/* Generic CPU instance pointer */ |
408 |
u_int id; |
cpu_gen_t *gen; |
|
|
|
|
/* CPU states */ |
|
|
volatile u_int state,prev_state; |
|
|
volatile m_uint64_t seq_state; |
|
|
|
|
|
/* Thread running this CPU */ |
|
|
pthread_t cpu_thread; |
|
|
int cpu_thread_running; |
|
409 |
|
|
410 |
/* VM instance */ |
/* VM instance */ |
411 |
vm_instance_t *vm; |
vm_instance_t *vm; |
421 |
void (*mts_unmap)(cpu_mips_t *cpu,m_uint64_t vaddr,m_uint32_t len, |
void (*mts_unmap)(cpu_mips_t *cpu,m_uint64_t vaddr,m_uint32_t len, |
422 |
m_uint32_t val,int tlb_index); |
m_uint32_t val,int tlb_index); |
423 |
|
|
424 |
void (*mts_rebuild)(cpu_mips_t *cpu); |
void (*mts_shutdown)(cpu_mips_t *cpu); |
425 |
|
|
426 |
/* MTS64 chunk list */ |
/* MTS cache statistics */ |
427 |
mts64_chunk_t *mts64_chunk_list; |
m_uint64_t mts_misses,mts_lookups; |
|
mts64_chunk_t *mts64_chunk_free_list; |
|
|
mts64_entry_t *mts64_entry_free_list; |
|
|
|
|
|
/* MTS64 cache statistics */ |
|
|
m_uint64_t mts64_misses,mts64_lookups; |
|
|
|
|
|
/* Reverse map for MTS64 */ |
|
|
mts64_entry_t *mts64_rmap[MIPS64_TLB_MAX_ENTRIES]; |
|
428 |
|
|
429 |
/* JIT flush method */ |
/* JIT flush method */ |
430 |
u_int jit_flush_method; |
u_int jit_flush_method; |
435 |
/* Fast memory operations use */ |
/* Fast memory operations use */ |
436 |
u_int fast_memop; |
u_int fast_memop; |
437 |
|
|
438 |
|
/* Direct block jump */ |
439 |
|
u_int exec_blk_direct_jump; |
440 |
|
|
441 |
|
/* Address mode (32 or 64 bits) */ |
442 |
|
u_int addr_mode; |
443 |
|
|
444 |
/* Current exec page (non-JIT) info */ |
/* Current exec page (non-JIT) info */ |
445 |
m_uint64_t njm_exec_page; |
m_uint64_t njm_exec_page; |
446 |
mips_insn_t *njm_exec_ptr; |
mips_insn_t *njm_exec_ptr; |
448 |
/* Performance counter (number of instructions executed by CPU) */ |
/* Performance counter (number of instructions executed by CPU) */ |
449 |
m_uint64_t perf_counter; |
m_uint64_t perf_counter; |
450 |
|
|
|
/* Memory access log for fault debugging */ |
|
|
u_int memlog_pos; |
|
|
memlog_access_t memlog_array[MEMLOG_COUNT]; |
|
|
|
|
451 |
/* Breakpoints */ |
/* Breakpoints */ |
452 |
m_uint64_t breakpoints[MIPS64_MAX_BREAKPOINTS]; |
m_uint64_t breakpoints[MIPS64_MAX_BREAKPOINTS]; |
453 |
u_int breakpoints_enabled; |
u_int breakpoints_enabled; |
455 |
/* Symtrace */ |
/* Symtrace */ |
456 |
int sym_trace; |
int sym_trace; |
457 |
rbtree_tree *sym_tree; |
rbtree_tree *sym_tree; |
|
|
|
|
/* Next CPU in group */ |
|
|
cpu_mips_t *next; |
|
458 |
}; |
}; |
459 |
|
|
460 |
#define MIPS64_IRQ_LOCK(cpu) pthread_mutex_lock(&(cpu)->irq_lock) |
#define MIPS64_IRQ_LOCK(cpu) pthread_mutex_lock(&(cpu)->irq_lock) |
478 |
/* Set the CPU PRID register */ |
/* Set the CPU PRID register */ |
479 |
void mips64_set_prid(cpu_mips_t *cpu,m_uint32_t prid); |
void mips64_set_prid(cpu_mips_t *cpu,m_uint32_t prid); |
480 |
|
|
481 |
/* Virtual idle loop */ |
/* Set idle PC value */ |
482 |
void mips64_idle_loop(cpu_mips_t *cpu); |
void mips64_set_idle_pc(cpu_gen_t *cpu,m_uint64_t addr); |
|
|
|
|
/* Break idle wait state */ |
|
|
void mips64_idle_break_wait(cpu_mips_t *cpu); |
|
483 |
|
|
484 |
/* Timer IRQ */ |
/* Timer IRQ */ |
485 |
void *mips64_timer_irq_run(cpu_mips_t *cpu); |
void *mips64_timer_irq_run(cpu_mips_t *cpu); |
486 |
|
|
487 |
/* Determine an "idling" PC */ |
/* Determine an "idling" PC */ |
488 |
int mips64_get_idling_pc(cpu_mips_t *cpu); |
int mips64_get_idling_pc(cpu_gen_t *cpu); |
489 |
|
|
490 |
|
/* Set an IRQ (VM IRQ standard routing) */ |
491 |
|
void mips64_vm_set_irq(vm_instance_t *vm,u_int irq); |
492 |
|
|
493 |
|
/* Clear an IRQ (VM IRQ standard routing) */ |
494 |
|
void mips64_vm_clear_irq(vm_instance_t *vm,u_int irq); |
495 |
|
|
496 |
/* Update the IRQ flag */ |
/* Update the IRQ flag */ |
497 |
void mips64_update_irq_flag(cpu_mips_t *cpu); |
void mips64_update_irq_flag(cpu_mips_t *cpu); |
544 |
/* Virtual breakpoint */ |
/* Virtual breakpoint */ |
545 |
fastcall void mips64_run_breakpoint(cpu_mips_t *cpu); |
fastcall void mips64_run_breakpoint(cpu_mips_t *cpu); |
546 |
|
|
547 |
|
/* Add a virtual breakpoint */ |
548 |
|
int mips64_add_breakpoint(cpu_gen_t *cpu,m_uint64_t pc); |
549 |
|
|
550 |
|
/* Remove a virtual breakpoint */ |
551 |
|
void mips64_remove_breakpoint(cpu_gen_t *cpu,m_uint64_t pc); |
552 |
|
|
553 |
/* Debugging for register-jump to address 0 */ |
/* Debugging for register-jump to address 0 */ |
554 |
fastcall void mips64_debug_jr0(cpu_mips_t *cpu); |
fastcall void mips64_debug_jr0(cpu_mips_t *cpu); |
555 |
|
|
556 |
|
/* Set a register */ |
557 |
|
void mips64_reg_set(cpu_gen_t *cpu,u_int reg,m_uint64_t val); |
558 |
|
|
559 |
/* Dump registers of a MIPS64 processor */ |
/* Dump registers of a MIPS64 processor */ |
560 |
void mips64_dump_regs(cpu_mips_t *cpu); |
void mips64_dump_regs(cpu_gen_t *cpu); |
561 |
|
|
562 |
/* Dump a memory block */ |
/* Dump a memory block */ |
563 |
void mips64_dump_memory(cpu_mips_t *cpu,m_uint64_t vaddr,u_int count); |
void mips64_dump_memory(cpu_mips_t *cpu,m_uint64_t vaddr,u_int count); |
572 |
int mips64_load_raw_image(cpu_mips_t *cpu,char *filename,m_uint64_t vaddr); |
int mips64_load_raw_image(cpu_mips_t *cpu,char *filename,m_uint64_t vaddr); |
573 |
|
|
574 |
/* Load an ELF image into the simulated memory */ |
/* Load an ELF image into the simulated memory */ |
575 |
int mips64_load_elf_image(cpu_mips_t *cpu,char *filename, |
int mips64_load_elf_image(cpu_mips_t *cpu,char *filename,int skip_load, |
576 |
m_uint32_t *entry_point); |
m_uint32_t *entry_point); |
577 |
|
|
578 |
/* Symbol lookup */ |
/* Symbol lookup */ |