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.


restructured device manager deinitialization
[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->cons_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->cons_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
106     
107     return 0;
108 }
109
110
111 int v3_free_vm_devices(struct v3_vm_info * vm) {
112     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
113     struct vm_device * dev;
114     struct vm_device * tmp;
115
116     list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
117         v3_remove_device(dev);
118     }
119
120     return 0;
121 }
122
123 int v3_deinit_dev_mgr(struct v3_vm_info * vm) {
124     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
125
126     v3_free_htable(mgr->blk_table, 0, 0);
127     v3_free_htable(mgr->net_table, 0, 0);
128     v3_free_htable(mgr->char_table, 0, 0);
129     v3_free_htable(mgr->cons_table, 0, 0);
130
131     v3_free_htable(mgr->dev_table, 0, 0);
132
133     return 0;
134 }
135
136
137
138 int v3_create_device(struct v3_vm_info * vm, const char * dev_name, v3_cfg_tree_t * cfg) {
139     int (*dev_init)(struct v3_vm_info * vm, void * cfg_data);
140
141     dev_init = (void *)v3_htable_search(master_dev_table, (addr_t)dev_name);
142
143     if (dev_init == NULL) {
144         PrintError("Could not find device %s in master device table\n", dev_name);
145         return -1;
146     }
147
148
149     if (dev_init(vm, cfg) == -1) {
150         PrintError("Could not initialize Device %s\n", dev_name);
151         return -1;
152     }
153
154     return 0;
155 }
156
157
158
159
160 struct vm_device * v3_find_dev(struct v3_vm_info * vm, const char * dev_name) {
161     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
162
163     if (!dev_name) {
164         return NULL;
165     }
166
167     return (struct vm_device *)v3_htable_search(mgr->dev_table, (addr_t)dev_name);
168 }
169
170
171 /****************************************************************/
172 /* The remaining functions are called by the devices themselves */
173 /****************************************************************/
174
175 struct dev_io_hook {
176     uint16_t port;
177
178     struct list_head node;
179
180 };
181
182 /* IO HOOKS */
183 int v3_dev_hook_io(struct vm_device * dev, uint16_t port,
184                    int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data),
185                    int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data)) {
186     struct dev_io_hook * io_hook = NULL;
187     int ret = 0;
188     
189    ret = v3_hook_io_port(dev->vm, port, 
190                          (int (*)(struct guest_info * core, ushort_t, void *, uint_t, void *))read, 
191                          (int (*)(struct guest_info * core, ushort_t, void *, uint_t, void *))write, 
192                          (void *)dev->private_data);
193
194    if (ret == -1) {
195        return -1;
196    }
197
198    io_hook = V3_Malloc(sizeof(struct dev_io_hook));
199
200    if (io_hook == NULL) {
201        PrintError("Could not allocate io hook dev state\n");
202        return -1;
203    }
204
205    io_hook->port = port;
206    list_add(&(io_hook->node), &(dev->io_hooks));
207
208    return 0;
209 }
210
211
212 int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
213     struct dev_io_hook * io_hook = NULL;
214     struct dev_io_hook * tmp;
215
216     list_for_each_entry_safe(io_hook, tmp, &(dev->io_hooks), node) {
217         if (io_hook->port == port) {
218
219             list_del(&(io_hook->node));
220             V3_Free(io_hook);
221             
222             return v3_unhook_io_port(dev->vm, port);        
223         }
224     }
225
226     return -1;
227 }
228
229
230
231 int v3_remove_device(struct vm_device * dev) {
232     struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
233     struct dev_io_hook * io_hook = NULL;
234     struct dev_io_hook * tmp;
235
236     list_for_each_entry_safe(io_hook, tmp, &(dev->io_hooks), node) {
237         v3_unhook_io_port(dev->vm, io_hook->port);          
238         list_del(&(io_hook->node));
239         V3_Free(io_hook);    
240     }
241
242     if (dev->ops->free) {
243         dev->ops->free(dev->private_data);
244     } else {
245         PrintError("Error: %s free() not implemented\n",  dev->name);
246     }
247
248     list_del(&(dev->dev_link));
249     mgr->num_devs--;
250
251     dev->vm = NULL;
252
253     V3_Free(dev);
254     return -1;
255 }
256
257
258 struct vm_device * v3_add_device(struct v3_vm_info * vm,
259                                  char * name, 
260                                  struct v3_device_ops * ops, 
261                                  void * private_data) {
262     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
263     struct vm_device * dev = NULL;
264
265     dev = (struct vm_device *)V3_Malloc(sizeof(struct vm_device));
266
267     if (dev == NULL) {
268         return NULL;
269     }
270
271     INIT_LIST_HEAD(&(dev->io_hooks));
272
273     strncpy(dev->name, name, 32);
274     dev->ops = ops;
275     dev->private_data = private_data;
276
277     dev->vm = vm;
278
279     list_add(&(dev->dev_link), &(mgr->dev_list));
280     mgr->num_devs++;
281
282     v3_htable_insert(mgr->dev_table, (addr_t)(dev->name), (addr_t)dev);
283
284     return dev;
285 }
286
287
288 void v3_print_dev_mgr(struct v3_vm_info * vm) {
289     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
290     struct vm_device * dev;
291
292     V3_Print("%d devices registered with manager\n", mgr->num_devs);
293
294     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
295         V3_Print("Device: %s\n", dev->name);
296     }
297
298     return;
299 }
300
301
302
303
304 struct blk_frontend {
305     int (*connect)(struct v3_vm_info * vm, 
306                     void * frontend_data, 
307                     struct v3_dev_blk_ops * ops, 
308                     v3_cfg_tree_t * cfg, 
309                     void * priv_data);
310         
311
312     struct list_head blk_node;
313
314     void * priv_data;
315 };
316
317
318
319 int v3_dev_add_blk_frontend(struct v3_vm_info * vm, 
320                             char * name, 
321                             int (*connect)(struct v3_vm_info * vm, 
322                                             void * frontend_data, 
323                                             struct v3_dev_blk_ops * ops, 
324                                             v3_cfg_tree_t * cfg, 
325                                             void * priv_data), 
326                             void * priv_data) {
327
328     struct blk_frontend * frontend = NULL;
329
330     frontend = (struct blk_frontend *)V3_Malloc(sizeof(struct blk_frontend));
331     memset(frontend, 0, sizeof(struct blk_frontend));
332     
333     frontend->connect = connect;
334     frontend->priv_data = priv_data;
335         
336     list_add(&(frontend->blk_node), &(vm->dev_mgr.blk_list));
337     v3_htable_insert(vm->dev_mgr.blk_table, (addr_t)(name), (addr_t)frontend);
338
339     return 0;
340 }
341
342 int v3_dev_connect_blk(struct v3_vm_info * vm, 
343                        char * frontend_name, 
344                        struct v3_dev_blk_ops * ops, 
345                        v3_cfg_tree_t * cfg, 
346                        void * private_data) {
347
348     struct blk_frontend * frontend = NULL;
349
350     frontend = (struct blk_frontend *)v3_htable_search(vm->dev_mgr.blk_table,
351                                                        (addr_t)frontend_name);
352     
353     if (frontend == NULL) {
354         PrintError("Could not find frontend blk device %s\n", frontend_name);
355         return 0;
356     }
357
358     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
359         PrintError("Error connecting to block frontend %s\n", frontend_name);
360         return -1;
361     }
362
363     return 0;
364 }
365
366
367
368 struct net_frontend {
369     int (*connect)(struct v3_vm_info * vm, 
370                     void * frontend_data, 
371                     struct v3_dev_net_ops * ops, 
372                     v3_cfg_tree_t * cfg, 
373                     void * priv_data);
374     
375
376     struct list_head net_node;
377
378     void * priv_data;
379 };
380
381
382 int v3_dev_add_net_frontend(struct v3_vm_info * vm, 
383                             char * name, 
384                             int (*connect)(struct v3_vm_info * vm, 
385                                             void * frontend_data, 
386                                             struct v3_dev_net_ops * ops, 
387                                             v3_cfg_tree_t * cfg, 
388                                             void * private_data), 
389                             void * priv_data)
390 {
391     struct net_frontend * frontend = NULL;
392
393     frontend = (struct net_frontend *)V3_Malloc(sizeof(struct net_frontend));
394     memset(frontend, 0, sizeof(struct net_frontend));
395     
396     frontend->connect = connect;
397     frontend->priv_data = priv_data;
398         
399     list_add(&(frontend->net_node), &(vm->dev_mgr.net_list));
400     v3_htable_insert(vm->dev_mgr.net_table, (addr_t)(name), (addr_t)frontend);
401
402     return 0;
403 }
404
405
406 int v3_dev_connect_net(struct v3_vm_info * vm, 
407                        char * frontend_name, 
408                        struct v3_dev_net_ops * ops, 
409                        v3_cfg_tree_t * cfg, 
410                        void * private_data)
411 {
412     struct net_frontend * frontend = NULL;
413
414     frontend = (struct net_frontend *)v3_htable_search(vm->dev_mgr.net_table,
415                                                        (addr_t)frontend_name);
416     
417     if (frontend == NULL) {
418         PrintError("Could not find frontend net device %s\n", frontend_name);
419         return 0;
420     }
421
422     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
423         PrintError("Error connecting to net frontend %s\n", frontend_name);
424         return -1;
425     }
426
427     return 0;
428 }
429
430
431 struct cons_frontend {
432     int (*connect)(struct v3_vm_info * vm, 
433                    void * frontend_data, 
434                    struct v3_dev_console_ops * ops, 
435                    v3_cfg_tree_t * cfg, 
436                    void * priv_data);
437     
438
439     struct list_head cons_node;
440
441     void * priv_data;
442 };
443
444 int v3_dev_add_console_frontend(struct v3_vm_info * vm, 
445                                 char * name, 
446                                 int (*connect)(struct v3_vm_info * vm, 
447                                                void * frontend_data, 
448                                                struct v3_dev_console_ops * ops, 
449                                                v3_cfg_tree_t * cfg, 
450                                                void * private_data), 
451                                 void * priv_data)
452 {
453     struct cons_frontend * frontend = NULL;
454
455     frontend = (struct cons_frontend *)V3_Malloc(sizeof(struct cons_frontend));
456     memset(frontend, 0, sizeof(struct cons_frontend));
457     
458     frontend->connect = connect;
459     frontend->priv_data = priv_data;
460         
461     list_add(&(frontend->cons_node), &(vm->dev_mgr.cons_list));
462     v3_htable_insert(vm->dev_mgr.cons_table, (addr_t)(name), (addr_t)frontend);
463
464     return 0;
465 }
466
467
468 int v3_dev_connect_console(struct v3_vm_info * vm, 
469                            char * frontend_name, 
470                            struct v3_dev_console_ops * ops, 
471                            v3_cfg_tree_t * cfg, 
472                            void * private_data)
473 {
474     struct cons_frontend * frontend = NULL;
475
476     frontend = (struct cons_frontend *)v3_htable_search(vm->dev_mgr.cons_table,
477                                                         (addr_t)frontend_name);
478     
479     if (frontend == NULL) {
480         PrintError("Could not find frontend console device %s\n", frontend_name);
481         return 0;
482     }
483     
484     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
485         PrintError("Error connecting to console frontend %s\n", frontend_name);
486         return -1;
487     }
488
489     return 0;
490 }
491
492 struct char_frontend {
493     int (*connect)(struct v3_vm_info * vm, 
494                    void * frontend_data, 
495                    struct v3_dev_char_ops * ops, 
496                    v3_cfg_tree_t * cfg, 
497                    void * priv_data, 
498                    void ** push_fn_arg);
499     
500
501     struct list_head char_node;
502
503     void * priv_data;
504 };
505
506 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
507                              char * name, 
508                              int (*connect)(struct v3_vm_info * vm, 
509                                             void * frontend_data, 
510                                             struct v3_dev_char_ops * ops, 
511                                             v3_cfg_tree_t * cfg, 
512                                             void * private_data, 
513                                             void ** push_fn_arg), 
514                              void * priv_data)
515 {
516     struct char_frontend * frontend = NULL;
517
518     frontend = (struct char_frontend *)V3_Malloc(sizeof(struct char_frontend));
519     memset(frontend, 0, sizeof(struct char_frontend));
520     
521     frontend->connect = connect;
522     frontend->priv_data = priv_data;
523         
524     list_add(&(frontend->char_node), &(vm->dev_mgr.char_list));
525     v3_htable_insert(vm->dev_mgr.char_table, (addr_t)(name), (addr_t)frontend);
526
527     return 0;
528 }
529
530
531 int v3_dev_connect_char(struct v3_vm_info * vm, 
532                         char * frontend_name, 
533                         struct v3_dev_char_ops * ops, 
534                         v3_cfg_tree_t * cfg, 
535                         void * private_data, 
536                         void ** push_fn_arg)
537 {
538     struct char_frontend * frontend = NULL;
539
540     frontend = (struct char_frontend *)v3_htable_search(vm->dev_mgr.char_table,
541                                                         (addr_t)frontend_name);
542     
543     if (frontend == NULL) {
544         PrintError("Could not find frontend char device %s\n", frontend_name);
545         return 0;
546     }
547     
548     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data, push_fn_arg) == -1) {
549         PrintError("Error connecting to char frontend %s\n", frontend_name);
550         return -1;
551     }
552
553     return 0;
554 }
555