Index: qemu/cpu-all.h =================================================================== --- qemu.orig/cpu-all.h 2007-09-15 15:34:51.000000000 +0000 +++ qemu/cpu-all.h 2007-09-15 16:05:04.000000000 +0000 @@ -861,6 +861,54 @@ void dump_exec_info(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +/* Bus operations */ +typedef struct qemu_bus qemu_bus; + +typedef void (*qemu_mem_rw_handler)(void *opaque, + target_phys_addr_t addr, + uint8_t *buf, unsigned int len, + int is_write); + +qemu_bus *bus_init(unsigned int bus_bits, qemu_mem_rw_handler handler, + void *handler_opaque); +void bus_register_physical_memory(qemu_bus *bus, + target_phys_addr_t start_addr, + unsigned long size, + unsigned long phys_offset); +int bus_register_io_memory(qemu_bus *bus, + int io_index, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, + void *opaque); +/* Direction CPU->bridge->device/memory */ +void bus_rw_south(qemu_bus *bus, target_phys_addr_t addr, uint8_t *buf, + unsigned int len, int is_write); +static inline void bus_read_south(qemu_bus *bus, target_phys_addr_t addr, + uint8_t *buf, unsigned int len) +{ + bus_rw_south(bus, addr, buf, len, 0); +} +static inline void bus_write_south(qemu_bus *bus, target_phys_addr_t addr, + const uint8_t *buf, unsigned int len) +{ + bus_rw_south(bus, addr, (uint8_t *)buf, len, 1); +} +void bus_write_south_rom(qemu_bus *bus, target_phys_addr_t addr, + const uint8_t *buf, unsigned int len); +/* From device towards CPU/memory (DMA) */ +void bus_rw_north(qemu_bus *bus, target_phys_addr_t addr, uint8_t *buf, + unsigned int len, int is_write); +static inline void bus_read_north(qemu_bus *bus, target_phys_addr_t addr, + uint8_t *buf, unsigned int len) +{ + bus_rw_north(bus, addr, buf, len, 0); +} +static inline void bus_write_north(qemu_bus *bus, target_phys_addr_t addr, + const uint8_t *buf, unsigned int len) +{ + bus_rw_north(bus, addr, (uint8_t *)buf, len, 1); +} + /*******************************************/ /* host CPU ticks (if available) */ Index: qemu/exec.c =================================================================== --- qemu.orig/exec.c 2007-09-15 15:34:51.000000000 +0000 +++ qemu/exec.c 2007-09-15 16:05:54.000000000 +0000 @@ -2905,3 +2905,258 @@ #undef env #endif + +typedef struct BusPageDesc { + /* offset in host memory of the page + io_index in the low 12 bits */ + target_phys_addr_t phys_offset; +} BusPageDesc; + +struct qemu_bus { + /* Northbound access handler */ + qemu_mem_rw_handler north_handler; + void *handler_opaque; + /* Southbound access management */ + BusPageDesc **l1_bus_map; + unsigned int bus_bits, l1_bits, l2_bits, l1_size, l2_size; + 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]; + unsigned int io_mem_nb; +}; + +static BusPageDesc *bus_page_find_alloc(qemu_bus *bus, + target_phys_addr_t index, int alloc) +{ + void **lp, **p; + BusPageDesc *pd; + + p = (void **)bus->l1_bus_map; +#if TARGET_PHYS_ADDR_SPACE_BITS > 32 + lp = p + ((index >> (bus->l1_bits + bus->l2_bits)) & (bus->l1_size - 1)); + p = *lp; + if (!p) { + /* allocate if not found */ + if (!alloc) + return NULL; + p = qemu_vmalloc(sizeof(void *) * bus->l1_size); + memset(p, 0, sizeof(void *) * bus->l1_size); + *lp = p; + } +#endif + lp = p + ((index >> bus->l2_bits) & (bus->l1_size - 1)); + pd = *lp; + if (!pd) { + unsigned int i; + /* allocate if not found */ + if (!alloc) + return NULL; + pd = qemu_vmalloc(sizeof(BusPageDesc) * bus->l2_size); + *lp = pd; + for (i = 0; i < bus->l2_size; i++) + pd[i].phys_offset = IO_MEM_UNASSIGNED; + } + return ((BusPageDesc *)pd) + (index & (bus->l2_size - 1)); +} + +static inline BusPageDesc *bus_page_find(qemu_bus *bus, + target_phys_addr_t index) +{ + return bus_page_find_alloc(bus, index, 0); +} + +int bus_register_io_memory(qemu_bus *bus, + int io_index, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, + void *opaque) +{ + unsigned int i; + + 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 < 3; i++) { + bus->io_mem_read[io_index][i] = mem_read[i]; + bus->io_mem_write[io_index][i] = mem_write[i]; + } + bus->io_mem_opaque[io_index] = opaque; + return io_index << IO_MEM_SHIFT; +} + +void bus_rw_south(qemu_bus *bus, target_phys_addr_t addr, uint8_t *buf, + unsigned int len, int is_write) +{ + int l, io_index; + uint8_t *ptr; + uint32_t val; + target_phys_addr_t page; + unsigned long pd; + BusPageDesc *p; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + p = bus_page_find(bus, page >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if (is_write) { + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + /* XXX: could force cpu_single_env to NULL to avoid + potential bugs */ + if (l >= 4 && ((addr & 3) == 0)) { + /* 32 bit write access */ + val = ldl_p(buf); + bus->io_mem_write[io_index][2](io_mem_opaque[io_index], + addr, val); + l = 4; + } else if (l >= 2 && ((addr & 1) == 0)) { + /* 16 bit write access */ + val = lduw_p(buf); + bus->io_mem_write[io_index][1](io_mem_opaque[io_index], + addr, val); + l = 2; + } else { + /* 8 bit write access */ + val = ldub_p(buf); + bus->io_mem_write[io_index][0](io_mem_opaque[io_index], + addr, val); + l = 1; + } + } else { + unsigned long addr1; + + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + /* RAM case */ + ptr = phys_ram_base + addr1; + memcpy(ptr, buf, l); + if (!cpu_physical_memory_is_dirty(addr1)) { + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + l, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + (0xff & ~CODE_DIRTY_FLAG); + } + } + } else { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { + /* I/O case */ + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (l >= 4 && ((addr & 3) == 0)) { + /* 32 bit read access */ + val = bus->io_mem_read[io_index][2](io_mem_opaque[io_index], + addr); + stl_p(buf, val); + l = 4; + } else if (l >= 2 && ((addr & 1) == 0)) { + /* 16 bit read access */ + val = bus->io_mem_read[io_index][1](io_mem_opaque[io_index], + addr); + stw_p(buf, val); + l = 2; + } else { + /* 8 bit read access */ + val = bus->io_mem_read[io_index][0](io_mem_opaque[io_index], + addr); + stb_p(buf, val); + l = 1; + } + } else { + /* RAM case */ + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + memcpy(buf, ptr, l); + } + } + len -= l; + buf += l; + addr += l; + } +} + +/* used for ROM loading : can write in RAM and ROM */ +void bus_write_south_rom(qemu_bus *bus, target_phys_addr_t addr, + const uint8_t *buf, unsigned int len) +{ + int l; + uint8_t *ptr; + target_phys_addr_t page; + unsigned long pd; + BusPageDesc *p; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + p = bus_page_find(bus, page >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM && + (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { + /* do nothing */ + } else { + unsigned long addr1; + + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + /* ROM/RAM case */ + ptr = phys_ram_base + addr1; + memcpy(ptr, buf, l); + } + len -= l; + buf += l; + addr += l; + } +} + +void bus_rw_north(qemu_bus *bus, target_phys_addr_t addr, uint8_t *buf, + unsigned int len, int is_write) +{ + bus->north_handler(bus->handler_opaque, addr, buf, len, is_write); +} + +qemu_bus *bus_init(unsigned int bus_bits, qemu_mem_rw_handler north_handler, + void *handler_opaque) +{ + qemu_bus *bus; + + bus = qemu_mallocz(sizeof(qemu_bus)); + bus->north_handler = north_handler; + bus->bus_bits = bus_bits; + bus->l2_bits = 10; + bus->l1_bits = bus->bus_bits - bus->l2_bits - TARGET_PAGE_BITS; + bus->l1_size = (1 << bus->l1_bits); + bus->l2_size = (1 << bus->l2_bits); + bus->l1_bus_map = qemu_vmalloc(bus->l1_size * sizeof(void *)); + memset(bus->l1_bus_map, 0, bus->l1_size * sizeof(void *)); + bus->handler_opaque = handler_opaque; + + /* Register default types */ + bus_register_io_memory(bus, IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, + unassigned_mem_write, NULL); + bus_register_io_memory(bus, IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, + unassigned_mem_read, unassigned_mem_write, NULL); + bus_register_io_memory(bus, IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, + error_mem_read, notdirty_mem_write, NULL); + bus->io_mem_nb = 5; + + return bus; +}