]> xenbits.xensource.com Git - xen.git/commitdiff
hvm ioemu: Avoid accessing invalid pseudophysical addresses in HVM
authorKeir Fraser <keir@xensource.com>
Mon, 9 Apr 2007 11:05:26 +0000 (12:05 +0100)
committerKeir Fraser <keir@xensource.com>
Mon, 9 Apr 2007 11:05:26 +0000 (12:05 +0100)
guest's memory map.
Signed-off-by: Keir Fraser <keir@xensource.com>
tools/ioemu/target-i386-dm/exec-dm.c
tools/ioemu/vl.c
tools/ioemu/vl.h

index d992f987e158715af96010cd33579a89ad04f6b5..4f56a2d71566b140e1d64201abd93022775c92a1 100644 (file)
@@ -128,12 +128,10 @@ char *logfilename = "/tmp/qemu.log";
 FILE *logfile;
 int loglevel;
 
-
 #ifdef MAPCACHE
 pthread_mutex_t mapcache_mutex;
 #endif
 
-
 void cpu_exec_init(CPUState *env)
 {
     CPUState **penv;
@@ -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_addr_t addr, uint8_t *buf,
                     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_addr_t addr, uint8_t *buf,
                     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 */
index 494ceb6e2a9990811bc07b9d53efea6e3e1d7387..2b11eb18d9cd72f5abc28b23ebcf355469f27084 100644 (file)
@@ -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,6 +5953,44 @@ static int qemu_map_cache_init(void)
     return 0;
 }
 
+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;
@@ -5939,34 +6002,12 @@ uint8_t *qemu_map_cache(target_phys_addr_t phys_addr)
 
     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);
-            }
-        }
+    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);
 
-        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;;
-    }
+    if (!test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping))
+        return NULL;
 
     last_address_index = address_index;
     last_address_vaddr = entry->vaddr_base;
@@ -6001,7 +6042,8 @@ void qemu_invalidate_map_cache(void)
 
     mapcache_unlock();
 }
-#endif
+
+#endif /* defined(MAPCACHE) */
 
 int main(int argc, char **argv)
 {
index 4ef250f766e583a68f6f828ccdfce8fc770cb5ad..635a86b071e23da7646cc00f26be066bd261dcbd 100644 (file)
@@ -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);