Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


linux userspace hypercall addition utility + Makefile updates
[palacios.git] / palacios / src / palacios / vmm_io.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm_io.h>
21 #include <palacios/vmm_string.h>
22 #include <palacios/vmm.h>
23 #include <palacios/vm_guest.h>
24
25
26
27 #ifndef V3_CONFIG_DEBUG_IO
28 #undef PrintDebug
29 #define PrintDebug(fmt, args...)
30 #endif
31
32 static int free_hook(struct v3_vm_info * vm, struct v3_io_hook * hook);
33
34 static int default_write(struct guest_info * core, uint16_t port, void *src, uint_t length, void * priv_data);
35 static int default_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data);
36
37
38 void v3_init_io_map(struct v3_vm_info * vm) {
39
40   vm->io_map.map.rb_node = NULL;
41   vm->io_map.arch_data = NULL;
42   vm->io_map.update_map = NULL;
43
44 }
45
46 int v3_deinit_io_map(struct v3_vm_info * vm) {
47     struct rb_node * node = v3_rb_first(&(vm->io_map.map));
48     struct v3_io_hook * hook = NULL;
49     struct rb_node * tmp_node = NULL;
50
51     while (node) {
52         hook = rb_entry(node, struct v3_io_hook, tree_node);
53         tmp_node = node;
54         node = v3_rb_next(node);
55
56         free_hook(vm, hook);
57     }
58
59     return 0;
60 }
61
62
63
64
65 static inline struct v3_io_hook * __insert_io_hook(struct v3_vm_info * vm, struct v3_io_hook * hook) {
66   struct rb_node ** p = &(vm->io_map.map.rb_node);
67   struct rb_node * parent = NULL;
68   struct v3_io_hook * tmp_hook = NULL;
69
70   while (*p) {
71     parent = *p;
72     tmp_hook = rb_entry(parent, struct v3_io_hook, tree_node);
73
74     if (hook->port < tmp_hook->port) {
75       p = &(*p)->rb_left;
76     } else if (hook->port > tmp_hook->port) {
77       p = &(*p)->rb_right;
78     } else {
79       return tmp_hook;
80     }
81   }
82
83   rb_link_node(&(hook->tree_node), parent, p);
84
85   return NULL;
86 }
87
88
89 static inline struct v3_io_hook * insert_io_hook(struct v3_vm_info * vm, struct v3_io_hook * hook) {
90   struct v3_io_hook * ret;
91
92   if ((ret = __insert_io_hook(vm, hook))) {
93     return ret;
94   }
95
96   v3_rb_insert_color(&(hook->tree_node), &(vm->io_map.map));
97
98   return NULL;
99 }
100
101
102 struct v3_io_hook * v3_get_io_hook(struct v3_vm_info * vm, uint16_t port) {
103   struct rb_node * n = vm->io_map.map.rb_node;
104   struct v3_io_hook * hook = NULL;
105
106   while (n) {
107     hook = rb_entry(n, struct v3_io_hook, tree_node);
108     
109     if (port < hook->port) {
110       n = n->rb_left;
111     } else if (port > hook->port) {
112       n = n->rb_right;
113     } else {
114       return hook;
115     }
116   }
117
118   return NULL;
119 }
120
121
122
123
124
125 int v3_hook_io_port(struct v3_vm_info * vm, uint16_t port, 
126                     int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data),
127                     int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data), 
128                     void * priv_data) {
129   struct v3_io_hook * io_hook = (struct v3_io_hook *)V3_Malloc(sizeof(struct v3_io_hook));
130
131   io_hook->port = port;
132
133   if (!read) {
134     io_hook->read = &default_read;
135   } else {
136     io_hook->read = read;
137   }
138
139   if (!write) {
140     io_hook->write = &default_write;
141   } else {
142     io_hook->write = write;
143   }
144
145   io_hook->priv_data = priv_data;
146
147   if (insert_io_hook(vm, io_hook)) {
148       PrintError("Could not insert IO hook for port %u (0x%x)\n", port, port);
149       V3_Free(io_hook);
150       return -1;
151   }
152
153   if (vm->io_map.update_map) {
154       if (vm->io_map.update_map(vm, port, 
155                                   ((read == NULL) ? 0 : 1), 
156                                   ((write == NULL) ? 0 : 1)) == -1) {
157           PrintError("Could not update IO map for port %u (0x%x)\n", port, port);
158           V3_Free(io_hook);
159           return -1;
160       }
161   }
162
163   return 0;
164 }
165
166
167 static int free_hook(struct v3_vm_info * vm, struct v3_io_hook * hook) {
168     v3_rb_erase(&(hook->tree_node), &(vm->io_map.map));
169
170     if (vm->io_map.update_map) {
171         // set the arch map to default (this should be 1, 1)
172         vm->io_map.update_map(vm, hook->port, 0, 0);
173     }
174
175     V3_Free(hook);
176
177     return 0;
178 }
179
180 int v3_unhook_io_port(struct v3_vm_info * vm, uint16_t port) {
181     struct v3_io_hook * hook = v3_get_io_hook(vm, port);
182
183     if (hook == NULL) {
184         PrintError("Could not find port to unhook %u (0x%x)\n", port, port);
185         return -1;
186     }
187
188     free_hook(vm, hook);
189
190     return 0;
191 }
192
193
194
195
196
197
198
199 void v3_refresh_io_map(struct v3_vm_info * vm) {
200     struct v3_io_map * io_map = &(vm->io_map);
201     struct v3_io_hook * tmp = NULL;
202     
203     if (io_map->update_map == NULL) {
204         PrintError("Trying to refresh an io map with no backend\n");
205         return;
206     }
207
208     v3_rb_for_each_entry(tmp, &(io_map->map), tree_node) {
209         io_map->update_map(vm, tmp->port, 
210                            ((tmp->read == NULL) ? 0 : 1), 
211                            ((tmp->write == NULL) ? 0 : 1));
212     }
213
214 }
215
216
217
218 void v3_print_io_map(struct v3_vm_info * vm) {
219     struct v3_io_map * io_map = &(vm->io_map);
220     struct v3_io_hook * tmp_hook = NULL;
221
222     V3_Print("VMM IO Map\n");
223
224     v3_rb_for_each_entry(tmp_hook, &(io_map->map), tree_node) {
225         V3_Print("IO Port: %hu (Read=%p) (Write=%p)\n", 
226                  tmp_hook->port, 
227                  (void *)(tmp_hook->read), (void *)(tmp_hook->write));
228     }
229 }
230
231
232
233 /*
234  * Write a byte to an I/O port.
235  */
236 void v3_outb(uint16_t port, uint8_t value) {
237     __asm__ __volatile__ (
238         "outb %b0, %w1"
239         :
240         : "a" (value), "Nd" (port)
241     );
242 }
243
244 /*
245  * Read a byte from an I/O port.
246  */
247 uint8_t v3_inb(uint16_t port) {
248     uint8_t value;
249
250     __asm__ __volatile__ (
251         "inb %w1, %b0"
252         : "=a" (value)
253         : "Nd" (port)
254     );
255
256     return value;
257 }
258
259 /*
260  * Write a word to an I/O port.
261  */
262 void v3_outw(uint16_t port, uint16_t value) {
263     __asm__ __volatile__ (
264         "outw %w0, %w1"
265         :
266         : "a" (value), "Nd" (port)
267     );
268 }
269
270 /*
271  * Read a word from an I/O port.
272  */
273 uint16_t v3_inw(uint16_t port) {
274     uint16_t value;
275
276     __asm__ __volatile__ (
277         "inw %w1, %w0"
278         : "=a" (value)
279         : "Nd" (port)
280     );
281
282     return value;
283 }
284
285 /*
286  * Write a double word to an I/O port.
287  */
288 void v3_outdw(uint16_t port, uint_t value) {
289     __asm__ __volatile__ (
290         "outl %0, %1"
291         :
292         : "a" (value), "Nd" (port)
293     );
294 }
295
296 /*
297  * Read a double word from an I/O port.
298  */
299 uint_t v3_indw(uint16_t port) {
300     uint_t value;
301
302     __asm__ __volatile__ (
303         "inl %1, %0"
304         : "=a" (value)
305         : "Nd" (port)
306     );
307
308     return value;
309 }
310
311
312
313
314 /* FIX ME */
315 static int default_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data) {
316     if (length == 1) {
317         v3_outb(port, *(uint8_t *)src);
318     } else if (length == 2) {
319         v3_outw(port, *(uint16_t *)src);
320     } else if (length == 4) {
321         v3_outdw(port, *(uint32_t *)src);
322     } else {
323         return -1;
324     }
325     
326     return length;
327 }
328
329 static int default_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data) {
330     if (length == 1) {
331         *(uint8_t *)dst = v3_inb(port);
332     } else if (length == 2) {
333         *(uint16_t *)dst = v3_inw(port);
334     } else if (length == 4) {
335         *(uint32_t *)dst = v3_indw(port);
336     } else {
337         return -1;
338     }
339
340     return length;
341 }