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.


a6f71e5b7a3c90d90ba087dcda37912019e06cc5
[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 V3_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 V3_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_deinit_devices() {    
90     v3_free_htable(master_dev_table, 0, 0);
91     return 0;
92 }
93
94
95 int v3_init_dev_mgr(struct v3_vm_info * vm) {
96     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
97
98     INIT_LIST_HEAD(&(mgr->dev_list));
99     mgr->num_devs = 0;
100
101     mgr->dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
102
103     INIT_LIST_HEAD(&(mgr->blk_list));
104     INIT_LIST_HEAD(&(mgr->net_list));
105     INIT_LIST_HEAD(&(mgr->char_list));
106     INIT_LIST_HEAD(&(mgr->cons_list));
107
108     mgr->blk_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
109     mgr->net_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
110     mgr->char_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
111     mgr->cons_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
112     
113     return 0;
114 }
115
116
117 int v3_free_vm_devices(struct v3_vm_info * vm) {
118     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
119     struct vm_device * dev;
120     struct vm_device * tmp;
121
122     list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
123         v3_remove_device(dev);
124     }
125
126     return 0;
127 }
128
129 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr);
130
131 int v3_deinit_dev_mgr(struct v3_vm_info * vm) {
132     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
133     
134     // clear frontend lists
135
136     free_frontends(vm, mgr);
137
138
139
140     v3_free_htable(mgr->dev_table, 0, 0);
141
142     return 0;
143 }
144
145
146
147 int v3_create_device(struct v3_vm_info * vm, const char * dev_name, v3_cfg_tree_t * cfg) {
148     int (*dev_init)(struct v3_vm_info * vm, void * cfg_data);
149
150     dev_init = (void *)v3_htable_search(master_dev_table, (addr_t)dev_name);
151
152     if (dev_init == NULL) {
153         PrintError("Could not find device %s in master device table\n", dev_name);
154         return -1;
155     }
156
157
158     if (dev_init(vm, cfg) == -1) {
159         PrintError("Could not initialize Device %s\n", dev_name);
160         return -1;
161     }
162
163     return 0;
164 }
165
166
167
168
169 struct vm_device * v3_find_dev(struct v3_vm_info * vm, const char * dev_name) {
170     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
171
172     if (!dev_name) {
173         return NULL;
174     }
175
176     return (struct vm_device *)v3_htable_search(mgr->dev_table, (addr_t)dev_name);
177 }
178
179
180 /****************************************************************/
181 /* The remaining functions are called by the devices themselves */
182 /****************************************************************/
183
184 typedef enum {DEV_IO_HOOK, DEV_MSR_HOOK, DEV_CPUID_HOOK, DEV_MEM_HOOK, DEV_HCALL_HOOK} dev_rsrc_type_t;
185
186 struct dev_rsrc {
187     dev_rsrc_type_t type;
188     uint64_t rsrc;
189
190     struct list_head node;
191 };
192
193
194
195 static int add_resource(struct vm_device * dev, dev_rsrc_type_t type, uint64_t rsrc_id) {
196     struct dev_rsrc * resource = NULL;
197
198     resource = V3_Malloc(sizeof(struct dev_rsrc));
199
200     if (resource == NULL) {
201         PrintError("Error: Could not allocate device resource\n");
202         return -1;
203     }
204
205     resource->rsrc = rsrc_id;
206     resource->type = type;
207
208     list_add(&(resource->node), &(dev->res_hooks));
209     return 0;
210 }
211
212 static int free_resource(struct vm_device * dev, dev_rsrc_type_t type, uint64_t rsrc_id) {
213     struct dev_rsrc * resource = NULL;
214     struct dev_rsrc * tmp;
215
216     list_for_each_entry_safe(resource, tmp, &(dev->res_hooks), node) {
217         if ((resource->type == type) && 
218             (resource->rsrc == rsrc_id)) {
219
220             list_del(&(resource->node));
221             V3_Free(resource);
222             
223             return 0;
224         }
225     }
226
227     return -1;
228 }
229
230
231 int v3_dev_hook_io(struct vm_device * dev, uint16_t port,
232                    int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data),
233                    int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data)) {
234     int ret = 0;
235     
236     ret = v3_hook_io_port(dev->vm, port, 
237                           (int (*)(struct guest_info * core, uint16_t, void *, uint_t, void *))read, 
238                           (int (*)(struct guest_info * core, uint16_t, void *, uint_t, void *))write, 
239                           (void *)dev->private_data);
240
241     if (ret == -1) {
242         return -1;
243     }
244
245     if (add_resource(dev, DEV_IO_HOOK, port) == -1) {
246         v3_unhook_io_port(dev->vm, port);
247         PrintError("Could not allocate io hook dev state\n");
248         return -1;
249     }
250     
251     return 0;
252 }
253
254
255 int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
256     if (free_resource(dev, DEV_IO_HOOK, port) == 0) {
257         return v3_unhook_io_port(dev->vm, port);           
258     } 
259
260     return -1;
261 }
262
263
264 int v3_dev_hook_msr(struct vm_device * dev, uint32_t msr,
265                     int (*read)(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data),
266                     int (*write)(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data)) {
267     int ret = 0;
268
269     ret = v3_hook_msr(dev->vm, msr, read, write, dev->private_data);
270
271     if (ret == -1) {
272         return -1;
273     }
274
275     if (add_resource(dev, DEV_MSR_HOOK, msr) == -1) {
276         v3_unhook_msr(dev->vm, msr);
277         return -1;
278     }
279
280     return 0;
281 }
282                   
283 int v3_dev_unhook_msr(struct vm_device * dev, uint32_t msr) {
284     if (free_resource(dev, DEV_MSR_HOOK, msr) == 0) {
285         return v3_unhook_msr(dev->vm, msr);
286     }
287
288     return -1;
289 }
290
291
292
293
294 int v3_remove_device(struct vm_device * dev) {
295     struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
296     struct dev_rsrc * resource = NULL;
297     struct dev_rsrc * tmp;
298
299     list_for_each_entry_safe(resource, tmp, &(dev->res_hooks), node) {
300         if (resource->type == DEV_IO_HOOK) {
301             v3_unhook_io_port(dev->vm, (uint16_t)(resource->rsrc));
302         } else if (resource->type == DEV_MSR_HOOK) {
303             v3_unhook_msr(dev->vm, (uint32_t)(resource->rsrc));
304         }
305
306         list_del(&(resource->node));
307         V3_Free(resource);    
308     }
309
310     if (dev->ops->free) {
311         dev->ops->free(dev->private_data);
312     } else {
313         PrintError("Error: %s free() not implemented\n",  dev->name);
314     }
315
316     list_del(&(dev->dev_link));
317     mgr->num_devs--;
318
319     dev->vm = NULL;
320
321     V3_Free(dev);
322     return -1;
323 }
324
325
326 struct vm_device * v3_add_device(struct v3_vm_info * vm,
327                                  char * name, 
328                                  struct v3_device_ops * ops, 
329                                  void * private_data) {
330     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
331     struct vm_device * dev = NULL;
332
333     dev = (struct vm_device *)V3_Malloc(sizeof(struct vm_device));
334
335     if (dev == NULL) {
336         return NULL;
337     }
338
339     INIT_LIST_HEAD(&(dev->res_hooks));
340
341     strncpy(dev->name, name, 32);
342     dev->ops = ops;
343     dev->private_data = private_data;
344
345     dev->vm = vm;
346
347     list_add(&(dev->dev_link), &(mgr->dev_list));
348     mgr->num_devs++;
349
350     v3_htable_insert(mgr->dev_table, (addr_t)(dev->name), (addr_t)dev);
351
352     return dev;
353 }
354
355
356 void v3_print_dev_mgr(struct v3_vm_info * vm) {
357     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
358     struct vm_device * dev;
359
360     V3_Print("%d devices registered with manager\n", mgr->num_devs);
361
362     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
363         V3_Print("Device: %s\n", dev->name);
364     }
365
366     return;
367 }
368
369
370
371
372 struct blk_frontend {
373     int (*connect)(struct v3_vm_info * vm, 
374                     void * frontend_data, 
375                     struct v3_dev_blk_ops * ops, 
376                     v3_cfg_tree_t * cfg, 
377                     void * priv_data);
378         
379
380     struct list_head blk_node;
381
382     void * priv_data;
383 };
384
385
386
387 int v3_dev_add_blk_frontend(struct v3_vm_info * vm, 
388                             char * name, 
389                             int (*connect)(struct v3_vm_info * vm, 
390                                             void * frontend_data, 
391                                             struct v3_dev_blk_ops * ops, 
392                                             v3_cfg_tree_t * cfg, 
393                                             void * priv_data), 
394                             void * priv_data) {
395
396     struct blk_frontend * frontend = NULL;
397
398     frontend = (struct blk_frontend *)V3_Malloc(sizeof(struct blk_frontend));
399     memset(frontend, 0, sizeof(struct blk_frontend));
400     
401     frontend->connect = connect;
402     frontend->priv_data = priv_data;
403         
404     list_add(&(frontend->blk_node), &(vm->dev_mgr.blk_list));
405     v3_htable_insert(vm->dev_mgr.blk_table, (addr_t)(name), (addr_t)frontend);
406
407     return 0;
408 }
409
410 int v3_dev_connect_blk(struct v3_vm_info * vm, 
411                        char * frontend_name, 
412                        struct v3_dev_blk_ops * ops, 
413                        v3_cfg_tree_t * cfg, 
414                        void * private_data) {
415
416     struct blk_frontend * frontend = NULL;
417
418     frontend = (struct blk_frontend *)v3_htable_search(vm->dev_mgr.blk_table,
419                                                        (addr_t)frontend_name);
420     
421     if (frontend == NULL) {
422         PrintError("Could not find frontend blk device %s\n", frontend_name);
423         return 0;
424     }
425
426     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
427         PrintError("Error connecting to block frontend %s\n", frontend_name);
428         return -1;
429     }
430
431     return 0;
432 }
433
434
435
436 struct net_frontend {
437     int (*connect)(struct v3_vm_info * vm, 
438                     void * frontend_data, 
439                     struct v3_dev_net_ops * ops, 
440                     v3_cfg_tree_t * cfg, 
441                     void * priv_data);
442     
443
444     struct list_head net_node;
445
446     void * priv_data;
447 };
448
449
450 int v3_dev_add_net_frontend(struct v3_vm_info * vm, 
451                             char * name, 
452                             int (*connect)(struct v3_vm_info * vm, 
453                                             void * frontend_data, 
454                                             struct v3_dev_net_ops * ops, 
455                                             v3_cfg_tree_t * cfg, 
456                                             void * private_data), 
457                             void * priv_data)
458 {
459     struct net_frontend * frontend = NULL;
460
461     frontend = (struct net_frontend *)V3_Malloc(sizeof(struct net_frontend));
462     memset(frontend, 0, sizeof(struct net_frontend));
463     
464     frontend->connect = connect;
465     frontend->priv_data = priv_data;
466         
467     list_add(&(frontend->net_node), &(vm->dev_mgr.net_list));
468     v3_htable_insert(vm->dev_mgr.net_table, (addr_t)(name), (addr_t)frontend);
469
470     return 0;
471 }
472
473
474 int v3_dev_connect_net(struct v3_vm_info * vm, 
475                        char * frontend_name, 
476                        struct v3_dev_net_ops * ops, 
477                        v3_cfg_tree_t * cfg, 
478                        void * private_data)
479 {
480     struct net_frontend * frontend = NULL;
481
482     frontend = (struct net_frontend *)v3_htable_search(vm->dev_mgr.net_table,
483                                                        (addr_t)frontend_name);
484     
485     if (frontend == NULL) {
486         PrintError("Could not find frontend net device %s\n", frontend_name);
487         return 0;
488     }
489
490     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
491         PrintError("Error connecting to net frontend %s\n", frontend_name);
492         return -1;
493     }
494
495     return 0;
496 }
497
498
499 struct cons_frontend {
500     int (*connect)(struct v3_vm_info * vm, 
501                    void * frontend_data, 
502                    struct v3_dev_console_ops * ops, 
503                    v3_cfg_tree_t * cfg, 
504                    void * priv_data);
505     
506
507     struct list_head cons_node;
508
509     void * priv_data;
510 };
511
512 int v3_dev_add_console_frontend(struct v3_vm_info * vm, 
513                                 char * name, 
514                                 int (*connect)(struct v3_vm_info * vm, 
515                                                void * frontend_data, 
516                                                struct v3_dev_console_ops * ops, 
517                                                v3_cfg_tree_t * cfg, 
518                                                void * private_data), 
519                                 void * priv_data)
520 {
521     struct cons_frontend * frontend = NULL;
522
523     frontend = (struct cons_frontend *)V3_Malloc(sizeof(struct cons_frontend));
524     memset(frontend, 0, sizeof(struct cons_frontend));
525     
526     frontend->connect = connect;
527     frontend->priv_data = priv_data;
528         
529     list_add(&(frontend->cons_node), &(vm->dev_mgr.cons_list));
530     v3_htable_insert(vm->dev_mgr.cons_table, (addr_t)(name), (addr_t)frontend);
531
532     return 0;
533 }
534
535
536 int v3_dev_connect_console(struct v3_vm_info * vm, 
537                            char * frontend_name, 
538                            struct v3_dev_console_ops * ops, 
539                            v3_cfg_tree_t * cfg, 
540                            void * private_data)
541 {
542     struct cons_frontend * frontend = NULL;
543
544     frontend = (struct cons_frontend *)v3_htable_search(vm->dev_mgr.cons_table,
545                                                         (addr_t)frontend_name);
546     
547     if (frontend == NULL) {
548         PrintError("Could not find frontend console device %s\n", frontend_name);
549         return 0;
550     }
551     
552     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
553         PrintError("Error connecting to console frontend %s\n", frontend_name);
554         return -1;
555     }
556
557     return 0;
558 }
559
560 struct char_frontend {
561     int (*connect)(struct v3_vm_info * vm, 
562                    void * frontend_data, 
563                    struct v3_dev_char_ops * ops, 
564                    v3_cfg_tree_t * cfg, 
565                    void * priv_data, 
566                    void ** push_fn_arg);
567     
568
569     struct list_head char_node;
570
571     void * priv_data;
572 };
573
574 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
575                              char * name, 
576                              int (*connect)(struct v3_vm_info * vm, 
577                                             void * frontend_data, 
578                                             struct v3_dev_char_ops * ops, 
579                                             v3_cfg_tree_t * cfg, 
580                                             void * private_data, 
581                                             void ** push_fn_arg), 
582                              void * priv_data)
583 {
584     struct char_frontend * frontend = NULL;
585
586     frontend = (struct char_frontend *)V3_Malloc(sizeof(struct char_frontend));
587     memset(frontend, 0, sizeof(struct char_frontend));
588     
589     frontend->connect = connect;
590     frontend->priv_data = priv_data;
591         
592     list_add(&(frontend->char_node), &(vm->dev_mgr.char_list));
593     v3_htable_insert(vm->dev_mgr.char_table, (addr_t)(name), (addr_t)frontend);
594
595     return 0;
596 }
597
598
599 int v3_dev_connect_char(struct v3_vm_info * vm, 
600                         char * frontend_name, 
601                         struct v3_dev_char_ops * ops, 
602                         v3_cfg_tree_t * cfg, 
603                         void * private_data, 
604                         void ** push_fn_arg)
605 {
606     struct char_frontend * frontend = NULL;
607
608     frontend = (struct char_frontend *)v3_htable_search(vm->dev_mgr.char_table,
609                                                         (addr_t)frontend_name);
610     
611     if (frontend == NULL) {
612         PrintError("Could not find frontend char device %s\n", frontend_name);
613         return 0;
614     }
615     
616     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data, push_fn_arg) == -1) {
617         PrintError("Error connecting to char frontend %s\n", frontend_name);
618         return -1;
619     }
620
621     return 0;
622 }
623
624
625
626 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr) {
627     struct char_frontend * chr = NULL;
628     struct char_frontend * tmp_chr = NULL;
629     struct cons_frontend * cons = NULL;
630     struct cons_frontend * tmp_cons = NULL;
631     struct net_frontend * net = NULL;
632     struct net_frontend * tmp_net = NULL;
633     struct blk_frontend * blk = NULL;
634     struct blk_frontend * tmp_blk = NULL;
635
636
637
638     list_for_each_entry_safe(chr, tmp_chr, &(mgr->char_list), char_node) {
639         list_del(&(chr->char_node));
640         V3_Free(chr);
641     }
642
643     list_for_each_entry_safe(cons, tmp_cons, &(mgr->cons_list), cons_node) {
644         list_del(&(cons->cons_node));
645         V3_Free(cons);
646     }
647
648     list_for_each_entry_safe(net, tmp_net, &(mgr->net_list), net_node) {
649         list_del(&(net->net_node));
650         V3_Free(net);
651     }
652
653     list_for_each_entry_safe(blk, tmp_blk, &(mgr->blk_list), blk_node) {
654         list_del(&(blk->blk_node));
655         V3_Free(blk);
656     }
657
658     v3_free_htable(mgr->blk_table, 0, 0);
659     v3_free_htable(mgr->net_table, 0, 0);
660     v3_free_htable(mgr->char_table, 0, 0);
661     v3_free_htable(mgr->cons_table, 0, 0);
662
663
664     return 0;
665 }