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.


Corrected write ordering in device manager state save to conform with stream requirements
[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 #endif
28
29
30 #ifndef V3_CONFIG_DEBUG_DEV_MGR
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35
36 static struct hashtable * master_dev_table = NULL;
37
38 static uint_t dev_hash_fn(addr_t key) {
39     char * name = (char *)key;
40     return v3_hash_buffer((uchar_t *)name, strlen(name));
41 }
42
43 static int dev_eq_fn(addr_t key1, addr_t key2) {
44     char * name1 = (char *)key1;
45     char * name2 = (char *)key2;
46     
47     return (strcmp(name1, name2) == 0);
48 }
49
50
51 int V3_init_devices() {
52     extern struct v3_device_info __start__v3_devices[];
53     extern struct v3_device_info __stop__v3_devices[];
54     struct v3_device_info * tmp_dev =  __start__v3_devices;
55     int i = 0;
56
57 #ifdef V3_CONFIG_DEBUG_DEV_MGR
58     {
59         int num_devices = (__stop__v3_devices - __start__v3_devices) / sizeof(struct v3_device_info);
60         PrintDebug("%d Virtual devices registered with Palacios\n", num_devices);
61     }
62 #endif
63
64     PrintDebug("Start addres=%p, Stop address=%p\n", __start__v3_devices, __stop__v3_devices);
65
66     master_dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
67
68
69
70     while (tmp_dev != __stop__v3_devices) {
71         V3_Print("Registering Device: %s\n", tmp_dev->name);
72
73         if (v3_htable_search(master_dev_table, (addr_t)(tmp_dev->name))) {
74             PrintError("Multiple instance of device (%s)\n", tmp_dev->name);
75             return -1;
76         }
77
78         if (v3_htable_insert(master_dev_table, 
79                              (addr_t)(tmp_dev->name), 
80                              (addr_t)(tmp_dev->init)) == 0) {
81             PrintError("Could not add device %s to master list\n", tmp_dev->name);
82             return -1;
83         }
84
85         tmp_dev = &(__start__v3_devices[++i]);
86     }
87
88
89     return 0;
90 }
91
92
93 int V3_deinit_devices() {    
94     v3_free_htable(master_dev_table, 0, 0);
95     return 0;
96 }
97
98
99 int v3_init_dev_mgr(struct v3_vm_info * vm) {
100     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
101
102     INIT_LIST_HEAD(&(mgr->dev_list));
103     mgr->num_devs = 0;
104
105     mgr->dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
106
107     INIT_LIST_HEAD(&(mgr->blk_list));
108     INIT_LIST_HEAD(&(mgr->net_list));
109     INIT_LIST_HEAD(&(mgr->char_list));
110     INIT_LIST_HEAD(&(mgr->cons_list));
111
112     mgr->blk_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
113     mgr->net_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
114     mgr->char_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
115     mgr->cons_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
116     
117     return 0;
118 }
119
120
121 int v3_free_vm_devices(struct v3_vm_info * vm) {
122     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
123     struct vm_device * dev;
124     struct vm_device * tmp;
125
126     list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
127         v3_remove_device(dev);
128     }
129
130     return 0;
131 }
132
133 #ifdef V3_CONFIG_CHECKPOINT
134
135 int v3_save_vm_devices(struct v3_vm_info * vm, struct v3_chkpt * chkpt) {
136     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
137     struct vm_device * dev;
138     struct v3_chkpt_ctx * dev_mgr_ctx = NULL;
139
140     uint32_t num_saved_devs = 0;
141     uint32_t table_len = mgr->num_devs * 32;
142     char * name_table = NULL;
143     uint32_t tbl_offset = 0;
144     
145     name_table = V3_Malloc(table_len);
146
147     memset(name_table, 0, table_len);
148     
149
150     dev_mgr_ctx = v3_chkpt_open_ctx(chkpt, NULL, "devices");
151
152     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
153         if (dev->ops->save) {
154             strncpy(name_table + tbl_offset, dev->name, 32);
155             tbl_offset += 32;
156             num_saved_devs++;
157         }         
158     }
159
160     v3_chkpt_save(dev_mgr_ctx, "num_devs", 4, &num_saved_devs); 
161     v3_chkpt_save(dev_mgr_ctx, "names", table_len, name_table);
162
163   list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
164         if (dev->ops->save) {
165             struct v3_chkpt_ctx * dev_ctx = NULL;
166             
167             V3_Print("Saving state for device (%s)\n", dev->name);
168             
169             dev_ctx = v3_chkpt_open_ctx(chkpt, dev_mgr_ctx, dev->name);
170
171             dev->ops->save(dev_ctx, dev->private_data);
172
173             v3_chkpt_close_ctx(dev_ctx);
174
175             // Error checking?? 
176         } else {
177             PrintError("Error: %s save() not implemented\n",  dev->name);
178         }
179     }
180
181     
182     // Specify which devices were saved
183     V3_Free(name_table);
184
185     v3_chkpt_close_ctx(dev_mgr_ctx);
186     
187     return 0;
188 }
189
190
191 int v3_load_vm_devices(struct v3_vm_info * vm, struct v3_chkpt * chkpt) {
192     struct vm_device * dev;
193     struct v3_chkpt_ctx * dev_mgr_ctx = NULL;
194     uint32_t num_devs = 0;
195     char * name_table = NULL;
196     int i = 0;
197
198     dev_mgr_ctx = v3_chkpt_open_ctx(chkpt, NULL, "devices");
199
200     v3_chkpt_load(dev_mgr_ctx, "num_devs", 4, &num_devs);
201
202     V3_Print("Loading State for %d devices\n", num_devs);
203     
204     name_table = V3_Malloc(32 * num_devs);
205
206     v3_chkpt_load(dev_mgr_ctx, "names", 32 * num_devs, name_table);
207
208     for (i = 0; i < num_devs; i++) {
209         char * name = &(name_table[i * 32]);
210         struct v3_chkpt_ctx * dev_ctx = NULL;
211         dev = v3_find_dev(vm, name);
212
213         if (!dev) {
214             PrintError("Tried to load state into non existant device: %s\n", name);
215             continue;
216         }
217
218         if (!dev->ops->load) {
219             PrintError("Error Device (%s) does not support load operation\n", name);
220             continue;
221         }
222
223         dev_ctx = v3_chkpt_open_ctx(chkpt, dev_mgr_ctx, name);
224
225         if (!dev_ctx) {
226             PrintError("Error missing device context (%s)\n", name);
227             continue;
228         }
229
230
231         dev->ops->load(dev_ctx, dev->private_data);
232     }
233
234     return 0;
235 }
236
237
238 #endif
239
240 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr);
241
242 int v3_deinit_dev_mgr(struct v3_vm_info * vm) {
243     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
244     
245     // clear frontend lists
246
247     free_frontends(vm, mgr);
248
249
250
251     v3_free_htable(mgr->dev_table, 0, 0);
252
253     return 0;
254 }
255
256
257
258 int v3_create_device(struct v3_vm_info * vm, const char * dev_name, v3_cfg_tree_t * cfg) {
259     int (*dev_init)(struct v3_vm_info * vm, void * cfg_data);
260
261     dev_init = (void *)v3_htable_search(master_dev_table, (addr_t)dev_name);
262
263     if (dev_init == NULL) {
264         PrintError("Could not find device %s in master device table\n", dev_name);
265         return -1;
266     }
267
268
269     if (dev_init(vm, cfg) == -1) {
270         PrintError("Could not initialize Device %s\n", dev_name);
271         return -1;
272     }
273
274     return 0;
275 }
276
277
278
279
280 struct vm_device * v3_find_dev(struct v3_vm_info * vm, const char * dev_name) {
281     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
282
283     if (!dev_name) {
284         return NULL;
285     }
286
287     return (struct vm_device *)v3_htable_search(mgr->dev_table, (addr_t)dev_name);
288 }
289
290
291 /****************************************************************/
292 /* The remaining functions are called by the devices themselves */
293 /****************************************************************/
294
295 typedef enum {DEV_IO_HOOK, DEV_MSR_HOOK, DEV_CPUID_HOOK, DEV_MEM_HOOK, DEV_HCALL_HOOK} dev_rsrc_type_t;
296
297 struct dev_rsrc {
298     dev_rsrc_type_t type;
299     uint64_t rsrc;
300
301     struct list_head node;
302 };
303
304
305
306 static int add_resource(struct vm_device * dev, dev_rsrc_type_t type, uint64_t rsrc_id) {
307     struct dev_rsrc * resource = NULL;
308
309     resource = V3_Malloc(sizeof(struct dev_rsrc));
310
311     if (resource == NULL) {
312         PrintError("Error: Could not allocate device resource\n");
313         return -1;
314     }
315
316     resource->rsrc = rsrc_id;
317     resource->type = type;
318
319     list_add(&(resource->node), &(dev->res_hooks));
320     return 0;
321 }
322
323 static int free_resource(struct vm_device * dev, dev_rsrc_type_t type, uint64_t rsrc_id) {
324     struct dev_rsrc * resource = NULL;
325     struct dev_rsrc * tmp;
326
327     list_for_each_entry_safe(resource, tmp, &(dev->res_hooks), node) {
328         if ((resource->type == type) && 
329             (resource->rsrc == rsrc_id)) {
330
331             list_del(&(resource->node));
332             V3_Free(resource);
333             
334             return 0;
335         }
336     }
337
338     return -1;
339 }
340
341
342 int v3_dev_hook_io(struct vm_device * dev, uint16_t port,
343                    int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data),
344                    int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data)) {
345     int ret = 0;
346     
347     ret = v3_hook_io_port(dev->vm, port, 
348                           (int (*)(struct guest_info * core, uint16_t, void *, uint_t, void *))read, 
349                           (int (*)(struct guest_info * core, uint16_t, void *, uint_t, void *))write, 
350                           (void *)dev->private_data);
351
352     if (ret == -1) {
353         return -1;
354     }
355
356     if (add_resource(dev, DEV_IO_HOOK, port) == -1) {
357         v3_unhook_io_port(dev->vm, port);
358         PrintError("Could not allocate io hook dev state\n");
359         return -1;
360     }
361     
362     return 0;
363 }
364
365
366 int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
367     if (free_resource(dev, DEV_IO_HOOK, port) == 0) {
368         return v3_unhook_io_port(dev->vm, port);           
369     } 
370
371     return -1;
372 }
373
374
375 int v3_dev_hook_msr(struct vm_device * dev, uint32_t msr,
376                     int (*read)(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data),
377                     int (*write)(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data)) {
378     int ret = 0;
379
380     ret = v3_hook_msr(dev->vm, msr, read, write, dev->private_data);
381
382     if (ret == -1) {
383         return -1;
384     }
385
386     if (add_resource(dev, DEV_MSR_HOOK, msr) == -1) {
387         v3_unhook_msr(dev->vm, msr);
388         return -1;
389     }
390
391     return 0;
392 }
393                   
394 int v3_dev_unhook_msr(struct vm_device * dev, uint32_t msr) {
395     if (free_resource(dev, DEV_MSR_HOOK, msr) == 0) {
396         return v3_unhook_msr(dev->vm, msr);
397     }
398
399     return -1;
400 }
401
402
403
404
405 int v3_remove_device(struct vm_device * dev) {
406     struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
407     struct dev_rsrc * resource = NULL;
408     struct dev_rsrc * tmp;
409
410     list_for_each_entry_safe(resource, tmp, &(dev->res_hooks), node) {
411         if (resource->type == DEV_IO_HOOK) {
412             v3_unhook_io_port(dev->vm, (uint16_t)(resource->rsrc));
413         } else if (resource->type == DEV_MSR_HOOK) {
414             v3_unhook_msr(dev->vm, (uint32_t)(resource->rsrc));
415         }
416
417         list_del(&(resource->node));
418         V3_Free(resource);    
419     }
420
421     if (dev->ops->free) {
422         dev->ops->free(dev->private_data);
423     } else {
424         PrintError("Error: %s free() not implemented\n",  dev->name);
425     }
426
427     list_del(&(dev->dev_link));
428     mgr->num_devs--;
429
430     dev->vm = NULL;
431
432     V3_Free(dev);
433     return -1;
434 }
435
436
437 struct vm_device * v3_add_device(struct v3_vm_info * vm,
438                                  char * name, 
439                                  struct v3_device_ops * ops, 
440                                  void * private_data) {
441     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
442     struct vm_device * dev = NULL;
443
444
445     // Check if we already registered a device of the same name
446     if (v3_htable_search(mgr->dev_table, (addr_t)name) != (addr_t)NULL) {
447         PrintError("Device with name (%s) already registered with VM\n", name); 
448         return NULL;
449     }
450
451     dev = (struct vm_device *)V3_Malloc(sizeof(struct vm_device));
452
453     if (dev == NULL) {
454         return NULL;
455     }
456
457     INIT_LIST_HEAD(&(dev->res_hooks));
458
459     strncpy(dev->name, name, 32);
460     dev->ops = ops;
461     dev->private_data = private_data;
462
463     dev->vm = vm;
464
465     list_add(&(dev->dev_link), &(mgr->dev_list));
466     mgr->num_devs++;
467
468     v3_htable_insert(mgr->dev_table, (addr_t)(dev->name), (addr_t)dev);
469
470     return dev;
471 }
472
473
474 void v3_print_dev_mgr(struct v3_vm_info * vm) {
475     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
476     struct vm_device * dev;
477
478     V3_Print("%d devices registered with manager\n", mgr->num_devs);
479
480     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
481         V3_Print("Device: %s\n", dev->name);
482     }
483
484     return;
485 }
486
487
488
489
490 struct blk_frontend {
491     int (*connect)(struct v3_vm_info * vm, 
492                     void * frontend_data, 
493                     struct v3_dev_blk_ops * ops, 
494                     v3_cfg_tree_t * cfg, 
495                     void * priv_data);
496         
497
498     struct list_head blk_node;
499
500     void * priv_data;
501 };
502
503
504
505 int v3_dev_add_blk_frontend(struct v3_vm_info * vm, 
506                             char * name, 
507                             int (*connect)(struct v3_vm_info * vm, 
508                                             void * frontend_data, 
509                                             struct v3_dev_blk_ops * ops, 
510                                             v3_cfg_tree_t * cfg, 
511                                             void * priv_data), 
512                             void * priv_data) {
513
514     struct blk_frontend * frontend = NULL;
515
516     frontend = (struct blk_frontend *)V3_Malloc(sizeof(struct blk_frontend));
517     memset(frontend, 0, sizeof(struct blk_frontend));
518     
519     frontend->connect = connect;
520     frontend->priv_data = priv_data;
521         
522     list_add(&(frontend->blk_node), &(vm->dev_mgr.blk_list));
523     v3_htable_insert(vm->dev_mgr.blk_table, (addr_t)(name), (addr_t)frontend);
524
525     return 0;
526 }
527
528 int v3_dev_connect_blk(struct v3_vm_info * vm, 
529                        char * frontend_name, 
530                        struct v3_dev_blk_ops * ops, 
531                        v3_cfg_tree_t * cfg, 
532                        void * private_data) {
533
534     struct blk_frontend * frontend = NULL;
535
536     frontend = (struct blk_frontend *)v3_htable_search(vm->dev_mgr.blk_table,
537                                                        (addr_t)frontend_name);
538     
539     if (frontend == NULL) {
540         PrintError("Could not find frontend blk device %s\n", frontend_name);
541         return 0;
542     }
543
544     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
545         PrintError("Error connecting to block frontend %s\n", frontend_name);
546         return -1;
547     }
548
549     return 0;
550 }
551
552
553
554 struct net_frontend {
555     int (*connect)(struct v3_vm_info * vm, 
556                     void * frontend_data, 
557                     struct v3_dev_net_ops * ops, 
558                     v3_cfg_tree_t * cfg, 
559                     void * priv_data);
560     
561
562     struct list_head net_node;
563
564     void * priv_data;
565 };
566
567
568 int v3_dev_add_net_frontend(struct v3_vm_info * vm, 
569                             char * name, 
570                             int (*connect)(struct v3_vm_info * vm, 
571                                             void * frontend_data, 
572                                             struct v3_dev_net_ops * ops, 
573                                             v3_cfg_tree_t * cfg, 
574                                             void * private_data), 
575                             void * priv_data)
576 {
577     struct net_frontend * frontend = NULL;
578
579     frontend = (struct net_frontend *)V3_Malloc(sizeof(struct net_frontend));
580     memset(frontend, 0, sizeof(struct net_frontend));
581     
582     frontend->connect = connect;
583     frontend->priv_data = priv_data;
584         
585     list_add(&(frontend->net_node), &(vm->dev_mgr.net_list));
586     v3_htable_insert(vm->dev_mgr.net_table, (addr_t)(name), (addr_t)frontend);
587
588     return 0;
589 }
590
591
592 int v3_dev_connect_net(struct v3_vm_info * vm, 
593                        char * frontend_name, 
594                        struct v3_dev_net_ops * ops, 
595                        v3_cfg_tree_t * cfg, 
596                        void * private_data)
597 {
598     struct net_frontend * frontend = NULL;
599
600     frontend = (struct net_frontend *)v3_htable_search(vm->dev_mgr.net_table,
601                                                        (addr_t)frontend_name);
602     
603     if (frontend == NULL) {
604         PrintError("Could not find frontend net device %s\n", frontend_name);
605         return 0;
606     }
607
608     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
609         PrintError("Error connecting to net frontend %s\n", frontend_name);
610         return -1;
611     }
612
613     return 0;
614 }
615
616
617 struct cons_frontend {
618     int (*connect)(struct v3_vm_info * vm, 
619                    void * frontend_data, 
620                    struct v3_dev_console_ops * ops, 
621                    v3_cfg_tree_t * cfg, 
622                    void * priv_data);
623     
624
625     struct list_head cons_node;
626
627     void * priv_data;
628 };
629
630 int v3_dev_add_console_frontend(struct v3_vm_info * vm, 
631                                 char * name, 
632                                 int (*connect)(struct v3_vm_info * vm, 
633                                                void * frontend_data, 
634                                                struct v3_dev_console_ops * ops, 
635                                                v3_cfg_tree_t * cfg, 
636                                                void * private_data), 
637                                 void * priv_data)
638 {
639     struct cons_frontend * frontend = NULL;
640
641     frontend = (struct cons_frontend *)V3_Malloc(sizeof(struct cons_frontend));
642     memset(frontend, 0, sizeof(struct cons_frontend));
643     
644     frontend->connect = connect;
645     frontend->priv_data = priv_data;
646         
647     list_add(&(frontend->cons_node), &(vm->dev_mgr.cons_list));
648     v3_htable_insert(vm->dev_mgr.cons_table, (addr_t)(name), (addr_t)frontend);
649
650     return 0;
651 }
652
653
654 int v3_dev_connect_console(struct v3_vm_info * vm, 
655                            char * frontend_name, 
656                            struct v3_dev_console_ops * ops, 
657                            v3_cfg_tree_t * cfg, 
658                            void * private_data)
659 {
660     struct cons_frontend * frontend = NULL;
661
662     frontend = (struct cons_frontend *)v3_htable_search(vm->dev_mgr.cons_table,
663                                                         (addr_t)frontend_name);
664     
665     if (frontend == NULL) {
666         PrintError("Could not find frontend console device %s\n", frontend_name);
667         return 0;
668     }
669     
670     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
671         PrintError("Error connecting to console frontend %s\n", frontend_name);
672         return -1;
673     }
674
675     return 0;
676 }
677
678 struct char_frontend {
679     int (*connect)(struct v3_vm_info * vm, 
680                    void * frontend_data, 
681                    struct v3_dev_char_ops * ops, 
682                    v3_cfg_tree_t * cfg, 
683                    void * priv_data, 
684                    void ** push_fn_arg);
685     
686
687     struct list_head char_node;
688
689     void * priv_data;
690 };
691
692 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
693                              char * name, 
694                              int (*connect)(struct v3_vm_info * vm, 
695                                             void * frontend_data, 
696                                             struct v3_dev_char_ops * ops, 
697                                             v3_cfg_tree_t * cfg, 
698                                             void * private_data, 
699                                             void ** push_fn_arg), 
700                              void * priv_data)
701 {
702     struct char_frontend * frontend = NULL;
703
704     frontend = (struct char_frontend *)V3_Malloc(sizeof(struct char_frontend));
705     memset(frontend, 0, sizeof(struct char_frontend));
706     
707     frontend->connect = connect;
708     frontend->priv_data = priv_data;
709         
710     list_add(&(frontend->char_node), &(vm->dev_mgr.char_list));
711     v3_htable_insert(vm->dev_mgr.char_table, (addr_t)(name), (addr_t)frontend);
712
713     return 0;
714 }
715
716
717 int v3_dev_connect_char(struct v3_vm_info * vm, 
718                         char * frontend_name, 
719                         struct v3_dev_char_ops * ops, 
720                         v3_cfg_tree_t * cfg, 
721                         void * private_data, 
722                         void ** push_fn_arg)
723 {
724     struct char_frontend * frontend = NULL;
725
726     frontend = (struct char_frontend *)v3_htable_search(vm->dev_mgr.char_table,
727                                                         (addr_t)frontend_name);
728     
729     if (frontend == NULL) {
730         PrintError("Could not find frontend char device %s\n", frontend_name);
731         return 0;
732     }
733     
734     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data, push_fn_arg) == -1) {
735         PrintError("Error connecting to char frontend %s\n", frontend_name);
736         return -1;
737     }
738
739     return 0;
740 }
741
742
743
744 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr) {
745     struct char_frontend * chr = NULL;
746     struct char_frontend * tmp_chr = NULL;
747     struct cons_frontend * cons = NULL;
748     struct cons_frontend * tmp_cons = NULL;
749     struct net_frontend * net = NULL;
750     struct net_frontend * tmp_net = NULL;
751     struct blk_frontend * blk = NULL;
752     struct blk_frontend * tmp_blk = NULL;
753
754
755
756     list_for_each_entry_safe(chr, tmp_chr, &(mgr->char_list), char_node) {
757         list_del(&(chr->char_node));
758         V3_Free(chr);
759     }
760
761     list_for_each_entry_safe(cons, tmp_cons, &(mgr->cons_list), cons_node) {
762         list_del(&(cons->cons_node));
763         V3_Free(cons);
764     }
765
766     list_for_each_entry_safe(net, tmp_net, &(mgr->net_list), net_node) {
767         list_del(&(net->net_node));
768         V3_Free(net);
769     }
770
771     list_for_each_entry_safe(blk, tmp_blk, &(mgr->blk_list), blk_node) {
772         list_del(&(blk->blk_node));
773         V3_Free(blk);
774     }
775
776     v3_free_htable(mgr->blk_table, 0, 0);
777     v3_free_htable(mgr->net_table, 0, 0);
778     v3_free_htable(mgr->char_table, 0, 0);
779     v3_free_htable(mgr->cons_table, 0, 0);
780
781
782     return 0;
783 }