📄 mips_mts.c
字号:
/* * Cisco router simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) * * Template code for MTS. */#define MTS_ENTRY MTS_PROTO(entry_t)#define MTS_CHUNK MTS_PROTO(chunk_t)/* Forward declarations */static forced_inline void *MTS_PROTO(access)(cpu_mips_t *cpu,m_uint64_t vaddr, u_int op_code,u_int op_size, u_int op_type,m_uint64_t *data, u_int *exc);static fastcall int MTS_PROTO(translate)(cpu_mips_t *cpu,m_uint64_t vaddr, m_uint32_t *phys_page);/* Initialize the MTS subsystem for the specified CPU */int MTS_PROTO(init)(cpu_mips_t *cpu){ size_t len; /* Initialize the cache entries to 0 (empty) */ len = MTS_PROTO_UP(HASH_SIZE) * sizeof(MTS_ENTRY *); if (!(cpu->mts_cache = malloc(len))) return(-1); memset(cpu->mts_cache,0,len); cpu->mts_lookups = 0; cpu->mts_misses = 0; /* Reset the TLB reverse map (used for selective invalidations) */ memset(cpu->mts_rmap,0,(cpu->cp0.tlb_entries * sizeof(MTS_ENTRY *))); return(0);}/* Free memory used by MTS */void MTS_PROTO(shutdown)(cpu_mips_t *cpu){ MTS_CHUNK *chunk,*next; int i; /* Reset the reverse map */ for(i=0;i<cpu->cp0.tlb_entries;i++) cpu->mts_rmap[i] = NULL; /* Free the cache itself */ free(cpu->mts_cache); cpu->mts_cache = NULL; /* Free the chunks */ for(chunk=cpu->mts_chunk_list;chunk;chunk=next) { next = chunk->next; free(chunk); } for(chunk=cpu->mts_chunk_free_list;chunk;chunk=next) { next = chunk->next; free(chunk); } cpu->mts_chunk_list = cpu->mts_chunk_free_list = NULL; cpu->mts_entry_free_list = NULL;}/* Show MTS detailed information (debugging only!) */void MTS_PROTO(show_stats)(cpu_mips_t *cpu){ MTS_CHUNK *chunk;#if DEBUG_MTS_MAP_VIRT MTS_ENTRY *entry; u_int i;#endif u_int count; printf("\nCPU%u: MTS%d statistics:\n",cpu->id,MTS_ADDR_SIZE); printf(" Total lookups: %llu, misses: %llu, efficiency: %g%%\n", cpu->mts_lookups, cpu->mts_misses, 100 - ((double)(cpu->mts_misses*100)/ (double)cpu->mts_lookups));#if DEBUG_MTS_MAP_VIRT /* Valid hash entries */ for(count=0,i=0;i<MTS_PROTO_UP(HASH_SIZE);i++) { if ((entry = cpu->mts_cache[i]) != NULL) { printf(" %4u: entry=%p, start=0x%16.16llx, " "len=0x%8.8x, action=0x%8.8llx\n", i,entry,(m_uint64_t)entry->start,entry->mask, (m_uint64_t)entry->action); count++; } } printf(" %u/%u valid hash entries.\n",count,MTS_PROTO_UP(HASH_SIZE));#endif /* Number of chunks */ for(count=0,chunk=cpu->mts_chunk_list;chunk;chunk=chunk->next) count++; printf(" Number of chunks: %u\n",count);#if DEBUG_MTS_MAP_VIRT /* Reverse map */ for(i=0;i<MIPS64_TLB_MAX_ENTRIES;i++) { for(count=0,entry=cpu->mts_rmap[i];entry;entry=entry->next) count++; if (count > 0) printf(" tlb_rmap[%u]: %u entries\n",i,count); }#endif}/* Allocate a new chunk */static int MTS_PROTO(alloc_chunk)(cpu_mips_t *cpu){ MTS_CHUNK *chunk; /* Try the free list first, then use standard allocation procedure */ if ((chunk = cpu->mts_chunk_free_list) != NULL) { cpu->mts_chunk_free_list = chunk->next; } else { if (!(chunk = malloc(sizeof(*chunk)))) return(-1); } chunk->count = 0; chunk->next = cpu->mts_chunk_list; cpu->mts_chunk_list = chunk; return(0);}/* Allocate a new entry */static MTS_ENTRY *MTS_PROTO(alloc_entry)(cpu_mips_t *cpu){ MTS_CHUNK *chunk = cpu->mts_chunk_list; MTS_ENTRY *entry; /* First, try to allocate the entry from the free list */ if ((entry = cpu->mts_entry_free_list) != NULL) { cpu->mts_entry_free_list = ((MTS_ENTRY *)cpu->mts_entry_free_list)->next; return entry; } /* A new chunk is required */ if (!chunk || (chunk->count == MTS_PROTO_UP(CHUNK_SIZE))) { if (MTS_PROTO(alloc_chunk)(cpu) == -1) return NULL; chunk = cpu->mts_chunk_list; } entry = &chunk->entry[chunk->count]; chunk->count++; return entry;}/* Invalidate the complete MTS cache */void MTS_PROTO(invalidate_cache)(cpu_mips_t *cpu){ MTS_CHUNK *chunk; size_t len; u_int i; len = MTS_PROTO_UP(HASH_SIZE) * sizeof(MTS_ENTRY *); memset(cpu->mts_cache,0,len); /* Move all chunks to the free list */ while((chunk = cpu->mts_chunk_list) != NULL) { cpu->mts_chunk_list = chunk->next; chunk->next = cpu->mts_chunk_free_list; cpu->mts_chunk_free_list = chunk; } /* Reset the free list of entries (since they are located in chunks) */ cpu->mts_entry_free_list = NULL; /* Reset the reverse map */ for(i=0;i<cpu->cp0.tlb_entries;i++) cpu->mts_rmap[i] = NULL;}/* Invalidate partially the MTS cache, given a TLB entry index */void MTS_PROTO(invalidate_tlb_entry)(cpu_mips_t *cpu,u_int tlb_index){ MTS_ENTRY *entry; for(entry=cpu->mts_rmap[tlb_index];entry;entry=entry->next) { *(entry->pself) = NULL; if (!entry->next) { entry->next = cpu->mts_entry_free_list; break; } } cpu->mts_entry_free_list = cpu->mts_rmap[tlb_index]; cpu->mts_rmap[tlb_index] = NULL;} /* * MTS mapping. * * It is NOT inlined since it triggers a GCC bug on my config (x86, GCC 3.3.5) */static no_inline int MTS_PROTO(map)(cpu_mips_t *cpu,m_uint64_t vaddr, mts_map_t *map,MTS_ENTRY *entry){ struct vdevice *dev; m_uint64_t lk_addr; m_uint32_t poffset; lk_addr = map->paddr + (vaddr - map->vaddr); if (!(dev = dev_lookup(cpu->vm,lk_addr,map->cached))) return(FALSE); if (map->paddr > dev->phys_addr) { poffset = map->paddr - dev->phys_addr; entry->start = map->vaddr; entry->phys_page = map->paddr >> MIPS_MIN_PAGE_SHIFT; entry->mask = ~((m_min(map->len,dev->phys_len - poffset)) - 1); entry->action = poffset; } else { poffset = dev->phys_addr - map->paddr; entry->start = map->vaddr + poffset; entry->phys_page = (map->paddr + poffset) >> MIPS_MIN_PAGE_SHIFT; entry->mask = ~((m_min(map->len - poffset,dev->phys_len)) - 1); entry->action = 0; } if (!dev->host_addr || (dev->flags & VDEVICE_FLAG_NO_MTS_MMAP)) entry->action += (dev->id << MTS_DEVID_SHIFT) | MTS_DEV_MASK; else entry->action += dev->host_addr; return(TRUE);}/* MTS lookup */static void *MTS_PROTO(lookup)(cpu_mips_t *cpu,m_uint64_t vaddr){ m_uint64_t data; u_int exc; return(MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_LOOKUP,4,MTS_READ, &data,&exc));}/* === MIPS Memory Operations ============================================= *//* LB: Load Byte */fastcall u_int MTS_PROTO(lb)(cpu_mips_t *cpu,m_uint64_t vaddr,u_int reg){ m_uint64_t data; void *haddr; u_int exc; haddr = MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_LB,1,MTS_READ,&data,&exc); if (likely(haddr != NULL)) data = *(m_uint8_t *)haddr; if (likely(!exc)) cpu->gpr[reg] = sign_extend(data,8); return(exc);}/* LBU: Load Byte Unsigned */fastcall u_int MTS_PROTO(lbu)(cpu_mips_t *cpu,m_uint64_t vaddr,u_int reg){ m_uint64_t data; void *haddr; u_int exc; haddr = MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_LBU,1,MTS_READ,&data,&exc); if (likely(haddr != NULL)) data = *(m_uint8_t *)haddr; if (likely(!exc)) cpu->gpr[reg] = data & 0xff; return(exc);}/* LH: Load Half-Word */fastcall u_int MTS_PROTO(lh)(cpu_mips_t *cpu,m_uint64_t vaddr,u_int reg){ m_uint64_t data; void *haddr; u_int exc; haddr = MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_LH,2,MTS_READ,&data,&exc); if (likely(haddr != NULL)) data = vmtoh16(*(m_uint16_t *)haddr); if (likely(!exc)) cpu->gpr[reg] = sign_extend(data,16); return(exc);}/* LHU: Load Half-Word Unsigned */fastcall u_int MTS_PROTO(lhu)(cpu_mips_t *cpu,m_uint64_t vaddr,u_int reg){ m_uint64_t data; void *haddr; u_int exc; haddr = MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_LHU,2,MTS_READ,&data,&exc); if (likely(haddr != NULL)) data = vmtoh16(*(m_uint16_t *)haddr); if (likely(!exc)) cpu->gpr[reg] = data & 0xffff; return(exc);}/* LW: Load Word */fastcall u_int MTS_PROTO(lw)(cpu_mips_t *cpu,m_uint64_t vaddr,u_int reg){ m_uint64_t data; void *haddr; u_int exc; haddr = MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_LW,4,MTS_READ,&data,&exc); if (likely(haddr != NULL)) data = vmtoh32(*(m_uint32_t *)haddr); if (likely(!exc)) cpu->gpr[reg] = sign_extend(data,32); return(exc);}/* LWU: Load Word Unsigned */fastcall u_int MTS_PROTO(lwu)(cpu_mips_t *cpu,m_uint64_t vaddr,u_int reg){ m_uint64_t data; void *haddr; u_int exc; haddr = MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_LWU,4,MTS_READ,&data,&exc); if (likely(haddr != NULL)) data = vmtoh32(*(m_uint32_t *)haddr); if (likely(!exc)) cpu->gpr[reg] = data & 0xffffffff; return(exc);}/* LD: Load Double-Word */fastcall u_int MTS_PROTO(ld)(cpu_mips_t *cpu,m_uint64_t vaddr,u_int reg){ m_uint64_t data; void *haddr; u_int exc; haddr = MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_LD,8,MTS_READ,&data,&exc); if (likely(haddr != NULL)) data = vmtoh64(*(m_uint64_t *)haddr); if (likely(!exc)) cpu->gpr[reg] = data; return(exc);}/* SB: Store Byte */fastcall u_int MTS_PROTO(sb)(cpu_mips_t *cpu,m_uint64_t vaddr,u_int reg){ m_uint64_t data; void *haddr; u_int exc; data = cpu->gpr[reg] & 0xff; haddr = MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_SB,1,MTS_WRITE,&data,&exc); if (likely(haddr != NULL)) *(m_uint8_t *)haddr = data; return(exc);}/* SH: Store Half-Word */fastcall u_int MTS_PROTO(sh)(cpu_mips_t *cpu,m_uint64_t vaddr,u_int reg){ m_uint64_t data; void *haddr; u_int exc; data = cpu->gpr[reg] & 0xffff; haddr = MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_SH,2,MTS_WRITE,&data,&exc); if (likely(haddr != NULL)) *(m_uint16_t *)haddr = htovm16(data); return(exc);}/* SW: Store Word */fastcall u_int MTS_PROTO(sw)(cpu_mips_t *cpu,m_uint64_t vaddr,u_int reg){ m_uint64_t data; void *haddr; u_int exc; data = cpu->gpr[reg] & 0xffffffff; haddr = MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_SW,4,MTS_WRITE,&data,&exc); if (likely(haddr != NULL)) *(m_uint32_t *)haddr = htovm32(data); return(exc);}/* SD: Store Double-Word */fastcall u_int MTS_PROTO(sd)(cpu_mips_t *cpu,m_uint64_t vaddr,u_int reg){ m_uint64_t data; void *haddr; u_int exc; data = cpu->gpr[reg]; haddr = MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_SD,8,MTS_WRITE,&data,&exc); if (likely(haddr != NULL)) *(m_uint64_t *)haddr = htovm64(data); return(exc);}/* LDC1: Load Double-Word To Coprocessor 1 */fastcall u_int MTS_PROTO(ldc1)(cpu_mips_t *cpu,m_uint64_t vaddr,u_int reg){ m_uint64_t data; void *haddr; u_int exc; haddr = MTS_PROTO(access)(cpu,vaddr,MIPS_MEMOP_LDC1,8,MTS_READ,&data,&exc); if (likely(haddr != NULL)) data = vmtoh64(*(m_uint64_t *)haddr); if (likely(!exc)) cpu->fpu.reg[reg] = data; return(exc);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -