Add linux-next specific files for 20110831
[linux-2.6/next.git] / tools / kvm / mmio.c
blobde7320fe74f023f382e1c37a0b68b55644ec5f3d
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 (*mmio_fn)(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr);
18 void *ptr;
21 static struct rb_root mmio_tree = RB_ROOT;
23 static struct mmio_mapping *mmio_search(struct rb_root *root, u64 addr, u64 len)
25 struct rb_int_node *node;
27 node = rb_int_search_range(root, addr, addr + len);
28 if (node == NULL)
29 return NULL;
31 return mmio_node(node);
34 /* Find lowest match, Check for overlap */
35 static struct mmio_mapping *mmio_search_single(struct rb_root *root, u64 addr)
37 struct rb_int_node *node;
39 node = rb_int_search_single(root, addr);
40 if (node == NULL)
41 return NULL;
43 return mmio_node(node);
46 static int mmio_insert(struct rb_root *root, struct mmio_mapping *data)
48 return rb_int_insert(root, &data->node);
51 static const char *to_direction(u8 is_write)
53 if (is_write)
54 return "write";
56 return "read";
59 bool kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, void (*mmio_fn)(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr), void *ptr)
61 struct mmio_mapping *mmio;
62 struct kvm_coalesced_mmio_zone zone;
63 int ret;
65 mmio = malloc(sizeof(*mmio));
66 if (mmio == NULL)
67 return false;
69 *mmio = (struct mmio_mapping) {
70 .node = RB_INT_INIT(phys_addr, phys_addr + phys_addr_len),
71 .mmio_fn = mmio_fn,
72 .ptr = ptr,
75 zone = (struct kvm_coalesced_mmio_zone) {
76 .addr = phys_addr,
77 .size = phys_addr_len,
79 ret = ioctl(kvm->vm_fd, KVM_REGISTER_COALESCED_MMIO, &zone);
80 if (ret < 0) {
81 free(mmio);
82 return false;
85 br_write_lock();
86 ret = mmio_insert(&mmio_tree, mmio);
87 br_write_unlock();
89 return ret;
92 bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
94 struct mmio_mapping *mmio;
95 struct kvm_coalesced_mmio_zone zone;
97 br_write_lock();
98 mmio = mmio_search_single(&mmio_tree, phys_addr);
99 if (mmio == NULL) {
100 br_write_unlock();
101 return false;
104 zone = (struct kvm_coalesced_mmio_zone) {
105 .addr = phys_addr,
106 .size = 1,
108 ioctl(kvm->vm_fd, KVM_UNREGISTER_COALESCED_MMIO, &zone);
110 rb_int_erase(&mmio_tree, &mmio->node);
111 br_write_unlock();
113 free(mmio);
114 return true;
117 bool kvm__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write)
119 struct mmio_mapping *mmio;
121 br_read_lock();
122 mmio = mmio_search(&mmio_tree, phys_addr, len);
124 if (mmio)
125 mmio->mmio_fn(phys_addr, data, len, is_write, mmio->ptr);
126 else
127 fprintf(stderr, "Warning: Ignoring MMIO %s at %016llx (length %u)\n",
128 to_direction(is_write), phys_addr, len);
129 br_read_unlock();
131 return true;