Aliases were added to workaround kvm's inability to destroy memory regions. This was fixed in 2.6.29, and advertised via KVM_CAP_DESTROY_MEMORY_REGION_WORKS. Also, alias support will be removed from the kernel in July 2010. Signed-off-by: Marcelo Tosatti <mtosatti@xxxxxxxxxx> Index: qemu-kvm/qemu-kvm.c =================================================================== --- qemu-kvm.orig/qemu-kvm.c +++ qemu-kvm/qemu-kvm.c @@ -1076,20 +1076,6 @@ int kvm_deassign_pci_device(kvm_context_ } #endif -int kvm_destroy_memory_region_works(kvm_context_t kvm) -{ - int ret = 0; - -#ifdef KVM_CAP_DESTROY_MEMORY_REGION_WORKS - ret = - kvm_ioctl(kvm_state, KVM_CHECK_EXTENSION, - KVM_CAP_DESTROY_MEMORY_REGION_WORKS); - if (ret <= 0) - ret = 0; -#endif - return ret; -} - int kvm_reinject_control(kvm_context_t kvm, int pit_reinject) { #ifdef KVM_CAP_REINJECT_CONTROL @@ -2055,11 +2041,6 @@ int kvm_main_loop(void) return 0; } -#ifdef TARGET_I386 -static int destroy_region_works = 0; -#endif - - #if !defined(TARGET_I386) int kvm_arch_init_irq_routing(void) { @@ -2071,6 +2052,10 @@ extern int no_hpet; static int kvm_create_context(void) { + static const char upgrade_note[] = + "Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n" + "(see http://sourceforge.net/projects/kvm).\n"; + int r; if (!kvm_irqchip) { @@ -2094,9 +2079,16 @@ static int kvm_create_context(void) return -1; } } -#ifdef TARGET_I386 - destroy_region_works = kvm_destroy_memory_region_works(kvm_context); -#endif + + /* There was a nasty bug in < kvm-80 that prevents memory slots from being + * destroyed properly. Since we rely on this capability, refuse to work + * with any kernel without this capability. */ + if (!kvm_check_extension(kvm_state, KVM_CAP_DESTROY_MEMORY_REGION_WORKS)) { + fprintf(stderr, + "KVM kernel module broken (DESTROY_MEMORY_REGION).\n%s", + upgrade_note); + return -EINVAL; + } r = kvm_arch_init_irq_routing(); if (r < 0) { @@ -2134,73 +2126,11 @@ static int kvm_create_context(void) return 0; } -#ifdef TARGET_I386 -static int must_use_aliases_source(target_phys_addr_t addr) -{ - if (destroy_region_works) - return false; - if (addr == 0xa0000 || addr == 0xa8000) - return true; - return false; -} - -static int must_use_aliases_target(target_phys_addr_t addr) -{ - if (destroy_region_works) - return false; - if (addr >= 0xe0000000 && addr < 0x100000000ull) - return true; - return false; -} - -static struct mapping { - target_phys_addr_t phys; - ram_addr_t ram; - ram_addr_t len; -} mappings[50]; -static int nr_mappings; - -static struct mapping *find_ram_mapping(ram_addr_t ram_addr) -{ - struct mapping *p; - - for (p = mappings; p < mappings + nr_mappings; ++p) { - if (p->ram <= ram_addr && ram_addr < p->ram + p->len) { - return p; - } - } - return NULL; -} - -static struct mapping *find_mapping(target_phys_addr_t start_addr) -{ - struct mapping *p; - - for (p = mappings; p < mappings + nr_mappings; ++p) { - if (p->phys <= start_addr && start_addr < p->phys + p->len) { - return p; - } - } - return NULL; -} - -static void drop_mapping(target_phys_addr_t start_addr) -{ - struct mapping *p = find_mapping(start_addr); - - if (p) - *p = mappings[--nr_mappings]; -} -#endif - void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, ram_addr_t phys_offset) { int r = 0; unsigned long area_flags; -#ifdef TARGET_I386 - struct mapping *p; -#endif if (start_addr + size > phys_ram_size) { phys_ram_size = start_addr + size; @@ -2210,19 +2140,13 @@ void kvm_set_phys_mem(target_phys_addr_t area_flags = phys_offset & ~TARGET_PAGE_MASK; if (area_flags != IO_MEM_RAM) { -#ifdef TARGET_I386 - if (must_use_aliases_source(start_addr)) { - kvm_destroy_memory_alias(kvm_context, start_addr); - return; - } - if (must_use_aliases_target(start_addr)) - return; -#endif while (size > 0) { - p = find_mapping(start_addr); - if (p) { - kvm_unregister_memory_area(kvm_context, p->phys, p->len); - drop_mapping(p->phys); + int slot; + + slot = get_slot(start_addr); + if (slot != -1) { + kvm_unregister_memory_area(kvm_context, slots[slot].phys_addr, + slots[slot].len); } start_addr += TARGET_PAGE_SIZE; if (size > TARGET_PAGE_SIZE) { @@ -2241,30 +2165,12 @@ void kvm_set_phys_mem(target_phys_addr_t if (area_flags >= TLB_MMIO) return; -#ifdef TARGET_I386 - if (must_use_aliases_source(start_addr)) { - p = find_ram_mapping(phys_offset); - if (p) { - kvm_create_memory_alias(kvm_context, start_addr, size, - p->phys + (phys_offset - p->ram)); - } - return; - } -#endif - r = kvm_register_phys_mem(kvm_context, start_addr, qemu_get_ram_ptr(phys_offset), size, 0); if (r < 0) { printf("kvm_cpu_register_physical_memory: failed\n"); exit(1); } -#ifdef TARGET_I386 - drop_mapping(start_addr); - p = &mappings[nr_mappings++]; - p->phys = start_addr; - p->ram = phys_offset; - p->len = size; -#endif return; } @@ -2342,10 +2248,6 @@ void kvm_qemu_log_memory(target_phys_add if (log) kvm_dirty_pages_log_enable_slot(kvm_context, start, size); else { -#ifdef TARGET_I386 - if (must_use_aliases_target(start)) - return; -#endif kvm_dirty_pages_log_disable_slot(kvm_context, start, size); } } @@ -2418,12 +2320,6 @@ int kvm_physical_sync_dirty_bitmap(targe target_phys_addr_t end_addr) { #ifndef TARGET_IA64 - -#ifdef TARGET_I386 - if (must_use_aliases_source(start_addr)) - return 0; -#endif - kvm_get_dirty_pages_range(kvm_context, start_addr, end_addr - start_addr, NULL, kvm_get_dirty_bitmap_cb); @@ -2433,11 +2329,6 @@ int kvm_physical_sync_dirty_bitmap(targe int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t len) { -#ifdef TARGET_I386 - if (must_use_aliases_source(phys_addr)) - return 0; -#endif - #ifndef TARGET_IA64 kvm_qemu_log_memory(phys_addr, len, 1); #endif @@ -2446,11 +2337,6 @@ int kvm_log_start(target_phys_addr_t phy int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t len) { -#ifdef TARGET_I386 - if (must_use_aliases_source(phys_addr)) - return 0; -#endif - #ifndef TARGET_IA64 kvm_qemu_log_memory(phys_addr, len, 0); #endif Index: qemu-kvm/qemu-kvm-x86.c =================================================================== --- qemu-kvm.orig/qemu-kvm-x86.c +++ qemu-kvm/qemu-kvm-x86.c @@ -214,71 +214,6 @@ int kvm_arch_run(CPUState *env) return r; } -#define MAX_ALIAS_SLOTS 4 -static struct { - uint64_t start; - uint64_t len; -} kvm_aliases[MAX_ALIAS_SLOTS]; - -static int get_alias_slot(uint64_t start) -{ - int i; - - for (i=0; i<MAX_ALIAS_SLOTS; i++) - if (kvm_aliases[i].start == start) - return i; - return -1; -} -static int get_free_alias_slot(void) -{ - int i; - - for (i=0; i<MAX_ALIAS_SLOTS; i++) - if (kvm_aliases[i].len == 0) - return i; - return -1; -} - -static void register_alias(int slot, uint64_t start, uint64_t len) -{ - kvm_aliases[slot].start = start; - kvm_aliases[slot].len = len; -} - -int kvm_create_memory_alias(kvm_context_t kvm, - uint64_t phys_start, - uint64_t len, - uint64_t target_phys) -{ - struct kvm_memory_alias alias = { - .flags = 0, - .guest_phys_addr = phys_start, - .memory_size = len, - .target_phys_addr = target_phys, - }; - int r; - int slot; - - slot = get_alias_slot(phys_start); - if (slot < 0) - slot = get_free_alias_slot(); - if (slot < 0) - return -EBUSY; - alias.slot = slot; - - r = kvm_vm_ioctl(kvm_state, KVM_SET_MEMORY_ALIAS, &alias); - if (r == -1) - return -errno; - - register_alias(slot, phys_start, len); - return 0; -} - -int kvm_destroy_memory_alias(kvm_context_t kvm, uint64_t phys_start) -{ - return kvm_create_memory_alias(kvm, phys_start, 0, 0); -} - #ifdef KVM_CAP_IRQCHIP int kvm_get_lapic(CPUState *env, struct kvm_lapic_state *s) @@ -616,18 +551,6 @@ static int kvm_enable_tpr_access_reporti } #endif -int kvm_qemu_create_memory_alias(uint64_t phys_start, - uint64_t len, - uint64_t target_phys) -{ - return kvm_create_memory_alias(kvm_context, phys_start, len, target_phys); -} - -int kvm_qemu_destroy_memory_alias(uint64_t phys_start) -{ - return kvm_destroy_memory_alias(kvm_context, phys_start); -} - #ifdef KVM_CAP_ADJUST_CLOCK static struct kvm_clock_data kvmclock_data; Index: qemu-kvm/qemu-kvm.h =================================================================== --- qemu-kvm.orig/qemu-kvm.h +++ qemu-kvm/qemu-kvm.h @@ -400,23 +400,6 @@ int kvm_unregister_coalesced_mmio(kvm_co uint32_t size); /*! - * \brief Create a memory alias - * - * Aliases a portion of physical memory to another portion. If the guest - * accesses the alias region, it will behave exactly as if it accessed - * the target memory. - */ -int kvm_create_memory_alias(kvm_context_t, uint64_t phys_start, uint64_t len, - uint64_t target_phys); - -/*! - * \brief Destroy a memory alias - * - * Removes an alias created with kvm_create_memory_alias(). - */ -int kvm_destroy_memory_alias(kvm_context_t, uint64_t phys_start); - -/*! * \brief Get a bitmap of guest ram pages which are allocated to the guest. * * \param kvm Pointer to the current kvm_context @@ -651,15 +634,6 @@ int kvm_deassign_irq(kvm_context_t kvm, #endif #endif -/*! - * \brief Determines whether destroying memory regions is allowed - * - * KVM before 2.6.29 had a bug when destroying memory regions. - * - * \param kvm Pointer to the current kvm_context - */ -int kvm_destroy_memory_region_works(kvm_context_t kvm); - #ifdef KVM_CAP_DEVICE_DEASSIGNMENT /*! * \brief Notifies host kernel about a PCI device to be deassigned from a guest -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html