[RFC,1/5] qemu_ram_map/unmap: Allow pre-allocated space to be mapped

Submitted by Alex Williamson on July 11, 2010, 6:09 p.m.

Details

Message ID 20100711180917.20121.51464.stgit@localhost6.localdomain6
State New
Headers show

Commit Message

Alex Williamson July 11, 2010, 6:09 p.m.
For assigned devices, we want to map the PCI BARs into the VM
address space.  This is just like mapping an option ROM except
the host backing is an mmap area instead of a chunk of vmalloc
memory.  This allow registration and removal of such areas.

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

 cpu-common.h |    3 +++
 exec.c       |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 0 deletions(-)

Patch hide | download patch | download mbox

diff --git a/cpu-common.h b/cpu-common.h
index 71e7933..8d03f4e 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -40,7 +40,10 @@  static inline void cpu_register_physical_memory(target_phys_addr_t start_addr,
 }
 
 ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr);
+ram_addr_t qemu_ram_map(DeviceState *dev, const char *name,
+                        ram_addr_t size, void *host);
 ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size);
+void qemu_ram_unmap(ram_addr_t addr);
 void qemu_ram_free(ram_addr_t addr);
 /* This should only be used for ram local to a device.  */
 void *qemu_get_ram_ptr(ram_addr_t addr);
diff --git a/exec.c b/exec.c
index 5420f56..a98b4e9 100644
--- a/exec.c
+++ b/exec.c
@@ -2808,6 +2808,49 @@  static ram_addr_t last_ram_offset(void)
     return last;
 }
 
+ram_addr_t qemu_ram_map(DeviceState *dev, const char *name,
+                        ram_addr_t size, void *host)
+{
+    RAMBlock *new_block, *block;
+
+    size = TARGET_PAGE_ALIGN(size);
+    new_block = qemu_mallocz(sizeof(*new_block));
+
+    if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
+        char *id = dev->parent_bus->info->get_dev_path(dev);
+        if (id) {
+            snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
+            qemu_free(id);
+        }
+    }
+    pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (!strcmp(block->idstr, new_block->idstr)) {
+            fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n",
+                    new_block->idstr);
+            abort();
+        }
+    }
+
+    new_block->host = host;
+
+    new_block->offset = find_ram_offset(size);
+    new_block->length = size;
+
+    QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
+
+    ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty,
+                                       last_ram_offset() >> TARGET_PAGE_BITS);
+    memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
+           0xff, size >> TARGET_PAGE_BITS);
+
+    if (kvm_enabled())
+        kvm_setup_guest_memory(new_block->host, size);
+
+    return new_block->offset;
+}
+
 ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
 {
     RAMBlock *new_block, *block;
@@ -2874,6 +2917,19 @@  ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
     return new_block->offset;
 }
 
+void qemu_ram_unmap(ram_addr_t addr)
+{
+    RAMBlock *block;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (addr == block->offset) {
+            QLIST_REMOVE(block, next);
+            qemu_free(block);
+            return;
+        }
+    }
+}
+
 void qemu_ram_free(ram_addr_t addr)
 {
     RAMBlock *block;