2009年1月13日火曜日

io_memory

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.c
/* 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;
#endif
cpu-all.h
/* 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 an
   exception, the write memory callback gets the ram offset instead of
   the 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 recent
   architecture 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);
#endif
    memory >>= 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;
}
subpage というのは、おそらく、通常のメモリページ以外のページ (io page など) という意味だと思う。

0 件のコメント:

コメントを投稿