129443dabSPekka Enberg #include "kvm/kvm.h" 29b735910SMarc Zyngier #include "kvm/kvm-cpu.h" 36b1994caSSasha Levin #include "kvm/rbtree-interval.h" 409577ac5SAlexandru Elisei #include "kvm/mutex.h" 529443dabSPekka Enberg 629443dabSPekka Enberg #include <stdio.h> 76b1994caSSasha Levin #include <stdlib.h> 86b1994caSSasha Levin 973f7e5b3SSasha Levin #include <sys/ioctl.h> 1073f7e5b3SSasha Levin #include <linux/kvm.h> 113fdf659dSSasha Levin #include <linux/types.h> 126b1994caSSasha Levin #include <linux/rbtree.h> 13495fbd4eSSasha Levin #include <linux/err.h> 14495fbd4eSSasha Levin #include <errno.h> 156b1994caSSasha Levin 166b1994caSSasha Levin #define mmio_node(n) rb_entry(n, struct mmio_mapping, node) 176b1994caSSasha Levin 1809577ac5SAlexandru Elisei static DEFINE_MUTEX(mmio_lock); 1909577ac5SAlexandru Elisei 206b1994caSSasha Levin struct mmio_mapping { 216b1994caSSasha Levin struct rb_int_node node; 22*96f0c86cSAndre Przywara mmio_handler_fn mmio_fn; 23d0b0df59SSasha Levin void *ptr; 2409577ac5SAlexandru Elisei u32 refcount; 2509577ac5SAlexandru Elisei bool remove; 266b1994caSSasha Levin }; 276b1994caSSasha Levin 286b1994caSSasha Levin static struct rb_root mmio_tree = RB_ROOT; 29*96f0c86cSAndre Przywara static struct rb_root pio_tree = RB_ROOT; 306b1994caSSasha Levin 316b1994caSSasha Levin static struct mmio_mapping *mmio_search(struct rb_root *root, u64 addr, u64 len) 326b1994caSSasha Levin { 336b1994caSSasha Levin struct rb_int_node *node; 346b1994caSSasha Levin 356b1994caSSasha Levin node = rb_int_search_range(root, addr, addr + len); 366b1994caSSasha Levin if (node == NULL) 376b1994caSSasha Levin return NULL; 386b1994caSSasha Levin 396b1994caSSasha Levin return mmio_node(node); 406b1994caSSasha Levin } 416b1994caSSasha Levin 426b1994caSSasha Levin /* Find lowest match, Check for overlap */ 436b1994caSSasha Levin static struct mmio_mapping *mmio_search_single(struct rb_root *root, u64 addr) 446b1994caSSasha Levin { 456b1994caSSasha Levin struct rb_int_node *node; 466b1994caSSasha Levin 476b1994caSSasha Levin node = rb_int_search_single(root, addr); 486b1994caSSasha Levin if (node == NULL) 496b1994caSSasha Levin return NULL; 506b1994caSSasha Levin 516b1994caSSasha Levin return mmio_node(node); 526b1994caSSasha Levin } 536b1994caSSasha Levin 546b1994caSSasha Levin static int mmio_insert(struct rb_root *root, struct mmio_mapping *data) 556b1994caSSasha Levin { 566b1994caSSasha Levin return rb_int_insert(root, &data->node); 576b1994caSSasha Levin } 5829443dabSPekka Enberg 5909577ac5SAlexandru Elisei static void mmio_remove(struct rb_root *root, struct mmio_mapping *data) 6009577ac5SAlexandru Elisei { 6109577ac5SAlexandru Elisei rb_int_erase(root, &data->node); 6209577ac5SAlexandru Elisei } 6309577ac5SAlexandru Elisei 643fdf659dSSasha Levin static const char *to_direction(u8 is_write) 6529443dabSPekka Enberg { 6629443dabSPekka Enberg if (is_write) 6729443dabSPekka Enberg return "write"; 6829443dabSPekka Enberg 6929443dabSPekka Enberg return "read"; 7029443dabSPekka Enberg } 7129443dabSPekka Enberg 7209577ac5SAlexandru Elisei static struct mmio_mapping *mmio_get(struct rb_root *root, u64 phys_addr, u32 len) 7309577ac5SAlexandru Elisei { 7409577ac5SAlexandru Elisei struct mmio_mapping *mmio; 7509577ac5SAlexandru Elisei 7609577ac5SAlexandru Elisei mutex_lock(&mmio_lock); 7709577ac5SAlexandru Elisei mmio = mmio_search(root, phys_addr, len); 7809577ac5SAlexandru Elisei if (mmio) 7909577ac5SAlexandru Elisei mmio->refcount++; 8009577ac5SAlexandru Elisei mutex_unlock(&mmio_lock); 8109577ac5SAlexandru Elisei 8209577ac5SAlexandru Elisei return mmio; 8309577ac5SAlexandru Elisei } 8409577ac5SAlexandru Elisei 8509577ac5SAlexandru Elisei /* Called with mmio_lock held. */ 8609577ac5SAlexandru Elisei static void mmio_deregister(struct kvm *kvm, struct rb_root *root, struct mmio_mapping *mmio) 8709577ac5SAlexandru Elisei { 8809577ac5SAlexandru Elisei struct kvm_coalesced_mmio_zone zone = (struct kvm_coalesced_mmio_zone) { 8909577ac5SAlexandru Elisei .addr = rb_int_start(&mmio->node), 9009577ac5SAlexandru Elisei .size = 1, 9109577ac5SAlexandru Elisei }; 9209577ac5SAlexandru Elisei ioctl(kvm->vm_fd, KVM_UNREGISTER_COALESCED_MMIO, &zone); 9309577ac5SAlexandru Elisei 9409577ac5SAlexandru Elisei mmio_remove(root, mmio); 9509577ac5SAlexandru Elisei free(mmio); 9609577ac5SAlexandru Elisei } 9709577ac5SAlexandru Elisei 9809577ac5SAlexandru Elisei static void mmio_put(struct kvm *kvm, struct rb_root *root, struct mmio_mapping *mmio) 9909577ac5SAlexandru Elisei { 10009577ac5SAlexandru Elisei mutex_lock(&mmio_lock); 10109577ac5SAlexandru Elisei mmio->refcount--; 10209577ac5SAlexandru Elisei if (mmio->remove && mmio->refcount == 0) 10309577ac5SAlexandru Elisei mmio_deregister(kvm, root, mmio); 10409577ac5SAlexandru Elisei mutex_unlock(&mmio_lock); 10509577ac5SAlexandru Elisei } 10609577ac5SAlexandru Elisei 107*96f0c86cSAndre Przywara static bool trap_is_mmio(unsigned int flags) 108*96f0c86cSAndre Przywara { 109*96f0c86cSAndre Przywara return (flags & IOTRAP_BUS_MASK) == DEVICE_BUS_MMIO; 110*96f0c86cSAndre Przywara } 111*96f0c86cSAndre Przywara 112*96f0c86cSAndre Przywara int kvm__register_iotrap(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, 113*96f0c86cSAndre Przywara mmio_handler_fn mmio_fn, void *ptr, 114*96f0c86cSAndre Przywara unsigned int flags) 1156b1994caSSasha Levin { 1166b1994caSSasha Levin struct mmio_mapping *mmio; 11773f7e5b3SSasha Levin struct kvm_coalesced_mmio_zone zone; 118f588adbbSSasha Levin int ret; 1196b1994caSSasha Levin 1206b1994caSSasha Levin mmio = malloc(sizeof(*mmio)); 1216b1994caSSasha Levin if (mmio == NULL) 122495fbd4eSSasha Levin return -ENOMEM; 1236b1994caSSasha Levin 1246b1994caSSasha Levin *mmio = (struct mmio_mapping) { 1256b1994caSSasha Levin .node = RB_INT_INIT(phys_addr, phys_addr + phys_addr_len), 126d0b0df59SSasha Levin .mmio_fn = mmio_fn, 127d0b0df59SSasha Levin .ptr = ptr, 12809577ac5SAlexandru Elisei /* 12909577ac5SAlexandru Elisei * Start from 0 because kvm__deregister_mmio() doesn't decrement 13009577ac5SAlexandru Elisei * the reference count. 13109577ac5SAlexandru Elisei */ 13209577ac5SAlexandru Elisei .refcount = 0, 13309577ac5SAlexandru Elisei .remove = false, 1346b1994caSSasha Levin }; 1356b1994caSSasha Levin 136*96f0c86cSAndre Przywara if (trap_is_mmio(flags) && (flags & IOTRAP_COALESCE)) { 13773f7e5b3SSasha Levin zone = (struct kvm_coalesced_mmio_zone) { 13873f7e5b3SSasha Levin .addr = phys_addr, 13973f7e5b3SSasha Levin .size = phys_addr_len, 14073f7e5b3SSasha Levin }; 14173f7e5b3SSasha Levin ret = ioctl(kvm->vm_fd, KVM_REGISTER_COALESCED_MMIO, &zone); 14273f7e5b3SSasha Levin if (ret < 0) { 14373f7e5b3SSasha Levin free(mmio); 144495fbd4eSSasha Levin return -errno; 14573f7e5b3SSasha Levin } 1469aa9d62aSSasha Levin } 147*96f0c86cSAndre Przywara 14809577ac5SAlexandru Elisei mutex_lock(&mmio_lock); 149*96f0c86cSAndre Przywara if (trap_is_mmio(flags)) 150f588adbbSSasha Levin ret = mmio_insert(&mmio_tree, mmio); 151*96f0c86cSAndre Przywara else 152*96f0c86cSAndre Przywara ret = mmio_insert(&pio_tree, mmio); 15309577ac5SAlexandru Elisei mutex_unlock(&mmio_lock); 154f588adbbSSasha Levin 155f588adbbSSasha Levin return ret; 1566b1994caSSasha Levin } 1576b1994caSSasha Levin 158*96f0c86cSAndre Przywara bool kvm__deregister_iotrap(struct kvm *kvm, u64 phys_addr, unsigned int flags) 1596b1994caSSasha Levin { 1606b1994caSSasha Levin struct mmio_mapping *mmio; 161*96f0c86cSAndre Przywara struct rb_root *tree; 162*96f0c86cSAndre Przywara 163*96f0c86cSAndre Przywara if (trap_is_mmio(flags)) 164*96f0c86cSAndre Przywara tree = &mmio_tree; 165*96f0c86cSAndre Przywara else 166*96f0c86cSAndre Przywara tree = &pio_tree; 1676b1994caSSasha Levin 16809577ac5SAlexandru Elisei mutex_lock(&mmio_lock); 169*96f0c86cSAndre Przywara mmio = mmio_search_single(tree, phys_addr); 170f588adbbSSasha Levin if (mmio == NULL) { 17109577ac5SAlexandru Elisei mutex_unlock(&mmio_lock); 1726b1994caSSasha Levin return false; 173f588adbbSSasha Levin } 17409577ac5SAlexandru Elisei /* 17509577ac5SAlexandru Elisei * The PCI emulation code calls this function when memory access is 17609577ac5SAlexandru Elisei * disabled for a device, or when a BAR has a new address assigned. PCI 17709577ac5SAlexandru Elisei * emulation doesn't use any locks and as a result we can end up in a 17809577ac5SAlexandru Elisei * situation where we have called mmio_get() to do emulation on one VCPU 17909577ac5SAlexandru Elisei * thread (let's call it VCPU0), and several other VCPU threads have 18009577ac5SAlexandru Elisei * called kvm__deregister_mmio(). In this case, if we decrement refcount 18109577ac5SAlexandru Elisei * kvm__deregister_mmio() (either directly, or by calling mmio_put()), 18209577ac5SAlexandru Elisei * refcount will reach 0 and we will free the mmio node before VCPU0 has 18309577ac5SAlexandru Elisei * called mmio_put(). This will trigger use-after-free errors on VCPU0. 18409577ac5SAlexandru Elisei */ 18509577ac5SAlexandru Elisei if (mmio->refcount == 0) 186*96f0c86cSAndre Przywara mmio_deregister(kvm, tree, mmio); 18709577ac5SAlexandru Elisei else 18809577ac5SAlexandru Elisei mmio->remove = true; 18909577ac5SAlexandru Elisei mutex_unlock(&mmio_lock); 1906b1994caSSasha Levin 1916b1994caSSasha Levin return true; 1926b1994caSSasha Levin } 1936b1994caSSasha Levin 194*96f0c86cSAndre Przywara bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, 195*96f0c86cSAndre Przywara u32 len, u8 is_write) 19629443dabSPekka Enberg { 197f588adbbSSasha Levin struct mmio_mapping *mmio; 198f588adbbSSasha Levin 19909577ac5SAlexandru Elisei mmio = mmio_get(&mmio_tree, phys_addr, len); 20009577ac5SAlexandru Elisei if (!mmio) { 2019b735910SMarc Zyngier if (vcpu->kvm->cfg.mmio_debug) 2023fdf659dSSasha Levin fprintf(stderr, "Warning: Ignoring MMIO %s at %016llx (length %u)\n", 20369f50425SAndreas Herrmann to_direction(is_write), 20469f50425SAndreas Herrmann (unsigned long long)phys_addr, len); 20509577ac5SAlexandru Elisei goto out; 206d562e086SCyrill Gorcunov } 20729443dabSPekka Enberg 20809577ac5SAlexandru Elisei mmio->mmio_fn(vcpu, phys_addr, data, len, is_write, mmio->ptr); 20909577ac5SAlexandru Elisei mmio_put(vcpu->kvm, &mmio_tree, mmio); 21009577ac5SAlexandru Elisei 21109577ac5SAlexandru Elisei out: 21229443dabSPekka Enberg return true; 21329443dabSPekka Enberg } 214*96f0c86cSAndre Przywara 215*96f0c86cSAndre Przywara bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data, 216*96f0c86cSAndre Przywara int direction, int size, u32 count) 217*96f0c86cSAndre Przywara { 218*96f0c86cSAndre Przywara struct mmio_mapping *mmio; 219*96f0c86cSAndre Przywara bool is_write = direction == KVM_EXIT_IO_OUT; 220*96f0c86cSAndre Przywara 221*96f0c86cSAndre Przywara mmio = mmio_get(&pio_tree, port, size); 222*96f0c86cSAndre Przywara if (!mmio) { 223*96f0c86cSAndre Przywara if (vcpu->kvm->cfg.ioport_debug) { 224*96f0c86cSAndre Przywara fprintf(stderr, "IO error: %s port=%x, size=%d, count=%u\n", 225*96f0c86cSAndre Przywara to_direction(direction), port, size, count); 226*96f0c86cSAndre Przywara 227*96f0c86cSAndre Przywara return false; 228*96f0c86cSAndre Przywara } 229*96f0c86cSAndre Przywara return true; 230*96f0c86cSAndre Przywara } 231*96f0c86cSAndre Przywara 232*96f0c86cSAndre Przywara while (count--) { 233*96f0c86cSAndre Przywara mmio->mmio_fn(vcpu, port, data, size, is_write, mmio->ptr); 234*96f0c86cSAndre Przywara 235*96f0c86cSAndre Przywara data += size; 236*96f0c86cSAndre Przywara } 237*96f0c86cSAndre Przywara 238*96f0c86cSAndre Przywara mmio_put(vcpu->kvm, &pio_tree, mmio); 239*96f0c86cSAndre Przywara 240*96f0c86cSAndre Przywara return true; 241*96f0c86cSAndre Przywara } 242