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.


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