From: "Blue Swirl" <blauwirbel@gmail.com>
To: Paul Brook <paul@codesourcery.com>
Cc: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] Re: PATCH, RFC: Generic DMA framework
Date: Sat, 15 Sep 2007 19:16:51 +0300 [thread overview]
Message-ID: <f43fc5580709150916g4fb73e4ah448834879b07fe8f@mail.gmail.com> (raw)
In-Reply-To: <200709081703.08899.paul@codesourcery.com>
[-- Attachment #1: Type: text/plain, Size: 226 bytes --]
I made a first implementation of this concept. CPU->bus uses
"southbound" functions, device->CPU "northbound" ones.
The system is not symmetric, the device address range allocation could
well be separate.
What do you think?
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: bus_ops.diff --]
[-- Type: text/x-diff; name="bus_ops.diff", Size: 11704 bytes --]
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;
+}
prev parent reply other threads:[~2007-09-15 16:16 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-08-14 19:48 [Qemu-devel] PATCH, RFC: Generic DMA framework Blue Swirl
2007-08-16 18:18 ` [Qemu-devel] " Blue Swirl
2007-08-16 19:58 ` malc
2007-08-19 17:46 ` Blue Swirl
2007-08-24 19:40 ` Blue Swirl
2007-08-24 20:18 ` Paul Brook
2007-08-24 23:33 ` Fabrice Bellard
2007-08-25 0:29 ` Paul Brook
2007-08-26 11:30 ` Fabrice Bellard
2007-08-26 17:54 ` Blue Swirl
2007-08-28 19:03 ` Blue Swirl
2007-08-28 19:43 ` Paul Brook
2007-08-29 17:00 ` Blue Swirl
2007-08-29 20:39 ` Paul Brook
2007-08-29 21:18 ` Paul Brook
2007-09-08 14:07 ` Blue Swirl
2007-09-08 14:31 ` Paul Brook
2007-09-08 14:53 ` Blue Swirl
2007-09-08 16:03 ` Paul Brook
2007-09-15 16:16 ` Blue Swirl [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f43fc5580709150916g4fb73e4ah448834879b07fe8f@mail.gmail.com \
--to=blauwirbel@gmail.com \
--cc=paul@codesourcery.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).