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.


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