From: Gianni Tedesco <gianni@scaramanga.co.uk>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH,RFC]: Generic memory callback regions
Date: Tue, 01 Jun 2004 03:53:02 +0100 [thread overview]
Message-ID: <1086058382.21903.53.camel@sherbert> (raw)
[-- Attachment #1: Type: text/plain, Size: 913 bytes --]
Hi,
This patch adds an API for CONFIG_SOFTMMU mode that hardware drivers can
use to add memory regions backed by callback functions. It simply adds a
layer for storing opaque data above the basic cpu_register_io_memory /
cpu_register_physical memory functions. I used a linked list to store
the data structures, i think O(ln/2) avg. lookup time will be fine as I
don't envisage many of these regions existing.
I've tested it as far as I currently can for the pciproxy code and it
seems to do the correct thing. I could work around this manually within
the pciproxy code itself, but I figured a generic interface would be
something useful for other drivers (such as any PCI card with MMIO
resources).
Ideas / thoughts / bugs?
--
// Gianni Tedesco (gianni at scaramanga dot co dot uk)
lynx --source www.scaramanga.co.uk/scaramanga.asc | gpg --import
8646BE7D: 6D9F 2287 870E A2C9 8F60 3A3C 91B5 7669 8646 BE7D
[-- Attachment #2: qemu-mem-callbacks-1.diff --]
[-- Type: text/x-patch, Size: 6319 bytes --]
diff -urN qemu.orig/cpu-all.h qemu.callback_mem/cpu-all.h
--- qemu.orig/cpu-all.h 2004-05-21 13:59:13.000000000 +0100
+++ qemu.callback_mem/cpu-all.h 2004-06-01 03:11:05.000000000 +0100
@@ -680,10 +680,28 @@
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
#define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */
#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */
+#define IO_MEM_CALLBACK (5 << IO_MEM_SHIFT) /* Callback functions */
typedef void CPUWriteMemoryFunc(target_phys_addr_t addr, uint32_t value);
typedef uint32_t CPUReadMemoryFunc(target_phys_addr_t addr);
+typedef void (*CPUWriteMemoryCallback)(void *opaque,
+ target_phys_addr_t addr,
+ int len,
+ uint32_t val);
+typedef uint32_t (*CPUReadMemoryCallback)(void *opaque,
+ target_phys_addr_t addr,
+ int len);
+
+int cpu_register_callback_memory(target_phys_addr_t start_addr,
+ unsigned long size,
+ CPUReadMemoryCallback mem_read,
+ CPUWriteMemoryCallback mem_write,
+ void *opaque);
+int cpu_unregister_callback_memory(target_phys_addr_t start_addr,
+ unsigned long size);
+
+
void cpu_register_physical_memory(target_phys_addr_t start_addr,
unsigned long size,
unsigned long phys_offset);
diff -urN qemu.orig/exec.c qemu.callback_mem/exec.c
--- qemu.orig/exec.c 2004-05-25 23:48:00.000000000 +0100
+++ qemu.callback_mem/exec.c 2004-06-01 03:42:42.000000000 +0100
@@ -731,6 +731,149 @@
}
}
+#if defined(CONFIG_SOFTMMU)
+struct cpu_callback {
+ struct cpu_callback *prev, *next;
+ target_phys_addr_t begin, end;
+ CPUReadMemoryCallback read;
+ CPUWriteMemoryCallback write;
+ void *opaque;
+};
+
+static struct cpu_callback cpu_cbfn = {
+ .prev = &cpu_cbfn,
+ .next = &cpu_cbfn,
+};
+
+static struct cpu_callback *cpu_cbfn_lookup(target_phys_addr_t begin,
+ target_phys_addr_t end)
+{
+ struct cpu_callback *c;
+
+ for(c=cpu_cbfn.next; c != &cpu_cbfn; c=c->next) {
+ if ( (begin < c->end && end > c->end) ||
+ (end > c->begin && begin < c->begin) ) {
+ fprintf(stderr, "cpu_cbfn_lookup: %x/%u straddles region: "
+ "%x-%x\n", begin, end-begin, c->begin, c->end);
+ }
+ if ( begin >= c->begin && end <= c->end )
+ return c;
+ }
+
+ fprintf(stderr, "cpu_cbfn_lookup: %x/%u not found\n", begin, end-begin);
+ return NULL;
+}
+
+static void cpu_cbfn_write(target_phys_addr_t addr, int len, uint32_t value)
+{
+ struct cpu_callback *c;
+ c = cpu_cbfn_lookup(addr, addr + len);
+ if ( c == NULL )
+ return;
+ if ( c->write )
+ (*c->write)(c->opaque, addr, len, value);
+}
+
+static uint32_t cpu_cbfn_read(target_phys_addr_t addr, int len)
+{
+ struct cpu_callback *c;
+ c = cpu_cbfn_lookup(addr, addr + len);
+ if ( c == NULL )
+ return 0xffffffff;
+ if ( c->read )
+ return (*c->read)(c->opaque, addr, len);
+ return 0; /* NULL read handler means return all zeros */
+}
+
+static uint32_t cpu_cbfn_readb(target_phys_addr_t addr)
+{
+ return cpu_cbfn_read(addr, 1);
+}
+static uint32_t cpu_cbfn_readw(target_phys_addr_t addr)
+{
+ return cpu_cbfn_read(addr, 2);
+}
+static uint32_t cpu_cbfn_readl(target_phys_addr_t addr)
+{
+ return cpu_cbfn_read(addr, 4);
+}
+static void cpu_cbfn_writeb(target_phys_addr_t addr, uint32_t value)
+{
+ return cpu_cbfn_write(addr, 1, value);
+}
+static void cpu_cbfn_writew(target_phys_addr_t addr, uint32_t value)
+{
+ return cpu_cbfn_write(addr, 2, value);
+}
+static void cpu_cbfn_writel(target_phys_addr_t addr, uint32_t value)
+{
+ return cpu_cbfn_write(addr, 4, value);
+}
+
+static CPUReadMemoryFunc *cpu_callback_read[3]={
+ cpu_cbfn_readb,
+ cpu_cbfn_readw,
+ cpu_cbfn_readl,
+};
+static CPUWriteMemoryFunc *cpu_callback_write[3]={
+ cpu_cbfn_writeb,
+ cpu_cbfn_writew,
+ cpu_cbfn_writel,
+};
+
+int cpu_register_callback_memory(target_phys_addr_t start_addr,
+ unsigned long size,
+ CPUReadMemoryCallback mem_read,
+ CPUWriteMemoryCallback mem_write,
+ void *opaque)
+{
+ struct cpu_callback *c;
+ target_phys_addr_t end_addr = start_addr + size;
+
+ /* Check for overlaps (not permitted) */
+ for(c=cpu_cbfn.next; c != &cpu_cbfn; c=c->next) {
+ if ( (c->begin >= start_addr && c->begin <= end_addr) ||
+ (start_addr >= c->begin && start_addr <= c->end) ) {
+ fprintf(stderr, "mem_callback: %x:%x overlaps %x:%x\n",
+ start_addr, end_addr, c->begin, c->end);
+ return 1;
+ }
+ }
+
+ c = malloc(sizeof(*c));
+ if ( c == NULL )
+ return 0;
+
+ c->next = cpu_cbfn.next;
+ c->next->prev = c;
+ c->prev = &cpu_cbfn;
+ c->prev->next = c;
+ c->begin = start_addr;
+ c->end = end_addr;
+ c->read = mem_read;
+ c->write = mem_write;
+ c->opaque = opaque;
+
+ cpu_register_physical_memory(start_addr, size, IO_MEM_CALLBACK);
+
+ return 1;
+}
+
+int cpu_unregister_callback_memory(target_phys_addr_t start_addr,
+ unsigned long size)
+{
+ struct cpu_callback *c;
+ c = cpu_cbfn_lookup(start_addr, start_addr + size);
+ if ( c == NULL )
+ return 0;
+
+ c->prev->next = c->next;
+ c->next->prev = c->prev;
+ free(c);
+ return 1;
+}
+#endif
+
#if !defined(CONFIG_SOFTMMU)
static void tb_invalidate_phys_page(target_ulong addr,
unsigned long pc, void *puc)
@@ -1901,6 +2044,9 @@
cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write);
cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write);
cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write);
+#if defined(CONFIG_SOFTMMU)
+ cpu_register_io_memory(IO_MEM_CALLBACK >> IO_MEM_SHIFT, cpu_callback_read, cpu_callback_write);
+#endif
io_mem_nb = 5;
/* alloc dirty bits array */
next reply other threads:[~2004-06-01 2:54 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-06-01 2:53 Gianni Tedesco [this message]
2004-06-01 11:13 ` [Qemu-devel] [PATCH,RFC]: Generic memory callback regions Joe Batt
2004-06-01 11:26 ` Gianni Tedesco
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=1086058382.21903.53.camel@sherbert \
--to=gianni@scaramanga.co.uk \
--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).