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.


77308d9fc7c4d26b120294d6c7c041f2b7df105b
[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
24
25
26
27 #ifndef CONFIG_DEBUG_IO
28 #undef PrintDebug
29 #define PrintDebug(fmt, args...)
30 #endif
31
32
33 static int default_write(uint16_t port, void *src, uint_t length, void * priv_data);
34 static int default_read(uint16_t port, void * dst, uint_t length, void * priv_data);
35
36
37 void v3_init_io_map(struct guest_info * info) {
38
39   info->io_map.map.rb_node = NULL;
40   info->io_map.arch_data = NULL;
41   info->io_map.update_map = NULL;
42
43 }
44
45
46
47
48 static inline struct v3_io_hook * __insert_io_hook(struct guest_info * info, struct v3_io_hook * hook) {
49   struct rb_node ** p = &(info->io_map.map.rb_node);
50   struct rb_node * parent = NULL;
51   struct v3_io_hook * tmp_hook = NULL;
52
53   while (*p) {
54     parent = *p;
55     tmp_hook = rb_entry(parent, struct v3_io_hook, tree_node);
56
57     if (hook->port < tmp_hook->port) {
58       p = &(*p)->rb_left;
59     } else if (hook->port > tmp_hook->port) {
60       p = &(*p)->rb_right;
61     } else {
62       return tmp_hook;
63     }
64   }
65   rb_link_node(&(hook->tree_node), parent, p);
66
67   return NULL;
68 }
69
70
71 static inline struct v3_io_hook * insert_io_hook(struct guest_info * info, struct v3_io_hook * hook) {
72   struct v3_io_hook * ret;
73
74   if ((ret = __insert_io_hook(info, hook))) {
75     return ret;
76   }
77
78   v3_rb_insert_color(&(hook->tree_node), &(info->io_map.map));
79
80   return NULL;
81 }
82
83
84 struct v3_io_hook * v3_get_io_hook(struct guest_info * info, uint16_t port) {
85   struct rb_node * n = info->io_map.map.rb_node;
86   struct v3_io_hook * hook = NULL;
87
88   while (n) {
89     hook = rb_entry(n, struct v3_io_hook, tree_node);
90     
91     if (port < hook->port) {
92       n = n->rb_left;
93     } else if (port > hook->port) {
94       n = n->rb_right;
95     } else {
96       return hook;
97     }
98   }
99
100   return NULL;
101 }
102
103
104
105
106
107 int v3_hook_io_port(struct guest_info * info, uint16_t port, 
108                     int (*read)(uint16_t port, void * dst, uint_t length, void * priv_data),
109                     int (*write)(uint16_t port, void * src, uint_t length, void * priv_data), 
110                     void * priv_data) {
111   struct v3_io_hook * io_hook = (struct v3_io_hook *)V3_Malloc(sizeof(struct v3_io_hook));
112
113   io_hook->port = port;
114
115   if (!read) {
116     io_hook->read = &default_read;
117   } else {
118     io_hook->read = read;
119   }
120
121   if (!write) {
122     io_hook->write = &default_write;
123   } else {
124     io_hook->write = write;
125   }
126
127
128   io_hook->priv_data = priv_data;
129
130   if (insert_io_hook(info, io_hook)) {
131       PrintError("Could not insert IO hook for port %u (0x%x)\n", port, port);
132       V3_Free(io_hook);
133       return -1;
134   }
135
136   if (info->io_map.update_map) {
137       if (info->io_map.update_map(info, port, 
138                                   ((read == NULL) ? 0 : 1), 
139                                   ((write == NULL) ? 0 : 1)) == -1) {
140           PrintError("Could not update IO map for port %u (0x%x)\n", port, port);
141           V3_Free(io_hook);
142           return -1;
143       }
144   }
145
146   return 0;
147 }
148
149 int v3_unhook_io_port(struct guest_info * info, uint16_t port) {
150     struct v3_io_hook * hook = v3_get_io_hook(info, port);
151
152     if (hook == NULL) {
153         PrintError("Could not find port to unhook %u (0x%x)\n", port, port);
154         return -1;
155     }
156
157     v3_rb_erase(&(hook->tree_node), &(info->io_map.map));
158
159     if (info->io_map.update_map) {
160         // set the arch map to default (this should be 1, 1)
161         info->io_map.update_map(info, port, 0, 0);
162     }
163
164     V3_Free(hook);
165
166     return 0;
167 }
168
169
170
171
172
173
174
175 void v3_refresh_io_map(struct guest_info * info) {
176     struct v3_io_map * io_map = &(info->io_map);
177     struct v3_io_hook * tmp = NULL;
178     
179     if (io_map->update_map == NULL) {
180         PrintError("Trying to refresh an io map with no backend\n");
181         return;
182     }
183
184     v3_rb_for_each_entry(tmp, &(io_map->map), tree_node) {
185         io_map->update_map(info, tmp->port, 
186                            ((tmp->read == NULL) ? 0 : 1), 
187                            ((tmp->write == NULL) ? 0 : 1));
188     }
189
190 }
191
192
193
194 void v3_print_io_map(struct guest_info * info) {
195     struct v3_io_map * io_map = &(info->io_map);
196     struct v3_io_hook * tmp_hook = NULL;
197
198     V3_Print("VMM IO Map\n");
199
200     v3_rb_for_each_entry(tmp_hook, &(io_map->map), tree_node) {
201         V3_Print("IO Port: %hu (Read=%p) (Write=%p)\n", 
202                  tmp_hook->port, 
203                  (void *)(tmp_hook->read), (void *)(tmp_hook->write));
204     }
205 }
206
207
208
209 /*
210  * Write a byte to an I/O port.
211  */
212 void v3_outb(uint16_t port, uint8_t value) {
213     __asm__ __volatile__ (
214         "outb %b0, %w1"
215         :
216         : "a" (value), "Nd" (port)
217     );
218 }
219
220 /*
221  * Read a byte from an I/O port.
222  */
223 uint8_t v3_inb(uint16_t port) {
224     uint8_t value;
225
226     __asm__ __volatile__ (
227         "inb %w1, %b0"
228         : "=a" (value)
229         : "Nd" (port)
230     );
231
232     return value;
233 }
234
235 /*
236  * Write a word to an I/O port.
237  */
238 void v3_outw(uint16_t port, uint16_t value) {
239     __asm__ __volatile__ (
240         "outw %w0, %w1"
241         :
242         : "a" (value), "Nd" (port)
243     );
244 }
245
246 /*
247  * Read a word from an I/O port.
248  */
249 uint16_t v3_inw(uint16_t port) {
250     uint16_t value;
251
252     __asm__ __volatile__ (
253         "inw %w1, %w0"
254         : "=a" (value)
255         : "Nd" (port)
256     );
257
258     return value;
259 }
260
261 /*
262  * Write a double word to an I/O port.
263  */
264 void v3_outdw(uint16_t port, uint_t value) {
265     __asm__ __volatile__ (
266         "outl %0, %1"
267         :
268         : "a" (value), "Nd" (port)
269     );
270 }
271
272 /*
273  * Read a double word from an I/O port.
274  */
275 uint_t v3_indw(uint16_t port) {
276     uint_t value;
277
278     __asm__ __volatile__ (
279         "inl %1, %0"
280         : "=a" (value)
281         : "Nd" (port)
282     );
283
284     return value;
285 }
286
287
288
289
290 /* FIX ME */
291 static int default_write(uint16_t port, void * src, uint_t length, void * priv_data) {
292     if (length == 1) {
293         v3_outb(port, *(uint8_t *)src);
294     } else if (length == 2) {
295         v3_outw(port, *(uint16_t *)src);
296     } else if (length == 4) {
297         v3_outdw(port, *(uint32_t *)src);
298     } else {
299         return -1;
300     }
301     
302     return length;
303 }
304
305 static int default_read(uint16_t port, void * dst, uint_t length, void * priv_data) {
306     if (length == 1) {
307         *(uint8_t *)dst = v3_inb(port);
308     } else if (length == 2) {
309         *(uint16_t *)dst = v3_inw(port);
310     } else if (length == 4) {
311         *(uint32_t *)dst = v3_indw(port);
312     } else {
313         return -1;
314     }
315
316     return length;
317 }