Merge branch 'perf/urgent'
[linux-2.6/x86.git] / tools / kvm / mmio.c
blob64bef37d3e2110c6bcfcd1ff3b49bdc367f88d81
1 #include "kvm/kvm.h"
2 #include "kvm/rbtree-interval.h"
3 #include "kvm/brlock.h"
5 #include <stdio.h>
6 #include <stdlib.h>
8 #include <sys/ioctl.h>
9 #include <linux/kvm.h>
10 #include <linux/types.h>
11 #include <linux/rbtree.h>
13 #define mmio_node(n) rb_entry(n, struct mmio_mapping, node)
15 struct mmio_mapping {
16 struct rb_int_node node;
17 void (*kvm_mmio_callback_fn)(u64 addr, u8 *data, u32 len, u8 is_write);
20 static struct rb_root mmio_tree = RB_ROOT;
22 static struct mmio_mapping *mmio_search(struct rb_root *root, u64 addr, u64 len)
24 struct rb_int_node *node;
26 node = rb_int_search_range(root, addr, addr + len);
27 if (node == NULL)
28 return NULL;
30 return mmio_node(node);
33 /* Find lowest match, Check for overlap */
34 static struct mmio_mapping *mmio_search_single(struct rb_root *root, u64 addr)
36 struct rb_int_node *node;
38 node = rb_int_search_single(root, addr);
39 if (node == NULL)
40 return NULL;
42 return mmio_node(node);
45 static int mmio_insert(struct rb_root *root, struct mmio_mapping *data)
47 return rb_int_insert(root, &data->node);
50 static const char *to_direction(u8 is_write)
52 if (is_write)
53 return "write";
55 return "read";
58 bool kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, void (*kvm_mmio_callback_fn)(u64 addr, u8 *data, u32 len, u8 is_write))
60 struct mmio_mapping *mmio;
61 struct kvm_coalesced_mmio_zone zone;
62 int ret;
64 mmio = malloc(sizeof(*mmio));
65 if (mmio == NULL)
66 return false;
68 *mmio = (struct mmio_mapping) {
69 .node = RB_INT_INIT(phys_addr, phys_addr + phys_addr_len),
70 .kvm_mmio_callback_fn = kvm_mmio_callback_fn,
73 zone = (struct kvm_coalesced_mmio_zone) {
74 .addr = phys_addr,
75 .size = phys_addr_len,
77 ret = ioctl(kvm->vm_fd, KVM_REGISTER_COALESCED_MMIO, &zone);
78 if (ret < 0) {
79 free(mmio);
80 return false;
83 br_write_lock();
84 ret = mmio_insert(&mmio_tree, mmio);
85 br_write_unlock();
87 return ret;
90 bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
92 struct mmio_mapping *mmio;
93 struct kvm_coalesced_mmio_zone zone;
95 br_write_lock();
96 mmio = mmio_search_single(&mmio_tree, phys_addr);
97 if (mmio == NULL) {
98 br_write_unlock();
99 return false;
102 zone = (struct kvm_coalesced_mmio_zone) {
103 .addr = phys_addr,
104 .size = 1,
106 ioctl(kvm->vm_fd, KVM_UNREGISTER_COALESCED_MMIO, &zone);
108 rb_int_erase(&mmio_tree, &mmio->node);
109 br_write_unlock();
111 free(mmio);
112 return true;
115 bool kvm__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write)
117 struct mmio_mapping *mmio;
119 br_read_lock();
120 mmio = mmio_search(&mmio_tree, phys_addr, len);
122 if (mmio)
123 mmio->kvm_mmio_callback_fn(phys_addr, data, len, is_write);
124 else
125 fprintf(stderr, "Warning: Ignoring MMIO %s at %016llx (length %u)\n",
126 to_direction(is_write), phys_addr, len);
127 br_read_unlock();
129 return true;