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.


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