?? bus.c
字號:
/* * ---------------------------------------------------------- * Add a mapping to the linked list of mappings of device * ----------------------------------------------------------- */void Mem_AreaAddMapping(BusDevice *bdev,uint32_t base,uint32_t mapsize,uint32_t flags) { MemMapping *mapping=malloc(sizeof(MemMapping)); if(!mapping) { fprintf(stderr,"Out of memory allocating MemMaping\n"); exit(837); } mapping->next=bdev->first_mapping; bdev->first_mapping=mapping; mapping->base=base; mapping->mapsize = mapsize; mapping->flags = flags & bdev->hw_flags; bdev->Map(bdev->owner,base,mapping->mapsize,flags); /* Check for traces ??? */ /* Need to Invalidate Tlb because we cache Host Virtual Addresses */ if(InvalidateProc) { InvalidateProc(); }}/* * --------------------------------------------------------------------------------- * Map a range * Forwards all decoded bits (devsize-1) to the device * This function may only called by device emulators in response to * a map request. * --------------------------------------------------------------------------------- */ voidMem_MapRange(uint32_t base,uint8_t *start_mem,uint32_t devsize,uint32_t mapsize,uint32_t flags) { uint32_t count=0; uint32_t addr; uint32_t pos=base & (devsize-1); uint8_t *mem = start_mem+pos; for(addr=base; 1 ;) { if((mapsize>=MEM_MAP_BLOCKSIZE) && !(addr & MEM_MAP_BLOCKMASK)) { Mem_MapBlock(addr,mem,flags); mem+=MEM_MAP_BLOCKSIZE; pos+=MEM_MAP_BLOCKSIZE; count+=MEM_MAP_BLOCKSIZE; addr+=MEM_MAP_BLOCKSIZE; mapsize-=MEM_MAP_BLOCKSIZE; } else if((mapsize >= twoLevelMMap.scnd_lvl_blocksize) && !(addr & twoLevelMMap.scnd_lvl_blockmask)) { Mem_Map2LvlBlock(addr,mem,flags); mem+=twoLevelMMap.scnd_lvl_blocksize; pos+=twoLevelMMap.scnd_lvl_blocksize; count+=twoLevelMMap.scnd_lvl_blocksize; addr+=twoLevelMMap.scnd_lvl_blocksize; mapsize-=twoLevelMMap.scnd_lvl_blocksize; } else { if(mapsize) { fprintf(stderr,"Bus: Can not map completely, rest: %08x, addr %08x" ", twoLevelMMap.scnd_lvl_blockmask %08x blocksize %08x\n",mapsize,addr,twoLevelMMap.scnd_lvl_blockmask,twoLevelMMap.scnd_lvl_blocksize); exit(3789); } return; } if(pos>=devsize) { pos=0; mem=start_mem; } /* Special case 4GB */ if(!count) { return; } }}static voidMem_SplitLargePage(uint32_t pgaddr) { uint32_t addr = pgaddr & ~MEM_MAP_BLOCKMASK; int index=(addr>>MEM_MAP_SHIFT); uint8_t *rhva = mem_map_read[index]; uint8_t *whva = mem_map_write[index]; uint8_t *hva = 0; uint32_t slvl_size = twoLevelMMap.scnd_lvl_blocksize; int flags; int count; flags = 0; if(!rhva && ! whva) { /* nothing to split */ return; } if((rhva != whva) && (rhva !=0) && (whva !=0)) { fprintf(stderr,"Can not split page with different read/write addresses\n"); return; } if(rhva) { flags |= MEM_FLAG_READABLE; hva = rhva; } if(whva) { flags |= MEM_FLAG_WRITABLE; hva = whva; } if(!Mem_UnMapBlock(addr)) { fprintf(stderr,"Failed to unmap block at %08x\n",addr); } for(count=0;count < MEM_MAP_BLOCKSIZE;count+=slvl_size) { Mem_Map2LvlBlock(addr+count,hva+count,flags); }}voidMem_TracePage(uint32_t pgaddr) { int index; uint8_t *hva; uint8_t **slvl_map; Mem_SplitLargePage(pgaddr); index = pgaddr >> twoLevelMMap.frst_lvl_shift; if(unlikely(!(slvl_map = twoLevelMMap.flvlmap_write[index]))) { fprintf(stderr,"no slvl map for addr %08x\n",pgaddr); // jk return; } index = (pgaddr & twoLevelMMap.scnd_lvl_mask) >> twoLevelMMap.scnd_lvl_shift; hva = slvl_map[index]; if(hva && !((unsigned long)hva & PG_TRACED)) { slvl_map[index] += PG_TRACED; } else { fprintf(stderr,"Page is already traced %08x hva %p %08x\n",pgaddr,hva,!((unsigned long)hva & PG_TRACED)); } if(InvalidateProc) { InvalidateProc(); }}voidMem_UntracePage(uint32_t pgaddr) { int index; uint8_t *hva; uint8_t **slvl_map; index = pgaddr >> twoLevelMMap.frst_lvl_shift; if(unlikely(!(slvl_map = twoLevelMMap.flvlmap_write[index]))) { fprintf(stderr,"no slvl map for addr %08x\n",pgaddr); // jk return; } index = (pgaddr & twoLevelMMap.scnd_lvl_mask) >> twoLevelMMap.scnd_lvl_shift; hva = slvl_map[index]; if(hva && ((unsigned long)hva & PG_TRACED)) { slvl_map[index] -= PG_TRACED; //fprintf(stderr,"Untraced page at %08x, hva %p\n",pgaddr,slvl_map[index]); } else { fprintf(stderr,"Page was not traced %08x, hva %p\n",pgaddr,slvl_map[index]); } if(InvalidateProc) { InvalidateProc(); }}void Mem_TraceRegion(uint32_t start,uint32_t length) { uint32_t i; int slvl_size = twoLevelMMap.scnd_lvl_blocksize; fprintf(stderr,"Trace region from %08x length %08x\n",start,length); // jk for(i=0;i<length;i+=slvl_size) { Mem_TracePage(start+i); } }void Mem_UntraceRegion(uint32_t start,uint32_t length) { uint32_t i; int slvl_size = twoLevelMMap.scnd_lvl_blocksize; fprintf(stderr,"Untrace region from %08x length %08x\n",start,length); // jk for(i=0;i<length;i+=slvl_size) { Mem_UntracePage(start+i); } }/* * -------------------------------------------------------------------- * Take existing mapping and split up a range from large pages * into small pages. * address may not wrap and size may not be 4G * -------------------------------------------------------------------- */voidMem_SplitLargePages(uint32_t start,uint32_t size) { uint32_t addr = start & ~MEM_MAP_BLOCKMASK; do { Mem_SplitLargePage(addr); addr += MEM_MAP_BLOCKSIZE; } while((addr-start) < size);}/* * --------------------------------------------------------------------------------- * UnMap a range * This function may only called by device emulators in response to * an unmap request. * --------------------------------------------------------------------------------- */ voidMem_UnMapRange(uint32_t base,uint32_t mapsize) { uint32_t addr; uint32_t count=0; for(addr=base;1;) { if((mapsize>=MEM_MAP_BLOCKSIZE) && !(addr & MEM_MAP_BLOCKMASK)) { if(Mem_UnMapBlock(addr) > 0) { count+=MEM_MAP_BLOCKSIZE; addr+=MEM_MAP_BLOCKSIZE; mapsize-=MEM_MAP_BLOCKSIZE; } else { Mem_UnMap2LvlBlock(addr); count+=twoLevelMMap.scnd_lvl_blocksize; addr+=twoLevelMMap.scnd_lvl_blocksize; mapsize-=twoLevelMMap.scnd_lvl_blocksize; } } else if((mapsize >= twoLevelMMap.scnd_lvl_blocksize) && !(addr & twoLevelMMap.scnd_lvl_blockmask)) { Mem_UnMap2LvlBlock(addr); count+=twoLevelMMap.scnd_lvl_blocksize; addr+=twoLevelMMap.scnd_lvl_blocksize; mapsize-=twoLevelMMap.scnd_lvl_blocksize; } else { return; } /* Special case 4GB */ if(!count) { return; } }}void Mem_AreaDeleteMappings(BusDevice *bdev) { while(bdev->first_mapping) { MemMapping *mapping=bdev->first_mapping; bdev->UnMap(bdev->owner,mapping->base,mapping->mapsize); bdev->first_mapping=mapping->next; free(mapping); } /* Need to Invalidate Tlb because we cache Host Virtual Addresses */ if(InvalidateProc) { InvalidateProc(); }}/* * ---------------------------------------------------------------------- * Update Mappings is called by a chip emulator whenever it changes * its memory map by itself * ---------------------------------------------------------------------- */void Mem_AreaUpdateMappings(BusDevice *bdev) { MemMapping *cursor; /* First do a total Cleanup then map again */ for(cursor=bdev->first_mapping; cursor; cursor=cursor->next) { bdev->UnMap(bdev->owner,cursor->base,cursor->mapsize); } for(cursor=bdev->first_mapping; cursor; cursor=cursor->next) { bdev->Map(bdev->owner,cursor->base,cursor->mapsize,cursor->flags); } /* Need to Invalidate Tlb because we cache Host Virtual Addresses */ if(InvalidateProc) { InvalidateProc(); }}/* * ------------------------------- * IO-Handling * ------------------------------- */#define IOH_HASH(addr) ((addr) + ((addr)>>18))&IOH_HASH_MASKIOHandler *IOH_Find(uint32_t address) { IOHandler *cursor; IOHandler **slvl_map; uint32_t hash=IOH_HASH(address); uint32_t index; for(cursor=iohandlerHash[hash];cursor;cursor=cursor->next) { if(cursor->cpu_addr==address) { return cursor; } } index=(address>>IOH_MAP_SHIFT); if(iohandlerMap[index]) { return (iohandlerMap[index]); } index = (address>>IOH_FLVL_SHIFT); if((slvl_map = iohandlerFlvlMap[index])) { index = (address & IOH_SLVL_MASK) >> IOH_SLVL_SHIFT; return slvl_map[index]; } return NULL;}IOHandler *IOH_HashFind(uint32_t address) { IOHandler *cursor; uint32_t hash=IOH_HASH(address); for(cursor=iohandlerHash[hash];cursor;cursor=cursor->next) { if(cursor->cpu_addr==address) { return cursor; } } return NULL;}static voidIOH_New(uint32_t cpu_addr,IOReadProc *readproc,IOWriteProc *writeproc,void *clientData,int len,uint32_t flags) { uint32_t hash; IOHandler *h; int swap_endian; int byteorder; if(flags & IOH_FLG_BIG_ENDIAN) { byteorder = en_BIG_ENDIAN; } else if(flags & IOH_FLG_HOST_ENDIAN) { byteorder = HOST_BYTEORDER; } else { byteorder = en_LITTLE_ENDIAN; } if(byteorder != HOST_BYTEORDER) { swap_endian=1; } else { swap_endian=0; } if(IOH_HashFind(cpu_addr)) { fprintf(stderr,"Bug, more than one IO-Handler for address %08x\n",cpu_addr); exit(4324); } h=malloc(sizeof(IOHandler)); if(!h) { perror("Out of memory allocating IOHandler\n"); exit(97); } memset(h,0,sizeof(IOHandler)); h->cpu_addr=cpu_addr; h->clientData=clientData; h->readproc=readproc; h->writeproc=writeproc; hash=IOH_HASH(cpu_addr); h->next=iohandlerHash[hash]; h->swap_endian = swap_endian; h->flags = flags; h->len = len; iohandlerHash[hash]=h;}voidIOH_New8f(uint32_t cpu_addr,IOReadProc *readproc,IOWriteProc *writeproc,void *clientData,uint32_t flags) { IOH_New(cpu_addr,readproc,writeproc,clientData,1,flags);}voidIOH_New16f(uint32_t cpu_addr,IOReadProc *readproc,IOWriteProc *writeproc,void *clientData,uint32_t flags) { if(flags & (IOH_FLG_PA_CBSE)) { int i; for(i=0;i<2;i++) { IOH_New(cpu_addr+i,readproc,writeproc,clientData,2,flags); } } else { IOH_New(cpu_addr,readproc,writeproc,clientData,2,flags); }}voidIOH_New32f(uint32_t cpu_addr,IOReadProc *readproc,IOWriteProc *writeproc,void *clientData,uint32_t flags) { /* Partial access: call base */ if(flags & IOH_FLG_PA_CBSE) { int i; for(i=0;i<4;i++) { IOH_New(cpu_addr+i,readproc,writeproc,clientData,4,flags); } } else { IOH_New(cpu_addr,readproc,writeproc,clientData,4,flags); }}/* * ------------------------------------------------------------- * Allocate an iohandler and initialize the structure * ------------------------------------------------------------- */static inline IOHandler *allocate_iohandler(uint32_t addr,IOReadProc *readproc,IOWriteProc *writeproc,int swap_endian,void *clientData) { IOHandler *h; h=malloc(sizeof(IOHandler)); if(!h) { perror("Out of memory allocating IOHandler\n"); exit(97); } memset(h,0,sizeof(IOHandler)); h->cpu_addr=addr; h->clientData=clientData; h->readproc=readproc; h->writeproc=writeproc; h->next=NULL; h->swap_endian = swap_endian; return h;}static inline void IOH_MapBlock(uint32_t addr, IOHandler *h) { uint32_t index=addr>>IOH_MAP_SHIFT; if(iohandlerMap[index]) { fprintf(stderr,"IO-Region %08x already allocated !\n",addr); exit(5342); } iohandlerMap[index]=h;}static inline voidIOH_Map2LvlBlock(uint32_t addr,IOHandler *h) { IOHandler **sl_map; int fl_index=addr>>IOH_FLVL_SHIFT;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -