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.


more device free updates
[palacios.git] / palacios / src / palacios / vmm_dev_mgr.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_dev_mgr.h>
21 #include <palacios/vm_guest.h>
22 #include <palacios/vmm.h>
23 #include <palacios/vmm_decoder.h>
24
25
26 #ifndef CONFIG_DEBUG_DEV_MGR
27 #undef PrintDebug
28 #define PrintDebug(fmt, args...)
29 #endif
30
31
32 static struct hashtable * master_dev_table = NULL;
33
34 static uint_t dev_hash_fn(addr_t key) {
35     char * name = (char *)key;
36     return v3_hash_buffer((uchar_t *)name, strlen(name));
37 }
38
39 static int dev_eq_fn(addr_t key1, addr_t key2) {
40     char * name1 = (char *)key1;
41     char * name2 = (char *)key2;
42     
43     return (strcmp(name1, name2) == 0);
44 }
45
46
47 int v3_init_devices() {
48     extern struct v3_device_info __start__v3_devices[];
49     extern struct v3_device_info __stop__v3_devices[];
50     struct v3_device_info * tmp_dev =  __start__v3_devices;
51     int i = 0;
52
53 #ifdef CONFIG_DEBUG_DEV_MGR
54     {
55         int num_devices = (__stop__v3_devices - __start__v3_devices) / sizeof(struct v3_device_info);
56         PrintDebug("%d Virtual devices registered with Palacios\n", num_devices);
57     }
58 #endif
59
60     PrintDebug("Start addres=%p, Stop address=%p\n", __start__v3_devices, __stop__v3_devices);
61
62     master_dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
63
64
65
66     while (tmp_dev != __stop__v3_devices) {
67         PrintDebug("Device: %s\n", tmp_dev->name);
68
69         if (v3_htable_search(master_dev_table, (addr_t)(tmp_dev->name))) {
70             PrintError("Multiple instance of device (%s)\n", tmp_dev->name);
71             return -1;
72         }
73
74         if (v3_htable_insert(master_dev_table, 
75                              (addr_t)(tmp_dev->name), 
76                              (addr_t)(tmp_dev->init)) == 0) {
77             PrintError("Could not add device %s to master list\n", tmp_dev->name);
78             return -1;
79         }
80
81         tmp_dev = &(__start__v3_devices[++i]);
82     }
83
84
85     return 0;
86 }
87
88
89 int v3_init_dev_mgr(struct v3_vm_info * vm) {
90     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
91
92     INIT_LIST_HEAD(&(mgr->dev_list));
93     mgr->num_devs = 0;
94
95     mgr->dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
96
97     INIT_LIST_HEAD(&(mgr->blk_list));
98     INIT_LIST_HEAD(&(mgr->net_list));
99     INIT_LIST_HEAD(&(mgr->char_list));
100     INIT_LIST_HEAD(&(mgr->console_list));
101
102     mgr->blk_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
103     mgr->net_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
104     mgr->char_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
105     mgr->console_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
106     
107     return 0;
108 }
109
110
111 int v3_dev_mgr_deinit(struct v3_vm_info * vm) {
112     struct vm_device * dev;
113     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
114     struct vm_device * tmp;
115
116     list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
117         v3_detach_device(dev);
118     }
119
120     v3_free_htable(mgr->blk_table, 0, 0);
121     v3_free_htable(mgr->net_table, 0, 0);
122     v3_free_htable(mgr->char_table, 0, 0);
123     v3_free_htable(mgr->console_table, 0, 0);
124
125     v3_free_htable(mgr->dev_table, 0, 0);
126
127     return 0;
128 }
129
130 /*
131 int v3_init_core_dev_mgr(struct v3_vm_info * vm) {
132     struct v3_core_dev_mgr * mgr = &(vm->core_dev_mgr);
133
134     INIT_LIST_HEAD(&(mgr->dev_list));
135     mgr->dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
136
137     return 0;
138 }
139
140 int v3_core_dev_mgr_deinit(struct v3_vm_info * vm) {
141     struct vm_device * dev;
142     struct v3_core_dev_mgr * mgr = &(vm->core_dev_mgr);
143     struct vm_device * tmp;
144
145     list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
146         v3_detach_device(dev);
147     }
148
149     // TODO: Clear hash tables 
150
151 }
152 */
153
154
155 int v3_create_device(struct v3_vm_info * vm, const char * dev_name, v3_cfg_tree_t * cfg) {
156     int (*dev_init)(struct v3_vm_info * vm, void * cfg_data);
157
158     dev_init = (void *)v3_htable_search(master_dev_table, (addr_t)dev_name);
159
160     if (dev_init == NULL) {
161         PrintError("Could not find device %s in master device table\n", dev_name);
162         return -1;
163     }
164
165
166     if (dev_init(vm, cfg) == -1) {
167         PrintError("Could not initialize Device %s\n", dev_name);
168         return -1;
169     }
170
171     return 0;
172 }
173
174
175 void v3_free_device(struct vm_device * dev) {
176     V3_Free(dev);
177 }
178
179
180
181 struct vm_device * v3_find_dev(struct v3_vm_info * vm, const char * dev_name) {
182     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
183
184     if (!dev_name) {
185         return NULL;
186     }
187
188     return (struct vm_device *)v3_htable_search(mgr->dev_table, (addr_t)dev_name);
189 }
190
191
192 /****************************************************************/
193 /* The remaining functions are called by the devices themselves */
194 /****************************************************************/
195
196 /* IO HOOKS */
197 int v3_dev_hook_io(struct vm_device * dev, uint16_t port,
198                    int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, struct vm_device * dev),
199                    int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, struct vm_device * dev)) {
200     return v3_hook_io_port(dev->vm, port, 
201                            (int (*)(struct guest_info * core, ushort_t, void *, uint_t, void *))read, 
202                            (int (*)(struct guest_info * core, ushort_t, void *, uint_t, void *))write, 
203                            (void *)dev);
204 }
205
206
207 int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
208     return v3_unhook_io_port(dev->vm, port);
209 }
210
211
212
213 int v3_detach_device(struct vm_device * dev) {
214     struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
215
216     if (dev->ops->free) {
217         dev->ops->free(dev);
218     } else {
219         PrintError("Error: %s free() not implemented\n",  dev->name);
220     }
221
222     list_del(&(dev->dev_link));
223     mgr->num_devs--;
224
225     dev->vm = NULL;
226
227     v3_free_device(dev);
228     return -1;
229 }
230
231
232 struct vm_device * v3_allocate_device(char * name, 
233                                       struct v3_device_ops * ops, 
234                                       void * private_data) {
235     struct vm_device * dev = NULL;
236
237     dev = (struct vm_device*)V3_Malloc(sizeof(struct vm_device));
238
239     strncpy(dev->name, name, 32);
240     dev->ops = ops;
241     dev->private_data = private_data;
242
243     dev->vm = NULL;
244
245     return dev;
246 }
247
248
249 int v3_attach_device(struct v3_vm_info * vm, struct vm_device * dev ) {
250     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
251
252     dev->vm = vm;
253
254     list_add(&(dev->dev_link), &(mgr->dev_list));
255     mgr->num_devs++;
256
257
258     v3_htable_insert(mgr->dev_table, (addr_t)(dev->name), (addr_t)dev);
259
260     return 0;
261 }
262
263
264
265 void v3_print_dev_mgr(struct v3_vm_info * vm) {
266     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
267     struct vm_device * dev;
268
269     V3_Print("%d devices registered with manager\n", mgr->num_devs);
270
271     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
272         V3_Print("Device: %s\n", dev->name);
273     }
274
275     return;
276 }
277
278
279
280
281 struct blk_frontend {
282     int (*connect)(struct v3_vm_info * vm, 
283                     void * frontend_data, 
284                     struct v3_dev_blk_ops * ops, 
285                     v3_cfg_tree_t * cfg, 
286                     void * priv_data);
287         
288
289     struct list_head blk_node;
290
291     void * priv_data;
292 };
293
294
295
296 int v3_dev_add_blk_frontend(struct v3_vm_info * vm, 
297                             char * name, 
298                             int (*connect)(struct v3_vm_info * vm, 
299                                             void * frontend_data, 
300                                             struct v3_dev_blk_ops * ops, 
301                                             v3_cfg_tree_t * cfg, 
302                                             void * priv_data), 
303                             void * priv_data) {
304
305     struct blk_frontend * frontend = NULL;
306
307     frontend = (struct blk_frontend *)V3_Malloc(sizeof(struct blk_frontend));
308     memset(frontend, 0, sizeof(struct blk_frontend));
309     
310     frontend->connect = connect;
311     frontend->priv_data = priv_data;
312         
313     list_add(&(frontend->blk_node), &(vm->dev_mgr.blk_list));
314     v3_htable_insert(vm->dev_mgr.blk_table, (addr_t)(name), (addr_t)frontend);
315
316     return 0;
317 }
318
319 int v3_dev_connect_blk(struct v3_vm_info * vm, 
320                        char * frontend_name, 
321                        struct v3_dev_blk_ops * ops, 
322                        v3_cfg_tree_t * cfg, 
323                        void * private_data) {
324
325     struct blk_frontend * frontend = NULL;
326
327     frontend = (struct blk_frontend *)v3_htable_search(vm->dev_mgr.blk_table,
328                                                        (addr_t)frontend_name);
329     
330     if (frontend == NULL) {
331         PrintError("Could not find frontend blk device %s\n", frontend_name);
332         return 0;
333     }
334
335     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
336         PrintError("Error connecting to block frontend %s\n", frontend_name);
337         return -1;
338     }
339
340     return 0;
341 }
342
343
344
345 struct net_frontend {
346     int (*connect)(struct v3_vm_info * vm, 
347                     void * frontend_data, 
348                     struct v3_dev_net_ops * ops, 
349                     v3_cfg_tree_t * cfg, 
350                     void * priv_data);
351     
352
353     struct list_head net_node;
354
355     void * priv_data;
356 };
357
358
359 int v3_dev_add_net_frontend(struct v3_vm_info * vm, 
360                             char * name, 
361                             int (*connect)(struct v3_vm_info * vm, 
362                                             void * frontend_data, 
363                                             struct v3_dev_net_ops * ops, 
364                                             v3_cfg_tree_t * cfg, 
365                                             void * private_data), 
366                             void * priv_data)
367 {
368     struct net_frontend * frontend = NULL;
369
370     frontend = (struct net_frontend *)V3_Malloc(sizeof(struct net_frontend));
371     memset(frontend, 0, sizeof(struct net_frontend));
372     
373     frontend->connect = connect;
374     frontend->priv_data = priv_data;
375         
376     list_add(&(frontend->net_node), &(vm->dev_mgr.net_list));
377     v3_htable_insert(vm->dev_mgr.net_table, (addr_t)(name), (addr_t)frontend);
378
379     return 0;
380 }
381
382
383 int v3_dev_connect_net(struct v3_vm_info * vm, 
384                        char * frontend_name, 
385                        struct v3_dev_net_ops * ops, 
386                        v3_cfg_tree_t * cfg, 
387                        void * private_data)
388 {
389     struct net_frontend * frontend = NULL;
390
391     frontend = (struct net_frontend *)v3_htable_search(vm->dev_mgr.net_table,
392                                                        (addr_t)frontend_name);
393     
394     if (frontend == NULL) {
395         PrintError("Could not find frontend net device %s\n", frontend_name);
396         return 0;
397     }
398
399     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
400         PrintError("Error connecting to net frontend %s\n", frontend_name);
401         return -1;
402     }
403
404     return 0;
405 }
406
407
408 struct char_frontend {
409     int (*connect)(struct v3_vm_info * vm, 
410                    void * frontend_data, 
411                    struct v3_dev_char_ops * ops, 
412                    v3_cfg_tree_t * cfg, 
413                    void * priv_data, 
414                    void ** push_fn_arg);
415     
416
417     struct list_head char_node;
418
419     void * priv_data;
420 };
421
422
423
424 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
425                              char * name, 
426                              int (*connect)(struct v3_vm_info * vm, 
427                                             void * frontend_data, 
428                                             struct v3_dev_char_ops * ops, 
429                                             v3_cfg_tree_t * cfg, 
430                                             void * private_data, 
431                                             void ** push_fn_arg), 
432                              void * priv_data)
433 {
434     struct char_frontend * frontend = NULL;
435
436     frontend = (struct char_frontend *)V3_Malloc(sizeof(struct char_frontend));
437     memset(frontend, 0, sizeof(struct char_frontend));
438     
439     frontend->connect = connect;
440     frontend->priv_data = priv_data;
441         
442     list_add(&(frontend->char_node), &(vm->dev_mgr.char_list));
443     v3_htable_insert(vm->dev_mgr.char_table, (addr_t)(name), (addr_t)frontend);
444
445     return 0;
446 }
447
448
449 int v3_dev_connect_char(struct v3_vm_info * vm, 
450                         char * frontend_name, 
451                         struct v3_dev_char_ops * ops, 
452                         v3_cfg_tree_t * cfg, 
453                         void * private_data, 
454                         void ** push_fn_arg)
455 {
456     struct char_frontend * frontend = NULL;
457
458     frontend = (struct char_frontend *)v3_htable_search(vm->dev_mgr.char_table,
459                                                         (addr_t)frontend_name);
460     
461     if (frontend == NULL) {
462         PrintError("Could not find frontend char device %s\n", frontend_name);
463         return 0;
464     }
465     
466     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data, push_fn_arg) == -1) {
467         PrintError("Error connecting to char frontend %s\n", frontend_name);
468         return -1;
469     }
470
471     return 0;
472 }
473