cpu_register_io_memory が返す整数値は、io メモリ配列の index に関連付けられたディスクリプタ
int cpu_register_io_memory(int io_index,CPUReadMemoryFunc **mem_read,CPUWriteMemoryFunc **mem_write,void *opaque){int i, subwidth = 0;if (io_index <= 0) {if (io_mem_nb >= IO_MEM_NB_ENTRIES)return -1;io_index = io_mem_nb++;} else {if (io_index >= IO_MEM_NB_ENTRIES)return -1;}for(i = 0;i <>if (!mem_read[i] || !mem_write[i])subwidth = IO_MEM_SUBWIDTH;io_mem_read[io_index][i] = mem_read[i];io_mem_write[io_index][i] = mem_write[i];}io_mem_opaque[io_index] = opaque;return (io_index <<>}io_index を IO_MEM_SHIFT ぶん右シフトしたものが、io_mem* 配列の index になる。CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index){return io_mem_write[io_index >> IO_MEM_SHIFT];}CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index){
return io_mem_read[io_index >> IO_MEM_SHIFT];}io メモリ配列の 0、1、2、4 は、それぞれ RAM、ROM、UNASSIGNED、NOTDIRTY に決め打たれているので、io_mem_nb は 5 からスタート。static void io_mem_init(void){cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);io_mem_nb = 5;#if defined(CONFIG_SOFTMMU)io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,watch_mem_write, NULL);#endif/* alloc dirty bits array */phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);}io メモリ配列は最大 IO_MEM_NB_ENTRIES 個で、最後の要素の index + 1 が io_mem_nb 変数。exec.ccpu-all.h/* io memory support */CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];void *io_mem_opaque[IO_MEM_NB_ENTRIES];static int io_mem_nb;#if defined(CONFIG_SOFTMMU)static int io_mem_watch;#endifsubpage というのは、おそらく、通常のメモリページ以外のページ (io page など) という意味だと思う。/* physical memory access */#define TLB_INVALID_MASK (1 <<>#define IO_MEM_SHIFT 4#define IO_MEM_NB_ENTRIES (1 << (TARGET_PAGE_BITS - IO_MEM_SHIFT))#define IO_MEM_RAM (0 <<>#define IO_MEM_ROM (1 <<>#define IO_MEM_UNASSIGNED (2 <<>#define IO_MEM_NOTDIRTY (4 <<>/* acts like a ROM when read and like a device when written. As anexception, the write memory callback gets the ram offset instead ofthe physical address */#define IO_MEM_ROMD (1)#define IO_MEM_SUBPAGE (2)#define IO_MEM_SUBWIDTH (4)target-arm/cpu.h#if defined(CONFIG_USER_ONLY)#define TARGET_PAGE_BITS 12#else/* The ARM MMU allows 1k pages. *//* ??? Linux doesn't actually use these, and they're deprecated in recentarchitecture revisions. Maybe a configure option to disable them. */#define TARGET_PAGE_BITS 10#endif通常は TARGET_PAGE_BITS が 10 なので IO_MEM_NB_ENTRIES は 64 かな。物理メモリを割り付ける際には、cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); のように、phys_offset を指定して呼び出すが、これが (phys_offset & ~TARGET_PAGE_MASK) != 0 の場合 io memory page と見なされ、start_addr から size までの範囲に io_mem*TARGET_MAGE_MASK はcpu-all.h#define TARGET_PAGE_SIZE (1 <<>#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)TARGET_PAGE_SIZE が 1024 で、TARGET_PAGE_MASK は 0 ~ 9 ビット目までのマスク。実際に page に io_memory を関連付けるのは、subpage_register()。static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,int memory){int idx, eidx;unsigned int i;if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)return -1;idx = SUBPAGE_IDX(start);eidx = SUBPAGE_IDX(end);#if defined(DEBUG_SUBPAGE)printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,mmio, start, end, idx, eidx, memory);#endifmemory >>= IO_MEM_SHIFT;for (; idx <= eidx; idx++) {for (i = 0; i <>if (io_mem_read[memory][i]) {mmio->mem_read[idx][i] = &io_mem_read[memory][i];mmio->opaque[idx][0][i] = io_mem_opaque[memory];}if (io_mem_write[memory][i]) {mmio->mem_write[idx][i] = &io_mem_write[memory][i];mmio->opaque[idx][1][i] = io_mem_opaque[memory];}}}return 0;}
0 件のコメント:
コメントを投稿