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_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(VM_NONE, VCORE_NONE, "%d Virtual devices registered with Palacios\n", num_devices);
64     }
65 #endif
66
67     PrintDebug(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "Registering Device: %s\n", tmp_dev->name);
75
76         if (v3_htable_search(master_dev_table, (addr_t)(tmp_dev->name))) {
77             PrintError(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(vm, VCORE_NONE, "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, "devices");
158
159     if (!dev_mgr_ctx) { 
160         PrintError(vm, VCORE_NONE,"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(vm, VCORE_NONE, "Skipping device %s\n", dev->name);
172         }
173     }
174
175     if (v3_chkpt_save(dev_mgr_ctx, "num_devs", 4, &num_saved_devs) == -1) {
176         PrintError(vm, VCORE_NONE,"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(vm, VCORE_NONE,"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
195       if (dev->ops->save_extended) { 
196
197         V3_Print(vm, VCORE_NONE,"Saving state for device (%s) using extended interface\n",dev->name);
198
199         if (dev->ops->save_extended(chkpt,dev->name,dev->private_data)) {
200           PrintError(vm, VCORE_NONE,"Unable to save device %s\n",dev->name);
201           return -1;
202         }
203
204       } else if (dev->ops->save) {
205
206         struct v3_chkpt_ctx * dev_ctx = NULL;
207         
208         V3_Print(vm, VCORE_NONE,"Saving state for device (%s)\n", dev->name);
209         
210         dev_ctx = v3_chkpt_open_ctx(chkpt, dev->name);
211         
212         if (!dev_ctx) { 
213           PrintError(vm, VCORE_NONE,"Unable to open context for device %s\n",dev->name);
214           return -1;
215         }
216         
217         if (dev->ops->save(dev_ctx, dev->private_data)) {
218           PrintError(vm, VCORE_NONE,"Unable t save device %s\n",dev->name);
219           v3_chkpt_close_ctx(dev_ctx); 
220           return -1;
221         }
222         
223         v3_chkpt_close_ctx(dev_ctx);
224         
225       } else {
226         PrintError(vm, VCORE_NONE,"Error: %s save() not implemented\n",  dev->name);
227       }
228     }
229     
230     return 0;
231 }
232
233
234 int v3_load_vm_devices(struct v3_vm_info * vm, struct v3_chkpt * chkpt) {
235     struct vm_device * dev;
236     struct v3_chkpt_ctx * dev_mgr_ctx = NULL;
237     uint32_t num_devs = 0;
238     char * name_table = NULL;
239     int i = 0;
240
241     dev_mgr_ctx = v3_chkpt_open_ctx(chkpt, "devices");
242
243     if (!dev_mgr_ctx) { 
244         PrintError(vm, VCORE_NONE,"Unable to open devices for load\n");
245         return -1;
246     }
247
248     if (v3_chkpt_load(dev_mgr_ctx, "num_devs", 4, &num_devs) == -1) {
249         PrintError(vm, VCORE_NONE,"Unable to load num_devs\n");
250         v3_chkpt_close_ctx(dev_mgr_ctx);
251         return -1;
252     }
253
254     V3_Print(vm, VCORE_NONE,"Loading State for %d devices\n", num_devs);
255     
256     name_table = V3_Malloc(V3_MAX_DEVICE_NAME * num_devs);
257     
258     if (!name_table) { 
259         PrintError(vm, VCORE_NONE,"Unable to allocate space for device table\n");
260         v3_chkpt_close_ctx(dev_mgr_ctx);
261         return -1;
262     }
263
264     if (v3_chkpt_load(dev_mgr_ctx, "names", V3_MAX_DEVICE_NAME * num_devs, name_table) == -1) {
265         PrintError(vm, VCORE_NONE,"Unable to load device name table\n");
266         v3_chkpt_close_ctx(dev_mgr_ctx);
267         V3_Free(name_table);
268     }
269
270     v3_chkpt_close_ctx(dev_mgr_ctx);
271
272     for (i = 0; i < num_devs; i++) {
273         char * name = &(name_table[i * V3_MAX_DEVICE_NAME]);
274         struct v3_chkpt_ctx * dev_ctx = NULL;
275         dev = v3_find_dev(vm, name);
276
277         if (!dev) {
278             PrintError(vm, VCORE_NONE,"Tried to load state into non existant device: %s\n", name);
279             return -1;
280         }
281
282         if (dev->ops->load_extended) {
283
284           V3_Print(vm, VCORE_NONE,"Loading state for device (%s) using extended interface\n",name);
285
286           if (dev->ops->load_extended(chkpt,name,dev->private_data)) { 
287             PrintError(vm, VCORE_NONE,"Load of device %s failed\n",name);
288             return -1;
289           } 
290
291         } else if (dev->ops->load) {
292           
293           dev_ctx = v3_chkpt_open_ctx(chkpt, name);
294
295           if (!dev_ctx) {
296             PrintError(vm, VCORE_NONE,"Error missing device context (%s)\n", name);
297             return -1;
298           }
299
300           if (dev->ops->load(dev_ctx, dev->private_data)) { 
301             PrintError(vm, VCORE_NONE,"Load of device %s failed\n",name);
302             v3_chkpt_close_ctx(dev_ctx);        
303             return -1;
304           }
305
306           // should close context regardless of whether load was successful
307           v3_chkpt_close_ctx(dev_ctx);
308
309         }  else {
310           PrintError(vm, VCORE_NONE,"Error Device (%s) does not support load operation\n", name);
311           // this is OK
312         }
313     }
314
315     V3_Free(name_table);
316
317     return 0;
318 }
319
320
321 #endif
322
323 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr);
324
325 int v3_deinit_dev_mgr(struct v3_vm_info * vm) {
326     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
327     
328     // clear frontend lists
329
330     free_frontends(vm, mgr);
331
332     v3_free_htable(mgr->dev_table, 0, 0);
333
334     return 0;
335 }
336
337
338
339 int v3_create_device(struct v3_vm_info * vm, const char * dev_name, v3_cfg_tree_t * cfg) {
340     int (*dev_init)(struct v3_vm_info * vm, void * cfg_data);
341
342     dev_init = (void *)v3_htable_search(master_dev_table, (addr_t)dev_name);
343
344     if (dev_init == NULL) {
345         PrintError(vm, VCORE_NONE,"Could not find device %s in master device table\n", dev_name);
346         return -1;
347     }
348
349
350     if (dev_init(vm, cfg) == -1) {
351         PrintError(vm, VCORE_NONE,"Could not initialize Device %s\n", dev_name);
352         return -1;
353     }
354
355     return 0;
356 }
357
358
359
360
361 struct vm_device * v3_find_dev(struct v3_vm_info * vm, const char * dev_name) {
362     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
363
364     if (!dev_name) {
365         return NULL;
366     }
367
368     return (struct vm_device *)v3_htable_search(mgr->dev_table, (addr_t)dev_name);
369 }
370
371
372 /****************************************************************/
373 /* The remaining functions are called by the devices themselves */
374 /****************************************************************/
375
376 typedef enum {DEV_IO_HOOK, DEV_MSR_HOOK, DEV_CPUID_HOOK, DEV_MEM_HOOK, DEV_HCALL_HOOK} dev_rsrc_type_t;
377
378 struct dev_rsrc {
379     dev_rsrc_type_t type;
380     uint64_t rsrc;
381
382     struct list_head node;
383 };
384
385
386
387 static int add_resource(struct vm_device * dev, dev_rsrc_type_t type, uint64_t rsrc_id) {
388     struct dev_rsrc * resource = NULL;
389
390     resource = V3_Malloc(sizeof(struct dev_rsrc));
391
392     if (resource == NULL) {
393         PrintError(VM_NONE, VCORE_NONE,"Error: Could not allocate device resource\n");
394         return -1;
395     }
396
397     resource->rsrc = rsrc_id;
398     resource->type = type;
399
400     list_add(&(resource->node), &(dev->res_hooks));
401     return 0;
402 }
403
404 static int free_resource(struct vm_device * dev, dev_rsrc_type_t type, uint64_t rsrc_id) {
405     struct dev_rsrc * resource = NULL;
406     struct dev_rsrc * tmp;
407
408     list_for_each_entry_safe(resource, tmp, &(dev->res_hooks), node) {
409         if ((resource->type == type) && 
410             (resource->rsrc == rsrc_id)) {
411
412             list_del(&(resource->node));
413             V3_Free(resource);
414             
415             return 0;
416         }
417     }
418
419     return -1;
420 }
421
422
423 int v3_dev_hook_io(struct vm_device * dev, uint16_t port,
424                    int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data),
425                    int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data)) {
426     int ret = 0;
427     
428     ret = v3_hook_io_port(dev->vm, port, 
429                           (int (*)(struct guest_info * core, uint16_t, void *, uint_t, void *))read, 
430                           (int (*)(struct guest_info * core, uint16_t, void *, uint_t, void *))write, 
431                           (void *)dev->private_data);
432
433     if (ret == -1) {
434         return -1;
435     }
436
437     if (add_resource(dev, DEV_IO_HOOK, port) == -1) {
438         v3_unhook_io_port(dev->vm, port);
439         PrintError(dev->vm, VCORE_NONE,"Could not allocate io hook dev state\n");
440         return -1;
441     }
442     
443     return 0;
444 }
445
446
447 int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
448     if (free_resource(dev, DEV_IO_HOOK, port) == 0) {
449         return v3_unhook_io_port(dev->vm, port);           
450     } 
451
452     return -1;
453 }
454
455
456 int v3_dev_hook_msr(struct vm_device * dev, uint32_t msr,
457                     int (*read)(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data),
458                     int (*write)(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data)) {
459     int ret = 0;
460
461     ret = v3_hook_msr(dev->vm, msr, read, write, dev->private_data);
462
463     if (ret == -1) {
464         return -1;
465     }
466
467     if (add_resource(dev, DEV_MSR_HOOK, msr) == -1) {
468         v3_unhook_msr(dev->vm, msr);
469         return -1;
470     }
471
472     return 0;
473 }
474                   
475 int v3_dev_unhook_msr(struct vm_device * dev, uint32_t msr) {
476     if (free_resource(dev, DEV_MSR_HOOK, msr) == 0) {
477         return v3_unhook_msr(dev->vm, msr);
478     }
479
480     return -1;
481 }
482
483
484
485
486 int v3_remove_device(struct vm_device * dev) {
487     struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
488     struct dev_rsrc * resource = NULL;
489     struct dev_rsrc * tmp;
490
491     list_for_each_entry_safe(resource, tmp, &(dev->res_hooks), node) {
492         if (resource->type == DEV_IO_HOOK) {
493             v3_unhook_io_port(dev->vm, (uint16_t)(resource->rsrc));
494         } else if (resource->type == DEV_MSR_HOOK) {
495             v3_unhook_msr(dev->vm, (uint32_t)(resource->rsrc));
496         }
497
498         list_del(&(resource->node));
499         V3_Free(resource);    
500     }
501
502     if (dev->ops->free) {
503         dev->ops->free(dev->private_data);
504     } else {
505         PrintError(VM_NONE, VCORE_NONE,"Error: %s free() not implemented\n",  dev->name);
506     }
507
508     list_del(&(dev->dev_link));
509     mgr->num_devs--;
510
511     dev->vm = NULL;
512
513     V3_Free(dev);
514     return -1;
515 }
516
517
518 struct vm_device * v3_add_device(struct v3_vm_info * vm,
519                                  char * name, 
520                                  struct v3_device_ops * ops, 
521                                  void * private_data) {
522     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
523     struct vm_device * dev = NULL;
524
525
526     // Check if we already registered a device of the same name
527     if (v3_htable_search(mgr->dev_table, (addr_t)name) != (addr_t)NULL) {
528         PrintError(vm, VCORE_NONE,"Device with name (%s) already registered with VM\n", name); 
529         return NULL;
530     }
531
532     dev = (struct vm_device *)V3_Malloc(sizeof(struct vm_device));
533
534     if (dev == NULL) {
535         PrintError(vm, VCORE_NONE,"Cannot allocate in adding a device\n");
536         return NULL;
537     }
538
539     INIT_LIST_HEAD(&(dev->res_hooks));
540
541     strncpy(dev->name, name, 32);
542     dev->ops = ops;
543     dev->private_data = private_data;
544
545     dev->vm = vm;
546
547     list_add(&(dev->dev_link), &(mgr->dev_list));
548     mgr->num_devs++;
549
550     v3_htable_insert(mgr->dev_table, (addr_t)(dev->name), (addr_t)dev);
551
552     return dev;
553 }
554
555
556 void v3_print_dev_mgr(struct v3_vm_info * vm) {
557     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
558     struct vm_device * dev;
559
560     V3_Print(vm, VCORE_NONE,"%d devices registered with manager\n", mgr->num_devs);
561
562     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
563         V3_Print(vm, VCORE_NONE,"Device: %s\n", dev->name);
564     }
565
566     return;
567 }
568
569
570
571
572 struct blk_frontend {
573     int (*connect)(struct v3_vm_info * vm, 
574                     void * frontend_data, 
575                     struct v3_dev_blk_ops * ops, 
576                     v3_cfg_tree_t * cfg, 
577                     void * priv_data);
578         
579
580     struct list_head blk_node;
581
582     void * priv_data;
583 };
584
585
586
587 int v3_dev_add_blk_frontend(struct v3_vm_info * vm, 
588                             char * name, 
589                             int (*connect)(struct v3_vm_info * vm, 
590                                             void * frontend_data, 
591                                             struct v3_dev_blk_ops * ops, 
592                                             v3_cfg_tree_t * cfg, 
593                                             void * priv_data), 
594                             void * priv_data) {
595
596     struct blk_frontend * frontend = NULL;
597
598     frontend = (struct blk_frontend *)V3_Malloc(sizeof(struct blk_frontend));
599
600     if (!frontend) {
601         PrintError(vm, VCORE_NONE,"Cannot allocate in adding a block front end\n");
602         return -1;
603     }
604
605     memset(frontend, 0, sizeof(struct blk_frontend));
606     
607     frontend->connect = connect;
608     frontend->priv_data = priv_data;
609         
610     list_add(&(frontend->blk_node), &(vm->dev_mgr.blk_list));
611     v3_htable_insert(vm->dev_mgr.blk_table, (addr_t)(name), (addr_t)frontend);
612
613     return 0;
614 }
615
616 int v3_dev_connect_blk(struct v3_vm_info * vm, 
617                        char * frontend_name, 
618                        struct v3_dev_blk_ops * ops, 
619                        v3_cfg_tree_t * cfg, 
620                        void * private_data) {
621
622     struct blk_frontend * frontend = NULL;
623
624     frontend = (struct blk_frontend *)v3_htable_search(vm->dev_mgr.blk_table,
625                                                        (addr_t)frontend_name);
626     
627     if (frontend == NULL) {
628         PrintError(vm, VCORE_NONE,"Could not find frontend blk device %s\n", frontend_name);
629         return 0;
630     }
631
632     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
633         PrintError(vm, VCORE_NONE,"Error connecting to block frontend %s\n", frontend_name);
634         return -1;
635     }
636
637     return 0;
638 }
639
640
641
642 struct net_frontend {
643     int (*connect)(struct v3_vm_info * vm, 
644                     void * frontend_data, 
645                     struct v3_dev_net_ops * ops, 
646                     v3_cfg_tree_t * cfg, 
647                     void * priv_data);
648     
649
650     struct list_head net_node;
651
652     void * priv_data;
653 };
654
655
656 int v3_dev_add_net_frontend(struct v3_vm_info * vm, 
657                             char * name, 
658                             int (*connect)(struct v3_vm_info * vm, 
659                                             void * frontend_data, 
660                                             struct v3_dev_net_ops * ops, 
661                                             v3_cfg_tree_t * cfg, 
662                                             void * private_data), 
663                             void * priv_data)
664 {
665     struct net_frontend * frontend = NULL;
666
667     frontend = (struct net_frontend *)V3_Malloc(sizeof(struct net_frontend));
668
669     if (!frontend) {
670         PrintError(vm, VCORE_NONE,"Cannot allocate in adding a net front end\n");
671         return -1;
672     }
673
674     memset(frontend, 0, sizeof(struct net_frontend));
675     
676     frontend->connect = connect;
677     frontend->priv_data = priv_data;
678         
679     list_add(&(frontend->net_node), &(vm->dev_mgr.net_list));
680     v3_htable_insert(vm->dev_mgr.net_table, (addr_t)(name), (addr_t)frontend);
681
682     return 0;
683 }
684
685
686 int v3_dev_connect_net(struct v3_vm_info * vm, 
687                        char * frontend_name, 
688                        struct v3_dev_net_ops * ops, 
689                        v3_cfg_tree_t * cfg, 
690                        void * private_data)
691 {
692     struct net_frontend * frontend = NULL;
693
694     frontend = (struct net_frontend *)v3_htable_search(vm->dev_mgr.net_table,
695                                                        (addr_t)frontend_name);
696     
697     if (frontend == NULL) {
698         PrintError(vm, VCORE_NONE,"Could not find frontend net device %s\n", frontend_name);
699         return 0;
700     }
701
702     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
703         PrintError(vm, VCORE_NONE,"Error connecting to net frontend %s\n", frontend_name);
704         return -1;
705     }
706
707     return 0;
708 }
709
710
711 struct cons_frontend {
712     int (*connect)(struct v3_vm_info * vm, 
713                    void * frontend_data, 
714                    struct v3_dev_console_ops * ops, 
715                    v3_cfg_tree_t * cfg, 
716                    void * priv_data);
717     
718
719     struct list_head cons_node;
720
721     void * priv_data;
722 };
723
724 int v3_dev_add_console_frontend(struct v3_vm_info * vm, 
725                                 char * name, 
726                                 int (*connect)(struct v3_vm_info * vm, 
727                                                void * frontend_data, 
728                                                struct v3_dev_console_ops * ops, 
729                                                v3_cfg_tree_t * cfg, 
730                                                void * private_data), 
731                                 void * priv_data)
732 {
733     struct cons_frontend * frontend = NULL;
734
735     frontend = (struct cons_frontend *)V3_Malloc(sizeof(struct cons_frontend));
736
737     if (!frontend) {
738         PrintError(vm, VCORE_NONE,"Cannot allocate in adding a console front end\n");
739         return -1;
740     }
741
742     memset(frontend, 0, sizeof(struct cons_frontend));
743     
744     frontend->connect = connect;
745     frontend->priv_data = priv_data;
746         
747     list_add(&(frontend->cons_node), &(vm->dev_mgr.cons_list));
748     v3_htable_insert(vm->dev_mgr.cons_table, (addr_t)(name), (addr_t)frontend);
749
750     return 0;
751 }
752
753
754 int v3_dev_connect_console(struct v3_vm_info * vm, 
755                            char * frontend_name, 
756                            struct v3_dev_console_ops * ops, 
757                            v3_cfg_tree_t * cfg, 
758                            void * private_data)
759 {
760     struct cons_frontend * frontend = NULL;
761
762     frontend = (struct cons_frontend *)v3_htable_search(vm->dev_mgr.cons_table,
763                                                         (addr_t)frontend_name);
764     
765     if (frontend == NULL) {
766         PrintError(vm, VCORE_NONE,"Could not find frontend console device %s\n", frontend_name);
767         return 0;
768     }
769     
770     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
771         PrintError(vm, VCORE_NONE,"Error connecting to console frontend %s\n", frontend_name);
772         return -1;
773     }
774
775     return 0;
776 }
777
778 struct char_frontend {
779     int (*connect)(struct v3_vm_info * vm, 
780                    void * frontend_data, 
781                    struct v3_dev_char_ops * ops, 
782                    v3_cfg_tree_t * cfg, 
783                    void * priv_data, 
784                    void ** push_fn_arg);
785     
786
787     struct list_head char_node;
788
789     void * priv_data;
790 };
791
792 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
793                              char * name, 
794                              int (*connect)(struct v3_vm_info * vm, 
795                                             void * frontend_data, 
796                                             struct v3_dev_char_ops * ops, 
797                                             v3_cfg_tree_t * cfg, 
798                                             void * private_data, 
799                                             void ** push_fn_arg), 
800                              void * priv_data)
801 {
802     struct char_frontend * frontend = NULL;
803
804     frontend = (struct char_frontend *)V3_Malloc(sizeof(struct char_frontend));
805
806     if (!frontend) {
807         PrintError(vm, VCORE_NONE,"Cannot allocate in adding a char front end\n");
808         return -1;
809     }
810
811     memset(frontend, 0, sizeof(struct char_frontend));
812     
813     frontend->connect = connect;
814     frontend->priv_data = priv_data;
815         
816     list_add(&(frontend->char_node), &(vm->dev_mgr.char_list));
817     v3_htable_insert(vm->dev_mgr.char_table, (addr_t)(name), (addr_t)frontend);
818
819     return 0;
820 }
821
822
823 int v3_dev_connect_char(struct v3_vm_info * vm, 
824                         char * frontend_name, 
825                         struct v3_dev_char_ops * ops, 
826                         v3_cfg_tree_t * cfg, 
827                         void * private_data, 
828                         void ** push_fn_arg)
829 {
830     struct char_frontend * frontend = NULL;
831
832     frontend = (struct char_frontend *)v3_htable_search(vm->dev_mgr.char_table,
833                                                         (addr_t)frontend_name);
834     
835     if (frontend == NULL) {
836         PrintError(vm, VCORE_NONE,"Could not find frontend char device %s\n", frontend_name);
837         return 0;
838     }
839     
840     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data, push_fn_arg) == -1) {
841         PrintError(vm, VCORE_NONE,"Error connecting to char frontend %s\n", frontend_name);
842         return -1;
843     }
844
845     return 0;
846 }
847
848
849
850 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr) {
851     struct char_frontend * chr = NULL;
852     struct char_frontend * tmp_chr = NULL;
853     struct cons_frontend * cons = NULL;
854     struct cons_frontend * tmp_cons = NULL;
855     struct net_frontend * net = NULL;
856     struct net_frontend * tmp_net = NULL;
857     struct blk_frontend * blk = NULL;
858     struct blk_frontend * tmp_blk = NULL;
859
860
861
862     list_for_each_entry_safe(chr, tmp_chr, &(mgr->char_list), char_node) {
863         list_del(&(chr->char_node));
864         V3_Free(chr);
865     }
866
867     list_for_each_entry_safe(cons, tmp_cons, &(mgr->cons_list), cons_node) {
868         list_del(&(cons->cons_node));
869         V3_Free(cons);
870     }
871
872     list_for_each_entry_safe(net, tmp_net, &(mgr->net_list), net_node) {
873         list_del(&(net->net_node));
874         V3_Free(net);
875     }
876
877     list_for_each_entry_safe(blk, tmp_blk, &(mgr->blk_list), blk_node) {
878         list_del(&(blk->blk_node));
879         V3_Free(blk);
880     }
881
882     v3_free_htable(mgr->blk_table, 0, 0);
883     v3_free_htable(mgr->net_table, 0, 0);
884     v3_free_htable(mgr->char_table, 0, 0);
885     v3_free_htable(mgr->cons_table, 0, 0);
886
887
888     return 0;
889 }
890
891 int v3_attach_device(struct v3_vm_info * vm, struct vm_device * dev)
892 {
893   PrintError(vm, VCORE_NONE, "v3_attach_device is deprecated and no longer works\n");
894   return -1;
895 }
896
897 int v3_detach_device(struct vm_device * dev)
898 {
899   PrintError(VM_NONE, VCORE_NONE, "v3_detach_device is deprecated and no longer works\n");
900   return -1;
901 }
902
903 struct vm_device * v3_allocate_device(char * name, struct v3_device_ops * ops, void * private_data)
904 {
905   PrintError(VM_NONE, VCORE_NONE, "v3_allocate_device is deprecated and no longer works\n");
906   return 0;
907 }