⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mips64.c

📁 思科路由器仿真器,用来仿7200系列得,可以在电脑上模拟路由器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Cisco router simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) * * XXX TODO: proper context save/restore for CPUs. */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/mman.h>#include <fcntl.h>#include <assert.h>#include "rbtree.h"#include "cpu.h"#include "mips64_mem.h"#include "mips64_exec.h"#include "mips64_jit.h"#include "dynamips.h"#include "memory.h"#include "device.h"/* MIPS general purpose registers names */char *mips64_gpr_reg_names[MIPS64_GPR_NR] = {   "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3",   "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",   "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",   "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra",};/* Cacheability and Coherency Attribute */static int cca_cache_status[8] = {   1, 1, 0, 1, 0, 1, 0, 0,};/* Get register index given its name */int mips64_get_reg_index(char *name){   int i;   for(i=0;i<MIPS64_GPR_NR;i++)      if (!strcmp(mips64_gpr_reg_names[i],name))         return(i);   return(-1);}/* Get cacheability info */int mips64_cca_cached(m_uint8_t val){   return(cca_cache_status[val & 0x03]);}/* Reset a MIPS64 CPU */int mips64_reset(cpu_mips_t *cpu){   cpu->pc = MIPS_ROM_PC;   cpu->gpr[MIPS_GPR_SP] = MIPS_ROM_SP;   cpu->cp0.reg[MIPS_CP0_STATUS] = MIPS_CP0_STATUS_BEV;   cpu->cp0.reg[MIPS_CP0_CAUSE]  = 0;   cpu->cp0.reg[MIPS_CP0_CONFIG] = 0x00c08ff0ULL;   /* Clear the complete TLB */   memset(&cpu->cp0.tlb,0,MIPS64_TLB_MAX_ENTRIES*sizeof(tlb_entry_t));   /* Restart the MTS subsystem */   mips64_set_addr_mode(cpu,32/*64*/);  /* zzz */   cpu->gen->mts_rebuild(cpu->gen);   /* Flush JIT structures */   mips64_jit_flush(cpu,0);   return(0);}/* Initialize a MIPS64 processor */int mips64_init(cpu_mips_t *cpu){   cpu->addr_bus_mask = 0xFFFFFFFFFFFFFFFFULL;   cpu->cp0.reg[MIPS_CP0_PRID] = MIPS_PRID_R4600;   cpu->cp0.tlb_entries = MIPS64_TLB_STD_ENTRIES;   /* Initialize idle timer */   cpu->gen->idle_max = 1500;   cpu->gen->idle_sleep_time = 30000;   /* Timer IRQ parameters (default frequency: 250 Hz <=> 4ms period) */   cpu->timer_irq_check_itv = 1000;   cpu->timer_irq_freq      = 250;   /* Enable fast memory operations */   cpu->fast_memop = TRUE;   /* Enable/Disable direct block jump */   cpu->exec_blk_direct_jump = cpu->vm->exec_blk_direct_jump;   /* Create the IRQ lock (for non-jit architectures) */   pthread_mutex_init(&cpu->irq_lock,NULL);   /* Idle loop mutex and condition */   pthread_mutex_init(&cpu->gen->idle_mutex,NULL);   pthread_cond_init(&cpu->gen->idle_cond,NULL);   /* Set the CPU methods */   cpu->gen->reg_set =  (void *)mips64_reg_set;   cpu->gen->reg_dump = (void *)mips64_dump_regs;   cpu->gen->mmu_dump = (void *)mips64_tlb_dump;   cpu->gen->mmu_raw_dump = (void *)mips64_tlb_raw_dump;   cpu->gen->add_breakpoint = (void *)mips64_add_breakpoint;   cpu->gen->remove_breakpoint = (void *)mips64_remove_breakpoint;   cpu->gen->set_idle_pc = (void *)mips64_set_idle_pc;   cpu->gen->get_idling_pc = (void *)mips64_get_idling_pc;   /* Set the startup parameters */   mips64_reset(cpu);   return(0);}/* Delete a MIPS64 processor */void mips64_delete(cpu_mips_t *cpu){   if (cpu) {      mips64_mem_shutdown(cpu);      mips64_jit_shutdown(cpu);   }}/* Set the CPU PRID register */void mips64_set_prid(cpu_mips_t *cpu,m_uint32_t prid){   cpu->cp0.reg[MIPS_CP0_PRID] = prid;   if ((prid == MIPS_PRID_R7000) || (prid == MIPS_PRID_BCM1250))      cpu->cp0.tlb_entries = MIPS64_TLB_MAX_ENTRIES;}/* Set idle PC value */void mips64_set_idle_pc(cpu_gen_t *cpu,m_uint64_t addr){   CPU_MIPS64(cpu)->idle_pc = addr;}/* Timer IRQ */void *mips64_timer_irq_run(cpu_mips_t *cpu){   pthread_mutex_t umutex = PTHREAD_MUTEX_INITIALIZER;   pthread_cond_t ucond = PTHREAD_COND_INITIALIZER;   struct timespec t_spc;   m_tmcnt_t expire;   u_int interval;   u_int threshold;   interval = 1000000 / cpu->timer_irq_freq;   threshold = cpu->timer_irq_freq * 10;   expire = m_gettime_usec() + interval;   while(cpu->gen->state != CPU_STATE_HALTED) {      pthread_mutex_lock(&umutex);      t_spc.tv_sec = expire / 1000000;      t_spc.tv_nsec = (expire % 1000000) * 1000;      pthread_cond_timedwait(&ucond,&umutex,&t_spc);      pthread_mutex_unlock(&umutex);      if (likely(!cpu->irq_disable) &&           likely(cpu->gen->state == CPU_STATE_RUNNING))       {         cpu->timer_irq_pending++;         if (unlikely(cpu->timer_irq_pending > threshold)) {            cpu->timer_irq_pending = 0;            cpu->timer_drift++;#if 0            printf("Timer IRQ not accurate (%u pending IRQ): "                   "reduce the \"--timer-irq-check-itv\" parameter "                   "(current value: %u)\n",                   cpu->timer_irq_pending,cpu->timer_irq_check_itv);#endif         }      }      expire += interval;   }   return NULL;}#define IDLE_HASH_SIZE  8192/* Idle PC hash item */struct mips64_idle_pc_hash {   m_uint64_t pc;   u_int count;   struct mips64_idle_pc_hash *next;};/* Determine an "idling" PC */int mips64_get_idling_pc(cpu_gen_t *cpu){   cpu_mips_t *mcpu = CPU_MIPS64(cpu);   struct mips64_idle_pc_hash **pc_hash,*p;   struct cpu_idle_pc *res;   u_int h_index,res_count;   m_uint64_t cur_pc;   int i;   cpu->idle_pc_prop_count = 0;   if (mcpu->idle_pc != 0) {      printf("\nYou already use an idle PC, using the calibration would give "             "incorrect results.\n");      return(-1);   }   printf("\nPlease wait while gathering statistics...\n");   pc_hash = calloc(IDLE_HASH_SIZE,sizeof(struct mips64_idle_pc_hash *));   /* Disable IRQ */   mcpu->irq_disable = TRUE;   /* Take 1000 measures, each mesure every 10ms */   for(i=0;i<1000;i++) {      cur_pc = mcpu->pc;      h_index = (cur_pc >> 2) & (IDLE_HASH_SIZE-1);      for(p=pc_hash[h_index];p;p=p->next)         if (p->pc == cur_pc) {            p->count++;            break;         }      if (!p) {         if ((p = malloc(sizeof(*p)))) {            p->pc    = cur_pc;            p->count = 1;            p->next  = pc_hash[h_index];            pc_hash[h_index] = p;         }      }      usleep(10000);   }   /* Select PCs */   for(i=0,res_count=0;i<IDLE_HASH_SIZE;i++) {      for(p=pc_hash[i];p;p=p->next)         if ((p->count >= 20) && (p->count <= 80)) {            res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++];            res->pc    = p->pc;            res->count = p->count;            if (cpu->idle_pc_prop_count >= CPU_IDLE_PC_MAX_RES)               goto done;         }   } done:   /* Set idle PC */   if (cpu->idle_pc_prop_count) {      printf("Done. Suggested idling PC:\n");      for(i=0;i<cpu->idle_pc_prop_count;i++) {         printf("   0x%llx (count=%u)\n",                cpu->idle_pc_prop[i].pc,                cpu->idle_pc_prop[i].count);      }               printf("Restart the emulator with \"--idle-pc=0x%llx\" (for example)\n",             cpu->idle_pc_prop[0].pc);   } else {      printf("Done. No suggestion for idling PC\n");      for(i=0;i<IDLE_HASH_SIZE;i++)         for(p=pc_hash[i];p;p=p->next) {            printf("  0x%16.16llx (%3u)\n",p->pc,p->count);            if (cpu->idle_pc_prop_count < CPU_IDLE_PC_MAX_RES) {               res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++];               res->pc    = p->pc;               res->count = p->count;            }         }             printf("\n");   }   /* Re-enable IRQ */   mcpu->irq_disable = FALSE;   return(0);}/* Set an IRQ (VM IRQ standard routing) */void mips64_vm_set_irq(vm_instance_t *vm,u_int irq){   cpu_mips_t *boot_cpu;   boot_cpu = CPU_MIPS64(vm->boot_cpu);   if (boot_cpu->irq_disable) {      boot_cpu->irq_pending = 0;      return;   }   mips64_set_irq(boot_cpu,irq);   if (boot_cpu->irq_idle_preempt[irq])      cpu_idle_break_wait(vm->boot_cpu);}/* Clear an IRQ (VM IRQ standard routing) */void mips64_vm_clear_irq(vm_instance_t *vm,u_int irq){   cpu_mips_t *boot_cpu;   boot_cpu = CPU_MIPS64(vm->boot_cpu);   mips64_clear_irq(boot_cpu,irq);}/* Update the IRQ flag (inline) */static forced_inline int mips64_update_irq_flag_fast(cpu_mips_t *cpu){   mips_cp0_t *cp0 = &cpu->cp0;   m_uint32_t imask,sreg_mask;   m_uint32_t cause;   cpu->irq_pending = FALSE;   cause = cp0->reg[MIPS_CP0_CAUSE] & ~MIPS_CP0_CAUSE_IMASK;   cp0->reg[MIPS_CP0_CAUSE] = cause | cpu->irq_cause;   sreg_mask = MIPS_CP0_STATUS_IE|MIPS_CP0_STATUS_EXL|MIPS_CP0_STATUS_ERL;   if ((cp0->reg[MIPS_CP0_STATUS] & sreg_mask) == MIPS_CP0_STATUS_IE) {      imask = cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_IMASK;      if (unlikely(cp0->reg[MIPS_CP0_CAUSE] & imask)) {         cpu->irq_pending = TRUE;         return(TRUE);      }   }   return(FALSE);}/* Update the IRQ flag */void mips64_update_irq_flag(cpu_mips_t *cpu){   mips64_update_irq_flag_fast(cpu);}/* Generate an exception */void mips64_trigger_exception(cpu_mips_t *cpu,u_int exc_code,int bd_slot){   mips_cp0_t *cp0 = &cpu->cp0;   m_uint64_t cause,vector;   /* we don't set EPC if EXL is set */   if (!(cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL))   {      cp0->reg[MIPS_CP0_EPC] = cpu->pc;      /* keep IM, set exception code and bd slot */      cause = cp0->reg[MIPS_CP0_CAUSE] & MIPS_CP0_CAUSE_IMASK;      if (bd_slot)         cause |= MIPS_CP0_CAUSE_BD_SLOT;      else         cause &= ~MIPS_CP0_CAUSE_BD_SLOT;      cause |= (exc_code << MIPS_CP0_CAUSE_SHIFT);      cp0->reg[MIPS_CP0_CAUSE] = cause;      /* XXX properly set vector */      vector = 0x180ULL;   }   else   {      /* keep IM and set exception code */      cause = cp0->reg[MIPS_CP0_CAUSE] & MIPS_CP0_CAUSE_IMASK;      cause |= (exc_code << MIPS_CP0_CAUSE_SHIFT);      cp0->reg[MIPS_CP0_CAUSE] = cause;      /* set vector */      vector = 0x180ULL;   }   /* Set EXL bit in status register */   cp0->reg[MIPS_CP0_STATUS] |= MIPS_CP0_STATUS_EXL;   /* Use bootstrap vectors ? */   if (cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_BEV)      cpu->pc = 0xffffffffbfc00200ULL + vector;   else      cpu->pc = 0xffffffff80000000ULL + vector;   /* Clear the pending IRQ flag */   cpu->irq_pending = 0;}/* * 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){   cpu->cp0_virt_cnt_reg++;#if 0 /* TIMER_IRQ */   mips_cp0_t *cp0 = &cpu->cp0;   if (unlikely((cpu->cp0_virt_cnt_reg == cpu->cp0_virt_cmp_reg))) {      cp0->reg[MIPS_CP0_COUNT] = (m_uint32_t)cp0->reg[MIPS_CP0_COMPARE];      mips64_set_irq(cpu,7);      mips64_update_irq_flag_fast(cpu);   }#endif}/* Trigger the Timer IRQ */fastcall void mips64_trigger_timer_irq(cpu_mips_t *cpu){   mips_cp0_t *cp0 = &cpu->cp0;   cpu->timer_irq_count++;   cp0->reg[MIPS_CP0_COUNT] = (m_uint32_t)cp0->reg[MIPS_CP0_COMPARE];   mips64_set_irq(cpu,7);   mips64_update_irq_flag_fast(cpu);}/* Execute ERET instruction */fastcall void mips64_exec_eret(cpu_mips_t *cpu){   mips_cp0_t *cp0 = &cpu->cp0;   if (cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_ERL) {      cp0->reg[MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_ERL;      cpu->pc = cp0->reg[MIPS_CP0_ERR_EPC];   } else {      cp0->reg[MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_EXL;      cpu->pc = cp0->reg[MIPS_CP0_EPC];   }   /* We have to clear the LLbit */   cpu->ll_bit = 0;         /* Update the pending IRQ flag */   mips64_update_irq_flag_fast(cpu);}/* Execute SYSCALL instruction */fastcall void mips64_exec_syscall(cpu_mips_t *cpu){#if DEBUG_SYSCALL   printf("MIPS64: SYSCALL at PC=0x%llx (RA=0x%llx)\n"          "   a0=0x%llx, a1=0x%llx, a2=0x%llx, a3=0x%llx\n",          cpu->pc, cpu->gpr[MIPS_GPR_RA],          cpu->gpr[MIPS_GPR_A0], cpu->gpr[MIPS_GPR_A1],           cpu->gpr[MIPS_GPR_A2], cpu->gpr[MIPS_GPR_A3]);#endif      /* XXX TODO: Branch Delay slot */   mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_SYSCALL,0);}/* Execute BREAK instruction */fastcall void mips64_exec_break(cpu_mips_t *cpu,u_int code){   printf("MIPS64: BREAK instruction (code=%u)\n",code);   mips64_dump_regs(cpu->gen);   /* XXX TODO: Branch Delay slot */   mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_BP,0);}/* Trigger a Trap Exception */fastcall void mips64_trigger_trap_exception(cpu_mips_t *cpu){     /* XXX TODO: Branch Delay slot */   printf("MIPS64: TRAP exception, CPU=%p\n",cpu);   mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_TRAP,0);}/* Trigger IRQs */fastcall void mips64_trigger_irq(cpu_mips_t *cpu){   if (unlikely(cpu->irq_disable)) {      cpu->irq_pending = 0;      return;   }   cpu->irq_count++;   if (mips64_update_irq_flag_fast(cpu))      mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_INTERRUPT,0);   else      cpu->irq_fp_count++;}/* DMFC1 */fastcall void mips64_exec_dmfc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg){   cpu->gpr[gp_reg] = cpu->fpu.reg[cp1_reg];}/* DMTC1 */fastcall void mips64_exec_dmtc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg){   cpu->fpu.reg[cp1_reg] = cpu->gpr[gp_reg];}/* MFC1 */fastcall void mips64_exec_mfc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg){   m_int64_t val;   val = cpu->fpu.reg[cp1_reg] & 0xffffffff;   cpu->gpr[gp_reg] = sign_extend(val,32);}/* MTC1 */fastcall void mips64_exec_mtc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg){   cpu->fpu.reg[cp1_reg] = cpu->gpr[gp_reg] & 0xffffffff;}/* Virtual breakpoint */fastcall void mips64_run_breakpoint(cpu_mips_t *cpu){   cpu_log(cpu->gen,"BREAKPOINT",           "Virtual breakpoint reached at PC=0x%llx\n",cpu->pc);   printf("[[[ Virtual Breakpoint reached at PC=0x%llx RA=0x%llx]]]\n",          cpu->pc,cpu->gpr[MIPS_GPR_RA]);   mips64_dump_regs(cpu->gen);   memlog_dump(cpu->gen);}/* Add a virtual breakpoint */int mips64_add_breakpoint(cpu_gen_t *cpu,m_uint64_t pc){   cpu_mips_t *mcpu = CPU_MIPS64(cpu);   int i;   for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)      if (!mcpu->breakpoints[i])         break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -