diff -r 30cdeb686b93 tools/ioemu/cpu-defs.h --- a/tools/ioemu/cpu-defs.h Sat Jul 8 18:22:34 2006 +++ b/tools/ioemu/cpu-defs.h Sun Jul 9 17:32:55 2006 @@ -34,6 +34,8 @@ #else #define HOST_LONG_BITS 32 #endif + +#define TARGET_PHYS_ADDR_BITS 64 #ifndef TARGET_PHYS_ADDR_BITS #if TARGET_LONG_BITS >= HOST_LONG_BITS diff -r 30cdeb686b93 tools/ioemu/cpu.h --- a/tools/ioemu/cpu.h Sat Jul 8 18:22:34 2006 +++ b/tools/ioemu/cpu.h Sun Jul 9 17:32:55 2006 @@ -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 #endif /* target supports implicit self modifying code */ diff -r 30cdeb686b93 tools/ioemu/exec.c --- a/tools/ioemu/exec.c Sat Jul 8 18:22:34 2006 +++ b/tools/ioemu/exec.c Sun Jul 9 17:32:55 2006 @@ -34,6 +34,7 @@ #include "cpu.h" #include "exec-all.h" +#include "vl.h" //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH @@ -386,6 +387,12 @@ } #endif +#if defined(__i386__) || defined(__x86_64__) +#define phys_ram_addr(x) ((uint8_t *)(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) { @@ -403,6 +410,25 @@ pd = page; io_index = iomem_index(page); + +#if defined(__i386__) || defined(__x86_64__) + if ( !io_index ) + { + uint8_t *mc_pd = 0; + + /* + * The above ensures that copy happen within the page. We + * need to check when acrossing the MAPCACHE_BUCKET_SIZE boundary. + */ + if ( !(page % MCACHE_BUCKET_SIZE) ) + mc_pd = 0; + if ( !mc_pd ) + mc_pd = xen_map_cache(page); + + pd = (unsigned long) mc_pd; + } +#endif + if (is_write) { if (io_index) { if (l >= 4 && ((addr & 3) == 0)) { @@ -426,7 +452,7 @@ addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); /* RAM case */ - ptr = phys_ram_base + addr1; + ptr = phys_ram_addr(addr1); memcpy(ptr, buf, l); #ifdef __ia64__ sync_icache((unsigned long)ptr,l); @@ -452,8 +478,8 @@ } } else { /* RAM case */ - ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + - (addr & ~TARGET_PAGE_MASK); + ptr = phys_ram_addr((pd & TARGET_PAGE_MASK) + + (unsigned long)(addr & ~TARGET_PAGE_MASK)); memcpy(buf, ptr, l); } } diff -r 30cdeb686b93 tools/ioemu/vl.c --- a/tools/ioemu/vl.c Sat Jul 8 18:22:34 2006 +++ b/tools/ioemu/vl.c Sun Jul 9 17:32:55 2006 @@ -2664,6 +2664,109 @@ return 0; } +#if defined(__i386__) || defined(__x86_64__) +static struct map_cache *mapcache_entry; +static unsigned long nr_buckets; + +static inline struct map_cache * +get_hash_bucket(target_phys_addr_t addr) +{ + return &mapcache_entry[(addr >> MCACHE_BUCKET_SHIFT) % nr_buckets]; +} + +/* + * For most cases (>99.9%), the page address is same. + */ +target_phys_addr_t last_page = ~0LL; +uint8_t *last_page_mapped; + +#define likely(x) __builtin_expect((x),1) + +static int xen_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, "map_cache_init nr_buckets = %lx\n", nr_buckets); + + if ( (mapcache_entry = + (struct map_cache *)malloc(nr_buckets * sizeof(struct map_cache))) == NULL ) + { + errno = ENOMEM; + return errno; + } + + memset(mapcache_entry, 0, nr_buckets * sizeof(struct map_cache)); + + /* + * To avoid ENOMEM from xc_map_foreign_batch() at runtime, we + * pre-fill the all the map caches at front. + */ + for (i = 0; i < nr_buckets; i++) + (void)xen_map_cache((target_phys_addr_t)(i << MCACHE_BUCKET_SHIFT)); + + return 0; +} + +uint8_t *xen_map_cache(target_phys_addr_t page) +{ + struct map_cache *entry; + + if ( likely(page == last_page) ) + return last_page_mapped; + + entry = get_hash_bucket(page); + + if ( entry->mc_addr == 0 || entry->phys_addr != (page & MCACHE_BUCKET_MASK) ) + { + /* + * We need to remap the existing mapping. First unmap if existing mapping + * is there. + */ + uint8_t *mc_addr; + unsigned long pfn = (page & MCACHE_BUCKET_MASK) >> PAGE_SHIFT; + + if ( entry->mc_addr ) + { + errno = munmap(entry->mc_addr, MCACHE_BUCKET_SIZE); + + if ( errno ) + { + fprintf(logfile, "unmap fails %d\n", errno); + exit(-1); + } + } + + if ( (mc_addr = xc_map_foreign_batch( + xc_handle, domid, + PROT_READ|PROT_WRITE, + &page_array[pfn], + (MCACHE_BUCKET_SIZE >> PAGE_SHIFT))) == 0 ) + { + + fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno); + exit(-1); + } + + entry->mc_addr = mc_addr; + entry->phys_addr = page & MCACHE_BUCKET_MASK; + entry->map_count++; + } + + last_page = page; + last_page_mapped = (uint8_t *)(entry->mc_addr + (page & ~MCACHE_BUCKET_MASK)); + + return last_page_mapped; +} +#endif + +xen_pfn_t *page_array; + int main(int argc, char **argv) { #ifdef CONFIG_GDBSTUB @@ -2691,7 +2794,7 @@ char qemu_dm_logfilename[64]; const char *loadvm = NULL; unsigned long nr_pages; - xen_pfn_t *page_array; + extern void *shared_page; #if !defined(CONFIG_SOFTMMU) @@ -2947,7 +3050,7 @@ help(); break; case QEMU_OPTION_m: - ram_size = atol(optarg) * 1024 * 1024; + ram_size = (uint64_t)atol(optarg) * 1024 * 1024; if (ram_size <= 0) help(); break; @@ -3185,12 +3288,10 @@ fprintf(logfile, "xc_get_pfn_list returned error %d\n", errno); exit(-1); } - if ( (phys_ram_base = xc_map_foreign_batch(xc_handle, domid, - PROT_READ|PROT_WRITE, - page_array, - nr_pages - 1)) == 0 ) + + if ( xen_map_cache_init(nr_pages) ) { - fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno); + fprintf(logfile, "map_cache_init returned error %d\n", errno); exit(-1); } diff -r 30cdeb686b93 tools/ioemu/vl.h --- a/tools/ioemu/vl.h Sat Jul 8 18:22:34 2006 +++ b/tools/ioemu/vl.h Sun Jul 9 17:32:55 2006 @@ -126,6 +126,29 @@ unsigned int address_bits, unsigned long *extent_start); +extern unsigned long *page_array; +#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) +#define MCACHE_BUCKET_MASK ~(MCACHE_BUCKET_SIZE - 1) + +struct map_cache +{ + target_phys_addr_t phys_addr; /* MCACHE_BUCKET_SIZE unit */ + uint8_t *mc_addr; /* virtual address */ + unsigned int map_count; /* how many times remapped? */ +}; + +uint8_t *xen_map_cache(target_phys_addr_t phys_addr); +#endif + extern int xc_handle; extern int domid; extern int audio_enabled;