diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/ioemu/target-i386-dm/cpu.h | 3 | ||||
-rw-r--r-- | tools/ioemu/target-i386-dm/exec-dm.c | 17 | ||||
-rw-r--r-- | tools/ioemu/vl.c | 124 | ||||
-rw-r--r-- | tools/ioemu/vl.h | 20 |
4 files changed, 136 insertions, 28 deletions
diff --git a/tools/ioemu/target-i386-dm/cpu.h b/tools/ioemu/target-i386-dm/cpu.h index dc016edd3e..017b8c021b 100644 --- a/tools/ioemu/target-i386-dm/cpu.h +++ b/tools/ioemu/target-i386-dm/cpu.h @@ -25,7 +25,8 @@ #ifdef TARGET_X86_64 #define TARGET_LONG_BITS 64 #else -#define TARGET_LONG_BITS 32 +/* #define TARGET_LONG_BITS 32 */ +#define TARGET_LONG_BITS 64 /* for Qemu map cache */ #endif /* target supports implicit self modifying code */ diff --git a/tools/ioemu/target-i386-dm/exec-dm.c b/tools/ioemu/target-i386-dm/exec-dm.c index be8b280dda..755d547772 100644 --- a/tools/ioemu/target-i386-dm/exec-dm.c +++ b/tools/ioemu/target-i386-dm/exec-dm.c @@ -36,6 +36,7 @@ #include "cpu.h" #include "exec-all.h" +#include "vl.h" //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH @@ -426,6 +427,12 @@ static inline int paddr_is_ram(target_phys_addr_t addr) #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)) +#endif + void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write) { @@ -438,7 +445,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK); if (l > len) l = len; - + io_index = iomem_index(addr); if (is_write) { if (io_index) { @@ -460,9 +467,10 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } } else if (paddr_is_ram(addr)) { /* Reading from RAM */ - memcpy(phys_ram_base + addr, buf, l); + ptr = phys_ram_addr(addr); + memcpy(ptr, buf, l); #ifdef __ia64__ - sync_icache((unsigned long)(phys_ram_base + addr), l); + sync_icache(ptr, l); #endif } } else { @@ -485,7 +493,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } } else if (paddr_is_ram(addr)) { /* Reading from RAM */ - memcpy(buf, phys_ram_base + addr, l); + ptr = phys_ram_addr(addr); + memcpy(buf, ptr, l); } else { /* Neither RAM nor known MMIO space */ memset(buf, 0xff, len); diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index a2700ef313..b65f61d8df 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -5808,6 +5808,92 @@ int set_mm_mapping(int xc_handle, uint32_t domid, return 0; } +#if defined(__i386__) || defined(__x86_64__) +static struct map_cache *mapcache_entry; +static unsigned long nr_buckets; + +static int qemu_map_cache_init(unsigned long nr_pages) +{ + unsigned long max_pages = MAX_MCACHE_SIZE >> PAGE_SHIFT; + int i; + + if (nr_pages < max_pages) + max_pages = nr_pages; + + nr_buckets = (max_pages << PAGE_SHIFT) >> MCACHE_BUCKET_SHIFT; + + fprintf(logfile, "qemu_map_cache_init nr_buckets = %lx\n", nr_buckets); + + mapcache_entry = malloc(nr_buckets * sizeof(struct map_cache)); + if (mapcache_entry == NULL) { + errno = ENOMEM; + return -1; + } + + memset(mapcache_entry, 0, nr_buckets * sizeof(struct map_cache)); + + /* + * To avoid ENOMEM from xc_map_foreign_batch() at runtime, we + * pre-fill all the map caches in advance. + */ + for (i = 0; i < nr_buckets; i++) + (void)qemu_map_cache(((target_phys_addr_t)i) << MCACHE_BUCKET_SHIFT); + + 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); + + /* For most cases (>99.9%), the page address is the same. */ + static unsigned long last_address_index = ~0UL; + static uint8_t *last_address_vaddr; + + 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; +} +#endif + int main(int argc, char **argv) { #ifdef CONFIG_GDBSTUB @@ -6130,6 +6216,7 @@ int main(int argc, char **argv) break; case QEMU_OPTION_m: ram_size = atol(optarg) * 1024 * 1024; + ram_size = (uint64_t)atol(optarg) * 1024 * 1024; if (ram_size <= 0) help(); #ifndef CONFIG_DM @@ -6400,50 +6487,41 @@ int main(int argc, char **argv) shared_page_nr = nr_pages - 1; #endif - page_array = (xen_pfn_t *)malloc(tmp_nr_pages * sizeof(xen_pfn_t)); - if (page_array == NULL) { - fprintf(logfile, "malloc returned error %d\n", errno); - exit(-1); - } - #if defined(__i386__) || defined(__x86_64__) - for ( i = 0; i < tmp_nr_pages; i++) - page_array[i] = i; - phys_ram_base = xc_map_foreign_batch(xc_handle, domid, - PROT_READ|PROT_WRITE, page_array, - tmp_nr_pages); - if (phys_ram_base == NULL) { - fprintf(logfile, "batch map guest memory returned error %d\n", errno); + if ( qemu_map_cache_init(tmp_nr_pages) ) + { + fprintf(logfile, "qemu_map_cache_init returned: error %d\n", errno); exit(-1); } shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, - page_array[shared_page_nr]); + PROT_READ|PROT_WRITE, shared_page_nr); if (shared_page == NULL) { fprintf(logfile, "map shared IO page returned error %d\n", errno); exit(-1); } - fprintf(logfile, "shared page at pfn:%lx, mfn: %"PRIx64"\n", - shared_page_nr, (uint64_t)(page_array[shared_page_nr])); + fprintf(logfile, "shared page at pfn:%lx\n", shared_page_nr); buffered_io_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ|PROT_WRITE, - page_array[shared_page_nr - 2]); + shared_page_nr - 2); if (buffered_io_page == NULL) { fprintf(logfile, "map buffered IO page returned error %d\n", errno); exit(-1); } - fprintf(logfile, "buffered io page at pfn:%lx, mfn: %"PRIx64"\n", - shared_page_nr - 2, (uint64_t)(page_array[shared_page_nr - 2])); - - free(page_array); + fprintf(logfile, "buffered io page at pfn:%lx\n", shared_page_nr - 2); #elif defined(__ia64__) - + + page_array = (xen_pfn_t *)malloc(tmp_nr_pages * sizeof(xen_pfn_t)); + if (page_array == NULL) { + fprintf(logfile, "malloc returned error %d\n", errno); + exit(-1); + } + if (xc_ia64_get_pfn_list(xc_handle, domid, page_array, IO_PAGE_START >> PAGE_SHIFT, 3) != 3) { fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index 3df963241c..9e4d92a17b 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -156,6 +156,26 @@ extern void *shared_vram; extern FILE *logfile; + +#if defined(__i386__) || defined(__x86_64__) +#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); +#endif + extern int xc_handle; extern int domid; |