From: Jack Lange Date: Thu, 26 Jul 2012 18:36:44 +0000 (-0400) Subject: initial implementation of hookable exits X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=45990b15161a5d97d4e4b7c4caeb84afb933de98;hp=a5264d4dcf50d633e01e92dba62a5cf00c3bae2a;p=palacios.git initial implementation of hookable exits --- diff --git a/palacios/include/palacios/svm_exits.h b/palacios/include/palacios/svm_exits.h new file mode 100644 index 0000000..9052c24 --- /dev/null +++ b/palacios/include/palacios/svm_exits.h @@ -0,0 +1,34 @@ +/* + * 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 + * Copyright (c) 2012, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * + * 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 diff --git a/palacios/include/palacios/vm_guest.h b/palacios/include/palacios/vm_guest.h index fb91c1d..9cee679 100644 --- a/palacios/include/palacios/vm_guest.h +++ b/palacios/include/palacios/vm_guest.h @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef V3_CONFIG_TELEMETRY @@ -160,6 +161,7 @@ struct v3_vm_info { 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; diff --git a/palacios/include/palacios/vmm_exits.h b/palacios/include/palacios/vmm_exits.h new file mode 100644 index 0000000..e793137 --- /dev/null +++ b/palacios/include/palacios/vmm_exits.h @@ -0,0 +1,106 @@ +/* + * 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 + * Copyright (c) 2012, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * + * 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 + + + +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 diff --git a/palacios/src/palacios/Makefile b/palacios/src/palacios/Makefile index cdbf81a..ef6c90e 100644 --- a/palacios/src/palacios/Makefile +++ b/palacios/src/palacios/Makefile @@ -37,6 +37,7 @@ obj-y := \ vmm_bitmap.o \ vmm_barrier.o \ vmm_timeout.o \ + vmm_exits.o obj-$(V3_CONFIG_XED) += vmm_xed.o @@ -52,6 +53,7 @@ obj-$(V3_CONFIG_SVM) += svm.o \ svm_pause.o \ svm_wbinvd.o \ svm_handler.o \ + svm_exits.o \ vmcb.o obj-$(V3_CONFIG_VMX) += vmx.o \ diff --git a/palacios/src/palacios/svm.c b/palacios/src/palacios/svm.c index 8a1b3e4..b7b1d7a 100644 --- a/palacios/src/palacios/svm.c +++ b/palacios/src/palacios/svm.c @@ -534,12 +534,7 @@ int 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 { diff --git a/palacios/src/palacios/svm_exits.c b/palacios/src/palacios/svm_exits.c new file mode 100644 index 0000000..b47507d --- /dev/null +++ b/palacios/src/palacios/svm_exits.c @@ -0,0 +1,78 @@ +/* + * 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 + * Copyright (c) 2012, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + + +#include +#include +#include + + + +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; +} diff --git a/palacios/src/palacios/svm_handler.c b/palacios/src/palacios/svm_handler.c index 5849055..b270907 100644 --- a/palacios/src/palacios/svm_handler.c +++ b/palacios/src/palacios/svm_handler.c @@ -256,7 +256,7 @@ int v3_handle_svm_exit(struct guest_info * info, addr_t exit_code, addr_t exit_i #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; } @@ -265,10 +265,11 @@ int v3_handle_svm_exit(struct guest_info * info, addr_t exit_code, addr_t exit_i #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"); diff --git a/palacios/src/palacios/vm_guest.c b/palacios/src/palacios/vm_guest.c index 957c3dd..365fc62 100644 --- a/palacios/src/palacios/vm_guest.c +++ b/palacios/src/palacios/vm_guest.c @@ -204,6 +204,7 @@ static int info_hcall(struct guest_info * core, uint_t hcall_id, void * priv_dat #include #include #include +#include #endif #ifdef V3_CONFIG_VMX @@ -227,6 +228,8 @@ int v3_init_vm(struct v3_vm_info * vm) { 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); @@ -265,6 +268,7 @@ int v3_init_vm(struct v3_vm_info * 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 @@ -340,6 +344,8 @@ int v3_free_vm_internal(struct v3_vm_info * vm) { v3_deinit_io_map(vm); v3_deinit_hypercall_map(vm); + v3_deinit_exit_hooks(vm); + #ifdef V3_CONFIG_TELEMETRY v3_deinit_telemetry(vm); #endif @@ -405,6 +411,9 @@ int v3_init_core(struct guest_info * core) { PrintError("Invalid CPU Type 0x%x\n", v3_mach_type); return -1; } + + v3_init_exit_hooks_core(core); + return 0; } diff --git a/palacios/src/palacios/vmm_exits.c b/palacios/src/palacios/vmm_exits.c new file mode 100644 index 0000000..e76a3b3 --- /dev/null +++ b/palacios/src/palacios/vmm_exits.c @@ -0,0 +1,180 @@ +/* + * 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 + * Copyright (c) 2012, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + + +#include +#include +#include + + +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; + +}