--- /dev/null
+/*
+ * 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) 2012, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2012, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+
+#ifndef __SVM_EXITS_H__
+#define __SVM_EXITS_H__
+
+
+#ifdef __V3VEE__
+
+int v3_init_svm_exits(struct v3_vm_info * vm);
+
+
+
+#endif
+
+#endif
#include <palacios/vmm_extensions.h>
#include <palacios/vmm_barrier.h>
#include <palacios/vmm_timeout.h>
+#include <palacios/vmm_exits.h>
#ifdef V3_CONFIG_TELEMETRY
struct v3_io_map io_map;
struct v3_msr_map msr_map;
struct v3_cpuid_map cpuid_map;
+ struct v3_exit_map exit_map;
v3_hypercall_map_t hcall_map;
--- /dev/null
+/*
+ * 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) 2012, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2012, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#ifndef __VMM_EXITS_H__
+#define __VMM_EXITS_H__
+
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm_types.h>
+
+
+
+struct guest_info;
+struct v3_vm_info;
+
+typedef enum { V3_EXIT_RDTSC,
+ V3_EXIT_RDTSCP,
+ V3_EXIT_SWINTR,
+ V3_EXIT_INVALID } v3_exit_type_t;
+
+
+
+
+struct v3_exit_hook {
+
+ int (*enable)(struct guest_info * core, v3_exit_type_t exit_type);
+ int (*disable)(struct guest_info * core, v3_exit_type_t exit_type);
+
+ struct {
+ union {
+ uint32_t flags;
+ struct {
+ uint32_t hooked : 1;
+ uint32_t registered : 1;
+ uint32_t rsvd : 30;
+ } __attribute__((packed));
+ } __attribute__((packed));
+
+ } __attribute__((packed));
+
+
+
+ int (*handler)(struct guest_info * core, v3_exit_type_t exit_type,
+ void * priv_data, void * exit_data);
+ void * priv_data;
+
+};
+
+
+struct v3_exit_map {
+
+ struct v3_exit_hook * exits;
+};
+
+
+
+
+int v3_init_exit_hooks(struct v3_vm_info * vm);
+int v3_deinit_exit_hooks(struct v3_vm_info * vm);
+
+int v3_init_exit_hooks_core(struct guest_info * core);
+
+
+
+int v3_register_exit(struct v3_vm_info * vm, v3_exit_type_t exit_type,
+ int (*enable)(struct guest_info * core, v3_exit_type_t exit_type),
+ int (*disable)(struct guest_info * core, v3_exit_type_t exit_type));
+
+
+
+int v3_dispatch_exit_hook(struct guest_info * core, v3_exit_type_t exit_type, void * exit_data);
+
+
+
+
+
+
+int v3_hook_exit(struct v3_vm_info * vm, v3_exit_type_t exit_type,
+ int (*handler)(struct guest_info * core, v3_exit_type_t exit_type,
+ void * priv_data, void * exit_data),
+ void * priv_data,
+ struct guest_info * current_core);
+
+int v3_unhook_exit(struct v3_vm_info * vm, v3_exit_type_t exit_type);
+
+
+#endif
+
+#endif
vmm_bitmap.o \
vmm_barrier.o \
vmm_timeout.o \
+ vmm_exits.o
obj-$(V3_CONFIG_XED) += vmm_xed.o
svm_pause.o \
svm_wbinvd.o \
svm_handler.o \
+ svm_exits.o \
vmcb.o
obj-$(V3_CONFIG_VMX) += vmx.o \
v3_svm_config_tsc_virtualization(struct guest_info * info) {
vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
- if (info->time_state.flags & VM_TIME_TRAP_RDTSC) {
- ctrl_area->instrs.RDTSC = 1;
- ctrl_area->svm_instrs.RDTSCP = 1;
- } else {
- ctrl_area->instrs.RDTSC = 0;
- ctrl_area->svm_instrs.RDTSCP = 0;
+ if (!(info->time_state.flags & VM_TIME_TRAP_RDTSC)) {
if (info->time_state.flags & VM_TIME_TSC_PASSTHROUGH) {
ctrl_area->TSC_OFFSET = 0;
} else {
--- /dev/null
+/*
+ * 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) 2012, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2012, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+#include <palacios/vmm.h>
+#include <palacios/vmcb.h>
+#include <palacios/vmm_exits.h>
+
+
+
+static int enable_exit(struct guest_info * core, v3_exit_type_t exit_type) {
+ vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(core->vmm_data));
+
+ switch (exit_type) {
+
+ case V3_EXIT_RDTSC:
+ ctrl_area->instrs.RDTSC = 1;
+ break;
+ case V3_EXIT_RDTSCP:
+ ctrl_area->svm_instrs.RDTSCP = 1;
+ break;
+
+ default:
+ PrintError("Unhandled Exit Type (%d)\n", exit_type);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int disable_exit(struct guest_info * core, v3_exit_type_t exit_type) {
+ vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(core->vmm_data));
+
+ switch (exit_type) {
+
+ case V3_EXIT_RDTSC:
+ ctrl_area->instrs.RDTSC = 0;
+ break;
+ case V3_EXIT_RDTSCP:
+ ctrl_area->svm_instrs.RDTSCP = 0;
+ break;
+
+ default:
+ PrintError("Unhandled Exit Type (%d)\n", exit_type);
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+int v3_init_svm_exits(struct v3_vm_info * vm) {
+
+ int ret = 0;
+
+ ret |= v3_register_exit(vm, V3_EXIT_RDTSC, enable_exit, disable_exit);
+ ret |= v3_register_exit(vm, V3_EXIT_RDTSCP, enable_exit, disable_exit);
+
+ return ret;
+}
#ifdef V3_CONFIG_DEBUG_TIME
PrintDebug("RDTSC/RDTSCP\n");
#endif
- if (v3_handle_rdtsc(info) == -1) {
+ if (v3_dispatch_exit_hook(info, V3_EXIT_RDTSC, NULL) == -1) {
PrintError("Error Handling RDTSC instruction\n");
return -1;
}
#ifdef V3_CONFIG_DEBUG_TIME
PrintDebug("RDTSCP\n");
#endif
- if (v3_handle_rdtscp(info) == -1) {
- PrintError("Error Handling RDTSCP instruction\n");
+ if (v3_dispatch_exit_hook(info, V3_EXIT_RDTSCP, NULL) == -1) {
+ PrintError("Error handling RDTSCP instruction\n");
return -1;
}
+
break;
case SVM_EXIT_SHUTDOWN:
PrintDebug("Guest-initiated shutdown\n");
#include <palacios/svm.h>
#include <palacios/svm_io.h>
#include <palacios/svm_msr.h>
+#include <palacios/svm_exits.h>
#endif
#ifdef V3_CONFIG_VMX
v3_init_msr_map(vm);
v3_init_cpuid_map(vm);
v3_init_host_events(vm);
+ v3_init_exit_hooks(vm);
+
v3_init_intr_routers(vm);
v3_init_ext_manager(vm);
case V3_SVM_REV3_CPU:
v3_init_svm_io_map(vm);
v3_init_svm_msr_map(vm);
+ v3_init_svm_exits(vm);
break;
#endif
#ifdef V3_CONFIG_VMX
v3_deinit_io_map(vm);
v3_deinit_hypercall_map(vm);
+ v3_deinit_exit_hooks(vm);
+
#ifdef V3_CONFIG_TELEMETRY
v3_deinit_telemetry(vm);
#endif
PrintError("Invalid CPU Type 0x%x\n", v3_mach_type);
return -1;
}
+
+ v3_init_exit_hooks_core(core);
+
return 0;
}
--- /dev/null
+/*
+ * 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) 2012, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2012, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+#include <palacios/vmm.h>
+#include <palacios/vmm_exits.h>
+#include <palacios/vm_guest.h>
+
+
+int v3_init_exit_hooks(struct v3_vm_info * vm) {
+ struct v3_exit_map * map = &(vm->exit_map);
+
+ map->exits = V3_Malloc(sizeof(struct v3_exit_hook) * V3_EXIT_INVALID);
+
+ if (map->exits == NULL) {
+ PrintError("Error allocating exit map\n");
+ return -1;
+ }
+
+ memset(map->exits, 0, sizeof(struct v3_exit_hook) * V3_EXIT_INVALID);
+
+
+ return 0;
+}
+
+int v3_deinit_exit_hooks(struct v3_vm_info * vm) {
+ struct v3_exit_map * map = &(vm->exit_map);
+
+ V3_Free(map->exits);
+
+ return 0;
+}
+
+
+
+
+int v3_init_exit_hooks_core(struct guest_info * core) {
+ struct v3_vm_info * vm = core->vm_info;
+ struct v3_exit_map * map = &(vm->exit_map);
+ struct v3_exit_hook * hook = NULL;
+ int i = 0;
+
+ for (i = 0; i < V3_EXIT_INVALID; i++) {
+ hook = &(map->exits[i]);
+
+ if (hook->hooked) {
+ if (hook->enable(core, i) != 0) {
+ PrintError("Error could not enable exit hook %d on core %d\n", i, core->vcpu_id);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int v3_deinit_exit_hooks_core(struct guest_info * core) {
+
+ return 0;
+}
+
+
+
+int v3_dispatch_exit_hook(struct guest_info * core, v3_exit_type_t exit_type, void * exit_data) {
+ struct v3_exit_map * map = &(core->vm_info->exit_map);
+ struct v3_exit_hook * hook = NULL;
+
+ if (exit_type >= V3_EXIT_INVALID) {
+ PrintError("Error: Tried to dispatch invalid exit type (%d)\n", exit_type);
+ return -1;
+ }
+
+ hook = &(map->exits[exit_type]);
+
+ if (hook->hooked == 0) {
+ PrintError("Tried to dispatch an unhooked exit (%d)\n", exit_type);
+ return -1;
+ }
+
+ return hook->handler(core, exit_type, hook->priv_data, exit_data);
+
+}
+
+
+int v3_register_exit(struct v3_vm_info * vm, v3_exit_type_t exit_type,
+ int (*enable)(struct guest_info * core, v3_exit_type_t exit_type),
+ int (*disable)(struct guest_info * core, v3_exit_type_t exit_type)) {
+ struct v3_exit_map * map = &(vm->exit_map);
+ struct v3_exit_hook * hook = NULL;
+
+ if (exit_type >= V3_EXIT_INVALID) {
+ PrintError("Error: Tried to register invalid exit type (%d)\n", exit_type);
+ return -1;
+ }
+
+ hook = &(map->exits[exit_type]);
+
+ if (hook->registered == 1) {
+ PrintError("Tried to reregister an exit (%d)\n", exit_type);
+ return -1;
+ }
+
+ hook->registered = 1;
+ hook->enable = enable;
+ hook->disable = disable;
+
+
+ return 0;
+}
+
+
+int v3_hook_exit(struct v3_vm_info * vm, v3_exit_type_t exit_type,
+ int (*handler)(struct guest_info * core, v3_exit_type_t exit_type,
+ void * priv_data, void * exit_data),
+ void * priv_data,
+ struct guest_info * current_core) {
+ struct v3_exit_map * map = &(vm->exit_map);
+ struct v3_exit_hook * hook = NULL;
+
+
+ if (exit_type >= V3_EXIT_INVALID) {
+ PrintError("Error: Tried to hook invalid exit type (%d)\n", exit_type);
+ return -1;
+ }
+
+ hook = &(map->exits[exit_type]);
+
+ if (hook->registered == 0) {
+ PrintError("Tried to hook unregistered exit (%d)\n", exit_type);
+ return -1;
+ }
+
+ if (hook->hooked != 0) {
+ PrintError("Tried to rehook exit (%d)\n", exit_type);
+ return -1;
+ }
+
+
+ hook->hooked = 1;
+ hook->handler = handler;
+ hook->priv_data = priv_data;
+
+ if (vm->run_state != VM_INVALID) {
+ int i = 0;
+
+ while (v3_raise_barrier(vm, current_core) == -1);
+
+ for (i = 0; i < vm->num_cores; i++) {
+
+ if (hook->enable(&(vm->cores[i]), exit_type) != 0) {
+ PrintError("Error could not enable exit hook %d on core %d\n", exit_type, i);
+ v3_lower_barrier(vm);
+ return -1;
+ }
+ }
+
+ v3_lower_barrier(vm);
+ }
+
+
+
+ return 0;
+
+}