diff -r 2f8a7e5fd8ba tools/ioemu/hw/xen_platform.c --- a/tools/ioemu/hw/xen_platform.c Fri Jan 26 10:10:12 2007 +0000 +++ b/tools/ioemu/hw/xen_platform.c Fri Jan 26 22:16:29 2007 +0800 @@ -82,6 +82,61 @@ static void platform_mmio_map(PCIDevice cpu_register_physical_memory(addr, 0x1000000, mmio_io_addr); } +#if defined(__i386__) || defined(__x86_64__) +static void mapcache_invl_blk_addr_ioport_write(void *opaque, + uint32_t addr, uint32_t val) +{ + qemu_map_cache_set_invalid_block_addr(val, addr & 0x7, 1); +} + +static void mapcache_invl_blk_addr_ioport_writew(void *opaque, + uint32_t addr, uint32_t val) +{ + qemu_map_cache_set_invalid_block_addr(val, addr & 0x7, 2); +} + +static void mapcache_invl_blk_addr_ioport_writel(void *opaque, + uint32_t addr, uint32_t val) +{ + qemu_map_cache_set_invalid_block_addr(val, addr & 0x7, 4); +} + +static void mapcache_invl_blk_ioport_write(void *opaque, + uint32_t addr, uint32_t val) +{ + mapcache_lock(); + qemu_map_cache_invalidate_block(); + mapcache_unlock(); +} + +static void mapcache_ioport_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + register_ioport_write(addr, 8, 1, + mapcache_invl_blk_addr_ioport_write, NULL); + register_ioport_write(addr, 8, 2, + mapcache_invl_blk_addr_ioport_writew, NULL); + register_ioport_write(addr, 8, 4, + mapcache_invl_blk_addr_ioport_writel, NULL); + + register_ioport_write(addr + 8, 1, 1, + mapcache_invl_blk_ioport_write, NULL); + register_ioport_write(addr + 8, 2, 2, + mapcache_invl_blk_ioport_write, NULL); + register_ioport_write(addr + 8, 4, 4, + mapcache_invl_blk_ioport_write, NULL); +} + +/* reserved 16 I/O ports for invalidating Qemu mapcache */ +#define pci_register_io_region_for_mapcache() do { \ + pci_register_io_region(d, region_num, 0x10, PCI_ADDRESS_SPACE_IO, \ + mapcache_ioport_map); \ + ++region_num; \ + } while (0) +#else +#define pci_register_io_region_for_mapcache() (void(0)) +#endif + struct pci_config_header { uint16_t vendor_id; uint16_t device_id; @@ -112,6 +167,7 @@ void pci_xen_platform_init(PCIBus *bus) { PCIDevice *d; struct pci_config_header *pch; + int region_num = 0; printf("Register xen platform.\n"); d = pci_register_device(bus, "xen-platform", sizeof(PCIDevice), -1, NULL, @@ -132,12 +188,16 @@ void pci_xen_platform_init(PCIBus *bus) pch->subsystem_vendor_id = pch->vendor_id; /* Duplicate vendor id. */ pch->subsystem_id = 0x0001; /* Hardcode sub-id as 1. */ - pci_register_io_region(d, 0, 0x100, PCI_ADDRESS_SPACE_IO, + pci_register_io_region(d, region_num, 0x100, PCI_ADDRESS_SPACE_IO, platform_ioport_map); + ++region_num; /* reserve 16MB mmio address for share memory*/ - pci_register_io_region(d, 1, 0x1000000, PCI_ADDRESS_SPACE_MEM_PREFETCH, - platform_mmio_map); + pci_register_io_region(d, region_num, 0x1000000, + PCI_ADDRESS_SPACE_MEM_PREFETCH, platform_mmio_map); + ++region_num; + + pci_register_io_region_for_mapcache(); register_savevm("platform", 0, 1, generic_pci_save, generic_pci_load, d); printf("Done register platform.\n"); diff -r 2f8a7e5fd8ba tools/ioemu/target-i386-dm/exec-dm.c --- a/tools/ioemu/target-i386-dm/exec-dm.c Fri Jan 26 10:10:12 2007 +0000 +++ b/tools/ioemu/target-i386-dm/exec-dm.c Fri Jan 26 22:16:29 2007 +0800 @@ -129,18 +129,8 @@ int loglevel; int loglevel; -#if defined(__i386__) || defined(__x86_64__) -#define MAPCACHE -#endif - #ifdef MAPCACHE -#include -static pthread_mutex_t mapcache_mutex; -#define mapcache_lock() pthread_mutex_lock(&mapcache_mutex) -#define mapcache_unlock() pthread_mutex_unlock(&mapcache_mutex) -#else -#define mapcache_lock() ( (void)0 ) -#define mapcache_unlock() ( (void)0 ) +pthread_mutex_t mapcache_mutex; #endif diff -r 2f8a7e5fd8ba tools/ioemu/vl.c --- a/tools/ioemu/vl.c Fri Jan 26 10:10:12 2007 +0000 +++ b/tools/ioemu/vl.c Fri Jan 26 22:16:29 2007 +0800 @@ -285,7 +285,7 @@ int register_ioport_write(int start, int for(i = start; i < start + length; i += size) { ioport_write_table[bsize][i] = func; if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque) - hw_error("register_ioport_read: invalid opaque"); + hw_error("register_ioport_write: invalid opaque"); ioport_opaque[i] = opaque; } return 0; @@ -5826,6 +5826,12 @@ static struct map_cache *mapcache_entry; static struct map_cache *mapcache_entry; static unsigned long nr_buckets; +/* For most cases (>99.9%), the page address is the same. */ +static unsigned long last_address_index = ~0UL; +static uint8_t *last_address_vaddr; + +static uint64_t map_cache_invalid_block_addr; + static int qemu_map_cache_init(unsigned long nr_pages) { unsigned long max_pages = MAX_MCACHE_SIZE >> PAGE_SHIFT; @@ -5853,6 +5859,8 @@ static int qemu_map_cache_init(unsigned for (i = 0; i < nr_buckets; i++) (void)qemu_map_cache(((target_phys_addr_t)i) << MCACHE_BUCKET_SHIFT); + map_cache_invalid_block_addr = 0; + return 0; } @@ -5861,10 +5869,6 @@ uint8_t *qemu_map_cache(target_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; @@ -5904,6 +5908,53 @@ uint8_t *qemu_map_cache(target_phys_addr last_address_vaddr = entry->vaddr_base; return last_address_vaddr + address_offset; +} + +void qemu_map_cache_set_invalid_block_addr(uint64_t val, + unsigned int offset, + unsigned int len) +{ + uint64_t mask = ((1ULL << (len*8))-1) << (8*offset); + uint64_t tmp = map_cache_invalid_block_addr & ~mask; + + tmp |= (val << (8*offset)) & mask; + map_cache_invalid_block_addr = tmp; +} + +/* The addr of the guest physical memory block that HVM balloon driver wants + * Qemu to unmap must be a multiple of 1M, and the size of the block must be + * 1M bytes; if there are several 1M blocks, HVM balloon driver must let Qemu + * do the unmapping several times, one block each time. */ +#define MCACHE_INVALID_BLOCK_SIZE (1ULL << 20) +void qemu_map_cache_invalidate_block(void) +{ + unsigned long address_index = + map_cache_invalid_block_addr >> MCACHE_BUCKET_SHIFT; + int i; + + for (i = 0; i < MCACHE_INVALID_BLOCK_SIZE / MCACHE_BUCKET_SIZE; ++i) { + struct map_cache *entry = + &mapcache_entry[(address_index+i) % nr_buckets]; + + if (entry->vaddr_base == NULL || entry->paddr_index != address_index+i) + 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; + + if (address_index+i == last_address_index) { + last_address_index = ~0UL; + last_address_vaddr = NULL; + } + } + + map_cache_invalid_block_addr = 0; } #endif diff -r 2f8a7e5fd8ba tools/ioemu/vl.h --- a/tools/ioemu/vl.h Fri Jan 26 10:10:12 2007 +0000 +++ b/tools/ioemu/vl.h Fri Jan 26 22:16:29 2007 +0800 @@ -158,6 +158,7 @@ extern FILE *logfile; #if defined(__i386__) || defined(__x86_64__) +#define MAPCACHE #if defined(__i386__) #define MAX_MCACHE_SIZE 0x40000000 /* 1GB max for x86 */ #define MCACHE_BUCKET_SHIFT 16 @@ -174,6 +175,21 @@ struct map_cache { }; uint8_t *qemu_map_cache(target_phys_addr_t phys_addr); +void qemu_map_cache_set_invalid_block_addr(uint64_t val, + unsigned int offset, + unsigned int len); + +void qemu_map_cache_invalidate_block(void); +#endif + +#ifdef MAPCACHE +#include +extern pthread_mutex_t mapcache_mutex; +#define mapcache_lock() pthread_mutex_lock(&mapcache_mutex) +#define mapcache_unlock() pthread_mutex_unlock(&mapcache_mutex) +#else +#define mapcache_lock() ((void)0) +#define mapcache_unlock() ((void)0) #endif extern int xc_handle; diff -r 2f8a7e5fd8ba unmodified_drivers/linux-2.6/platform-pci/platform-pci.c --- a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c Fri Jan 26 10:10:12 2007 +0000 +++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c Fri Jan 26 22:16:58 2007 +0800 @@ -214,6 +214,27 @@ static uint64_t get_callback_via(struct #endif } +#define MCACHE_INVALID_BLOCK_SIZE (1ULL << 20) +#define MCACHE_INVALID_BLOCK_MASK (MCACHE_INVALID_BLOCK_SIZE - 1) + +/* I/O port range for invalidating Qemu mapcache */ +static uint16_t ioaddr_qmc, iolen_qmc; + +int invalidate_qemu_mapcache(uint64_t block_addr) +{ + /* the block_addr must be 1M-byte boundary aligned, and the size of */ + /* the memory block must be 1M bytes */ + if (block_addr & MCACHE_INVALID_BLOCK_MASK) + return -EINVAL; + + outl((uint32_t)block_addr, ioaddr_qmc); + outl((uint32_t)(block_addr >> 32), ioaddr_qmc + 4); + outb(0, ioaddr_qmc + 8); + + return 0; +} +EXPORT_SYMBOL(invalidate_qemu_mapcache); + static int __devinit platform_pci_init(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -232,9 +253,13 @@ static int __devinit platform_pci_init(s mmio_addr = pci_resource_start(pdev, 1); mmio_len = pci_resource_len(pdev, 1); + ioaddr_qmc = pci_resource_start(pdev, 2); + iolen_qmc = pci_resource_len(pdev, 2); + callback_via = get_callback_via(pdev); - if (mmio_addr == 0 || ioaddr == 0 || callback_via == 0) { + if (mmio_addr == 0 || ioaddr == 0 || ioaddr_qmc == 0 || iolen_qmc != 16 || + callback_via == 0) { printk(KERN_WARNING DRV_NAME ":no resources found\n"); return -ENOENT; }