# 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
|