All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.