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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmm_dev_mgr.h>
21 #include <palacios/vm_guest.h>
22 #include <palacios/vmm.h>
23 #include <palacios/vmm_decoder.h>
25 #ifdef V3_CONFIG_CHECKPOINT
26 #include <palacios/vmm_checkpoint.h>
30 #ifndef V3_CONFIG_DEBUG_DEV_MGR
32 #define PrintDebug(fmt, args...)
36 static struct hashtable * master_dev_table = NULL;
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));
43 static int dev_eq_fn(addr_t key1, addr_t key2) {
44 char * name1 = (char *)key1;
45 char * name2 = (char *)key2;
47 return (strcmp(name1, name2) == 0);
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;
57 #ifdef V3_CONFIG_DEBUG_DEV_MGR
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);
64 PrintDebug("Start addres=%p, Stop address=%p\n", __start__v3_devices, __stop__v3_devices);
66 master_dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
70 while (tmp_dev != __stop__v3_devices) {
71 V3_Print("Registering Device: %s\n", tmp_dev->name);
73 if (v3_htable_search(master_dev_table, (addr_t)(tmp_dev->name))) {
74 PrintError("Multiple instance of device (%s)\n", tmp_dev->name);
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);
85 tmp_dev = &(__start__v3_devices[++i]);
93 int V3_deinit_devices() {
94 v3_free_htable(master_dev_table, 0, 0);
99 int v3_init_dev_mgr(struct v3_vm_info * vm) {
100 struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
102 INIT_LIST_HEAD(&(mgr->dev_list));
105 mgr->dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
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));
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);
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;
126 list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
127 v3_remove_device(dev);
133 #ifdef V3_CONFIG_CHECKPOINT
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;
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;
145 name_table = V3_Malloc(table_len);
148 PrintError("Unable to allocate space in device manager save\n");
152 memset(name_table, 0, table_len);
154 dev_mgr_ctx = v3_chkpt_open_ctx(chkpt, NULL, "devices");
157 PrintError("Unable to open device manager context\n");
162 list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
163 if (dev->ops->save) {
164 strncpy(name_table + tbl_offset, dev->name, 32);
168 PrintDebug("Skipping device %s\n");
172 if (v3_chkpt_save(dev_mgr_ctx, "num_devs", 4, &num_saved_devs) == -1) {
173 PrintError("Unable to store num_devs\n");
174 v3_chkpt_close_ctx(dev_mgr_ctx);
179 if (v3_chkpt_save(dev_mgr_ctx, "names", num_saved_devs*32, name_table) == -1) {
180 PrintError("Unable to store names of devices\n");
181 v3_chkpt_close_ctx(dev_mgr_ctx);
186 v3_chkpt_close_ctx(dev_mgr_ctx);
190 list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
191 if (dev->ops->save) {
192 struct v3_chkpt_ctx * dev_ctx = NULL;
194 V3_Print("Saving state for device (%s)\n", dev->name);
196 dev_ctx = v3_chkpt_open_ctx(chkpt, NULL, dev->name);
199 PrintError("Unable to open context for device %s\n",dev->name);
203 if (dev->ops->save(dev_ctx, dev->private_data)) {
204 PrintError("Unable t save device %s\n",dev->name);
205 v3_chkpt_close_ctx(dev_ctx);
209 v3_chkpt_close_ctx(dev_ctx);
213 PrintError("Error: %s save() not implemented\n", dev->name);
221 int v3_load_vm_devices(struct v3_vm_info * vm, struct v3_chkpt * chkpt) {
222 struct vm_device * dev;
223 struct v3_chkpt_ctx * dev_mgr_ctx = NULL;
224 uint32_t num_devs = 0;
225 char * name_table = NULL;
228 dev_mgr_ctx = v3_chkpt_open_ctx(chkpt, NULL, "devices");
231 PrintError("Unable to open devices for load\n");
235 if (v3_chkpt_load(dev_mgr_ctx, "num_devs", 4, &num_devs) == -1) {
236 PrintError("Unable to load num_devs\n");
237 v3_chkpt_close_ctx(dev_mgr_ctx);
241 V3_Print("Loading State for %d devices\n", num_devs);
243 name_table = V3_Malloc(32 * num_devs);
246 PrintError("Unable to allocate space for device table\n");
247 v3_chkpt_close_ctx(dev_mgr_ctx);
251 if (v3_chkpt_load(dev_mgr_ctx, "names", 32 * num_devs, name_table) == -1) {
252 PrintError("Unable to load device name table\n");
253 v3_chkpt_close_ctx(dev_mgr_ctx);
257 v3_chkpt_close_ctx(dev_mgr_ctx);
259 for (i = 0; i < num_devs; i++) {
260 char * name = &(name_table[i * 32]);
261 struct v3_chkpt_ctx * dev_ctx = NULL;
262 dev = v3_find_dev(vm, name);
265 PrintError("Tried to load state into non existant device: %s\n", name);
269 if (!dev->ops->load) {
270 PrintError("Error Device (%s) does not support load operation\n", name);
274 dev_ctx = v3_chkpt_open_ctx(chkpt, NULL, name);
277 PrintError("Error missing device context (%s)\n", name);
282 if (dev->ops->load(dev_ctx, dev->private_data)) {
283 PrintError("Load of device %s failed\n",name);
286 v3_chkpt_close_ctx(dev_ctx);
297 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr);
299 int v3_deinit_dev_mgr(struct v3_vm_info * vm) {
300 struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
302 // clear frontend lists
304 free_frontends(vm, mgr);
306 v3_free_htable(mgr->dev_table, 0, 0);
313 int v3_create_device(struct v3_vm_info * vm, const char * dev_name, v3_cfg_tree_t * cfg) {
314 int (*dev_init)(struct v3_vm_info * vm, void * cfg_data);
316 dev_init = (void *)v3_htable_search(master_dev_table, (addr_t)dev_name);
318 if (dev_init == NULL) {
319 PrintError("Could not find device %s in master device table\n", dev_name);
324 if (dev_init(vm, cfg) == -1) {
325 PrintError("Could not initialize Device %s\n", dev_name);
335 struct vm_device * v3_find_dev(struct v3_vm_info * vm, const char * dev_name) {
336 struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
342 return (struct vm_device *)v3_htable_search(mgr->dev_table, (addr_t)dev_name);
346 /****************************************************************/
347 /* The remaining functions are called by the devices themselves */
348 /****************************************************************/
350 typedef enum {DEV_IO_HOOK, DEV_MSR_HOOK, DEV_CPUID_HOOK, DEV_MEM_HOOK, DEV_HCALL_HOOK} dev_rsrc_type_t;
353 dev_rsrc_type_t type;
356 struct list_head node;
361 static int add_resource(struct vm_device * dev, dev_rsrc_type_t type, uint64_t rsrc_id) {
362 struct dev_rsrc * resource = NULL;
364 resource = V3_Malloc(sizeof(struct dev_rsrc));
366 if (resource == NULL) {
367 PrintError("Error: Could not allocate device resource\n");
371 resource->rsrc = rsrc_id;
372 resource->type = type;
374 list_add(&(resource->node), &(dev->res_hooks));
378 static int free_resource(struct vm_device * dev, dev_rsrc_type_t type, uint64_t rsrc_id) {
379 struct dev_rsrc * resource = NULL;
380 struct dev_rsrc * tmp;
382 list_for_each_entry_safe(resource, tmp, &(dev->res_hooks), node) {
383 if ((resource->type == type) &&
384 (resource->rsrc == rsrc_id)) {
386 list_del(&(resource->node));
397 int v3_dev_hook_io(struct vm_device * dev, uint16_t port,
398 int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data),
399 int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data)) {
402 ret = v3_hook_io_port(dev->vm, port,
403 (int (*)(struct guest_info * core, uint16_t, void *, uint_t, void *))read,
404 (int (*)(struct guest_info * core, uint16_t, void *, uint_t, void *))write,
405 (void *)dev->private_data);
411 if (add_resource(dev, DEV_IO_HOOK, port) == -1) {
412 v3_unhook_io_port(dev->vm, port);
413 PrintError("Could not allocate io hook dev state\n");
421 int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
422 if (free_resource(dev, DEV_IO_HOOK, port) == 0) {
423 return v3_unhook_io_port(dev->vm, port);
430 int v3_dev_hook_msr(struct vm_device * dev, uint32_t msr,
431 int (*read)(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data),
432 int (*write)(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data)) {
435 ret = v3_hook_msr(dev->vm, msr, read, write, dev->private_data);
441 if (add_resource(dev, DEV_MSR_HOOK, msr) == -1) {
442 v3_unhook_msr(dev->vm, msr);
449 int v3_dev_unhook_msr(struct vm_device * dev, uint32_t msr) {
450 if (free_resource(dev, DEV_MSR_HOOK, msr) == 0) {
451 return v3_unhook_msr(dev->vm, msr);
460 int v3_remove_device(struct vm_device * dev) {
461 struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
462 struct dev_rsrc * resource = NULL;
463 struct dev_rsrc * tmp;
465 list_for_each_entry_safe(resource, tmp, &(dev->res_hooks), node) {
466 if (resource->type == DEV_IO_HOOK) {
467 v3_unhook_io_port(dev->vm, (uint16_t)(resource->rsrc));
468 } else if (resource->type == DEV_MSR_HOOK) {
469 v3_unhook_msr(dev->vm, (uint32_t)(resource->rsrc));
472 list_del(&(resource->node));
476 if (dev->ops->free) {
477 dev->ops->free(dev->private_data);
479 PrintError("Error: %s free() not implemented\n", dev->name);
482 list_del(&(dev->dev_link));
492 struct vm_device * v3_add_device(struct v3_vm_info * vm,
494 struct v3_device_ops * ops,
495 void * private_data) {
496 struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
497 struct vm_device * dev = NULL;
500 // Check if we already registered a device of the same name
501 if (v3_htable_search(mgr->dev_table, (addr_t)name) != (addr_t)NULL) {
502 PrintError("Device with name (%s) already registered with VM\n", name);
506 dev = (struct vm_device *)V3_Malloc(sizeof(struct vm_device));
512 INIT_LIST_HEAD(&(dev->res_hooks));
514 strncpy(dev->name, name, 32);
516 dev->private_data = private_data;
520 list_add(&(dev->dev_link), &(mgr->dev_list));
523 v3_htable_insert(mgr->dev_table, (addr_t)(dev->name), (addr_t)dev);
529 void v3_print_dev_mgr(struct v3_vm_info * vm) {
530 struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
531 struct vm_device * dev;
533 V3_Print("%d devices registered with manager\n", mgr->num_devs);
535 list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
536 V3_Print("Device: %s\n", dev->name);
545 struct blk_frontend {
546 int (*connect)(struct v3_vm_info * vm,
547 void * frontend_data,
548 struct v3_dev_blk_ops * ops,
553 struct list_head blk_node;
560 int v3_dev_add_blk_frontend(struct v3_vm_info * vm,
562 int (*connect)(struct v3_vm_info * vm,
563 void * frontend_data,
564 struct v3_dev_blk_ops * ops,
569 struct blk_frontend * frontend = NULL;
571 frontend = (struct blk_frontend *)V3_Malloc(sizeof(struct blk_frontend));
572 memset(frontend, 0, sizeof(struct blk_frontend));
574 frontend->connect = connect;
575 frontend->priv_data = priv_data;
577 list_add(&(frontend->blk_node), &(vm->dev_mgr.blk_list));
578 v3_htable_insert(vm->dev_mgr.blk_table, (addr_t)(name), (addr_t)frontend);
583 int v3_dev_connect_blk(struct v3_vm_info * vm,
584 char * frontend_name,
585 struct v3_dev_blk_ops * ops,
587 void * private_data) {
589 struct blk_frontend * frontend = NULL;
591 frontend = (struct blk_frontend *)v3_htable_search(vm->dev_mgr.blk_table,
592 (addr_t)frontend_name);
594 if (frontend == NULL) {
595 PrintError("Could not find frontend blk device %s\n", frontend_name);
599 if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
600 PrintError("Error connecting to block frontend %s\n", frontend_name);
609 struct net_frontend {
610 int (*connect)(struct v3_vm_info * vm,
611 void * frontend_data,
612 struct v3_dev_net_ops * ops,
617 struct list_head net_node;
623 int v3_dev_add_net_frontend(struct v3_vm_info * vm,
625 int (*connect)(struct v3_vm_info * vm,
626 void * frontend_data,
627 struct v3_dev_net_ops * ops,
629 void * private_data),
632 struct net_frontend * frontend = NULL;
634 frontend = (struct net_frontend *)V3_Malloc(sizeof(struct net_frontend));
635 memset(frontend, 0, sizeof(struct net_frontend));
637 frontend->connect = connect;
638 frontend->priv_data = priv_data;
640 list_add(&(frontend->net_node), &(vm->dev_mgr.net_list));
641 v3_htable_insert(vm->dev_mgr.net_table, (addr_t)(name), (addr_t)frontend);
647 int v3_dev_connect_net(struct v3_vm_info * vm,
648 char * frontend_name,
649 struct v3_dev_net_ops * ops,
653 struct net_frontend * frontend = NULL;
655 frontend = (struct net_frontend *)v3_htable_search(vm->dev_mgr.net_table,
656 (addr_t)frontend_name);
658 if (frontend == NULL) {
659 PrintError("Could not find frontend net device %s\n", frontend_name);
663 if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
664 PrintError("Error connecting to net frontend %s\n", frontend_name);
672 struct cons_frontend {
673 int (*connect)(struct v3_vm_info * vm,
674 void * frontend_data,
675 struct v3_dev_console_ops * ops,
680 struct list_head cons_node;
685 int v3_dev_add_console_frontend(struct v3_vm_info * vm,
687 int (*connect)(struct v3_vm_info * vm,
688 void * frontend_data,
689 struct v3_dev_console_ops * ops,
691 void * private_data),
694 struct cons_frontend * frontend = NULL;
696 frontend = (struct cons_frontend *)V3_Malloc(sizeof(struct cons_frontend));
697 memset(frontend, 0, sizeof(struct cons_frontend));
699 frontend->connect = connect;
700 frontend->priv_data = priv_data;
702 list_add(&(frontend->cons_node), &(vm->dev_mgr.cons_list));
703 v3_htable_insert(vm->dev_mgr.cons_table, (addr_t)(name), (addr_t)frontend);
709 int v3_dev_connect_console(struct v3_vm_info * vm,
710 char * frontend_name,
711 struct v3_dev_console_ops * ops,
715 struct cons_frontend * frontend = NULL;
717 frontend = (struct cons_frontend *)v3_htable_search(vm->dev_mgr.cons_table,
718 (addr_t)frontend_name);
720 if (frontend == NULL) {
721 PrintError("Could not find frontend console device %s\n", frontend_name);
725 if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
726 PrintError("Error connecting to console frontend %s\n", frontend_name);
733 struct char_frontend {
734 int (*connect)(struct v3_vm_info * vm,
735 void * frontend_data,
736 struct v3_dev_char_ops * ops,
739 void ** push_fn_arg);
742 struct list_head char_node;
747 int v3_dev_add_char_frontend(struct v3_vm_info * vm,
749 int (*connect)(struct v3_vm_info * vm,
750 void * frontend_data,
751 struct v3_dev_char_ops * ops,
754 void ** push_fn_arg),
757 struct char_frontend * frontend = NULL;
759 frontend = (struct char_frontend *)V3_Malloc(sizeof(struct char_frontend));
760 memset(frontend, 0, sizeof(struct char_frontend));
762 frontend->connect = connect;
763 frontend->priv_data = priv_data;
765 list_add(&(frontend->char_node), &(vm->dev_mgr.char_list));
766 v3_htable_insert(vm->dev_mgr.char_table, (addr_t)(name), (addr_t)frontend);
772 int v3_dev_connect_char(struct v3_vm_info * vm,
773 char * frontend_name,
774 struct v3_dev_char_ops * ops,
779 struct char_frontend * frontend = NULL;
781 frontend = (struct char_frontend *)v3_htable_search(vm->dev_mgr.char_table,
782 (addr_t)frontend_name);
784 if (frontend == NULL) {
785 PrintError("Could not find frontend char device %s\n", frontend_name);
789 if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data, push_fn_arg) == -1) {
790 PrintError("Error connecting to char frontend %s\n", frontend_name);
799 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr) {
800 struct char_frontend * chr = NULL;
801 struct char_frontend * tmp_chr = NULL;
802 struct cons_frontend * cons = NULL;
803 struct cons_frontend * tmp_cons = NULL;
804 struct net_frontend * net = NULL;
805 struct net_frontend * tmp_net = NULL;
806 struct blk_frontend * blk = NULL;
807 struct blk_frontend * tmp_blk = NULL;
811 list_for_each_entry_safe(chr, tmp_chr, &(mgr->char_list), char_node) {
812 list_del(&(chr->char_node));
816 list_for_each_entry_safe(cons, tmp_cons, &(mgr->cons_list), cons_node) {
817 list_del(&(cons->cons_node));
821 list_for_each_entry_safe(net, tmp_net, &(mgr->net_list), net_node) {
822 list_del(&(net->net_node));
826 list_for_each_entry_safe(blk, tmp_blk, &(mgr->blk_list), blk_node) {
827 list_del(&(blk->blk_node));
831 v3_free_htable(mgr->blk_table, 0, 0);
832 v3_free_htable(mgr->net_table, 0, 0);
833 v3_free_htable(mgr->char_table, 0, 0);
834 v3_free_htable(mgr->cons_table, 0, 0);