qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
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 */

             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).