From: Jack Lange Date: Tue, 19 Apr 2011 22:02:17 +0000 (-0500) Subject: added extension framework with initial inspector extension X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=55a97f129cf51e899308ba2d6070c77e4901559e;p=palacios.releases.git added extension framework with initial inspector extension --- diff --git a/Kconfig b/Kconfig index 7a48606..a524683 100644 --- a/Kconfig +++ b/Kconfig @@ -128,7 +128,7 @@ config MAX_CPUS endmenu source "palacios/src/interfaces/Kconfig" - +source "palacios/src/extensions/Kconfig" config TELEMETRY bool "Enable VMM telemetry support" @@ -171,13 +171,6 @@ config VNET Enable the Vnet in Palacios -config INSPECTOR - bool "Enable VM inspection" - depends on EXPERIMENTAL - default n - help - Enable inspection framework for vm internal state - endmenu diff --git a/Makefile b/Makefile index 46227ae..ed13298 100644 --- a/Makefile +++ b/Makefile @@ -435,6 +435,7 @@ core-y := palacios/src/palacios/ libs-y := palacios/lib/$(ARCH)/ devices-y := palacios/src/devices/ interfaces-y := palacios/src/interfaces/ +extensions-y := palacios/src/extensions/ modules-y := modules/ @@ -529,7 +530,7 @@ export INSTALL_PATH ?= /build palacios-dirs := $(patsubst %/,%,$(filter %/, \ - $(core-y) $(devices-y) $(interfaces-y) $(libs-y)) $(modules-y)) + $(core-y) $(devices-y) $(interfaces-y) $(extensions-y) $(libs-y)) $(modules-y)) @@ -540,13 +541,14 @@ palacios-dirs := $(patsubst %/,%,$(filter %/, \ palacios-cleandirs := $(sort $(palacios-dirs) $(patsubst %/,%,$(filter %/, \ $(core-n) $(core-) $(devices-n) $(devices-) \ - $(interfaces-n) $(interfaces-) $(modules-n) $(modules-)))) + $(interfaces-n) $(interfaces-) $(extensions-n) $(extensions-) $(modules-n) $(modules-)))) core-y := $(patsubst %/, %/built-in.o, $(core-y)) devices-y := $(patsubst %/, %/built-in.o, $(devices-y)) interfaces-y := $(patsubst %/, %/built-in.o, $(interfaces-y)) +extensions-y := $(patsubst %/, %/built-in.o, $(extensions-y)) libs-y := $(patsubst %/, %/built-in.o, $(libs-y)) modules-y := $(patsubst %/, %/built-in.o, $(modules-y)) #lnxmod-y := $(patsubst %/, %/built-in.o, $(lnxmod-y)) @@ -573,7 +575,7 @@ modules-y := $(patsubst %/, %/built-in.o, $(modules-y)) -palacios := $(core-y) $(devices-y) $(interfaces-y) $(libs-y) $(modules-y) +palacios := $(core-y) $(devices-y) $(interfaces-y) $(extensions-y) $(libs-y) $(modules-y) # Rule to link palacios - also used during CONFIG_CONFIGKALLSYMS diff --git a/linux_module/palacios-debugfs.c b/linux_module/palacios-debugfs.c index 5c76193..b35120e 100644 --- a/linux_module/palacios-debugfs.c +++ b/linux_module/palacios-debugfs.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include "palacios.h" diff --git a/palacios/include/palacios/vmm_inspector.h b/palacios/include/interfaces/inspector.h similarity index 97% rename from palacios/include/palacios/vmm_inspector.h rename to palacios/include/interfaces/inspector.h index ee0f70d..396e490 100644 --- a/palacios/include/palacios/vmm_inspector.h +++ b/palacios/include/interfaces/inspector.h @@ -36,12 +36,6 @@ typedef void v3_inspect_node_t; #define READ_ONLY 2 #define HOOKED 4 -struct v3_inspector_state { - struct v3_mtree state_tree; - -}; - - int v3_init_inspector(struct v3_vm_info * vm); int v3_init_inspector_core(struct guest_info * core); diff --git a/palacios/include/palacios/vm_guest.h b/palacios/include/palacios/vm_guest.h index 4b2728f..5d4527f 100644 --- a/palacios/include/palacios/vm_guest.h +++ b/palacios/include/palacios/vm_guest.h @@ -50,9 +50,6 @@ struct v3_sym_core_state; #endif -#ifdef CONFIG_INSPECTOR -#include -#endif #include @@ -187,9 +184,6 @@ struct v3_vm_info { struct v3_telemetry_state telemetry; #endif -#ifdef CONFIG_INSPECTOR - struct v3_inspector_state inspector; -#endif uint64_t yield_cycle_period; diff --git a/palacios/include/palacios/vmm_extensions.h b/palacios/include/palacios/vmm_extensions.h index 0135f88..fdddb69 100644 --- a/palacios/include/palacios/vmm_extensions.h +++ b/palacios/include/palacios/vmm_extensions.h @@ -23,8 +23,8 @@ #ifdef __V3VEE__ #include -#include #include +#include struct v3_vm_info; @@ -41,10 +41,10 @@ struct v3_extension_impl { char * name; int (*init)(struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data); int (*deinit)(struct v3_vm_info * vm, void * priv_data); - int (*core_init)(struct guest_info * core); - int (*core_deinit)(struct guest_info * core); - int (*on_entry)(struct guest_info * core); - int (*on_exit)(struct guest_info * core); + int (*core_init)(struct guest_info * core, void * priv_data); + int (*core_deinit)(struct guest_info * core, void * priv_data); + int (*on_entry)(struct guest_info * core, void * priv_data); + int (*on_exit)(struct guest_info * core, void * priv_data); }; struct v3_extension { @@ -64,6 +64,9 @@ int V3_deinit_extensions(); int v3_init_ext_manager(struct v3_vm_info * vm); int v3_add_extension(struct v3_vm_info * vm, const char * name, v3_cfg_tree_t * cfg); +int v3_init_core_extensions(struct guest_info * core); + +void * v3_get_extension_state(struct v3_vm_info * vm, const char * name); #define register_extension(ext) \ diff --git a/palacios/src/extensions/Kconfig b/palacios/src/extensions/Kconfig new file mode 100644 index 0000000..c7b7d69 --- /dev/null +++ b/palacios/src/extensions/Kconfig @@ -0,0 +1,41 @@ +menu "Extensions" + +config EXT_VTIME + bool "Enable Time virtualization" + default n + help + Enables the timer virtualization extensions. These hide the cost of + running inside the VMM context. This can aid the consistency of + time between multiple timers, but can cause the guest to run + a good bit slower than the host in VM-intensive parts of the code. + + +config EXT_VTSC + bool "Fully virtualize guest TSC" + default n + depends on EXT_VTIME + help + Virtualize the processor time stamp counter in the guest, + generally increasing consistency between various time sources + but also potentially making guest time run slower than real time. + +config EXT_MTRRS + bool "Support virtualized MTTRs" + default n + help + Provides a virtualized set of MTTR registers + +config EXT_MACH_CHECK + bool "Support Machine Check functionality" + default n + help + Provides a virtualized machine check architecture + + +config EXT_INSPECTOR + bool "VM Inspector" + default n + help + Provides the inspection extension + +endmenu diff --git a/palacios/src/extensions/Makefile b/palacios/src/extensions/Makefile new file mode 100644 index 0000000..8b9f3f6 --- /dev/null +++ b/palacios/src/extensions/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_EXT_MTRRS) += ext_mtrr.o +obj-$(CONFIG_EXT_VTSC) += ext_vtsc.o +obj-$(CONFIG_EXT_VTIME) += ext_vtime.o +obj-$(CONFIG_EXT_INSPECTOR) += ext_inspector.o diff --git a/palacios/src/palacios/vmm_inspector.c b/palacios/src/extensions/ext_inspector.c similarity index 81% rename from palacios/src/palacios/vmm_inspector.c rename to palacios/src/extensions/ext_inspector.c index 2ff611b..7b89a91 100644 --- a/palacios/src/palacios/vmm_inspector.c +++ b/palacios/src/extensions/ext_inspector.c @@ -18,29 +18,39 @@ */ -#include +//#include #include #include #include +#include + +#include +#include // Note that v3_inspect_node_t is actuall a struct v3_mtree // Its set as void for opaque portability +struct v3_inspector_state { + struct v3_mtree state_tree; + +}; -int v3_init_inspector(struct v3_vm_info * vm) { - struct v3_inspector_state * state = (struct v3_inspector_state *)&(vm->inspector); +static int init_inspector(struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) { + struct v3_inspector_state * state = V3_Malloc(sizeof(struct v3_inspector_state)); memset(state, 0, sizeof(struct v3_inspector_state)); strncpy(state->state_tree.name, "vm->name", 50); state->state_tree.subtree = 1; + *priv_data = state; + return 0; } -int v3_init_inspector_core(struct guest_info * core) { - struct v3_inspector_state * vm_state = &(core->vm_info->inspector); +static int init_inspector_core(struct guest_info * core, void * priv_data) { + struct v3_inspector_state * vm_state = priv_data; char core_name[50]; snprintf(core_name, 50, "core.%d", core->cpu_id); @@ -72,7 +82,7 @@ int v3_init_inspector_core(struct guest_info * core) { v3_inspect_64(cr_node, "EFER", (uint64_t *)&(core->ctrl_regs.efer)); - // struct v3_mtree * seg_node = v3_mtree_create_subtree(core_node, "SEGMENTS"); + //struct v3_mtree * seg_node = v3_mtree_create_subtree(core_node, "SEGMENTS"); @@ -82,6 +92,23 @@ int v3_init_inspector_core(struct guest_info * core) { } + + + +static struct v3_extension_impl inspector_impl = { + .name = "inspector", + .init = init_inspector, + .deinit = NULL, + .core_init = init_inspector_core, + .core_deinit = NULL, + .on_entry = NULL, + .on_exit = NULL +}; + + +register_extension(&inspector_impl); + + v3_inspect_node_t * v3_inspect_add_subtree(v3_inspect_node_t * root, char * name) { return v3_mtree_create_subtree(root, name); } @@ -122,8 +149,6 @@ int v3_inspect_buf(v3_inspect_node_t * node, char * name, - - int v3_find_inspection_value(v3_inspect_node_t * node, char * name, struct v3_inspection_value * value) { struct v3_mtree * mt_node = v3_mtree_find_node(node, name); @@ -152,7 +177,13 @@ struct v3_inspection_value v3_inspection_value(v3_inspect_node_t * node) { v3_inspect_node_t * v3_get_inspection_root(struct v3_vm_info * vm) { - return &(vm->inspector.state_tree); + struct v3_inspector_state * inspector = v3_get_extension_state(vm, inspector_impl.name); + + if (inspector == NULL) { + return NULL; + } + + return &(inspector->state_tree); } v3_inspect_node_t * v3_get_inspection_subtree(v3_inspect_node_t * root, char * name) { @@ -167,3 +198,7 @@ v3_inspect_node_t * v3_inspection_node_next(v3_inspect_node_t * node) { v3_inspect_node_t * v3_inspection_first_child(v3_inspect_node_t * root) { return v3_mtree_first_child(root); } + + + + diff --git a/palacios/src/extensions/ext_vtime.c b/palacios/src/extensions/ext_vtime.c new file mode 100644 index 0000000..665d6be --- /dev/null +++ b/palacios/src/extensions/ext_vtime.c @@ -0,0 +1,169 @@ +/* + * This file is part of the Palacios Virtual Machine Monitor developed + * by the V3VEE Project with funding from the United States National + * Science Foundation and the Department of Energy. + * + * The V3VEE Project is a joint project between Northwestern University + * and the University of New Mexico. You can find out more at + * http://www.v3vee.org + * + * Copyright (c) 2008, Jack Lange + * Copyright (c) 2008, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * Patrick G. Bridges + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ +#include +#include +#include + + + + +/* Overview + * + * Time handling in VMMs is challenging, and Palacios uses the highest + * resolution, lowest overhead timer on modern CPUs that it can - the + * processor timestamp counter (TSC). Note that on somewhat old processors + * this can be problematic; in particular, older AMD processors did not + * have a constant rate timestamp counter in the face of power management + * events. However, the latest Intel and AMD CPUs all do (should...) have a + * constant rate TSC, and Palacios relies on this fact. + * + * Basically, Palacios keeps track of three quantities as it runs to manage + * the passage of time: + * (1) The host timestamp counter - read directly from HW and never written + * (2) A monotonic guest timestamp counter used to measure the progression of + * time in the guest. This is computed using an offsets from (1) above. + * (3) The actual guest timestamp counter (which can be written by + * writing to the guest TSC MSR - MSR 0x10) from the monotonic guest TSC. + * This is also computed as an offset from (2) above when the TSC and + * this offset is updated when the TSC MSR is written. + * + * The value used to offset the guest TSC from the host TSC is the *sum* of all + * of these offsets (2 and 3) above + * + * Because all other devices are slaved off of the passage of time in the guest, + * it is (2) above that drives the firing of other timers in the guest, + * including timer devices such as the Programmable Interrupt Timer (PIT). + * + * Future additions: + * (1) Add support for temporarily skewing guest time off of where it should + * be to support slack simulation of guests. The idea is that simulators + * set this skew to be the difference between how much time passed for a + * simulated feature and a real implementation of that feature, making + * pass at a different rate from real time on this core. The VMM will then + * attempt to move this skew back towards 0 subject to resolution/accuracy + * constraints from various system timers. + * + * The main effort in doing this will be to get accuracy/resolution + * information from each local timer and to use this to bound how much skew + * is removed on each exit. + */ + + + +struct vtime_state { + uint32_t guest_cpu_freq; // can be lower than host CPU freq! + uint64_t initial_time; // Time when VMM started. + sint64_t guest_host_offset;// Offset of monotonic guest time from host time +}; + + + + +static int offset_time( struct guest_info * info, sint64_t offset ) +{ + struct vm_time * time_state = &(info->time_state); +// PrintDebug("Adding additional offset of %lld to guest time.\n", offset); + time_state->guest_host_offset += offset; + return 0; +} + + +// Control guest time in relation to host time so that the two stay +// appropriately synchronized to the extent possible. +int v3_adjust_time(struct guest_info * info) { + struct vm_time * time_state = &(info->time_state); + uint64_t host_time, target_host_time; + uint64_t guest_time, target_guest_time, old_guest_time; + uint64_t guest_elapsed, host_elapsed, desired_elapsed; + + /* Compute the target host time given how much time has *already* + * passed in the guest */ + guest_time = v3_get_guest_time(time_state); + guest_elapsed = (guest_time - time_state->initial_time); + desired_elapsed = (guest_elapsed * time_state->host_cpu_freq) / time_state->guest_cpu_freq; + target_host_time = time_state->initial_time + desired_elapsed; + + /* Now, let the host run while the guest is stopped to make the two + * sync up. */ + host_time = v3_get_host_time(time_state); + old_guest_time = v3_get_guest_time(time_state); + + while (target_host_time > host_time) { + v3_yield(info); + host_time = v3_get_host_time(time_state); + } + + guest_time = v3_get_guest_time(time_state); + + // We do *not* assume the guest timer was paused in the VM. If it was + // this offseting is 0. If it wasn't we need this. + offset_time(info, (sint64_t)old_guest_time - (sint64_t)guest_time); + + /* Now the host may have gotten ahead of the guest because + * yielding is a coarse grained thing. Figure out what guest time + * we want to be at, and use the use the offsetting mechanism in + * the VMM to make the guest run forward. We limit *how* much we skew + * it forward to prevent the guest time making large jumps, + * however. */ + host_elapsed = host_time - time_state->initial_time; + desired_elapsed = (host_elapsed * time_state->guest_cpu_freq) / time_state->host_cpu_freq; + target_guest_time = time_state->initial_time + desired_elapsed; + + if (guest_time < target_guest_time) { + uint64_t max_skew, desired_skew, skew; + + if (time_state->enter_time) { + max_skew = (time_state->exit_time - time_state->enter_time) / 10; + } else { + max_skew = 0; + } + + desired_skew = target_guest_time - guest_time; + skew = desired_skew > max_skew ? max_skew : desired_skew; +/* PrintDebug("Guest %llu cycles behind where it should be.\n", + desired_skew); + PrintDebug("Limit on forward skew is %llu. Skewing forward %llu.\n", + max_skew, skew); */ + + offset_time(info, skew); + } + + return 0; +} + + +static int init() { + khz = v3_cfg_val(cfg_tree, "khz"); + + if (khz) { + time_state->guest_cpu_freq = atoi(khz); + PrintDebug("Core %d CPU frequency requested at %d khz.\n", + info->cpu_id, time_state->guest_cpu_freq); + } + + if ( (khz == NULL) || + (time_state->guest_cpu_freq <= 0) || + (time_state->guest_cpu_freq > time_state->host_cpu_freq) ) { + + time_state->guest_cpu_freq = time_state->host_cpu_freq; + } + + +} diff --git a/palacios/src/extensions/ext_vtsc.c b/palacios/src/extensions/ext_vtsc.c new file mode 100644 index 0000000..96e7ce3 --- /dev/null +++ b/palacios/src/extensions/ext_vtsc.c @@ -0,0 +1,195 @@ +/* + * This file is part of the Palacios Virtual Machine Monitor developed + * by the V3VEE Project with funding from the United States National + * Science Foundation and the Department of Energy. + * + * The V3VEE Project is a joint project between Northwestern University + * and the University of New Mexico. You can find out more at + * http://www.v3vee.org + * + * Copyright (c) 2008, Jack Lange + * Copyright (c) 2008, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * Patrick G. Bridges + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + +#include +#include +#include + + +// Functions for handling exits on the TSC when fully virtualizing +// the timestamp counter. +#define TSC_MSR 0x10 +#define TSC_AUX_MSR 0xC0000103 + +int v3_handle_rdtscp(struct guest_info *info); +int v3_handle_rdtsc(struct guest_info *info); + + +struct vtsc_state { + + struct v3_msr tsc_aux; // Auxilliary MSR for RDTSCP + +}; + + + +/* + * Handle full virtualization of the time stamp counter. As noted + * above, we don't store the actual value of the TSC, only the guest's + * offset from monotonic guest's time. If the guest writes to the TSC, we + * handle this by changing that offset. + * + * Possible TODO: Proper hooking of TSC read/writes? + */ + +static int rdtsc(struct guest_info * info) { + uint64_t tscval = v3_get_guest_tsc(&info->time_state); + + info->vm_regs.rdx = tscval >> 32; + info->vm_regs.rax = tscval & 0xffffffffLL; + + return 0; +} + +int v3_handle_rdtsc(struct guest_info * info) { + rdtsc(info); + + info->vm_regs.rax &= 0x00000000ffffffffLL; + info->vm_regs.rdx &= 0x00000000ffffffffLL; + + info->rip += 2; + + return 0; +} + +int v3_rdtscp(struct guest_info * info) { + int ret; + /* First get the MSR value that we need. It's safe to futz with + * ra/c/dx here since they're modified by this instruction anyway. */ + info->vm_regs.rcx = TSC_AUX_MSR; + ret = v3_handle_msr_read(info); + + if (ret != 0) { + return ret; + } + + info->vm_regs.rcx = info->vm_regs.rax; + + /* Now do the TSC half of the instruction */ + ret = v3_rdtsc(info); + + if (ret != 0) { + return ret; + } + + return 0; +} + + +int v3_handle_rdtscp(struct guest_info * info) { + PrintDebug("Handling virtual RDTSCP call.\n"); + + v3_rdtscp(info); + + info->vm_regs.rax &= 0x00000000ffffffffLL; + info->vm_regs.rcx &= 0x00000000ffffffffLL; + info->vm_regs.rdx &= 0x00000000ffffffffLL; + + info->rip += 3; + + return 0; +} + + + + +static int tsc_aux_msr_read_hook(struct guest_info *info, uint_t msr_num, + struct v3_msr *msr_val, void *priv) { + struct vm_time * time_state = &(info->time_state); + + V3_ASSERT(msr_num == TSC_AUX_MSR); + + msr_val->lo = time_state->tsc_aux.lo; + msr_val->hi = time_state->tsc_aux.hi; + + return 0; +} + + +static int tsc_aux_msr_write_hook(struct guest_info *info, uint_t msr_num, + struct v3_msr msr_val, void *priv) { + struct vm_time * time_state = &(info->time_state); + + V3_ASSERT(msr_num == TSC_AUX_MSR); + + time_state->tsc_aux.lo = msr_val.lo; + time_state->tsc_aux.hi = msr_val.hi; + + return 0; +} + + +static int tsc_msr_read_hook(struct guest_info *info, uint_t msr_num, + struct v3_msr *msr_val, void *priv) { + uint64_t time = v3_get_guest_tsc(&info->time_state); + + V3_ASSERT(msr_num == TSC_MSR); + + msr_val->hi = time >> 32; + msr_val->lo = time & 0xffffffffLL; + + return 0; +} + + +static int tsc_msr_write_hook(struct guest_info *info, uint_t msr_num, + struct v3_msr msr_val, void *priv) { + struct vm_time * time_state = &(info->time_state); + uint64_t guest_time, new_tsc; + + V3_ASSERT(msr_num == TSC_MSR); + + new_tsc = (((uint64_t)msr_val.hi) << 32) | (uint64_t)msr_val.lo; + guest_time = v3_get_guest_time(time_state); + time_state->tsc_guest_offset = (sint64_t)new_tsc - (sint64_t)guest_time; + + return 0; +} + + +static int deinit() { + v3_unhook_msr(vm, TSC_MSR); + v3_unhook_msr(vm, TSC_AUX_MSR); +} + + +static int init() { + + time_state->tsc_aux.lo = 0; + time_state->tsc_aux.hi = 0; + + + + PrintDebug("Installing TSC MSR hook.\n"); + ret = v3_hook_msr(vm, TSC_MSR, + tsc_msr_read_hook, tsc_msr_write_hook, NULL); + + if (ret != 0) { + return ret; + } + + PrintDebug("Installing TSC_AUX MSR hook.\n"); + ret = v3_hook_msr(vm, TSC_AUX_MSR, tsc_aux_msr_read_hook, + tsc_aux_msr_write_hook, NULL); + + if (ret != 0) { + return ret; + } +} diff --git a/palacios/src/palacios/Makefile b/palacios/src/palacios/Makefile index 5747261..790280c 100644 --- a/palacios/src/palacios/Makefile +++ b/palacios/src/palacios/Makefile @@ -39,7 +39,6 @@ obj-y := \ vmm_multitree.o \ -obj-$(CONFIG_INSPECTOR) += vmm_inspector.o obj-$(CONFIG_XED) += vmm_xed.o diff --git a/palacios/src/palacios/vm_guest.c b/palacios/src/palacios/vm_guest.c index b8cc549..9c37d7b 100644 --- a/palacios/src/palacios/vm_guest.c +++ b/palacios/src/palacios/vm_guest.c @@ -530,9 +530,7 @@ int v3_init_vm(struct v3_vm_info * vm) { v3_set_foreground_vm(vm); } -#ifdef CONFIG_INSPECTOR - v3_init_inspector(vm); -#endif + #ifdef CONFIG_TELEMETRY v3_init_telemetry(vm); @@ -661,9 +659,7 @@ int v3_init_core(struct guest_info * core) { v3_cpu_arch_t cpu_type = v3_get_cpu_type(V3_Get_CPU()); struct v3_vm_info * vm = core->vm_info; -#ifdef CONFIG_INSPECTOR - v3_init_inspector_core(core); -#endif + /* * Initialize the subsystem data strutures diff --git a/palacios/src/palacios/vmm_extensions.c b/palacios/src/palacios/vmm_extensions.c index de1cfa0..e9a1ce6 100644 --- a/palacios/src/palacios/vmm_extensions.c +++ b/palacios/src/palacios/vmm_extensions.c @@ -69,6 +69,8 @@ int V3_init_extensions() { } + + int V3_deinit_extensions() { v3_free_htable(ext_table, 0, 0); return 0; @@ -85,6 +87,9 @@ int v3_init_ext_manager(struct v3_vm_info * vm) { return 0; } + +int v3_deinit_ext_manager(struct v3_vm_info * vm); + int v3_add_extension(struct v3_vm_info * vm, const char * name, v3_cfg_tree_t * cfg) { struct v3_extension_impl * impl = NULL; struct v3_extension * ext = NULL; @@ -125,3 +130,34 @@ int v3_add_extension(struct v3_vm_info * vm, const char * name, v3_cfg_tree_t * return 0; } + +int v3_init_core_extensions(struct guest_info * core) { + struct v3_extension * ext = NULL; + + list_for_each_entry(ext, &(core->vm_info->extensions.extensions), node) { + if ((ext->impl) && (ext->impl->core_init)) { + if (ext->impl->core_init(core, ext->priv_data) == -1) { + PrintError("Error configuring per core extension %s on core %d\n", + ext->impl->name, core->cpu_id); + return -1; + } + } + } + + return 0; +} + + + + +void * v3_get_extension_state(struct v3_vm_info * vm, const char * name) { + struct v3_extension * ext = NULL; + + list_for_each_entry(ext, &(vm->extensions.extensions), node) { + if (strncmp(ext->impl->name, name, strlen(ext->impl->name)) == 0) { + return ext->priv_data; + } + } + + return NULL; +}