/* * Cisco router simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) */ #ifndef __MIPS_64_H__ #define __MIPS_64_H__ #include <pthread.h> #include "utils.h" #include "rbtree.h" /* * MIPS General Purpose Registers */ #define MIPS_GPR_ZERO 0 /* zero */ #define MIPS_GPR_AT 1 /* at */ #define MIPS_GPR_V0 2 /* v0 */ #define MIPS_GPR_V1 3 /* v1 */ #define MIPS_GPR_A0 4 /* a0 */ #define MIPS_GPR_A1 5 /* a1 */ #define MIPS_GPR_A2 6 /* a2 */ #define MIPS_GPR_A3 7 /* a3 */ #define MIPS_GPR_T0 8 /* t0 */ #define MIPS_GPR_T1 9 /* t1 */ #define MIPS_GPR_T2 10 /* t2 */ #define MIPS_GPR_T3 11 /* t3 */ #define MIPS_GPR_T4 12 /* t4 */ #define MIPS_GPR_T5 13 /* t5 */ #define MIPS_GPR_T6 14 /* t6 */ #define MIPS_GPR_T7 15 /* t7 */ #define MIPS_GPR_S0 16 /* s0 */ #define MIPS_GPR_S1 17 /* s1 */ #define MIPS_GPR_S2 18 /* s2 */ #define MIPS_GPR_S3 19 /* s3 */ #define MIPS_GPR_S4 20 /* s4 */ #define MIPS_GPR_S5 21 /* s5 */ #define MIPS_GPR_S6 22 /* s6 */ #define MIPS_GPR_S7 23 /* s7 */ #define MIPS_GPR_T8 24 /* t8 */ #define MIPS_GPR_T9 25 /* t9 */ #define MIPS_GPR_K0 26 /* k0 */ #define MIPS_GPR_K1 27 /* k1 */ #define MIPS_GPR_GP 28 /* gp */ #define MIPS_GPR_SP 29 /* sp */ #define MIPS_GPR_FP 30 /* fp */ #define MIPS_GPR_RA 31 /* ra */ /* * Coprocessor 0 (System Coprocessor) Register definitions */ #define MIPS_CP0_INDEX 0 /* TLB Index */ #define MIPS_CP0_RANDOM 1 /* TLB Random */ #define MIPS_CP0_TLB_LO_0 2 /* TLB Entry Lo0 */ #define MIPS_CP0_TLB_LO_1 3 /* TLB Entry Lo1 */ #define MIPS_CP0_CONTEXT 4 /* Kernel PTE pointer */ #define MIPS_CP0_PAGEMASK 5 /* TLB Page Mask */ #define MIPS_CP0_WIRED 6 /* TLB Wired */ #define MIPS_CP0_INFO 7 /* Info (RM7000) */ #define MIPS_CP0_BADVADDR 8 /* Bad Virtual Address */ #define MIPS_CP0_COUNT 9 /* Count */ #define MIPS_CP0_TLB_HI 10 /* TLB Entry Hi */ #define MIPS_CP0_COMPARE 11 /* Timer Compare */ #define MIPS_CP0_STATUS 12 /* Status */ #define MIPS_CP0_CAUSE 13 /* Cause */ #define MIPS_CP0_EPC 14 /* Exception PC */ #define MIPS_CP0_PRID 15 /* Proc Rev ID */ #define MIPS_CP0_CONFIG 16 /* Configuration */ #define MIPS_CP0_LLADDR 17 /* Load/Link address */ #define MIPS_CP0_WATCHLO 18 /* Low Watch address */ #define MIPS_CP0_WATCHHI 19 /* High Watch address */ #define MIPS_CP0_XCONTEXT 20 /* Extended context */ #define MIPS_CP0_ECC 26 /* ECC and parity */ #define MIPS_CP0_CACHERR 27 /* Cache Err/Status */ #define MIPS_CP0_TAGLO 28 /* Cache Tag Lo */ #define MIPS_CP0_TAGHI 29 /* Cache Tag Hi */ #define MIPS_CP0_ERR_EPC 30 /* Error exception PC */ /* * CP0 Set 1 Registers (R7000) */ #define MIPS_CP0_S1_CONFIG 16 /* Configuration Register */ #define MIPS_CP0_S1_IPLLO 18 /* Priority level for IRQ [7:0] */ #define MIPS_CP0_S1_IPLHI 19 /* Priority level for IRQ [15:8] */ #define MIPS_CP0_S1_INTCTL 20 /* Interrupt Control */ #define MIPS_CP0_S1_DERRADDR0 26 /* Imprecise Error Address */ #define MIPS_CP0_S1_DERRADDR1 27 /* Imprecise Error Address */ /* * CP0 Status Register */ #define MIPS_CP0_STATUS_CU0 0x10000000 #define MIPS_CP0_STATUS_CU1 0x20000000 #define MIPS_CP0_STATUS_BEV 0x00400000 #define MIPS_CP0_STATUS_TS 0x00200000 #define MIPS_CP0_STATUS_SR 0x00100000 #define MIPS_CP0_STATUS_CH 0x00040000 #define MIPS_CP0_STATUS_CE 0x00020000 #define MIPS_CP0_STATUS_DE 0x00010000 #define MIPS_CP0_STATUS_RP 0x08000000 #define MIPS_CP0_STATUS_FR 0x04000000 #define MIPS_CP0_STATUS_RE 0x02000000 #define MIPS_CP0_STATUS_KX 0x00000080 #define MIPS_CP0_STATUS_SX 0x00000040 #define MIPS_CP0_STATUS_UX 0x00000020 #define MIPS_CP0_STATUS_KSU 0x00000018 #define MIPS_CP0_STATUS_ERL 0x00000004 #define MIPS_CP0_STATUS_EXL 0x00000002 #define MIPS_CP0_STATUS_IE 0x00000001 #define MIPS_CP0_STATUS_IMASK7 0x00008000 #define MIPS_CP0_STATUS_IMASK6 0x00004000 #define MIPS_CP0_STATUS_IMASK5 0x00002000 #define MIPS_CP0_STATUS_IMASK4 0x00001000 #define MIPS_CP0_STATUS_IMASK3 0x00000800 #define MIPS_CP0_STATUS_IMASK2 0x00000400 #define MIPS_CP0_STATUS_IMASK1 0x00000200 #define MIPS_CP0_STATUS_IMASK0 0x00000100 #define MIPS_CP0_STATUS_DS_MASK 0x00770000 #define MIPS_CP0_STATUS_CU_MASK 0xF0000000 #define MIPS_CP0_STATUS_IMASK 0x0000FF00 /* Addressing mode: Kernel, Supervisor and User */ #define MIPS_CP0_STATUS_KSU_SHIFT 0x03 #define MIPS_CP0_STATUS_KSU_MASK 0x03 #define MIPS_CP0_STATUS_KM 0x00 #define MIPS_CP0_STATUS_SM 0x01 #define MIPS_CP0_STATUS_UM 0x10 /* * CP0 Cause register */ #define MIPS_CP0_CAUSE_BD_SLOT 0x80000000 #define MIPS_CP0_CAUSE_MASK 0x0000007C #define MIPS_CP0_CAUSE_CEMASK 0x30000000 #define MIPS_CP0_CAUSE_IMASK 0x0000FF00 #define MIPS_CP0_CAUSE_SHIFT 2 #define MIPS_CP0_CAUSE_CESHIFT 28 #define MIPS_CP0_CAUSE_ISHIFT 8 #define MIPS_CP0_CAUSE_INTERRUPT 0 #define MIPS_CP0_CAUSE_TLB_MOD 1 #define MIPS_CP0_CAUSE_TLB_LOAD 2 #define MIPS_CP0_CAUSE_TLB_SAVE 3 #define MIPS_CP0_CAUSE_ADDR_LOAD 4 /* ADEL */ #define MIPS_CP0_CAUSE_ADDR_SAVE 5 /* ADES */ #define MIPS_CP0_CAUSE_BUS_INSTR 6 #define MIPS_CP0_CAUSE_BUS_DATA 7 #define MIPS_CP0_CAUSE_SYSCALL 8 #define MIPS_CP0_CAUSE_BP 9 #define MIPS_CP0_CAUSE_ILLOP 10 #define MIPS_CP0_CAUSE_CP_UNUSABLE 11 #define MIPS_CP0_CAUSE_OVFLW 12 #define MIPS_CP0_CAUSE_TRAP 13 #define MIPS_CP0_CAUSE_VC_INSTR 14 /* Virtual Coherency */ #define MIPS_CP0_CAUSE_FPE 15 #define MIPS_CP0_CAUSE_WATCH 23 #define MIPS_CP0_CAUSE_VC_DATA 31 /* Virtual Coherency */ #define MIPS_CP0_CAUSE_IBIT7 0x00008000 #define MIPS_CP0_CAUSE_IBIT6 0x00004000 #define MIPS_CP0_CAUSE_IBIT5 0x00002000 #define MIPS_CP0_CAUSE_IBIT4 0x00001000 #define MIPS_CP0_CAUSE_IBIT3 0x00000800 #define MIPS_CP0_CAUSE_IBIT2 0x00000400 #define MIPS_CP0_CAUSE_IBIT1 0x00000200 #define MIPS_CP0_CAUSE_IBIT0 0x00000100 /* TLB masks and shifts */ #define MIPS_TLB_PAGE_MASK 0x01ffe000 #define MIPS_TLB_PAGE_SHIFT 13 #define MIPS_TLB_VPN2_MASK_32 0xffffe000ULL #define MIPS_TLB_VPN2_MASK_64 0xc00000ffffffe000ULL #define MIPS_TLB_PFN_MASK 0x3fffffc0 #define MIPS_TLB_ASID_MASK 0x000000ff /* "asid" in EntryHi */ #define MIPS_TLB_G_MASK 0x00001000 /* "Global" in EntryHi */ #define MIPS_TLB_V_MASK 0x2 /* "Valid" in EntryLo */ #define MIPS_TLB_D_MASK 0x4 /* "Dirty" in EntryLo */ #define MIPS_TLB_C_MASK 0x38 /* Page Coherency Attribute */ #define MIPS_TLB_C_SHIFT 3 #define MIPS_CP0_LO_G_MASK 0x00000001 /* "Global" in Lo0/1 reg */ #define MIPS_CP0_HI_SAFE_MASK 0xffffe0ff /* Safety mask for Hi reg */ #define MIPS_CP0_LO_SAFE_MASK 0x7fffffff /* Safety mask for Lo reg */ /* MIPS "jr ra" instruction */ #define MIPS_INSN_JR_RA 0x03e00008 /* Minimum page size: 4 Kb */ #define MIPS_MIN_PAGE_SHIFT 12 #define MIPS_MIN_PAGE_SIZE (1 << MIPS_MIN_PAGE_SHIFT) #define MIPS_MIN_PAGE_IMASK (MIPS_MIN_PAGE_SIZE - 1) #define MIPS_MIN_PAGE_MASK 0xfffffffffffff000ULL /* Addressing mode: Kernel, Supervisor and User */ #define MIPS_MODE_KERNEL 00 /* Segments in 32-bit User mode */ #define MIPS_USEG_BASE 0x00000000 #define MIPS_USEG_SIZE 0x80000000 /* Segments in 32-bit Supervisor mode */ #define MIPS_SUSEG_BASE 0x00000000 #define MIPS_SUSEG_SIZE 0x80000000 #define MIPS_SSEG_BASE 0xc0000000 #define MIPS_SSEG_SIZE 0x20000000 /* Segments in 32-bit Kernel mode */ #define MIPS_KUSEG_BASE 0x00000000 #define MIPS_KUSEG_SIZE 0x80000000 #define MIPS_KSEG0_BASE 0x80000000 #define MIPS_KSEG0_SIZE 0x20000000 #define MIPS_KSEG1_BASE 0xa0000000 #define MIPS_KSEG1_SIZE 0x20000000 #define MIPS_KSSEG_BASE 0xc0000000 #define MIPS_KSSEG_SIZE 0x20000000 #define MIPS_KSEG3_BASE 0xe0000000 #define MIPS_KSEG3_SIZE 0x20000000 /* xkphys mask (36-bit physical address) */ #define MIPS64_XKPHYS_ZONE_MASK 0xF800000000000000ULL #define MIPS64_XKPHYS_PHYS_SIZE (1ULL << 36) #define MIPS64_XKPHYS_PHYS_MASK (MIPS64_XKPHYS_PHYS_SIZE - 1) #define MIPS64_XKPHYS_CCA_SHIFT 59 /* Initial Program Counter and Stack pointer for ROM */ #define MIPS_ROM_PC 0xffffffffbfc00000ULL #define MIPS_ROM_SP 0xffffffff80004000ULL /* Number of GPR (general purpose registers) */ #define MIPS64_GPR_NR 32 /* Number of registers in CP0 */ #define MIPS64_CP0_REG_NR 32 /* Number of registers in CP1 */ #define MIPS64_CP1_REG_NR 32 /* Number of TLB entries */ #define MIPS64_TLB_STD_ENTRIES 48 #define MIPS64_TLB_MAX_ENTRIES 64 #define MIPS64_TLB_IDX_MASK 0x3f /* 6 bits */ /* Enable the 64 TLB entries for R7000 CPU */ #define MIPS64_R7000_TLB64_ENABLE 0x20000000 /* Number of instructions per page */ #define MIPS_INSN_PER_PAGE (MIPS_MIN_PAGE_SIZE/sizeof(mips_insn_t)) /* MIPS CPU Identifiers */ #define MIPS_PRID_R4600 0x00002012 #define MIPS_PRID_R4700 0x00002112 #define MIPS_PRID_R5000 0x00002312 #define MIPS_PRID_R7000 0x00002721 #define MIPS_PRID_R527x 0x00002812 #define MIPS_PRID_BCM1250 0x00040102 /* Memory operations */ enum { MIPS_MEMOP_LOOKUP = 0, MIPS_MEMOP_LB, MIPS_MEMOP_LBU, MIPS_MEMOP_LH, MIPS_MEMOP_LHU, MIPS_MEMOP_LW, MIPS_MEMOP_LWU, MIPS_MEMOP_LD, MIPS_MEMOP_SB, MIPS_MEMOP_SH, MIPS_MEMOP_SW, MIPS_MEMOP_SD, MIPS_MEMOP_LWL, MIPS_MEMOP_LWR, MIPS_MEMOP_LDL, MIPS_MEMOP_LDR, MIPS_MEMOP_SWL, MIPS_MEMOP_SWR, MIPS_MEMOP_SDL, MIPS_MEMOP_SDR, MIPS_MEMOP_LL, MIPS_MEMOP_SC, MIPS_MEMOP_LDC1, MIPS_MEMOP_SDC1, MIPS_MEMOP_CACHE, MIPS_MEMOP_MAX, }; /* Maximum number of breakpoints */ #define MIPS64_MAX_BREAKPOINTS 8 /* MIPS CPU type */ typedef struct cpu_mips cpu_mips_t; /* Memory operation function prototype */ typedef fastcall void (*mips_memop_fn)(cpu_mips_t *cpu,m_uint64_t vaddr, u_int reg); /* TLB entry definition */ typedef struct { m_uint64_t mask; m_uint64_t hi; m_uint64_t lo0; m_uint64_t lo1; }tlb_entry_t; /* System Coprocessor (CP0) definition */ typedef struct { m_uint64_t reg[MIPS64_CP0_REG_NR]; tlb_entry_t tlb[MIPS64_TLB_MAX_ENTRIES]; /* Number of TLB entries */ u_int tlb_entries; /* Extensions for R7000 CP0 Set1 */ m_uint32_t ipl_lo,ipl_hi,int_ctl; m_uint32_t derraddr0,derraddr1; }mips_cp0_t; /* FPU Coprocessor (CP1) definition */ typedef struct { m_uint64_t reg[MIPS64_CP1_REG_NR]; }mips_cp1_t; /* MIPS CPU definition */ struct cpu_mips { /* MTS32/MTS64 caches */ union { mts32_entry_t *mts32_cache; mts64_entry_t *mts64_cache; }mts_u; /* Virtual version of CP0 Compare Register */ m_uint32_t cp0_virt_cnt_reg,cp0_virt_cmp_reg; /* General Purpose Registers, Pointer Counter, LO/HI, IRQ */ m_uint32_t irq_pending,irq_cause,ll_bit; m_uint64_t pc,gpr[MIPS64_GPR_NR]; m_uint64_t lo,hi,ret_pc; /* Code page translation cache */ mips64_jit_tcb_t **exec_blk_map; /* Virtual address to physical page translation */ fastcall int (*translate)(cpu_mips_t *cpu,m_uint64_t vaddr, m_uint32_t *phys_page); /* Memory access functions */ mips_memop_fn mem_op_fn[MIPS_MEMOP_MAX]; /* Memory lookup function (to load ELF image,...) */ void *(*mem_op_lookup)(cpu_mips_t *cpu,m_uint64_t vaddr); /* System coprocessor (CP0) */ mips_cp0_t cp0; /* FPU (CP1) */ mips_cp1_t fpu; /* Address bus mask for physical addresses */ m_uint64_t addr_bus_mask; /* IRQ counters and cause */ m_uint64_t irq_count,timer_irq_count,irq_fp_count; pthread_mutex_t irq_lock; /* Current and free lists of translated code blocks */ mips64_jit_tcb_t *tcb_list,*tcb_last,*tcb_free_list; /* Executable page area */ void *exec_page_area; size_t exec_page_area_size; size_t exec_page_count,exec_page_alloc; insn_exec_page_t *exec_page_free_list; insn_exec_page_t *exec_page_array; /* Idle PC value */ volatile m_uint64_t idle_pc; /* Timer IRQs */ volatile u_int timer_irq_pending; u_int timer_irq_freq; u_int timer_irq_check_itv; u_int timer_drift; /* IRQ disable flag */ volatile u_int irq_disable; /* IRQ idling preemption */ u_int irq_idle_preempt[8]; /* Generic CPU instance pointer */ cpu_gen_t *gen; /* VM instance */ vm_instance_t *vm; /* non-JIT mode instruction counter */ m_uint64_t insn_exec_count; /* MTS map/unmap/rebuild operations */ void (*mts_map)(cpu_mips_t *cpu,m_uint64_t vaddr, m_uint64_t paddr,m_uint32_t len, int cache_access,int tlb_index); void (*mts_unmap)(cpu_mips_t *cpu,m_uint64_t vaddr,m_uint32_t len, m_uint32_t val,int tlb_index); void (*mts_shutdown)(cpu_mips_t *cpu); /* MTS cache statistics */ m_uint64_t mts_misses,mts_lookups; /* JIT flush method */ u_int jit_flush_method; /* Number of compiled pages */ u_int compiled_pages; /* Fast memory operations use */ u_int fast_memop; /* Direct block jump */ u_int exec_blk_direct_jump; /* Address mode (32 or 64 bits) */ u_int addr_mode; /* Current exec page (non-JIT) info */ m_uint64_t njm_exec_page; mips_insn_t *njm_exec_ptr; /* Performance counter (number of instructions executed by CPU) */ m_uint32_t perf_counter; /* Breakpoints */ m_uint64_t breakpoints[MIPS64_MAX_BREAKPOINTS]; u_int breakpoints_enabled; /* Symtrace */ int sym_trace; rbtree_tree *sym_tree; }; #define MIPS64_IRQ_LOCK(cpu) pthread_mutex_lock(&(cpu)->irq_lock) #define MIPS64_IRQ_UNLOCK(cpu) pthread_mutex_unlock(&(cpu)->irq_lock) /* Register names */ extern char *mips64_gpr_reg_names[]; /* Get cacheability info */ int mips64_cca_cached(m_uint8_t val); /* Reset a MIPS64 CPU */ int mips64_reset(cpu_mips_t *cpu); /* Initialize a MIPS64 processor */ int mips64_init(cpu_mips_t *cpu); /* Delete a MIPS64 processor */ void mips64_delete(cpu_mips_t *cpu); /* Set the CPU PRID register */ void mips64_set_prid(cpu_mips_t *cpu,m_uint32_t prid); /* Set idle PC value */ void mips64_set_idle_pc(cpu_gen_t *cpu,m_uint64_t addr); /* Timer IRQ */ void *mips64_timer_irq_run(cpu_mips_t *cpu); /* Determine an "idling" PC */ int mips64_get_idling_pc(cpu_gen_t *cpu); /* Set an IRQ (VM IRQ standard routing) */ void mips64_vm_set_irq(vm_instance_t *vm,u_int irq); /* Clear an IRQ (VM IRQ standard routing) */ void mips64_vm_clear_irq(vm_instance_t *vm,u_int irq); /* Update the IRQ flag */ void mips64_update_irq_flag(cpu_mips_t *cpu); /* Generate an exception */ void mips64_trigger_exception(cpu_mips_t *cpu,u_int exc_code,int bd_slot); /* * Increment count register and trigger the timer IRQ if value in compare * register is the same. */ fastcall void mips64_exec_inc_cp0_cnt(cpu_mips_t *cpu); /* Trigger the Timer IRQ */ fastcall void mips64_trigger_timer_irq(cpu_mips_t *cpu); /* Execute ERET instruction */ fastcall void mips64_exec_eret(cpu_mips_t *cpu); /* Execute SYSCALL instruction */ fastcall void mips64_exec_syscall(cpu_mips_t *cpu); /* Execute BREAK instruction */ fastcall void mips64_exec_break(cpu_mips_t *cpu,u_int code); /* Trigger a Trap Exception */ fastcall void mips64_trigger_trap_exception(cpu_mips_t *cpu); /* Trigger IRQs */ fastcall void mips64_trigger_irq(cpu_mips_t *cpu); /* Set an IRQ */ void mips64_set_irq(cpu_mips_t *cpu,m_uint8_t irq); /* Clear an IRQ */ void mips64_clear_irq(cpu_mips_t *cpu,m_uint8_t irq); /* DMFC1 */ fastcall void mips64_exec_dmfc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg); /* DMTC1 */ fastcall void mips64_exec_dmtc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg); /* MFC1 */ fastcall void mips64_exec_mfc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg); /* MTC1 */ fastcall void mips64_exec_mtc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg); /* Virtual breakpoint */ fastcall void mips64_run_breakpoint(cpu_mips_t *cpu); /* Add a virtual breakpoint */ int mips64_add_breakpoint(cpu_gen_t *cpu,m_uint64_t pc); /* Remove a virtual breakpoint */ void mips64_remove_breakpoint(cpu_gen_t *cpu,m_uint64_t pc); /* Debugging for register-jump to address 0 */ fastcall void mips64_debug_jr0(cpu_mips_t *cpu); /* Set a register */ void mips64_reg_set(cpu_gen_t *cpu,u_int reg,m_uint64_t val); /* Dump registers of a MIPS64 processor */ void mips64_dump_regs(cpu_gen_t *cpu); /* Dump a memory block */ void mips64_dump_memory(cpu_mips_t *cpu,m_uint64_t vaddr,u_int count); /* Dump the stack */ void mips64_dump_stack(cpu_mips_t *cpu,u_int count); /* Save the CPU state into a file */ int mips64_save_state(cpu_mips_t *cpu,char *filename); /* Load a raw image into the simulated memory */ int mips64_load_raw_image(cpu_mips_t *cpu,char *filename,m_uint64_t vaddr); /* Load an ELF image into the simulated memory */ int mips64_load_elf_image(cpu_mips_t *cpu,char *filename,int skip_load, m_uint32_t *entry_point); /* Symbol lookup */ struct symbol *mips64_sym_lookup(cpu_mips_t *cpu,m_uint64_t addr); /* Insert a new symbol */ struct symbol *mips64_sym_insert(cpu_mips_t *cpu,char *name,m_uint64_t addr); /* Create the symbol tree */ int mips64_sym_create_tree(cpu_mips_t *cpu); /* Load a symbol file */ int mips64_sym_load_file(cpu_mips_t *cpu,char *filename); #endif