From: Jack Lange Date: Fri, 18 Sep 2009 22:34:52 +0000 (-0500) Subject: added cpuid hooking X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=c06413341bf1dca02f22c0502fa5c2d1c2c11eab added cpuid hooking --- diff --git a/palacios/include/palacios/vm_guest.h b/palacios/include/palacios/vm_guest.h index 749925d..86a1cc4 100644 --- a/palacios/include/palacios/vm_guest.h +++ b/palacios/include/palacios/vm_guest.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #ifdef CONFIG_TELEMETRY @@ -154,6 +155,8 @@ struct guest_info { struct v3_msr_map msr_map; + struct v3_cpuid_map cpuid_map; + // Symbiotic state struct v3_sym_state sym_state; diff --git a/palacios/include/palacios/vmm_cpuid.h b/palacios/include/palacios/vmm_cpuid.h new file mode 100644 index 0000000..a5f45ee --- /dev/null +++ b/palacios/include/palacios/vmm_cpuid.h @@ -0,0 +1,72 @@ +/* + * 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_CPUID_H__ +#define __VMM_CPUID_H__ + + +#ifdef __V3VEE__ + +#include +#include + + + +struct guest_info; + +void v3_init_cpuid_map(struct guest_info * info); + + +struct v3_cpuid_hook { + uint32_t cpuid; + + int (*hook_fn)(struct guest_info * info, uint32_t cpuid, \ + uint32_t * eax, uint32_t * ebx, \ + uint32_t * ecx, uint32_t * edx, \ + void * private_data); + void * private_data; + + struct rb_node tree_node; +}; + + + +struct v3_cpuid_map { + struct rb_root map; +}; + +void v3_print_cpuid_map(struct guest_info * info); + +int v3_hook_cpuid(struct guest_info * info, uint32_t cpuid, + int (*hook_fn)(struct guest_info * info, uint32_t cpuid, \ + uint32_t * eax, uint32_t * ebx, \ + uint32_t * ecx, uint32_t * edx, \ + void * private_data), + void * private_data); + +int v3_unhook_cpuid(struct guest_info * info, uint32_t cpuid); + +int v3_handle_cpuid(struct guest_info * info); + + + +#endif + +#endif diff --git a/palacios/include/palacios/vmm_lowlevel.h b/palacios/include/palacios/vmm_lowlevel.h index 71af105..8e85162 100644 --- a/palacios/include/palacios/vmm_lowlevel.h +++ b/palacios/include/palacios/vmm_lowlevel.h @@ -24,9 +24,10 @@ #define CPUID_EXT_FEATURE_IDS 0x80000001 -#ifdef __V3_32BIT__ -static void __inline__ v3_cpuid(uint_t target, addr_t * eax, addr_t * ebx, addr_t * ecx, addr_t * edx) { +static void __inline__ v3_cpuid(uint32_t target, + uint32_t * eax, uint32_t * ebx, + uint32_t * ecx, uint32_t * edx) { __asm__ __volatile__ ( "cpuid\n\t" : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx) @@ -35,19 +36,6 @@ static void __inline__ v3_cpuid(uint_t target, addr_t * eax, addr_t * ebx, addr_ return; } -#elif __V3_64BIT__ - -static void __inline__ v3_cpuid(uint_t target, addr_t * eax, addr_t * ebx, addr_t * ecx, addr_t * edx) { - __asm__ __volatile__ ( - "cpuid\n\t" - : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) - : "0" (target), "2" (*ecx) - ); - return; -} - -#endif - static void __inline__ v3_set_msr(uint_t msr, uint_t high_byte, uint_t low_byte) { __asm__ __volatile__ ( diff --git a/palacios/src/palacios/Makefile b/palacios/src/palacios/Makefile index 0999c36..d01dd6a 100644 --- a/palacios/src/palacios/Makefile +++ b/palacios/src/palacios/Makefile @@ -30,7 +30,8 @@ obj-y := \ vmm_util.o \ vmm_xed.o \ vmm_binaries.o \ - vmm_sym_iface.o + vmm_cpuid.o \ + vmm_sym_iface.o \ obj-$(CONFIG_SVM) += svm.o \ diff --git a/palacios/src/palacios/svm.c b/palacios/src/palacios/svm.c index 3c33292..7ba76eb 100644 --- a/palacios/src/palacios/svm.c +++ b/palacios/src/palacios/svm.c @@ -90,6 +90,7 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) { ctrl_area->svm_instrs.CLGI = 1; ctrl_area->svm_instrs.SKINIT = 1; ctrl_area->svm_instrs.RDTSCP = 1; + ctrl_area->svm_instrs.CPUID = 1; ctrl_area->svm_instrs.ICEBP = 1; ctrl_area->svm_instrs.WBINVD = 1; ctrl_area->svm_instrs.MONITOR = 1; @@ -176,13 +177,11 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) { ctrl_area->instrs.IOIO_PROT = 1; - v3_init_svm_msr_map(vm_info); ctrl_area->MSRPM_BASE_PA = (addr_t)V3_PAddr(vm_info->msr_map.arch_data); ctrl_area->instrs.MSR_PROT = 1; - PrintDebug("Exiting on interrupts\n"); ctrl_area->guest_ctrl.V_INTR_MASKING = 1; ctrl_area->instrs.INTR = 1; @@ -370,11 +369,11 @@ static int start_svm_guest(struct guest_info *info) { int v3_is_svm_capable() { // Dinda uint_t vm_cr_low = 0, vm_cr_high = 0; - addr_t eax = 0, ebx = 0, ecx = 0, edx = 0; + uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; v3_cpuid(CPUID_EXT_FEATURE_IDS, &eax, &ebx, &ecx, &edx); - PrintDebug("CPUID_EXT_FEATURE_IDS_ecx=%p\n", (void *)ecx); + PrintDebug("CPUID_EXT_FEATURE_IDS_ecx=0x%x\n", ecx); if ((ecx & CPUID_EXT_FEATURE_IDS_ecx_svm_avail) == 0) { PrintDebug("SVM Not Available\n"); @@ -389,7 +388,7 @@ int v3_is_svm_capable() { v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx); - PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=%p\n", (void *)edx); + PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx); if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) { PrintDebug("SVM BIOS Disabled, not unlockable\n"); @@ -402,10 +401,10 @@ int v3_is_svm_capable() { PrintDebug("SVM is available and enabled.\n"); v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx); - PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_eax=%p\n", (void *)eax); - PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ebx=%p\n", (void *)ebx); - PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ecx=%p\n", (void *)ecx); - PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=%p\n", (void *)edx); + PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_eax=0x%x\n", eax); + PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ebx=0x%x\n", ebx); + PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ecx=0x%x\n", ecx); + PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx); if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) { @@ -420,7 +419,7 @@ int v3_is_svm_capable() { } static int has_svm_nested_paging() { - addr_t eax = 0, ebx = 0, ecx = 0, edx = 0; + uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx); diff --git a/palacios/src/palacios/svm_handler.c b/palacios/src/palacios/svm_handler.c index 5736234..4c4aa2c 100644 --- a/palacios/src/palacios/svm_handler.c +++ b/palacios/src/palacios/svm_handler.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #ifdef CONFIG_TELEMETRY @@ -139,6 +140,7 @@ int v3_handle_svm_exit(struct guest_info * info) { break; } case VMEXIT_MSR: + if (guest_ctrl->exit_info1 == 0) { if (v3_handle_msr_read(info) == -1) { return -1; @@ -153,6 +155,14 @@ int v3_handle_svm_exit(struct guest_info * info) { } break; + + case VMEXIT_CPUID: + if (v3_handle_cpuid(info) == -1) { + PrintError("Error handling CPUID\n"); + return -1; + } + + break; case VMEXIT_CR0_WRITE: #ifdef CONFIG_DEBUG_CTRL_REGS PrintDebug("CR0 Write\n"); diff --git a/palacios/src/palacios/vmm_config.c b/palacios/src/palacios/vmm_config.c index d4bd23a..72887c6 100644 --- a/palacios/src/palacios/vmm_config.c +++ b/palacios/src/palacios/vmm_config.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef CONFIG_SYMBIOTIC_SWAP #include @@ -94,6 +95,7 @@ int v3_pre_config_guest(struct guest_info * info, struct v3_vm_config * config_p v3_init_hypercall_map(info); v3_init_io_map(info); v3_init_msr_map(info); + v3_init_cpuid_map(info); v3_init_host_events(info); // Initialize the memory map @@ -155,7 +157,7 @@ int v3_post_config_guest(struct guest_info * info, struct v3_vm_config * config_ return -1; } - v3_print_io_map(info); + // v3_print_io_map(info); v3_print_msr_map(info); info->run_state = VM_STOPPED; diff --git a/palacios/src/palacios/vmm_cpuid.c b/palacios/src/palacios/vmm_cpuid.c new file mode 100644 index 0000000..6dc29eb --- /dev/null +++ b/palacios/src/palacios/vmm_cpuid.c @@ -0,0 +1,161 @@ +/* + * 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 +#include + + + +void v3_init_cpuid_map(struct guest_info * info) { + info->cpuid_map.map.rb_node = NULL; +} + + +static inline struct v3_cpuid_hook * __insert_cpuid_hook(struct guest_info * info, struct v3_cpuid_hook * hook) { + struct rb_node ** p = &(info->cpuid_map.map.rb_node); + struct rb_node * parent = NULL; + struct v3_cpuid_hook * tmp_hook = NULL; + + while (*p) { + parent = *p; + tmp_hook = rb_entry(parent, struct v3_cpuid_hook, tree_node); + + if (hook->cpuid < tmp_hook->cpuid) { + p = &(*p)->rb_left; + } else if (hook->cpuid > tmp_hook->cpuid) { + p = &(*p)->rb_right; + } else { + return tmp_hook; + } + } + rb_link_node(&(hook->tree_node), parent, p); + + return NULL; +} + + +static inline struct v3_cpuid_hook * insert_cpuid_hook(struct guest_info * info, struct v3_cpuid_hook * hook) { + struct v3_cpuid_hook * ret; + + if ((ret = __insert_cpuid_hook(info, hook))) { + return ret; + } + + v3_rb_insert_color(&(hook->tree_node), &(info->cpuid_map.map)); + + return NULL; +} + + + +static struct v3_cpuid_hook * get_cpuid_hook(struct guest_info * info, uint32_t cpuid) { + struct rb_node * n = info->cpuid_map.map.rb_node; + struct v3_cpuid_hook * hook = NULL; + + while (n) { + hook = rb_entry(n, struct v3_cpuid_hook, tree_node); + + if (cpuid < hook->cpuid) { + n = n->rb_left; + } else if (cpuid > hook->cpuid) { + n = n->rb_right; + } else { + return hook; + } + } + + return NULL; +} + + +int v3_unhook_cpuid(struct guest_info * info, uint32_t cpuid) { + struct v3_cpuid_hook * hook = get_cpuid_hook(info, cpuid); + + if (hook == NULL) { + PrintError("Could not find cpuid to unhook (0x%x)\n", cpuid); + return -1; + } + + v3_rb_erase(&(hook->tree_node), &(info->cpuid_map.map)); + + V3_Free(hook); + + return 0; +} + +int v3_hook_cpuid(struct guest_info * info, uint32_t cpuid, + int (*hook_fn)(struct guest_info * info, uint32_t cpuid, \ + uint32_t * eax, uint32_t * ebx, \ + uint32_t * ecx, uint32_t * edx, \ + void * private_data), + void * private_data) { + struct v3_cpuid_hook * hook = NULL; + + if (hook_fn == NULL) { + PrintError("CPUID hook requested with null handler\n"); + return -1; + } + + hook = (struct v3_cpuid_hook *)V3_Malloc(sizeof(struct v3_cpuid_hook)); + hook->cpuid = cpuid; + hook->private_data = private_data; + hook->hook_fn = hook_fn; + + if (insert_cpuid_hook(info, hook)) { + PrintError("Could not hook cpuid 0x%x (already hooked)\n", cpuid); + V3_Free(hook); + return -1; + } + + return 0; +} + +int v3_handle_cpuid(struct guest_info * info) { + uint32_t cpuid = info->vm_regs.rax; + struct v3_cpuid_hook * hook = get_cpuid_hook(info, cpuid); + + if (hook == NULL) { + // call the passthrough handler + v3_cpuid(cpuid, + (uint32_t *)&(info->vm_regs.rax), + (uint32_t *)&(info->vm_regs.rbx), + (uint32_t *)&(info->vm_regs.rcx), + (uint32_t *)&(info->vm_regs.rdx)); + } else { + if (hook->hook_fn(info, cpuid, + (uint32_t *)&(info->vm_regs.rax), + (uint32_t *)&(info->vm_regs.rbx), + (uint32_t *)&(info->vm_regs.rcx), + (uint32_t *)&(info->vm_regs.rdx), + hook->private_data) == -1) { + PrintError("Error in cpuid handler for 0x%x\n", cpuid); + return -1; + } + } + + info->vm_regs.rax &= 0x00000000ffffffffLL; + info->vm_regs.rbx &= 0x00000000ffffffffLL; + info->vm_regs.rcx &= 0x00000000ffffffffLL; + info->vm_regs.rdx &= 0x00000000ffffffffLL; + + info->rip += 2; + + return 0; +} diff --git a/palacios/src/palacios/vmx.c b/palacios/src/palacios/vmx.c index 7789b70..90ff060 100644 --- a/palacios/src/palacios/vmx.c +++ b/palacios/src/palacios/vmx.c @@ -456,11 +456,11 @@ static int start_vmx_guest(struct guest_info* info) { int v3_is_vmx_capable() { v3_msr_t feature_msr; - addr_t eax = 0, ebx = 0, ecx = 0, edx = 0; + uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; v3_cpuid(0x1, &eax, &ebx, &ecx, &edx); - PrintDebug("ECX: %p\n", (void*)ecx); + PrintDebug("ECX: 0x%x\n", ecx); if (ecx & CPUID_1_ECX_VTXFLAG) { v3_get_msr(VMX_FEATURE_CONTROL_MSR, &(feature_msr.hi), &(feature_msr.lo)); diff --git a/palacios/src/palacios/vmx_handler.c b/palacios/src/palacios/vmx_handler.c index af76455..ee1824f 100644 --- a/palacios/src/palacios/vmx_handler.c +++ b/palacios/src/palacios/vmx_handler.c @@ -23,6 +23,8 @@ #include #include #include +#include + #include #include #include @@ -178,19 +180,13 @@ int v3_handle_vmx_exit(struct v3_gprs * gprs, struct guest_info * info, struct v } break; - case VMEXIT_CPUID: { - int instr_len; - uint32_t target = info->vm_regs.rax; - - v3_cpuid(target, (addr_t *)&(info->vm_regs.rax), (addr_t *)&(info->vm_regs.rbx), - (addr_t *)&(info->vm_regs.rcx), (addr_t *)&(info->vm_regs.rdx)); - - check_vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len); - - info->rip += instr_len; + case VMEXIT_CPUID: + if (v3_handle_cpuid(info) == -1) { + PrintError("Error Handling CPUID instruction\n"); + return -1; + } break; - } case VMEXIT_RDMSR: if (v3_handle_msr_read(info) == -1) { PrintError("Error handling MSR Read\n");