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.


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