#include <palacios/vmm_host_events.h>
#include <palacios/vmm_msr.h>
#include <palacios/vmm_hypercall.h>
+#include <palacios/vmm_cpuid.h>
#include <palacios/vmm_sym_iface.h>
#ifdef CONFIG_TELEMETRY
struct v3_msr_map msr_map;
+ struct v3_cpuid_map cpuid_map;
+
// Symbiotic state
struct v3_sym_state sym_state;
--- /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) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, 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_CPUID_H__
+#define __VMM_CPUID_H__
+
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm_types.h>
+#include <palacios/vmm_rbtree.h>
+
+
+
+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
#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)
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__ (
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 \
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;
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;
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");
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");
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) {
}
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);
#include <palacios/vmm_emulator.h>
#include <palacios/svm_msr.h>
#include <palacios/vmm_hypercall.h>
+#include <palacios/vmm_cpuid.h>
#include <palacios/vmm_direct_paging.h>
#ifdef CONFIG_TELEMETRY
break;
}
case VMEXIT_MSR:
+
if (guest_ctrl->exit_info1 == 0) {
if (v3_handle_msr_read(info) == -1) {
return -1;
}
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");
#include <palacios/vmm_hypercall.h>
#include <palacios/vmm_dev_mgr.h>
#include <palacios/vmm_sym_iface.h>
+#include <palacios/vmm_cpuid.h>
#ifdef CONFIG_SYMBIOTIC_SWAP
#include <palacios/vmm_sym_swap.h>
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
return -1;
}
- v3_print_io_map(info);
+ // v3_print_io_map(info);
v3_print_msr_map(info);
info->run_state = VM_STOPPED;
--- /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) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, 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_cpuid.h>
+#include <palacios/vmm_lowlevel.h>
+
+
+
+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;
+}
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));
#include <palacios/vmcs.h>
#include <palacios/vmx_lowlevel.h>
#include <palacios/vmx_io.h>
+#include <palacios/vmm_cpuid.h>
+
#include <palacios/vmx.h>
#include <palacios/vmm_ctrl_regs.h>
#include <palacios/vmm_lowlevel.h>
}
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");