From: Jack Lange Date: Mon, 16 Feb 2009 23:57:52 +0000 (-0600) Subject: added hypercall registration and handler X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=1dbd6d179c681dbce107af39c4089d1aa13a714d added hypercall registration and handler --- diff --git a/palacios/build/Makefile b/palacios/build/Makefile index 8e9d972..992dcfe 100644 --- a/palacios/build/Makefile +++ b/palacios/build/Makefile @@ -279,6 +279,7 @@ VMM_OBJS := \ palacios/vmm_profiler.o \ palacios/vmm_direct_paging.o \ palacios/vmm_ringbuffer.o \ + palacios/vmm_hypercall.o \ $(OBJ_FILES) # vmx.c vmcs_gen.c vmcs.c diff --git a/palacios/include/palacios/vm_guest.h b/palacios/include/palacios/vm_guest.h index 1eb4de6..64b5a71 100644 --- a/palacios/include/palacios/vm_guest.h +++ b/palacios/include/palacios/vm_guest.h @@ -32,6 +32,7 @@ #include #include #include +#include @@ -138,6 +139,9 @@ struct guest_info { struct v3_msr_map msr_map; + + v3_hypercall_map_t hcall_map; + // device_map struct vmm_dev_mgr dev_mgr; diff --git a/palacios/include/palacios/vmm_hypercall.h b/palacios/include/palacios/vmm_hypercall.h new file mode 100644 index 0000000..6ec1462 --- /dev/null +++ b/palacios/include/palacios/vmm_hypercall.h @@ -0,0 +1,47 @@ +/* + * 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 + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + + +#ifndef __VMM_HYPERCALL_H__ +#define __VMM_HYPERCALL_H__ + +#ifdef __V3VEE__ +#include +#include + +typedef struct rb_root v3_hypercall_map_t; + +struct guest_info; + +void v3_init_hypercall_map(struct guest_info * info); + + +int v3_register_hypercall(struct guest_info * info, uint_t hypercall_id, + int (*hypercall)(struct guest_info * info, uint_t hcall_id, void * priv_data), + void * priv_data); + + + +int v3_handle_hypercall(struct guest_info * info); + + + +#endif + +#endif diff --git a/palacios/src/palacios/svm_handler.c b/palacios/src/palacios/svm_handler.c index a4b0597..91c0440 100644 --- a/palacios/src/palacios/svm_handler.c +++ b/palacios/src/palacios/svm_handler.c @@ -31,6 +31,7 @@ #include #include #include +#include @@ -271,6 +272,22 @@ int v3_handle_svm_exit(struct guest_info * info) { */ break; } + + + + case VMEXIT_VMMCALL: + { + /* + * Hypercall + */ + + if (v3_handle_hypercall(info) == -1) { + return -1; + } + break; + } + + case VMEXIT_INTR: { // handled by interrupt dispatch earlier @@ -300,56 +317,6 @@ int v3_handle_svm_exit(struct guest_info * info) { break; -#if 0 - // Emulation handlers currently not used - case VMEXIT_EXCP1: - { -#ifdef DEBUG_EMULATOR - PrintDebug("DEBUG EXCEPTION\n"); -#endif - if (info->run_state == VM_EMULATING) { - if (v3_emulation_exit_handler(info) == -1) { - return -1; - } - } else { - PrintError("VMMCALL with not emulator...\n"); - return -1; - } - break; - } - - - case VMEXIT_VMMCALL: - { -#ifdef DEBUG_EMULATOR - PrintDebug("VMMCALL\n"); -#endif - if (info->run_state == VM_EMULATING) { - if (v3_emulation_exit_handler(info) == -1) { - return -1; - } - } else { - /* - ulong_t tsc_spread = 0; - ullong_t exit_tsc = 0; - - ulong_t rax = (ulong_t)info->vm_regs.rbx; - ulong_t rdx = (ulong_t)info->vm_regs.rcx; - - *(ulong_t *)(&exit_tsc) = rax; - *(((ulong_t *)(&exit_tsc)) + 1) = rdx; - - tsc_spread = info->exit_tsc - exit_tsc; - - PrintError("VMMCALL tsc diff = %lu\n",tsc_spread); - info->rip += 3; - */ - PrintError("VMMCALL with not emulator...\n"); - return -1; - } - break; - } -#endif case VMEXIT_WBINVD: diff --git a/palacios/src/palacios/vmm_config.c b/palacios/src/palacios/vmm_config.c index b713975..5e0defc 100644 --- a/palacios/src/palacios/vmm_config.c +++ b/palacios/src/palacios/vmm_config.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -85,6 +86,9 @@ int v3_config_guest(struct guest_info * info, struct v3_vm_config * config_ptr) v3_init_shadow_map(info); + v3_init_hypercall_map(info); + + if (v3_cpu_type == V3_SVM_REV3_CPU) { info->shdw_pg_mode = NESTED_PAGING; } else { diff --git a/palacios/src/palacios/vmm_hypercall.c b/palacios/src/palacios/vmm_hypercall.c new file mode 100644 index 0000000..3c570a3 --- /dev/null +++ b/palacios/src/palacios/vmm_hypercall.c @@ -0,0 +1,127 @@ +/* + * 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 + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + +#include +#include + + +void v3_init_hypercall_map(struct guest_info * info) { + info->hcall_map.rb_node = NULL; +} + + +struct hypercall { + uint_t id; + + int (*hcall_fn)(struct guest_info * info, uint_t hcall_id, void * priv_data); + void * priv_data; + + struct rb_node tree_node; +}; + + + +static inline struct hypercall * __insert_hypercall(struct guest_info * info, struct hypercall * hcall) { + struct rb_node ** p = &(info->hcall_map.rb_node); + struct rb_node * parent = NULL; + struct hypercall * tmp_hcall = NULL; + + while (*p) { + parent = *p; + tmp_hcall = rb_entry(parent, struct hypercall, tree_node); + + if (hcall->id < tmp_hcall->id) { + p = &(*p)->rb_left; + } else if (hcall->id > tmp_hcall->id) { + p = &(*p)->rb_right; + } else { + return tmp_hcall; + } + } + + rb_link_node(&(hcall->tree_node), parent, p); + + return NULL; +} + + +static inline struct hypercall * insert_hypercall(struct guest_info * info, struct hypercall * hcall) { + struct hypercall * ret; + + if ((ret = __insert_hypercall(info, hcall))) { + return ret; + } + + v3_rb_insert_color(&(hcall->tree_node), &(info->hcall_map)); + + return NULL; +} + + +static struct hypercall * get_hypercall(struct guest_info * info, uint_t id) { + struct rb_node * n = info->hcall_map.rb_node; + struct hypercall * hcall = NULL; + + while (n) { + hcall = rb_entry(n, struct hypercall, tree_node); + + if (id < hcall->id) { + n = n->rb_left; + } else if (id > hcall->id) { + n = n->rb_right; + } else { + return hcall; + } + } + + return NULL; +} + + +int v3_register_hypercall(struct guest_info * info, uint_t hypercall_id, + int (*hypercall)(struct guest_info * info, uint_t hcall_id, void * priv_data), + void * priv_data) { + + struct hypercall * hcall = (struct hypercall *)V3_Malloc(sizeof(struct hypercall)); + + hcall->id = hypercall_id; + hcall->priv_data = priv_data; + hcall->hcall_fn = hypercall; + + if (insert_hypercall(info, hcall)) { + V3_Free(hcall); + return -1; + } + + return 0; +} + + +int v3_handle_hypercall(struct guest_info * info) { + uint_t hypercall_id = *(uint_t *)&info->vm_regs.rax; + + struct hypercall * hcall = get_hypercall(info, hypercall_id); + + if (!hcall) { + PrintError("Invalid Hypercall (%d not registered)\n", hypercall_id); + return -1; + } + + return hcall->hcall_fn(info, hypercall_id, hcall->priv_data); +}