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

[Xen-changelog] [xen-unstable] hvm ioemu: Avoid accessing invalid pseudophysical addresses in HVM



# HG changeset patch
# User Keir Fraser <keir@xxxxxxxxxxxxx>
# Date 1176116726 -3600
# Node ID 400a3dca237e856c53934f4b81137581d727fdb3
# Parent  73abcf9abbc1df3d5960461d448a725d7120fb13
hvm ioemu: Avoid accessing invalid pseudophysical addresses in HVM
guest's memory map.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 tools/ioemu/target-i386-dm/exec-dm.c |   25 +----
 tools/ioemu/vl.c                     |  162 ++++++++++++++++++++++-------------
 tools/ioemu/vl.h                     |   15 ---
 3 files changed, 107 insertions(+), 95 deletions(-)

diff -r 73abcf9abbc1 -r 400a3dca237e tools/ioemu/target-i386-dm/exec-dm.c
--- a/tools/ioemu/target-i386-dm/exec-dm.c      Mon Apr 09 11:12:15 2007 +0100
+++ b/tools/ioemu/target-i386-dm/exec-dm.c      Mon Apr 09 12:05:26 2007 +0100
@@ -128,11 +128,9 @@ FILE *logfile;
 FILE *logfile;
 int loglevel;
 
-
 #ifdef MAPCACHE
 pthread_mutex_t mapcache_mutex;
 #endif
-
 
 void cpu_exec_init(CPUState *env)
 {
@@ -427,21 +425,10 @@ int iomem_index(target_phys_addr_t addr)
         return 0;
 }
 
-static inline int paddr_is_ram(target_phys_addr_t addr)
-{
-    /* Is this guest physical address RAM-backed? */
-#if defined(CONFIG_DM) && (defined(__i386__) || defined(__x86_64__))
-    return ((addr < HVM_BELOW_4G_MMIO_START) ||
-            (addr >= HVM_BELOW_4G_MMIO_START + HVM_BELOW_4G_MMIO_LENGTH));
-#else
-    return (addr < ram_size);
-#endif
-}
-
 #if defined(__i386__) || defined(__x86_64__)
 #define phys_ram_addr(x) (qemu_map_cache(x))
 #elif defined(__ia64__)
-#define phys_ram_addr(x) (phys_ram_base + (x))
+#define phys_ram_addr(x) ((addr < ram_size) ? (phys_ram_base + (x)) : NULL)
 #endif
 
 extern unsigned long *logdirty_bitmap;
@@ -481,16 +468,15 @@ void cpu_physical_memory_rw(target_phys_
                     io_mem_write[io_index][0](io_mem_opaque[io_index], addr, 
val);
                     l = 1;
                 }
-            } else if (paddr_is_ram(addr)) {
+            } else if ((ptr = phys_ram_addr(addr)) != NULL) {
                 /* Writing to RAM */
-                ptr = phys_ram_addr(addr);
                 memcpy(ptr, buf, l);
                 if (logdirty_bitmap != NULL) {
                     /* Record that we have dirtied this frame */
                     unsigned long pfn = addr >> TARGET_PAGE_BITS;
                     if (pfn / 8 >= logdirty_bitmap_size) {
-                        fprintf(logfile, "dirtying pfn %x >= bitmap size %x\n",
-                                pfn, logdirty_bitmap_size * 8);
+                        fprintf(logfile, "dirtying pfn %lx >= bitmap "
+                                "size %lx\n", pfn, logdirty_bitmap_size * 8);
                     } else {
                         logdirty_bitmap[pfn / HOST_LONG_BITS]
                             |= 1UL << pfn % HOST_LONG_BITS;
@@ -518,9 +504,8 @@ void cpu_physical_memory_rw(target_phys_
                     stb_raw(buf, val);
                     l = 1;
                 }
-            } else if (paddr_is_ram(addr)) {
+            } else if ((ptr = phys_ram_addr(addr)) != NULL) {
                 /* Reading from RAM */
-                ptr = phys_ram_addr(addr);
                 memcpy(buf, ptr, l);
             } else {
                 /* Neither RAM nor known MMIO space */
diff -r 73abcf9abbc1 -r 400a3dca237e tools/ioemu/vl.c
--- a/tools/ioemu/vl.c  Mon Apr 09 11:12:15 2007 +0100
+++ b/tools/ioemu/vl.c  Mon Apr 09 12:05:26 2007 +0100
@@ -5894,7 +5894,32 @@ void suspend(int sig)
     suspend_requested = 1;
 }
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(MAPCACHE)
+
+#if defined(__i386__) 
+#define MAX_MCACHE_SIZE    0x40000000 /* 1GB max for x86 */
+#define MCACHE_BUCKET_SHIFT 16
+#elif defined(__x86_64__)
+#define MAX_MCACHE_SIZE    0x1000000000 /* 64GB max for x86_64 */
+#define MCACHE_BUCKET_SHIFT 20
+#endif
+
+#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)
+
+#define BITS_PER_LONG (sizeof(long)*8)
+#define BITS_TO_LONGS(bits) \
+    (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
+#define DECLARE_BITMAP(name,bits) \
+    unsigned long name[BITS_TO_LONGS(bits)]
+#define test_bit(bit,map) \
+    (!!((map)[(bit)/BITS_PER_LONG] & (1UL << ((bit)%BITS_PER_LONG))))
+
+struct map_cache {
+    unsigned long paddr_index;
+    uint8_t      *vaddr_base;
+    DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>PAGE_SHIFT);
+};
+
 static struct map_cache *mapcache_entry;
 static unsigned long nr_buckets;
 
@@ -5928,69 +5953,85 @@ static int qemu_map_cache_init(void)
     return 0;
 }
 
-uint8_t *qemu_map_cache(target_phys_addr_t phys_addr)
-{
-    struct map_cache *entry;
-    unsigned long address_index  = phys_addr >> MCACHE_BUCKET_SHIFT;
-    unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1);
-
-    if (address_index == last_address_index)
-        return last_address_vaddr + address_offset;
-
-    entry = &mapcache_entry[address_index % nr_buckets];
-
-    if (entry->vaddr_base == NULL || entry->paddr_index != address_index) {
-        /* We need to remap a bucket. */
-        uint8_t *vaddr_base;
-        unsigned long pfns[MCACHE_BUCKET_SIZE >> PAGE_SHIFT];
-        unsigned int i;
-
-        if (entry->vaddr_base != NULL) {
-            errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
-            if (errno) {
-                fprintf(logfile, "unmap fails %d\n", errno);
-                exit(-1);
-            }
-        }
-
-        for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i++)
-            pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-PAGE_SHIFT)) + i;
-
-        vaddr_base = xc_map_foreign_batch(
-            xc_handle, domid, PROT_READ|PROT_WRITE,
-            pfns, MCACHE_BUCKET_SIZE >> PAGE_SHIFT);
-        if (vaddr_base == NULL) {
-            fprintf(logfile, "xc_map_foreign_batch error %d\n", errno);
-            exit(-1);
-        }
-
-        entry->vaddr_base  = vaddr_base;
-        entry->paddr_index = address_index;;
-    }
-
-    last_address_index = address_index;
-    last_address_vaddr = entry->vaddr_base;
-
-    return last_address_vaddr + address_offset;
-}
-
-void qemu_invalidate_map_cache(void)
-{
-    unsigned long i;
-
-    mapcache_lock();
-
-    for (i = 0; i < nr_buckets; i++) {
-        struct map_cache *entry = &mapcache_entry[i];
-
-        if (entry->vaddr_base == NULL)
-            continue;
-
+static void qemu_remap_bucket(struct map_cache *entry,
+                              unsigned long address_index)
+{
+    uint8_t *vaddr_base;
+    unsigned long pfns[MCACHE_BUCKET_SIZE >> PAGE_SHIFT];
+    unsigned int i, j;
+
+    if (entry->vaddr_base != NULL) {
         errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
         if (errno) {
             fprintf(logfile, "unmap fails %d\n", errno);
             exit(-1);
         }
+    }
+
+    for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i++)
+        pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-PAGE_SHIFT)) + i;
+
+    vaddr_base = xc_map_foreign_batch(xc_handle, domid, PROT_READ|PROT_WRITE,
+                                      pfns, MCACHE_BUCKET_SIZE >> PAGE_SHIFT);
+    if (vaddr_base == NULL) {
+        fprintf(logfile, "xc_map_foreign_batch error %d\n", errno);
+        exit(-1);
+    }
+
+    entry->vaddr_base  = vaddr_base;
+    entry->paddr_index = address_index;
+
+    for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i += BITS_PER_LONG) {
+        unsigned long word = 0;
+        j = ((i + BITS_PER_LONG) > (MCACHE_BUCKET_SIZE >> PAGE_SHIFT)) ?
+            (MCACHE_BUCKET_SIZE >> PAGE_SHIFT) % BITS_PER_LONG : BITS_PER_LONG;
+        while (j > 0)
+            word = (word << 1) | !(pfns[i + --j] & 0xF0000000UL);
+        entry->valid_mapping[i / BITS_PER_LONG] = word;
+    }
+}
+
+uint8_t *qemu_map_cache(target_phys_addr_t phys_addr)
+{
+    struct map_cache *entry;
+    unsigned long address_index  = phys_addr >> MCACHE_BUCKET_SHIFT;
+    unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1);
+
+    if (address_index == last_address_index)
+        return last_address_vaddr + address_offset;
+
+    entry = &mapcache_entry[address_index % nr_buckets];
+
+    if (entry->vaddr_base == NULL || entry->paddr_index != address_index ||
+        !test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping))
+        qemu_remap_bucket(entry, address_index);
+
+    if (!test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping))
+        return NULL;
+
+    last_address_index = address_index;
+    last_address_vaddr = entry->vaddr_base;
+
+    return last_address_vaddr + address_offset;
+}
+
+void qemu_invalidate_map_cache(void)
+{
+    unsigned long i;
+
+    mapcache_lock();
+
+    for (i = 0; i < nr_buckets; i++) {
+        struct map_cache *entry = &mapcache_entry[i];
+
+        if (entry->vaddr_base == NULL)
+            continue;
+
+        errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
+        if (errno) {
+            fprintf(logfile, "unmap fails %d\n", errno);
+            exit(-1);
+        }
 
         entry->paddr_index = 0;
         entry->vaddr_base  = NULL;
@@ -6001,7 +6042,8 @@ void qemu_invalidate_map_cache(void)
 
     mapcache_unlock();
 }
-#endif
+
+#endif /* defined(MAPCACHE) */
 
 int main(int argc, char **argv)
 {
diff -r 73abcf9abbc1 -r 400a3dca237e tools/ioemu/vl.h
--- a/tools/ioemu/vl.h  Mon Apr 09 11:12:15 2007 +0100
+++ b/tools/ioemu/vl.h  Mon Apr 09 12:05:26 2007 +0100
@@ -161,21 +161,6 @@ extern FILE *logfile;
 
 #define MAPCACHE
 
-#if defined(__i386__) 
-#define MAX_MCACHE_SIZE    0x40000000 /* 1GB max for x86 */
-#define MCACHE_BUCKET_SHIFT 16
-#elif defined(__x86_64__)
-#define MAX_MCACHE_SIZE    0x1000000000 /* 64GB max for x86_64 */
-#define MCACHE_BUCKET_SHIFT 20
-#endif
-
-#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)
-
-struct map_cache {
-    unsigned long paddr_index;
-    uint8_t      *vaddr_base;
-};
-
 uint8_t *qemu_map_cache(target_phys_addr_t phys_addr);
 void     qemu_invalidate_map_cache(void);
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.