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.


Context-based output infrastructure (V3_Print, etc) and modifications to use it
[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   if (!io_hook) {
132       PrintError(vm, VCORE_NONE, "Cannot allocate in hooking an I/O port\n");
133       return -1;
134   }
135
136
137   io_hook->port = port;
138
139   if (!read) {
140     io_hook->read = &default_read;
141   } else {
142     io_hook->read = read;
143   }
144
145   if (!write) {
146     io_hook->write = &default_write;
147   } else {
148     io_hook->write = write;
149   }
150
151   io_hook->priv_data = priv_data;
152
153   if (insert_io_hook(vm, io_hook)) {
154       PrintError(vm, VCORE_NONE, "Could not insert IO hook for port %u (0x%x)\n", port, port);
155       V3_Free(io_hook);
156       return -1;
157   }
158
159   if (vm->io_map.update_map) {
160       if (vm->io_map.update_map(vm, port, 
161                                   ((read == NULL) ? 0 : 1), 
162                                   ((write == NULL) ? 0 : 1)) == -1) {
163           PrintError(vm, VCORE_NONE, "Could not update IO map for port %u (0x%x)\n", port, port);
164           V3_Free(io_hook);
165           return -1;
166       }
167   }
168
169   return 0;
170 }
171
172
173 static int free_hook(struct v3_vm_info * vm, struct v3_io_hook * hook) {
174     v3_rb_erase(&(hook->tree_node), &(vm->io_map.map));
175
176     if (vm->io_map.update_map) {
177         // set the arch map to default (this should be 1, 1)
178         vm->io_map.update_map(vm, hook->port, 0, 0);
179     }
180
181     V3_Free(hook);
182
183     return 0;
184 }
185
186 int v3_unhook_io_port(struct v3_vm_info * vm, uint16_t port) {
187     struct v3_io_hook * hook = v3_get_io_hook(vm, port);
188
189     if (hook == NULL) {
190         PrintError(vm, VCORE_NONE, "Could not find port to unhook %u (0x%x)\n", port, port);
191         return -1;
192     }
193
194     free_hook(vm, hook);
195
196     return 0;
197 }
198
199
200
201
202
203
204
205 void v3_refresh_io_map(struct v3_vm_info * vm) {
206     struct v3_io_map * io_map = &(vm->io_map);
207     struct v3_io_hook * tmp = NULL;
208     
209     if (io_map->update_map == NULL) {
210         PrintError(vm, VCORE_NONE, "Trying to refresh an io map with no backend\n");
211         return;
212     }
213
214     v3_rb_for_each_entry(tmp, &(io_map->map), tree_node) {
215         io_map->update_map(vm, tmp->port, 
216                            ((tmp->read == NULL) ? 0 : 1), 
217                            ((tmp->write == NULL) ? 0 : 1));
218     }
219
220 }
221
222
223
224 void v3_print_io_map(struct v3_vm_info * vm) {
225     struct v3_io_map * io_map = &(vm->io_map);
226     struct v3_io_hook * tmp_hook = NULL;
227
228     V3_Print(vm, VCORE_NONE, "VMM IO Map\n");
229
230     v3_rb_for_each_entry(tmp_hook, &(io_map->map), tree_node) {
231         V3_Print(vm, VCORE_NONE, "IO Port: %hu (Read=%p) (Write=%p)\n", 
232                  tmp_hook->port, 
233                  (void *)(tmp_hook->read), (void *)(tmp_hook->write));
234     }
235 }
236
237
238
239 /*
240  * Write a byte to an I/O port.
241  */
242 void v3_outb(uint16_t port, uint8_t value) {
243     __asm__ __volatile__ (
244         "outb %b0, %w1"
245         :
246         : "a" (value), "Nd" (port)
247     );
248 }
249
250 /*
251  * Read a byte from an I/O port.
252  */
253 uint8_t v3_inb(uint16_t port) {
254     uint8_t value;
255
256     __asm__ __volatile__ (
257         "inb %w1, %b0"
258         : "=a" (value)
259         : "Nd" (port)
260     );
261
262     return value;
263 }
264
265 /*
266  * Write a word to an I/O port.
267  */
268 void v3_outw(uint16_t port, uint16_t value) {
269     __asm__ __volatile__ (
270         "outw %w0, %w1"
271         :
272         : "a" (value), "Nd" (port)
273     );
274 }
275
276 /*
277  * Read a word from an I/O port.
278  */
279 uint16_t v3_inw(uint16_t port) {
280     uint16_t value;
281
282     __asm__ __volatile__ (
283         "inw %w1, %w0"
284         : "=a" (value)
285         : "Nd" (port)
286     );
287
288     return value;
289 }
290
291 /*
292  * Write a double word to an I/O port.
293  */
294 void v3_outdw(uint16_t port, uint_t value) {
295     __asm__ __volatile__ (
296         "outl %0, %1"
297         :
298         : "a" (value), "Nd" (port)
299     );
300 }
301
302 /*
303  * Read a double word from an I/O port.
304  */
305 uint_t v3_indw(uint16_t port) {
306     uint_t value;
307
308     __asm__ __volatile__ (
309         "inl %1, %0"
310         : "=a" (value)
311         : "Nd" (port)
312     );
313
314     return value;
315 }
316
317
318
319
320 /* FIX ME */
321 static int default_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data) {
322     if (length == 1) {
323         v3_outb(port, *(uint8_t *)src);
324     } else if (length == 2) {
325         v3_outw(port, *(uint16_t *)src);
326     } else if (length == 4) {
327         v3_outdw(port, *(uint32_t *)src);
328     } else {
329         return -1;
330     }
331     
332     return length;
333 }
334
335 static int default_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data) {
336     if (length == 1) {
337         *(uint8_t *)dst = v3_inb(port);
338     } else if (length == 2) {
339         *(uint16_t *)dst = v3_inw(port);
340     } else if (length == 4) {
341         *(uint32_t *)dst = v3_indw(port);
342     } else {
343         return -1;
344     }
345
346     return length;
347 }