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.


Lots of pedantic error checking in Palacios proper, especially for memory
[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 #ifdef V3_CONFIG_CHECKPOINT
26 #include <palacios/vmm_checkpoint.h>
27
28 #define V3_MAX_DEVICE_NAME 32
29
30 #endif
31
32
33 #ifndef V3_CONFIG_DEBUG_DEV_MGR
34 #undef PrintDebug
35 #define PrintDebug(fmt, args...)
36 #endif
37
38
39 static struct hashtable * master_dev_table = NULL;
40
41 static uint_t dev_hash_fn(addr_t key) {
42     char * name = (char *)key;
43     return v3_hash_buffer((uchar_t *)name, strlen(name));
44 }
45
46 static int dev_eq_fn(addr_t key1, addr_t key2) {
47     char * name1 = (char *)key1;
48     char * name2 = (char *)key2;
49     
50     return (strcmp(name1, name2) == 0);
51 }
52
53
54 int V3_init_devices() {
55     extern struct v3_device_info __start__v3_devices[];
56     extern struct v3_device_info __stop__v3_devices[];
57     struct v3_device_info * tmp_dev =  __start__v3_devices;
58     int i = 0;
59
60 #ifdef V3_CONFIG_DEBUG_DEV_MGR
61     {
62         int num_devices = (__stop__v3_devices - __start__v3_devices) / sizeof(struct v3_device_info);
63         PrintDebug("%d Virtual devices registered with Palacios\n", num_devices);
64     }
65 #endif
66
67     PrintDebug("Start addres=%p, Stop address=%p\n", __start__v3_devices, __stop__v3_devices);
68
69     master_dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
70
71
72
73     while (tmp_dev != __stop__v3_devices) {
74         V3_Print("Registering Device: %s\n", tmp_dev->name);
75
76         if (v3_htable_search(master_dev_table, (addr_t)(tmp_dev->name))) {
77             PrintError("Multiple instance of device (%s)\n", tmp_dev->name);
78             return -1;
79         }
80
81         if (v3_htable_insert(master_dev_table, 
82                              (addr_t)(tmp_dev->name), 
83                              (addr_t)(tmp_dev->init)) == 0) {
84             PrintError("Could not add device %s to master list\n", tmp_dev->name);
85             return -1;
86         }
87
88         tmp_dev = &(__start__v3_devices[++i]);
89     }
90
91
92     return 0;
93 }
94
95
96 int V3_deinit_devices() {    
97     v3_free_htable(master_dev_table, 0, 0);
98     return 0;
99 }
100
101
102 int v3_init_dev_mgr(struct v3_vm_info * vm) {
103     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
104
105     INIT_LIST_HEAD(&(mgr->dev_list));
106     mgr->num_devs = 0;
107
108     mgr->dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
109
110     INIT_LIST_HEAD(&(mgr->blk_list));
111     INIT_LIST_HEAD(&(mgr->net_list));
112     INIT_LIST_HEAD(&(mgr->char_list));
113     INIT_LIST_HEAD(&(mgr->cons_list));
114
115     mgr->blk_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
116     mgr->net_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
117     mgr->char_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
118     mgr->cons_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
119     
120     return 0;
121 }
122
123
124 int v3_free_vm_devices(struct v3_vm_info * vm) {
125     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
126     struct vm_device * dev;
127     struct vm_device * tmp;
128
129     list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
130         v3_remove_device(dev);
131     }
132
133     return 0;
134 }
135
136 #ifdef V3_CONFIG_CHECKPOINT
137
138 int v3_save_vm_devices(struct v3_vm_info * vm, struct v3_chkpt * chkpt) {
139     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
140     struct vm_device * dev;
141     struct v3_chkpt_ctx * dev_mgr_ctx = NULL;
142
143     uint32_t num_saved_devs = 0;
144     uint32_t table_len = mgr->num_devs * V3_MAX_DEVICE_NAME;
145     char * name_table = NULL;
146     uint32_t tbl_offset = 0;
147     
148     name_table = V3_Malloc(table_len);
149
150     if (!name_table) { 
151         PrintError("Unable to allocate space in device manager save\n");
152         return -1;
153     }
154
155     memset(name_table, 0, table_len);
156     
157     dev_mgr_ctx = v3_chkpt_open_ctx(chkpt, NULL, "devices");
158
159     if (!dev_mgr_ctx) { 
160         PrintError("Unable to open device manager context\n");
161         V3_Free(name_table);
162         return -1;
163     }
164
165     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
166         if (dev->ops->save) {
167             strncpy(name_table + tbl_offset, dev->name, V3_MAX_DEVICE_NAME);
168             tbl_offset += V3_MAX_DEVICE_NAME;
169             num_saved_devs++;
170         }  else {
171             PrintDebug("Skipping device %s\n");
172         }
173     }
174
175     if (v3_chkpt_save(dev_mgr_ctx, "num_devs", 4, &num_saved_devs) == -1) {
176         PrintError("Unable to store num_devs\n");
177         v3_chkpt_close_ctx(dev_mgr_ctx); 
178         V3_Free(name_table);
179         return -1;
180     }
181
182     if (v3_chkpt_save(dev_mgr_ctx, "names", num_saved_devs*V3_MAX_DEVICE_NAME, name_table) == -1) {
183         PrintError("Unable to store names of devices\n");
184         v3_chkpt_close_ctx(dev_mgr_ctx); 
185         V3_Free(name_table);
186         return -1;
187     }
188     
189     v3_chkpt_close_ctx(dev_mgr_ctx);
190
191     V3_Free(name_table);
192
193     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
194         if (dev->ops->save) {
195             struct v3_chkpt_ctx * dev_ctx = NULL;
196             
197             V3_Print("Saving state for device (%s)\n", dev->name);
198             
199             dev_ctx = v3_chkpt_open_ctx(chkpt, NULL, dev->name);
200             
201             if (!dev_ctx) { 
202                 PrintError("Unable to open context for device %s\n",dev->name);
203                 return -1;
204             }
205
206             if (dev->ops->save(dev_ctx, dev->private_data)) {
207                 PrintError("Unable t save device %s\n",dev->name);
208                 v3_chkpt_close_ctx(dev_ctx); 
209                 return -1;
210             }
211
212             v3_chkpt_close_ctx(dev_ctx);
213
214             // Error checking?? 
215         } else {
216             PrintError("Error: %s save() not implemented\n",  dev->name);
217         }
218     }
219
220     return 0;
221 }
222
223
224 int v3_load_vm_devices(struct v3_vm_info * vm, struct v3_chkpt * chkpt) {
225     struct vm_device * dev;
226     struct v3_chkpt_ctx * dev_mgr_ctx = NULL;
227     uint32_t num_devs = 0;
228     char * name_table = NULL;
229     int i = 0;
230
231     dev_mgr_ctx = v3_chkpt_open_ctx(chkpt, NULL, "devices");
232
233     if (!dev_mgr_ctx) { 
234         PrintError("Unable to open devices for load\n");
235         return -1;
236     }
237
238     if (v3_chkpt_load(dev_mgr_ctx, "num_devs", 4, &num_devs) == -1) {
239         PrintError("Unable to load num_devs\n");
240         v3_chkpt_close_ctx(dev_mgr_ctx);
241         return -1;
242     }
243
244     V3_Print("Loading State for %d devices\n", num_devs);
245     
246     name_table = V3_Malloc(V3_MAX_DEVICE_NAME * num_devs);
247     
248     if (!name_table) { 
249         PrintError("Unable to allocate space for device table\n");
250         v3_chkpt_close_ctx(dev_mgr_ctx);
251         return -1;
252     }
253
254     if (v3_chkpt_load(dev_mgr_ctx, "names", V3_MAX_DEVICE_NAME * num_devs, name_table) == -1) {
255         PrintError("Unable to load device name table\n");
256         v3_chkpt_close_ctx(dev_mgr_ctx);
257         V3_Free(name_table);
258     }
259
260     v3_chkpt_close_ctx(dev_mgr_ctx);
261
262     for (i = 0; i < num_devs; i++) {
263         char * name = &(name_table[i * V3_MAX_DEVICE_NAME]);
264         struct v3_chkpt_ctx * dev_ctx = NULL;
265         dev = v3_find_dev(vm, name);
266
267         if (!dev) {
268             PrintError("Tried to load state into non existant device: %s\n", name);
269             continue;
270         }
271
272         if (!dev->ops->load) {
273             PrintError("Error Device (%s) does not support load operation\n", name);
274             continue;
275         }
276
277         dev_ctx = v3_chkpt_open_ctx(chkpt, NULL, name);
278
279         if (!dev_ctx) {
280             PrintError("Error missing device context (%s)\n", name);
281             continue;
282         }
283
284
285         if (dev->ops->load(dev_ctx, dev->private_data)) { 
286             PrintError("Load of device %s failed\n",name);
287         }
288
289         v3_chkpt_close_ctx(dev_ctx);
290     }
291
292     V3_Free(name_table);
293
294     return 0;
295 }
296
297
298 #endif
299
300 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr);
301
302 int v3_deinit_dev_mgr(struct v3_vm_info * vm) {
303     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
304     
305     // clear frontend lists
306
307     free_frontends(vm, mgr);
308
309     v3_free_htable(mgr->dev_table, 0, 0);
310
311     return 0;
312 }
313
314
315
316 int v3_create_device(struct v3_vm_info * vm, const char * dev_name, v3_cfg_tree_t * cfg) {
317     int (*dev_init)(struct v3_vm_info * vm, void * cfg_data);
318
319     dev_init = (void *)v3_htable_search(master_dev_table, (addr_t)dev_name);
320
321     if (dev_init == NULL) {
322         PrintError("Could not find device %s in master device table\n", dev_name);
323         return -1;
324     }
325
326
327     if (dev_init(vm, cfg) == -1) {
328         PrintError("Could not initialize Device %s\n", dev_name);
329         return -1;
330     }
331
332     return 0;
333 }
334
335
336
337
338 struct vm_device * v3_find_dev(struct v3_vm_info * vm, const char * dev_name) {
339     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
340
341     if (!dev_name) {
342         return NULL;
343     }
344
345     return (struct vm_device *)v3_htable_search(mgr->dev_table, (addr_t)dev_name);
346 }
347
348
349 /****************************************************************/
350 /* The remaining functions are called by the devices themselves */
351 /****************************************************************/
352
353 typedef enum {DEV_IO_HOOK, DEV_MSR_HOOK, DEV_CPUID_HOOK, DEV_MEM_HOOK, DEV_HCALL_HOOK} dev_rsrc_type_t;
354
355 struct dev_rsrc {
356     dev_rsrc_type_t type;
357     uint64_t rsrc;
358
359     struct list_head node;
360 };
361
362
363
364 static int add_resource(struct vm_device * dev, dev_rsrc_type_t type, uint64_t rsrc_id) {
365     struct dev_rsrc * resource = NULL;
366
367     resource = V3_Malloc(sizeof(struct dev_rsrc));
368
369     if (resource == NULL) {
370         PrintError("Error: Could not allocate device resource\n");
371         return -1;
372     }
373
374     resource->rsrc = rsrc_id;
375     resource->type = type;
376
377     list_add(&(resource->node), &(dev->res_hooks));
378     return 0;
379 }
380
381 static int free_resource(struct vm_device * dev, dev_rsrc_type_t type, uint64_t rsrc_id) {
382     struct dev_rsrc * resource = NULL;
383     struct dev_rsrc * tmp;
384
385     list_for_each_entry_safe(resource, tmp, &(dev->res_hooks), node) {
386         if ((resource->type == type) && 
387             (resource->rsrc == rsrc_id)) {
388
389             list_del(&(resource->node));
390             V3_Free(resource);
391             
392             return 0;
393         }
394     }
395
396     return -1;
397 }
398
399
400 int v3_dev_hook_io(struct vm_device * dev, uint16_t port,
401                    int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data),
402                    int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data)) {
403     int ret = 0;
404     
405     ret = v3_hook_io_port(dev->vm, port, 
406                           (int (*)(struct guest_info * core, uint16_t, void *, uint_t, void *))read, 
407                           (int (*)(struct guest_info * core, uint16_t, void *, uint_t, void *))write, 
408                           (void *)dev->private_data);
409
410     if (ret == -1) {
411         return -1;
412     }
413
414     if (add_resource(dev, DEV_IO_HOOK, port) == -1) {
415         v3_unhook_io_port(dev->vm, port);
416         PrintError("Could not allocate io hook dev state\n");
417         return -1;
418     }
419     
420     return 0;
421 }
422
423
424 int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
425     if (free_resource(dev, DEV_IO_HOOK, port) == 0) {
426         return v3_unhook_io_port(dev->vm, port);           
427     } 
428
429     return -1;
430 }
431
432
433 int v3_dev_hook_msr(struct vm_device * dev, uint32_t msr,
434                     int (*read)(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data),
435                     int (*write)(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data)) {
436     int ret = 0;
437
438     ret = v3_hook_msr(dev->vm, msr, read, write, dev->private_data);
439
440     if (ret == -1) {
441         return -1;
442     }
443
444     if (add_resource(dev, DEV_MSR_HOOK, msr) == -1) {
445         v3_unhook_msr(dev->vm, msr);
446         return -1;
447     }
448
449     return 0;
450 }
451                   
452 int v3_dev_unhook_msr(struct vm_device * dev, uint32_t msr) {
453     if (free_resource(dev, DEV_MSR_HOOK, msr) == 0) {
454         return v3_unhook_msr(dev->vm, msr);
455     }
456
457     return -1;
458 }
459
460
461
462
463 int v3_remove_device(struct vm_device * dev) {
464     struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
465     struct dev_rsrc * resource = NULL;
466     struct dev_rsrc * tmp;
467
468     list_for_each_entry_safe(resource, tmp, &(dev->res_hooks), node) {
469         if (resource->type == DEV_IO_HOOK) {
470             v3_unhook_io_port(dev->vm, (uint16_t)(resource->rsrc));
471         } else if (resource->type == DEV_MSR_HOOK) {
472             v3_unhook_msr(dev->vm, (uint32_t)(resource->rsrc));
473         }
474
475         list_del(&(resource->node));
476         V3_Free(resource);    
477     }
478
479     if (dev->ops->free) {
480         dev->ops->free(dev->private_data);
481     } else {
482         PrintError("Error: %s free() not implemented\n",  dev->name);
483     }
484
485     list_del(&(dev->dev_link));
486     mgr->num_devs--;
487
488     dev->vm = NULL;
489
490     V3_Free(dev);
491     return -1;
492 }
493
494
495 struct vm_device * v3_add_device(struct v3_vm_info * vm,
496                                  char * name, 
497                                  struct v3_device_ops * ops, 
498                                  void * private_data) {
499     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
500     struct vm_device * dev = NULL;
501
502
503     // Check if we already registered a device of the same name
504     if (v3_htable_search(mgr->dev_table, (addr_t)name) != (addr_t)NULL) {
505         PrintError("Device with name (%s) already registered with VM\n", name); 
506         return NULL;
507     }
508
509     dev = (struct vm_device *)V3_Malloc(sizeof(struct vm_device));
510
511     if (dev == NULL) {
512         PrintError("Cannot allocate in adding a device\n");
513         return NULL;
514     }
515
516     INIT_LIST_HEAD(&(dev->res_hooks));
517
518     strncpy(dev->name, name, 32);
519     dev->ops = ops;
520     dev->private_data = private_data;
521
522     dev->vm = vm;
523
524     list_add(&(dev->dev_link), &(mgr->dev_list));
525     mgr->num_devs++;
526
527     v3_htable_insert(mgr->dev_table, (addr_t)(dev->name), (addr_t)dev);
528
529     return dev;
530 }
531
532
533 void v3_print_dev_mgr(struct v3_vm_info * vm) {
534     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
535     struct vm_device * dev;
536
537     V3_Print("%d devices registered with manager\n", mgr->num_devs);
538
539     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
540         V3_Print("Device: %s\n", dev->name);
541     }
542
543     return;
544 }
545
546
547
548
549 struct blk_frontend {
550     int (*connect)(struct v3_vm_info * vm, 
551                     void * frontend_data, 
552                     struct v3_dev_blk_ops * ops, 
553                     v3_cfg_tree_t * cfg, 
554                     void * priv_data);
555         
556
557     struct list_head blk_node;
558
559     void * priv_data;
560 };
561
562
563
564 int v3_dev_add_blk_frontend(struct v3_vm_info * vm, 
565                             char * name, 
566                             int (*connect)(struct v3_vm_info * vm, 
567                                             void * frontend_data, 
568                                             struct v3_dev_blk_ops * ops, 
569                                             v3_cfg_tree_t * cfg, 
570                                             void * priv_data), 
571                             void * priv_data) {
572
573     struct blk_frontend * frontend = NULL;
574
575     frontend = (struct blk_frontend *)V3_Malloc(sizeof(struct blk_frontend));
576
577     if (!frontend) {
578         PrintError("Cannot allocate in adding a block front end\n");
579         return -1;
580     }
581
582     memset(frontend, 0, sizeof(struct blk_frontend));
583     
584     frontend->connect = connect;
585     frontend->priv_data = priv_data;
586         
587     list_add(&(frontend->blk_node), &(vm->dev_mgr.blk_list));
588     v3_htable_insert(vm->dev_mgr.blk_table, (addr_t)(name), (addr_t)frontend);
589
590     return 0;
591 }
592
593 int v3_dev_connect_blk(struct v3_vm_info * vm, 
594                        char * frontend_name, 
595                        struct v3_dev_blk_ops * ops, 
596                        v3_cfg_tree_t * cfg, 
597                        void * private_data) {
598
599     struct blk_frontend * frontend = NULL;
600
601     frontend = (struct blk_frontend *)v3_htable_search(vm->dev_mgr.blk_table,
602                                                        (addr_t)frontend_name);
603     
604     if (frontend == NULL) {
605         PrintError("Could not find frontend blk device %s\n", frontend_name);
606         return 0;
607     }
608
609     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
610         PrintError("Error connecting to block frontend %s\n", frontend_name);
611         return -1;
612     }
613
614     return 0;
615 }
616
617
618
619 struct net_frontend {
620     int (*connect)(struct v3_vm_info * vm, 
621                     void * frontend_data, 
622                     struct v3_dev_net_ops * ops, 
623                     v3_cfg_tree_t * cfg, 
624                     void * priv_data);
625     
626
627     struct list_head net_node;
628
629     void * priv_data;
630 };
631
632
633 int v3_dev_add_net_frontend(struct v3_vm_info * vm, 
634                             char * name, 
635                             int (*connect)(struct v3_vm_info * vm, 
636                                             void * frontend_data, 
637                                             struct v3_dev_net_ops * ops, 
638                                             v3_cfg_tree_t * cfg, 
639                                             void * private_data), 
640                             void * priv_data)
641 {
642     struct net_frontend * frontend = NULL;
643
644     frontend = (struct net_frontend *)V3_Malloc(sizeof(struct net_frontend));
645
646     if (!frontend) {
647         PrintError("Cannot allocate in adding a net front end\n");
648         return -1;
649     }
650
651     memset(frontend, 0, sizeof(struct net_frontend));
652     
653     frontend->connect = connect;
654     frontend->priv_data = priv_data;
655         
656     list_add(&(frontend->net_node), &(vm->dev_mgr.net_list));
657     v3_htable_insert(vm->dev_mgr.net_table, (addr_t)(name), (addr_t)frontend);
658
659     return 0;
660 }
661
662
663 int v3_dev_connect_net(struct v3_vm_info * vm, 
664                        char * frontend_name, 
665                        struct v3_dev_net_ops * ops, 
666                        v3_cfg_tree_t * cfg, 
667                        void * private_data)
668 {
669     struct net_frontend * frontend = NULL;
670
671     frontend = (struct net_frontend *)v3_htable_search(vm->dev_mgr.net_table,
672                                                        (addr_t)frontend_name);
673     
674     if (frontend == NULL) {
675         PrintError("Could not find frontend net device %s\n", frontend_name);
676         return 0;
677     }
678
679     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
680         PrintError("Error connecting to net frontend %s\n", frontend_name);
681         return -1;
682     }
683
684     return 0;
685 }
686
687
688 struct cons_frontend {
689     int (*connect)(struct v3_vm_info * vm, 
690                    void * frontend_data, 
691                    struct v3_dev_console_ops * ops, 
692                    v3_cfg_tree_t * cfg, 
693                    void * priv_data);
694     
695
696     struct list_head cons_node;
697
698     void * priv_data;
699 };
700
701 int v3_dev_add_console_frontend(struct v3_vm_info * vm, 
702                                 char * name, 
703                                 int (*connect)(struct v3_vm_info * vm, 
704                                                void * frontend_data, 
705                                                struct v3_dev_console_ops * ops, 
706                                                v3_cfg_tree_t * cfg, 
707                                                void * private_data), 
708                                 void * priv_data)
709 {
710     struct cons_frontend * frontend = NULL;
711
712     frontend = (struct cons_frontend *)V3_Malloc(sizeof(struct cons_frontend));
713
714     if (!frontend) {
715         PrintError("Cannot allocate in adding a console front end\n");
716         return -1;
717     }
718
719     memset(frontend, 0, sizeof(struct cons_frontend));
720     
721     frontend->connect = connect;
722     frontend->priv_data = priv_data;
723         
724     list_add(&(frontend->cons_node), &(vm->dev_mgr.cons_list));
725     v3_htable_insert(vm->dev_mgr.cons_table, (addr_t)(name), (addr_t)frontend);
726
727     return 0;
728 }
729
730
731 int v3_dev_connect_console(struct v3_vm_info * vm, 
732                            char * frontend_name, 
733                            struct v3_dev_console_ops * ops, 
734                            v3_cfg_tree_t * cfg, 
735                            void * private_data)
736 {
737     struct cons_frontend * frontend = NULL;
738
739     frontend = (struct cons_frontend *)v3_htable_search(vm->dev_mgr.cons_table,
740                                                         (addr_t)frontend_name);
741     
742     if (frontend == NULL) {
743         PrintError("Could not find frontend console device %s\n", frontend_name);
744         return 0;
745     }
746     
747     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
748         PrintError("Error connecting to console frontend %s\n", frontend_name);
749         return -1;
750     }
751
752     return 0;
753 }
754
755 struct char_frontend {
756     int (*connect)(struct v3_vm_info * vm, 
757                    void * frontend_data, 
758                    struct v3_dev_char_ops * ops, 
759                    v3_cfg_tree_t * cfg, 
760                    void * priv_data, 
761                    void ** push_fn_arg);
762     
763
764     struct list_head char_node;
765
766     void * priv_data;
767 };
768
769 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
770                              char * name, 
771                              int (*connect)(struct v3_vm_info * vm, 
772                                             void * frontend_data, 
773                                             struct v3_dev_char_ops * ops, 
774                                             v3_cfg_tree_t * cfg, 
775                                             void * private_data, 
776                                             void ** push_fn_arg), 
777                              void * priv_data)
778 {
779     struct char_frontend * frontend = NULL;
780
781     frontend = (struct char_frontend *)V3_Malloc(sizeof(struct char_frontend));
782
783     if (!frontend) {
784         PrintError("Cannot allocate in adding a char front end\n");
785         return -1;
786     }
787
788     memset(frontend, 0, sizeof(struct char_frontend));
789     
790     frontend->connect = connect;
791     frontend->priv_data = priv_data;
792         
793     list_add(&(frontend->char_node), &(vm->dev_mgr.char_list));
794     v3_htable_insert(vm->dev_mgr.char_table, (addr_t)(name), (addr_t)frontend);
795
796     return 0;
797 }
798
799
800 int v3_dev_connect_char(struct v3_vm_info * vm, 
801                         char * frontend_name, 
802                         struct v3_dev_char_ops * ops, 
803                         v3_cfg_tree_t * cfg, 
804                         void * private_data, 
805                         void ** push_fn_arg)
806 {
807     struct char_frontend * frontend = NULL;
808
809     frontend = (struct char_frontend *)v3_htable_search(vm->dev_mgr.char_table,
810                                                         (addr_t)frontend_name);
811     
812     if (frontend == NULL) {
813         PrintError("Could not find frontend char device %s\n", frontend_name);
814         return 0;
815     }
816     
817     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data, push_fn_arg) == -1) {
818         PrintError("Error connecting to char frontend %s\n", frontend_name);
819         return -1;
820     }
821
822     return 0;
823 }
824
825
826
827 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr) {
828     struct char_frontend * chr = NULL;
829     struct char_frontend * tmp_chr = NULL;
830     struct cons_frontend * cons = NULL;
831     struct cons_frontend * tmp_cons = NULL;
832     struct net_frontend * net = NULL;
833     struct net_frontend * tmp_net = NULL;
834     struct blk_frontend * blk = NULL;
835     struct blk_frontend * tmp_blk = NULL;
836
837
838
839     list_for_each_entry_safe(chr, tmp_chr, &(mgr->char_list), char_node) {
840         list_del(&(chr->char_node));
841         V3_Free(chr);
842     }
843
844     list_for_each_entry_safe(cons, tmp_cons, &(mgr->cons_list), cons_node) {
845         list_del(&(cons->cons_node));
846         V3_Free(cons);
847     }
848
849     list_for_each_entry_safe(net, tmp_net, &(mgr->net_list), net_node) {
850         list_del(&(net->net_node));
851         V3_Free(net);
852     }
853
854     list_for_each_entry_safe(blk, tmp_blk, &(mgr->blk_list), blk_node) {
855         list_del(&(blk->blk_node));
856         V3_Free(blk);
857     }
858
859     v3_free_htable(mgr->blk_table, 0, 0);
860     v3_free_htable(mgr->net_table, 0, 0);
861     v3_free_htable(mgr->char_table, 0, 0);
862     v3_free_htable(mgr->cons_table, 0, 0);
863
864
865     return 0;
866 }