qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 1/6] kvm: memory aliasing support for kvm


From: Glauber Costa
Subject: [Qemu-devel] [PATCH 1/6] kvm: memory aliasing support for kvm
Date: Wed, 19 Nov 2008 13:26:12 -0200

We use information encoded in phys_offset to support memory
alias for kvm-all.c. Recall that for any given memory slot,
userspace_addr = phys_ram_base + phys_offset (without any flags).

This way, we can detect whether or not the registered slot is
effectively pointing to the same area, regardless of the fact
that it has a different guest_phys_addr.

Signed-off-by: Glauber Costa <address@hidden>
---
 kvm-all.c         |   36 +++++++++++++++++++++++++-
 kvm.h             |    6 ++++
 target-i386/kvm.c |   72 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+), 1 deletions(-)

diff --git a/kvm-all.c b/kvm-all.c
index d3fcf8b..b5bbdcb 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -75,6 +75,28 @@ static KVMSlot *kvm_lookup_slot(KVMState *s, 
target_phys_addr_t start_addr)
     return NULL;
 }
 
+/*
+ * If we are trying to register a slot that points to the same address
+ * (phys_offset) of an already existing slot, data should go to the same
+ * place regardless of to which guest_phys_addr we write to. When we are
+ * using the kvm_alias API, it means it should be an alias.
+ */
+static KVMSlot *kvm_should_alias(KVMState *s, ram_addr_t phys_offset)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        KVMSlot *mem = &s->slots[i];
+
+        ram_addr_t addr = mem->userspace_addr - (ram_addr_t)phys_ram_base;
+
+        if (phys_offset >= addr &&
+            phys_offset < (addr + mem->memory_size))
+            return mem;
+    }
+    return NULL;
+}
+
 int kvm_init_vcpu(CPUState *env)
 {
     KVMState *s = kvm_state;
@@ -315,7 +337,7 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr,
 {
     KVMState *s = kvm_state;
     ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
-    KVMSlot *mem;
+    KVMSlot *mem, *as;
 
     /* KVM does not support read-only slots */
     phys_offset &= ~IO_MEM_ROM;
@@ -369,10 +391,22 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr,
             abort();
         }
     }
+
+    if (((flags == IO_MEM_UNASSIGNED) || (flags >= TLB_MMIO))
+        && (kvm_arch_destroy_alias_slot(s, start_addr)))
+            return;
+
     /* KVM does not need to know about this memory */
     if (flags >= IO_MEM_UNASSIGNED)
         return;
 
+    if ((as = kvm_should_alias(s, phys_offset))) {
+        target_phys_addr_t target_addr = as->guest_phys_addr;
+        target_addr += phys_offset - (as->userspace_addr - 
(ram_addr_t)phys_ram_base);
+        kvm_arch_set_alias_slot(s, start_addr, size, target_addr); 
+        return;
+    }
+
     mem = kvm_alloc_slot(s);
     mem->memory_size = size;
     mem->guest_phys_addr = start_addr;
diff --git a/kvm.h b/kvm.h
index 304de27..7588601 100644
--- a/kvm.h
+++ b/kvm.h
@@ -51,6 +51,12 @@ int kvm_vcpu_ioctl(CPUState *env, int type, ...);
 
 /* Arch specific hooks */
 
+int kvm_arch_is_alias_slot(target_phys_addr_t start_addr);
+int kvm_arch_destroy_alias_slot(KVMState *s, target_phys_addr_t start_addr);
+void kvm_arch_set_alias_slot(KVMState *s, target_phys_addr_t start_addr,
+                             ram_addr_t size,
+                             target_phys_addr_t target_addr);
+
 int kvm_arch_post_run(CPUState *env, struct kvm_run *run);
 
 int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run);
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 3f60654..4ede68a 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -33,6 +33,74 @@
     do { } while (0)
 #endif
 
+typedef struct kvm_memory_alias KVMAliasSlot;
+
+static KVMAliasSlot alias_slots[8];
+
+static KVMAliasSlot *kvm_lookup_alias_slot(target_phys_addr_t start_addr) 
+{ 
+    int i; 
+        
+    for (i = 0; i < ARRAY_SIZE(alias_slots); i++) { 
+        KVMAliasSlot *as = &alias_slots[i]; 
+ 
+        if (start_addr >= as->guest_phys_addr && 
+            start_addr < (as->guest_phys_addr + as->memory_size)) 
+            return as; 
+    } 
+ 
+    return NULL; 
+}
+
+int kvm_arch_is_alias_slot(target_phys_addr_t start_addr)
+{
+    return !!kvm_lookup_alias_slot(start_addr);
+}
+
+static KVMAliasSlot *kvm_alloc_alias_slot(void)
+{
+    int i; 
+            
+    for (i = 0; i < ARRAY_SIZE(alias_slots); i++) {
+        if (alias_slots[i].memory_size == 0)
+            return &alias_slots[i];
+    }
+
+    return NULL;
+}
+
+int kvm_arch_destroy_alias_slot(KVMState *s, target_phys_addr_t start_addr)
+{
+    
+    KVMAliasSlot *as = kvm_lookup_alias_slot(start_addr);
+    if (!as)
+        return 0;
+    as->memory_size = 0;
+    as->target_phys_addr = 0;
+
+    kvm_vm_ioctl(s, KVM_SET_MEMORY_ALIAS, as);
+    return 1;
+}
+
+void kvm_arch_set_alias_slot(KVMState *s, target_phys_addr_t start_addr,
+                      ram_addr_t size,
+                      target_phys_addr_t target_addr)
+{
+
+    int r;
+    KVMAliasSlot *as = kvm_lookup_alias_slot(start_addr);
+
+    if (!as)
+        as = kvm_alloc_alias_slot();
+
+    as->guest_phys_addr = (uint64_t)start_addr;
+    as->memory_size = (uint64_t)size;
+    as->target_phys_addr = (uint64_t)target_addr;
+    as->flags = 0;
+
+    r = kvm_vm_ioctl(s, KVM_SET_MEMORY_ALIAS, as);
+}
+
 int kvm_arch_init_vcpu(CPUState *env)
 {
     struct {
@@ -42,6 +110,10 @@ int kvm_arch_init_vcpu(CPUState *env)
     int limit, i, cpuid_i;
     uint32_t eax, ebx, ecx, edx;
 
+
+    for (i = 0; i < ARRAY_SIZE(alias_slots); i++)
+        alias_slots[i].slot = i;
+
     cpuid_i = 0;
 
     cpu_x86_cpuid(env, 0, &eax, &ebx, &ecx, &edx);
-- 
1.5.6.5





reply via email to

[Prev in Thread] Current Thread [Next in Thread]