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.h>
22 #include <palacios/vmm_extensions.h>
23 #include <palacios/vm_guest.h>
24 #include <palacios/vmm_hashtable.h>
27 static struct hashtable * ext_table = NULL;
30 * This is a place holder to ensure that the _v3_extensions section gets created by gcc
32 static struct {} null_ext __attribute__((__used__)) \
33 __attribute__((unused, __section__ ("_v3_extensions"), \
34 aligned(sizeof(addr_t))));
38 static uint_t ext_hash_fn(addr_t key) {
39 char * name = (char *)key;
40 return v3_hash_buffer((uint8_t *)name, strlen(name));
43 static int ext_eq_fn(addr_t key1, addr_t key2) {
44 char * name1 = (char *)key1;
45 char * name2 = (char *)key2;
47 return (strcmp(name1, name2) == 0);
52 int V3_init_extensions() {
53 extern struct v3_extension_impl * __start__v3_extensions[];
54 extern struct v3_extension_impl * __stop__v3_extensions[];
55 struct v3_extension_impl ** tmp_ext = __start__v3_extensions;
58 ext_table = v3_create_htable(0, ext_hash_fn, ext_eq_fn);
60 while (tmp_ext != __stop__v3_extensions) {
63 PrintError(VM_NONE, VCORE_NONE, "Impossible extension\n");
67 if ((*tmp_ext)->init && ((*tmp_ext)->init() != 0)) {
68 PrintError(VM_NONE, VCORE_NONE, "Could not initialize extension (%s)\n", (*tmp_ext)->name);
72 V3_Print(VM_NONE, VCORE_NONE, "Registering Extension (%s)\n", (*tmp_ext)->name);
74 if (v3_htable_search(ext_table, (addr_t)((*tmp_ext)->name))) {
75 PrintError(VM_NONE, VCORE_NONE, "Multiple instances of Extension (%s)\n", (*tmp_ext)->name);
79 if (v3_htable_insert(ext_table, (addr_t)((*tmp_ext)->name), (addr_t)(*tmp_ext)) == 0) {
80 PrintError(VM_NONE, VCORE_NONE, "Could not register Extension (%s)\n", (*tmp_ext)->name);
84 tmp_ext = &(__start__v3_extensions[++i]);
93 int V3_deinit_extensions() {
94 v3_free_htable(ext_table, 0, 0);
100 int v3_init_ext_manager(struct v3_vm_info * vm) {
101 struct v3_extensions * ext_state = &(vm->extensions);
103 INIT_LIST_HEAD(&(ext_state->extensions));
104 INIT_LIST_HEAD(&(ext_state->on_exits));
105 INIT_LIST_HEAD(&(ext_state->on_entries));
111 int v3_deinit_ext_manager(struct v3_vm_info * vm) {
112 struct v3_extensions * ext_state = &(vm->extensions);
113 struct v3_extension * ext = NULL;
114 struct v3_extension * tmp = NULL;
117 /* deinit per-core state first */
118 for (i = 0; i < vm->num_cores; i++)
119 v3_deinit_core_extensions(&(vm->cores[i]));
121 list_for_each_entry_safe(ext, tmp, &(ext_state->extensions), node) {
123 V3_Print(vm, VCORE_NONE, "Cleaning up Extension (%s)\n", ext->impl->name);
125 if (ext->impl->vm_deinit) {
126 if (ext->impl->vm_deinit(vm, ext->priv_data) == -1) {
127 PrintError(vm, VCORE_NONE, "Error cleaning up extension (%s)\n", ext->impl->name);
132 if (ext->impl->on_exit)
133 list_del(&ext->exit_node);
135 if (ext->impl->on_entry)
136 list_del(&ext->entry_node);
139 list_del(&ext->node);
149 int v3_add_extension(struct v3_vm_info * vm, const char * name, v3_cfg_tree_t * cfg) {
150 struct v3_extension_impl * impl = NULL;
151 struct v3_extension * ext = NULL;
154 impl = (void *)v3_htable_search(ext_table, (addr_t)name);
157 PrintError(vm, VCORE_NONE, "Could not find requested extension (%s)\n", name);
161 V3_ASSERT(vm, VCORE_NONE, impl->vm_init);
163 /* this allows each extension to track its own per-core state */
164 ext_size = sizeof(struct v3_extension) + (sizeof(void *) * vm->num_cores);
165 ext = V3_Malloc(ext_size);
168 PrintError(vm, VCORE_NONE, "Could not allocate extension\n");
174 if (impl->vm_init(vm, cfg, &(ext->priv_data)) == -1) {
175 PrintError(vm, VCORE_NONE, "Error initializing Extension (%s)\n", name);
180 list_add(&(ext->node), &(vm->extensions.extensions));
183 list_add(&(ext->exit_node), &(vm->extensions.on_exits));
186 if (impl->on_entry) {
187 list_add(&(ext->entry_node), &(vm->extensions.on_entries));
193 int v3_init_core_extensions(struct guest_info * core) {
194 struct v3_extension * ext = NULL;
195 uint32_t cpuid = core->vcpu_id;
197 list_for_each_entry(ext, &(core->vm_info->extensions.extensions), node) {
198 if ((ext->impl) && (ext->impl->core_init)) {
199 if (ext->impl->core_init(core, ext->priv_data, &(ext->core_ext_priv_data[cpuid])) == -1) {
200 PrintError(core->vm_info, core, "Error configuring per core extension %s on core %d\n",
201 ext->impl->name, core->vcpu_id);
211 int v3_deinit_core_extensions (struct guest_info * core) {
212 struct v3_extension * ext = NULL;
213 struct v3_extension * tmp = NULL;
214 struct v3_vm_info * vm = core->vm_info;
215 uint32_t cpuid = core->vcpu_id;
217 list_for_each_entry_safe(ext, tmp, &(vm->extensions.extensions), node) {
218 if ((ext->impl) && (ext->impl->core_deinit)) {
219 if (ext->impl->core_deinit(core, ext->priv_data, ext->core_ext_priv_data[cpuid]) == -1) {
220 PrintError(core->vm_info, core, "Error tearing down per core extension %s on core %d\n",
221 ext->impl->name, cpuid);
232 void * v3_get_extension_state(struct v3_vm_info * vm, const char * name) {
233 struct v3_extension * ext = NULL;
235 list_for_each_entry(ext, &(vm->extensions.extensions), node) {
236 if (strncmp(ext->impl->name, name, strlen(ext->impl->name)) == 0) {
237 return ext->priv_data;
245 void * v3_get_ext_core_state (struct guest_info * core, const char * name) {
246 struct v3_extension * ext = NULL;
247 struct v3_vm_info * vm = core->vm_info;
248 uint32_t cpuid = core->vcpu_id;
250 list_for_each_entry(ext, &(vm->extensions.extensions), node) {
251 if (strncmp(ext->impl->name, name, strlen(ext->impl->name)) == 0) {
252 return ext->core_ext_priv_data[cpuid];