Patchwork [v4,1/2] Minimal RAM API support

login
register
mail settings
Submitter Alex Williamson
Date Dec. 13, 2010, 9:24 p.m.
Message ID <20101213212430.2472.23807.stgit@s20.home>
Download mbox | patch
Permalink /patch/75423/
State New
Headers show

Comments

Alex Williamson - Dec. 13, 2010, 9:24 p.m.
This adds a minimum chunk of Anthony's RAM API support so that we
can identify actual VM RAM versus all the other things that make
use of qemu_ram_alloc.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---

 Makefile.objs |    1 +
 cpu-common.h  |    2 +
 memory.c      |   94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 memory.h      |   44 +++++++++++++++++++++++++++
 4 files changed, 141 insertions(+), 0 deletions(-)
 create mode 100644 memory.c
 create mode 100644 memory.h
Paul Brook - Dec. 15, 2010, 5:23 p.m.
> This adds a minimum chunk of Anthony's RAM API support so that we
> can identify actual VM RAM versus all the other things that make
> use of qemu_ram_alloc.

Why do we care? How are you defining "actual VM RAM"?

Surely the whole point of qemu_ram_alloc is to allocate a chunk of memory that 
can be mapped into the guest physical address space, so all uses of 
qemu_ram_alloc should be using this API.

Paul
Alex Williamson - Dec. 15, 2010, 7:11 p.m.
On Wed, 2010-12-15 at 17:23 +0000, Paul Brook wrote:
> > This adds a minimum chunk of Anthony's RAM API support so that we
> > can identify actual VM RAM versus all the other things that make
> > use of qemu_ram_alloc.
> 
> Why do we care? How are you defining "actual VM RAM"?
> 
> Surely the whole point of qemu_ram_alloc is to allocate a chunk of memory that 
> can be mapped into the guest physical address space, so all uses of 
> qemu_ram_alloc should be using this API.

http://wiki.qemu.org/Features/RamAPI
Anthony Liguori - Dec. 15, 2010, 7:34 p.m.
On 12/15/2010 11:23 AM, Paul Brook wrote:
>> This adds a minimum chunk of Anthony's RAM API support so that we
>> can identify actual VM RAM versus all the other things that make
>> use of qemu_ram_alloc.
>>      
> Why do we care? How are you defining "actual VM RAM"?
>
> Surely the whole point of qemu_ram_alloc is to allocate a chunk of memory that
> can be mapped into the guest physical address space, so all uses of
> qemu_ram_alloc should be using this API.
>    

"actual VM RAM" == the DIMM devices.  This address has exactly a 1-1 
mapping between memory content and an address.  It doesn't change during 
program execution.

It may be mapped in the CPU in weird ways, it may be visibly different 
to devices, but that's a different interface.

Why do we care about differentiating "actual VM RAM" from things that 
behave like RAM but are not actually RAM (like device ROM)?  Because the 
semantics are different.  ROM is non-volatile and RAM is volatile.  If 
we don't make that distinction in our interfaces, we loose the ability 
to model the behavioral differences.

For things like paravirtual devices, we can take short cuts (to optimize 
performance) by saying the device is directly connecting to RAM (and 
doesn't go through the normal translation hierarchy).

Regards,

Anthony Liguori

> Paul
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

Patch

diff --git a/Makefile.objs b/Makefile.objs
index cebb945..47f3c3a 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -172,6 +172,7 @@  hw-obj-y += pci.o pci_bridge.o msix.o msi.o
 hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
 hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
 hw-obj-y += watchdog.o
+hw-obj-y += memory.o
 hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
 hw-obj-$(CONFIG_ECC) += ecc.o
 hw-obj-$(CONFIG_NAND) += nand.o
diff --git a/cpu-common.h b/cpu-common.h
index 6d4a898..f08f93b 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -29,6 +29,8 @@  enum device_endian {
 /* address in the RAM (different from a physical address) */
 typedef unsigned long ram_addr_t;
 
+#include "memory.h"
+
 /* memory API */
 
 typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
diff --git a/memory.c b/memory.c
new file mode 100644
index 0000000..07cb020
--- /dev/null
+++ b/memory.c
@@ -0,0 +1,94 @@ 
+/*
+ * RAM API
+ *
+ *  Copyright Red Hat, Inc. 2010
+ *
+ * Authors:
+ *  Alex Williamson <alex.williamson@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include "memory.h"
+#include "range.h"
+
+typedef struct RamSlot {
+    target_phys_addr_t start_addr;
+    ram_addr_t size;
+    ram_addr_t offset;
+    QLIST_ENTRY(RamSlot) next;
+} RamSlot;
+
+static QLIST_HEAD(ram_slot_list, RamSlot) ram_slot_list =
+    QLIST_HEAD_INITIALIZER(ram_slot_list);
+
+static RamSlot *ram_find_slot(target_phys_addr_t start_addr, ram_addr_t size)
+{
+    RamSlot *slot;
+
+    QLIST_FOREACH(slot, &ram_slot_list, next) {
+        if (slot->start_addr == start_addr && slot->size == size) {
+            return slot;
+        }
+
+        if (ranges_overlap(start_addr, size, slot->start_addr, slot->size)) {
+            hw_error("Ram range overlaps existing slot\n");
+        }
+    }
+
+    return NULL;
+}
+
+int ram_register(target_phys_addr_t start_addr, ram_addr_t size,
+                 ram_addr_t phys_offset)
+{
+    RamSlot *slot;
+
+    if (!size) {
+        return -EINVAL;
+    }
+
+    assert(!ram_find_slot(start_addr, size));
+
+    slot = qemu_malloc(sizeof(RamSlot));
+
+    slot->start_addr = start_addr;
+    slot->size = size;
+    slot->offset = phys_offset;
+
+    QLIST_INSERT_HEAD(&ram_slot_list, slot, next);
+
+    cpu_register_physical_memory(slot->start_addr, slot->size, slot->offset);
+
+    return 0;
+}
+
+void ram_unregister(target_phys_addr_t start_addr, ram_addr_t size)
+{
+    RamSlot *slot;
+
+    if (!size) {
+        return;
+    }
+
+    slot = ram_find_slot(start_addr, size);
+    assert(slot != NULL);
+
+    QLIST_REMOVE(slot, next);
+    qemu_free(slot);
+    cpu_register_physical_memory(start_addr, size, IO_MEM_UNASSIGNED);
+}
+
+int ram_for_each_slot(void *opaque, ram_for_each_slot_fn fn)
+{
+    RamSlot *slot;
+
+    QLIST_FOREACH(slot, &ram_slot_list, next) {
+        int ret = fn(opaque, slot->start_addr, slot->size, slot->offset);
+        if (ret) {
+            return ret;
+        }
+    }
+    return 0;
+}
diff --git a/memory.h b/memory.h
new file mode 100644
index 0000000..98c85ea
--- /dev/null
+++ b/memory.h
@@ -0,0 +1,44 @@ 
+#ifndef QEMU_MEMORY_H
+#define QEMU_MEMORY_H
+/*
+ * RAM API
+ *
+ *  Copyright Red Hat, Inc. 2010
+ *
+ * Authors:
+ *  Alex Williamson <alex.williamson@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "cpu-common.h"
+
+typedef int (*ram_for_each_slot_fn)(void *opaque,
+                                    target_phys_addr_t start_addr,
+                                    ram_addr_t size,
+                                    ram_addr_t phys_offset);
+
+/**
+ * ram_register() : Register a region of guest physical memory
+ *
+ * The new region must not overlap an existing region.
+ */
+int ram_register(target_phys_addr_t start_addr, ram_addr_t size,
+                 ram_addr_t phys_offset);
+
+/**
+ * ram_unregister() : Unregister a region of guest physical memory
+ */
+void ram_unregister(target_phys_addr_t start_addr, ram_addr_t size);
+
+/**
+ * ram_for_each_slot() : Call fn() on each registered region
+ *
+ * Stop on non-zero return from fn().
+ */
+int ram_for_each_slot(void *opaque, ram_for_each_slot_fn fn);
+
+#endif /* QEMU_MEMORY_H */