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.


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