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.


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