ia64/xen-unstable

changeset 14774:400a3dca237e

hvm ioemu: Avoid accessing invalid pseudophysical addresses in HVM
guest's memory map.
Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir@xensource.com>
date Mon Apr 09 12:05:26 2007 +0100 (2007-04-09)
parents 73abcf9abbc1
children 1bde28f762a6 7cfe2a22462c fb0463b6094d
files tools/ioemu/target-i386-dm/exec-dm.c tools/ioemu/vl.c tools/ioemu/vl.h
line diff
     1.1 --- a/tools/ioemu/target-i386-dm/exec-dm.c	Mon Apr 09 11:12:15 2007 +0100
     1.2 +++ b/tools/ioemu/target-i386-dm/exec-dm.c	Mon Apr 09 12:05:26 2007 +0100
     1.3 @@ -128,12 +128,10 @@ char *logfilename = "/tmp/qemu.log";
     1.4  FILE *logfile;
     1.5  int loglevel;
     1.6  
     1.7 -
     1.8  #ifdef MAPCACHE
     1.9  pthread_mutex_t mapcache_mutex;
    1.10  #endif
    1.11  
    1.12 -
    1.13  void cpu_exec_init(CPUState *env)
    1.14  {
    1.15      CPUState **penv;
    1.16 @@ -427,21 +425,10 @@ int iomem_index(target_phys_addr_t addr)
    1.17          return 0;
    1.18  }
    1.19  
    1.20 -static inline int paddr_is_ram(target_phys_addr_t addr)
    1.21 -{
    1.22 -    /* Is this guest physical address RAM-backed? */
    1.23 -#if defined(CONFIG_DM) && (defined(__i386__) || defined(__x86_64__))
    1.24 -    return ((addr < HVM_BELOW_4G_MMIO_START) ||
    1.25 -            (addr >= HVM_BELOW_4G_MMIO_START + HVM_BELOW_4G_MMIO_LENGTH));
    1.26 -#else
    1.27 -    return (addr < ram_size);
    1.28 -#endif
    1.29 -}
    1.30 -
    1.31  #if defined(__i386__) || defined(__x86_64__)
    1.32  #define phys_ram_addr(x) (qemu_map_cache(x))
    1.33  #elif defined(__ia64__)
    1.34 -#define phys_ram_addr(x) (phys_ram_base + (x))
    1.35 +#define phys_ram_addr(x) ((addr < ram_size) ? (phys_ram_base + (x)) : NULL)
    1.36  #endif
    1.37  
    1.38  extern unsigned long *logdirty_bitmap;
    1.39 @@ -481,16 +468,15 @@ void cpu_physical_memory_rw(target_phys_
    1.40                      io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
    1.41                      l = 1;
    1.42                  }
    1.43 -            } else if (paddr_is_ram(addr)) {
    1.44 +            } else if ((ptr = phys_ram_addr(addr)) != NULL) {
    1.45                  /* Writing to RAM */
    1.46 -                ptr = phys_ram_addr(addr);
    1.47                  memcpy(ptr, buf, l);
    1.48                  if (logdirty_bitmap != NULL) {
    1.49                      /* Record that we have dirtied this frame */
    1.50                      unsigned long pfn = addr >> TARGET_PAGE_BITS;
    1.51                      if (pfn / 8 >= logdirty_bitmap_size) {
    1.52 -                        fprintf(logfile, "dirtying pfn %x >= bitmap size %x\n",
    1.53 -                                pfn, logdirty_bitmap_size * 8);
    1.54 +                        fprintf(logfile, "dirtying pfn %lx >= bitmap "
    1.55 +                                "size %lx\n", pfn, logdirty_bitmap_size * 8);
    1.56                      } else {
    1.57                          logdirty_bitmap[pfn / HOST_LONG_BITS]
    1.58                              |= 1UL << pfn % HOST_LONG_BITS;
    1.59 @@ -518,9 +504,8 @@ void cpu_physical_memory_rw(target_phys_
    1.60                      stb_raw(buf, val);
    1.61                      l = 1;
    1.62                  }
    1.63 -            } else if (paddr_is_ram(addr)) {
    1.64 +            } else if ((ptr = phys_ram_addr(addr)) != NULL) {
    1.65                  /* Reading from RAM */
    1.66 -                ptr = phys_ram_addr(addr);
    1.67                  memcpy(buf, ptr, l);
    1.68              } else {
    1.69                  /* Neither RAM nor known MMIO space */
     2.1 --- a/tools/ioemu/vl.c	Mon Apr 09 11:12:15 2007 +0100
     2.2 +++ b/tools/ioemu/vl.c	Mon Apr 09 12:05:26 2007 +0100
     2.3 @@ -5894,7 +5894,32 @@ void suspend(int sig)
     2.4      suspend_requested = 1;
     2.5  }
     2.6  
     2.7 -#if defined(__i386__) || defined(__x86_64__)
     2.8 +#if defined(MAPCACHE)
     2.9 +
    2.10 +#if defined(__i386__) 
    2.11 +#define MAX_MCACHE_SIZE    0x40000000 /* 1GB max for x86 */
    2.12 +#define MCACHE_BUCKET_SHIFT 16
    2.13 +#elif defined(__x86_64__)
    2.14 +#define MAX_MCACHE_SIZE    0x1000000000 /* 64GB max for x86_64 */
    2.15 +#define MCACHE_BUCKET_SHIFT 20
    2.16 +#endif
    2.17 +
    2.18 +#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)
    2.19 +
    2.20 +#define BITS_PER_LONG (sizeof(long)*8)
    2.21 +#define BITS_TO_LONGS(bits) \
    2.22 +    (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
    2.23 +#define DECLARE_BITMAP(name,bits) \
    2.24 +    unsigned long name[BITS_TO_LONGS(bits)]
    2.25 +#define test_bit(bit,map) \
    2.26 +    (!!((map)[(bit)/BITS_PER_LONG] & (1UL << ((bit)%BITS_PER_LONG))))
    2.27 +
    2.28 +struct map_cache {
    2.29 +    unsigned long paddr_index;
    2.30 +    uint8_t      *vaddr_base;
    2.31 +    DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>PAGE_SHIFT);
    2.32 +};
    2.33 +
    2.34  static struct map_cache *mapcache_entry;
    2.35  static unsigned long nr_buckets;
    2.36  
    2.37 @@ -5928,6 +5953,44 @@ static int qemu_map_cache_init(void)
    2.38      return 0;
    2.39  }
    2.40  
    2.41 +static void qemu_remap_bucket(struct map_cache *entry,
    2.42 +                              unsigned long address_index)
    2.43 +{
    2.44 +    uint8_t *vaddr_base;
    2.45 +    unsigned long pfns[MCACHE_BUCKET_SIZE >> PAGE_SHIFT];
    2.46 +    unsigned int i, j;
    2.47 +
    2.48 +    if (entry->vaddr_base != NULL) {
    2.49 +        errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
    2.50 +        if (errno) {
    2.51 +            fprintf(logfile, "unmap fails %d\n", errno);
    2.52 +            exit(-1);
    2.53 +        }
    2.54 +    }
    2.55 +
    2.56 +    for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i++)
    2.57 +        pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-PAGE_SHIFT)) + i;
    2.58 +
    2.59 +    vaddr_base = xc_map_foreign_batch(xc_handle, domid, PROT_READ|PROT_WRITE,
    2.60 +                                      pfns, MCACHE_BUCKET_SIZE >> PAGE_SHIFT);
    2.61 +    if (vaddr_base == NULL) {
    2.62 +        fprintf(logfile, "xc_map_foreign_batch error %d\n", errno);
    2.63 +        exit(-1);
    2.64 +    }
    2.65 +
    2.66 +    entry->vaddr_base  = vaddr_base;
    2.67 +    entry->paddr_index = address_index;
    2.68 +
    2.69 +    for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i += BITS_PER_LONG) {
    2.70 +        unsigned long word = 0;
    2.71 +        j = ((i + BITS_PER_LONG) > (MCACHE_BUCKET_SIZE >> PAGE_SHIFT)) ?
    2.72 +            (MCACHE_BUCKET_SIZE >> PAGE_SHIFT) % BITS_PER_LONG : BITS_PER_LONG;
    2.73 +        while (j > 0)
    2.74 +            word = (word << 1) | !(pfns[i + --j] & 0xF0000000UL);
    2.75 +        entry->valid_mapping[i / BITS_PER_LONG] = word;
    2.76 +    }
    2.77 +}
    2.78 +
    2.79  uint8_t *qemu_map_cache(target_phys_addr_t phys_addr)
    2.80  {
    2.81      struct map_cache *entry;
    2.82 @@ -5939,34 +6002,12 @@ uint8_t *qemu_map_cache(target_phys_addr
    2.83  
    2.84      entry = &mapcache_entry[address_index % nr_buckets];
    2.85  
    2.86 -    if (entry->vaddr_base == NULL || entry->paddr_index != address_index) {
    2.87 -        /* We need to remap a bucket. */
    2.88 -        uint8_t *vaddr_base;
    2.89 -        unsigned long pfns[MCACHE_BUCKET_SIZE >> PAGE_SHIFT];
    2.90 -        unsigned int i;
    2.91 -
    2.92 -        if (entry->vaddr_base != NULL) {
    2.93 -            errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
    2.94 -            if (errno) {
    2.95 -                fprintf(logfile, "unmap fails %d\n", errno);
    2.96 -                exit(-1);
    2.97 -            }
    2.98 -        }
    2.99 -
   2.100 -        for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i++)
   2.101 -            pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-PAGE_SHIFT)) + i;
   2.102 -
   2.103 -        vaddr_base = xc_map_foreign_batch(
   2.104 -            xc_handle, domid, PROT_READ|PROT_WRITE,
   2.105 -            pfns, MCACHE_BUCKET_SIZE >> PAGE_SHIFT);
   2.106 -        if (vaddr_base == NULL) {
   2.107 -            fprintf(logfile, "xc_map_foreign_batch error %d\n", errno);
   2.108 -            exit(-1);
   2.109 -        }
   2.110 -
   2.111 -        entry->vaddr_base  = vaddr_base;
   2.112 -        entry->paddr_index = address_index;;
   2.113 -    }
   2.114 +    if (entry->vaddr_base == NULL || entry->paddr_index != address_index ||
   2.115 +        !test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping))
   2.116 +        qemu_remap_bucket(entry, address_index);
   2.117 +
   2.118 +    if (!test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping))
   2.119 +        return NULL;
   2.120  
   2.121      last_address_index = address_index;
   2.122      last_address_vaddr = entry->vaddr_base;
   2.123 @@ -6001,7 +6042,8 @@ void qemu_invalidate_map_cache(void)
   2.124  
   2.125      mapcache_unlock();
   2.126  }
   2.127 -#endif
   2.128 +
   2.129 +#endif /* defined(MAPCACHE) */
   2.130  
   2.131  int main(int argc, char **argv)
   2.132  {
     3.1 --- a/tools/ioemu/vl.h	Mon Apr 09 11:12:15 2007 +0100
     3.2 +++ b/tools/ioemu/vl.h	Mon Apr 09 12:05:26 2007 +0100
     3.3 @@ -161,21 +161,6 @@ extern FILE *logfile;
     3.4  
     3.5  #define MAPCACHE
     3.6  
     3.7 -#if defined(__i386__) 
     3.8 -#define MAX_MCACHE_SIZE    0x40000000 /* 1GB max for x86 */
     3.9 -#define MCACHE_BUCKET_SHIFT 16
    3.10 -#elif defined(__x86_64__)
    3.11 -#define MAX_MCACHE_SIZE    0x1000000000 /* 64GB max for x86_64 */
    3.12 -#define MCACHE_BUCKET_SHIFT 20
    3.13 -#endif
    3.14 -
    3.15 -#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)
    3.16 -
    3.17 -struct map_cache {
    3.18 -    unsigned long paddr_index;
    3.19 -    uint8_t      *vaddr_base;
    3.20 -};
    3.21 -
    3.22  uint8_t *qemu_map_cache(target_phys_addr_t phys_addr);
    3.23  void     qemu_invalidate_map_cache(void);
    3.24