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.


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