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.


almost all deinitialization has been added
[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
26 #ifndef CONFIG_DEBUG_DEV_MGR
27 #undef PrintDebug
28 #define PrintDebug(fmt, args...)
29 #endif
30
31
32 static struct hashtable * master_dev_table = NULL;
33
34 static uint_t dev_hash_fn(addr_t key) {
35     char * name = (char *)key;
36     return v3_hash_buffer((uchar_t *)name, strlen(name));
37 }
38
39 static int dev_eq_fn(addr_t key1, addr_t key2) {
40     char * name1 = (char *)key1;
41     char * name2 = (char *)key2;
42     
43     return (strcmp(name1, name2) == 0);
44 }
45
46
47 int V3_init_devices() {
48     extern struct v3_device_info __start__v3_devices[];
49     extern struct v3_device_info __stop__v3_devices[];
50     struct v3_device_info * tmp_dev =  __start__v3_devices;
51     int i = 0;
52
53 #ifdef CONFIG_DEBUG_DEV_MGR
54     {
55         int num_devices = (__stop__v3_devices - __start__v3_devices) / sizeof(struct v3_device_info);
56         PrintDebug("%d Virtual devices registered with Palacios\n", num_devices);
57     }
58 #endif
59
60     PrintDebug("Start addres=%p, Stop address=%p\n", __start__v3_devices, __stop__v3_devices);
61
62     master_dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
63
64
65
66     while (tmp_dev != __stop__v3_devices) {
67         PrintDebug("Device: %s\n", tmp_dev->name);
68
69         if (v3_htable_search(master_dev_table, (addr_t)(tmp_dev->name))) {
70             PrintError("Multiple instance of device (%s)\n", tmp_dev->name);
71             return -1;
72         }
73
74         if (v3_htable_insert(master_dev_table, 
75                              (addr_t)(tmp_dev->name), 
76                              (addr_t)(tmp_dev->init)) == 0) {
77             PrintError("Could not add device %s to master list\n", tmp_dev->name);
78             return -1;
79         }
80
81         tmp_dev = &(__start__v3_devices[++i]);
82     }
83
84
85     return 0;
86 }
87
88
89 int v3_init_dev_mgr(struct v3_vm_info * vm) {
90     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
91
92     INIT_LIST_HEAD(&(mgr->dev_list));
93     mgr->num_devs = 0;
94
95     mgr->dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
96
97     INIT_LIST_HEAD(&(mgr->blk_list));
98     INIT_LIST_HEAD(&(mgr->net_list));
99     INIT_LIST_HEAD(&(mgr->char_list));
100     INIT_LIST_HEAD(&(mgr->cons_list));
101
102     mgr->blk_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
103     mgr->net_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
104     mgr->char_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
105     mgr->cons_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
106     
107     return 0;
108 }
109
110
111 int v3_free_vm_devices(struct v3_vm_info * vm) {
112     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
113     struct vm_device * dev;
114     struct vm_device * tmp;
115
116     list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
117         v3_remove_device(dev);
118     }
119
120     return 0;
121 }
122
123 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr);
124
125 int v3_deinit_dev_mgr(struct v3_vm_info * vm) {
126     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
127     
128     // clear frontend lists
129
130     free_frontends(vm, mgr);
131
132
133
134     v3_free_htable(mgr->dev_table, 0, 0);
135
136     return 0;
137 }
138
139
140
141 int v3_create_device(struct v3_vm_info * vm, const char * dev_name, v3_cfg_tree_t * cfg) {
142     int (*dev_init)(struct v3_vm_info * vm, void * cfg_data);
143
144     dev_init = (void *)v3_htable_search(master_dev_table, (addr_t)dev_name);
145
146     if (dev_init == NULL) {
147         PrintError("Could not find device %s in master device table\n", dev_name);
148         return -1;
149     }
150
151
152     if (dev_init(vm, cfg) == -1) {
153         PrintError("Could not initialize Device %s\n", dev_name);
154         return -1;
155     }
156
157     return 0;
158 }
159
160
161
162
163 struct vm_device * v3_find_dev(struct v3_vm_info * vm, const char * dev_name) {
164     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
165
166     if (!dev_name) {
167         return NULL;
168     }
169
170     return (struct vm_device *)v3_htable_search(mgr->dev_table, (addr_t)dev_name);
171 }
172
173
174 /****************************************************************/
175 /* The remaining functions are called by the devices themselves */
176 /****************************************************************/
177
178 struct dev_io_hook {
179     uint16_t port;
180
181     struct list_head node;
182
183 };
184
185 /* IO HOOKS */
186 int v3_dev_hook_io(struct vm_device * dev, uint16_t port,
187                    int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data),
188                    int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data)) {
189     struct dev_io_hook * io_hook = NULL;
190     int ret = 0;
191     
192    ret = v3_hook_io_port(dev->vm, port, 
193                          (int (*)(struct guest_info * core, ushort_t, void *, uint_t, void *))read, 
194                          (int (*)(struct guest_info * core, ushort_t, void *, uint_t, void *))write, 
195                          (void *)dev->private_data);
196
197    if (ret == -1) {
198        return -1;
199    }
200
201    io_hook = V3_Malloc(sizeof(struct dev_io_hook));
202
203    if (io_hook == NULL) {
204        PrintError("Could not allocate io hook dev state\n");
205        return -1;
206    }
207
208    io_hook->port = port;
209    list_add(&(io_hook->node), &(dev->io_hooks));
210
211    return 0;
212 }
213
214
215 int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
216     struct dev_io_hook * io_hook = NULL;
217     struct dev_io_hook * tmp;
218
219     list_for_each_entry_safe(io_hook, tmp, &(dev->io_hooks), node) {
220         if (io_hook->port == port) {
221
222             list_del(&(io_hook->node));
223             V3_Free(io_hook);
224             
225             return v3_unhook_io_port(dev->vm, port);        
226         }
227     }
228
229     return -1;
230 }
231
232
233
234 int v3_remove_device(struct vm_device * dev) {
235     struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
236     struct dev_io_hook * io_hook = NULL;
237     struct dev_io_hook * tmp;
238
239     list_for_each_entry_safe(io_hook, tmp, &(dev->io_hooks), node) {
240         v3_unhook_io_port(dev->vm, io_hook->port);          
241         list_del(&(io_hook->node));
242         V3_Free(io_hook);    
243     }
244
245     if (dev->ops->free) {
246         dev->ops->free(dev->private_data);
247     } else {
248         PrintError("Error: %s free() not implemented\n",  dev->name);
249     }
250
251     list_del(&(dev->dev_link));
252     mgr->num_devs--;
253
254     dev->vm = NULL;
255
256     V3_Free(dev);
257     return -1;
258 }
259
260
261 struct vm_device * v3_add_device(struct v3_vm_info * vm,
262                                  char * name, 
263                                  struct v3_device_ops * ops, 
264                                  void * private_data) {
265     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
266     struct vm_device * dev = NULL;
267
268     dev = (struct vm_device *)V3_Malloc(sizeof(struct vm_device));
269
270     if (dev == NULL) {
271         return NULL;
272     }
273
274     INIT_LIST_HEAD(&(dev->io_hooks));
275
276     strncpy(dev->name, name, 32);
277     dev->ops = ops;
278     dev->private_data = private_data;
279
280     dev->vm = vm;
281
282     list_add(&(dev->dev_link), &(mgr->dev_list));
283     mgr->num_devs++;
284
285     v3_htable_insert(mgr->dev_table, (addr_t)(dev->name), (addr_t)dev);
286
287     return dev;
288 }
289
290
291 void v3_print_dev_mgr(struct v3_vm_info * vm) {
292     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
293     struct vm_device * dev;
294
295     V3_Print("%d devices registered with manager\n", mgr->num_devs);
296
297     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
298         V3_Print("Device: %s\n", dev->name);
299     }
300
301     return;
302 }
303
304
305
306
307 struct blk_frontend {
308     int (*connect)(struct v3_vm_info * vm, 
309                     void * frontend_data, 
310                     struct v3_dev_blk_ops * ops, 
311                     v3_cfg_tree_t * cfg, 
312                     void * priv_data);
313         
314
315     struct list_head blk_node;
316
317     void * priv_data;
318 };
319
320
321
322 int v3_dev_add_blk_frontend(struct v3_vm_info * vm, 
323                             char * name, 
324                             int (*connect)(struct v3_vm_info * vm, 
325                                             void * frontend_data, 
326                                             struct v3_dev_blk_ops * ops, 
327                                             v3_cfg_tree_t * cfg, 
328                                             void * priv_data), 
329                             void * priv_data) {
330
331     struct blk_frontend * frontend = NULL;
332
333     frontend = (struct blk_frontend *)V3_Malloc(sizeof(struct blk_frontend));
334     memset(frontend, 0, sizeof(struct blk_frontend));
335     
336     frontend->connect = connect;
337     frontend->priv_data = priv_data;
338         
339     list_add(&(frontend->blk_node), &(vm->dev_mgr.blk_list));
340     v3_htable_insert(vm->dev_mgr.blk_table, (addr_t)(name), (addr_t)frontend);
341
342     return 0;
343 }
344
345 int v3_dev_connect_blk(struct v3_vm_info * vm, 
346                        char * frontend_name, 
347                        struct v3_dev_blk_ops * ops, 
348                        v3_cfg_tree_t * cfg, 
349                        void * private_data) {
350
351     struct blk_frontend * frontend = NULL;
352
353     frontend = (struct blk_frontend *)v3_htable_search(vm->dev_mgr.blk_table,
354                                                        (addr_t)frontend_name);
355     
356     if (frontend == NULL) {
357         PrintError("Could not find frontend blk device %s\n", frontend_name);
358         return 0;
359     }
360
361     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
362         PrintError("Error connecting to block frontend %s\n", frontend_name);
363         return -1;
364     }
365
366     return 0;
367 }
368
369
370
371 struct net_frontend {
372     int (*connect)(struct v3_vm_info * vm, 
373                     void * frontend_data, 
374                     struct v3_dev_net_ops * ops, 
375                     v3_cfg_tree_t * cfg, 
376                     void * priv_data);
377     
378
379     struct list_head net_node;
380
381     void * priv_data;
382 };
383
384
385 int v3_dev_add_net_frontend(struct v3_vm_info * vm, 
386                             char * name, 
387                             int (*connect)(struct v3_vm_info * vm, 
388                                             void * frontend_data, 
389                                             struct v3_dev_net_ops * ops, 
390                                             v3_cfg_tree_t * cfg, 
391                                             void * private_data), 
392                             void * priv_data)
393 {
394     struct net_frontend * frontend = NULL;
395
396     frontend = (struct net_frontend *)V3_Malloc(sizeof(struct net_frontend));
397     memset(frontend, 0, sizeof(struct net_frontend));
398     
399     frontend->connect = connect;
400     frontend->priv_data = priv_data;
401         
402     list_add(&(frontend->net_node), &(vm->dev_mgr.net_list));
403     v3_htable_insert(vm->dev_mgr.net_table, (addr_t)(name), (addr_t)frontend);
404
405     return 0;
406 }
407
408
409 int v3_dev_connect_net(struct v3_vm_info * vm, 
410                        char * frontend_name, 
411                        struct v3_dev_net_ops * ops, 
412                        v3_cfg_tree_t * cfg, 
413                        void * private_data)
414 {
415     struct net_frontend * frontend = NULL;
416
417     frontend = (struct net_frontend *)v3_htable_search(vm->dev_mgr.net_table,
418                                                        (addr_t)frontend_name);
419     
420     if (frontend == NULL) {
421         PrintError("Could not find frontend net device %s\n", frontend_name);
422         return 0;
423     }
424
425     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
426         PrintError("Error connecting to net frontend %s\n", frontend_name);
427         return -1;
428     }
429
430     return 0;
431 }
432
433
434 struct cons_frontend {
435     int (*connect)(struct v3_vm_info * vm, 
436                    void * frontend_data, 
437                    struct v3_dev_console_ops * ops, 
438                    v3_cfg_tree_t * cfg, 
439                    void * priv_data);
440     
441
442     struct list_head cons_node;
443
444     void * priv_data;
445 };
446
447 int v3_dev_add_console_frontend(struct v3_vm_info * vm, 
448                                 char * name, 
449                                 int (*connect)(struct v3_vm_info * vm, 
450                                                void * frontend_data, 
451                                                struct v3_dev_console_ops * ops, 
452                                                v3_cfg_tree_t * cfg, 
453                                                void * private_data), 
454                                 void * priv_data)
455 {
456     struct cons_frontend * frontend = NULL;
457
458     frontend = (struct cons_frontend *)V3_Malloc(sizeof(struct cons_frontend));
459     memset(frontend, 0, sizeof(struct cons_frontend));
460     
461     frontend->connect = connect;
462     frontend->priv_data = priv_data;
463         
464     list_add(&(frontend->cons_node), &(vm->dev_mgr.cons_list));
465     v3_htable_insert(vm->dev_mgr.cons_table, (addr_t)(name), (addr_t)frontend);
466
467     return 0;
468 }
469
470
471 int v3_dev_connect_console(struct v3_vm_info * vm, 
472                            char * frontend_name, 
473                            struct v3_dev_console_ops * ops, 
474                            v3_cfg_tree_t * cfg, 
475                            void * private_data)
476 {
477     struct cons_frontend * frontend = NULL;
478
479     frontend = (struct cons_frontend *)v3_htable_search(vm->dev_mgr.cons_table,
480                                                         (addr_t)frontend_name);
481     
482     if (frontend == NULL) {
483         PrintError("Could not find frontend console device %s\n", frontend_name);
484         return 0;
485     }
486     
487     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
488         PrintError("Error connecting to console frontend %s\n", frontend_name);
489         return -1;
490     }
491
492     return 0;
493 }
494
495 struct char_frontend {
496     int (*connect)(struct v3_vm_info * vm, 
497                    void * frontend_data, 
498                    struct v3_dev_char_ops * ops, 
499                    v3_cfg_tree_t * cfg, 
500                    void * priv_data, 
501                    void ** push_fn_arg);
502     
503
504     struct list_head char_node;
505
506     void * priv_data;
507 };
508
509 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
510                              char * name, 
511                              int (*connect)(struct v3_vm_info * vm, 
512                                             void * frontend_data, 
513                                             struct v3_dev_char_ops * ops, 
514                                             v3_cfg_tree_t * cfg, 
515                                             void * private_data, 
516                                             void ** push_fn_arg), 
517                              void * priv_data)
518 {
519     struct char_frontend * frontend = NULL;
520
521     frontend = (struct char_frontend *)V3_Malloc(sizeof(struct char_frontend));
522     memset(frontend, 0, sizeof(struct char_frontend));
523     
524     frontend->connect = connect;
525     frontend->priv_data = priv_data;
526         
527     list_add(&(frontend->char_node), &(vm->dev_mgr.char_list));
528     v3_htable_insert(vm->dev_mgr.char_table, (addr_t)(name), (addr_t)frontend);
529
530     return 0;
531 }
532
533
534 int v3_dev_connect_char(struct v3_vm_info * vm, 
535                         char * frontend_name, 
536                         struct v3_dev_char_ops * ops, 
537                         v3_cfg_tree_t * cfg, 
538                         void * private_data, 
539                         void ** push_fn_arg)
540 {
541     struct char_frontend * frontend = NULL;
542
543     frontend = (struct char_frontend *)v3_htable_search(vm->dev_mgr.char_table,
544                                                         (addr_t)frontend_name);
545     
546     if (frontend == NULL) {
547         PrintError("Could not find frontend char device %s\n", frontend_name);
548         return 0;
549     }
550     
551     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data, push_fn_arg) == -1) {
552         PrintError("Error connecting to char frontend %s\n", frontend_name);
553         return -1;
554     }
555
556     return 0;
557 }
558
559
560
561 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr) {
562     struct char_frontend * chr = NULL;
563     struct char_frontend * tmp_chr = NULL;
564     struct cons_frontend * cons = NULL;
565     struct cons_frontend * tmp_cons = NULL;
566     struct net_frontend * net = NULL;
567     struct net_frontend * tmp_net = NULL;
568     struct blk_frontend * blk = NULL;
569     struct blk_frontend * tmp_blk = NULL;
570
571
572
573     list_for_each_entry_safe(chr, tmp_chr, &(mgr->char_list), char_node) {
574         list_del(&(chr->char_node));
575         V3_Free(chr);
576     }
577
578     list_for_each_entry_safe(cons, tmp_cons, &(mgr->cons_list), cons_node) {
579         list_del(&(cons->cons_node));
580         V3_Free(cons);
581     }
582
583     list_for_each_entry_safe(net, tmp_net, &(mgr->net_list), net_node) {
584         list_del(&(net->net_node));
585         V3_Free(net);
586     }
587
588     list_for_each_entry_safe(blk, tmp_blk, &(mgr->blk_list), blk_node) {
589         list_del(&(blk->blk_node));
590         V3_Free(blk);
591     }
592
593     v3_free_htable(mgr->blk_table, 0, 0);
594     v3_free_htable(mgr->net_table, 0, 0);
595     v3_free_htable(mgr->char_table, 0, 0);
596     v3_free_htable(mgr->cons_table, 0, 0);
597
598
599     return 0;
600 }