github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/vmexit/vmexit_cpuid.c (about) 1 /* 2 * Copyright (c) 2013 Intel Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * Unless required by applicable law or agreed to in writing, software 9 * distributed under the License is distributed on an "AS IS" BASIS, 10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 * See the License for the specific language governing permissions and 12 * limitations under the License. 13 */ 14 15 #include "file_codes.h" 16 #define VMM_DEADLOOP() VMM_DEADLOOP_LOG(VMEXIT_CPUID_C) 17 #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(VMEXIT_CPUID_C, __condition) 18 #include "vmm_defs.h" 19 #include "list.h" 20 #include "memory_allocator.h" 21 #include "guest_cpu.h" 22 #include "guest.h" 23 #include "hw_utils.h" 24 #include "vmexit_cpuid.h" 25 #ifdef JLMDEBUG 26 #include "jlmdebug.h" 27 #endif 28 29 #define CPUID_EAX 0 30 #define CPUID_EBX 1 31 #define CPUID_ECX 2 32 #define CPUID_EDX 3 33 #define DESCRIPTOR_L_BIT 0x2000 34 35 typedef struct _CPUID_FILTER_DESCRIPTOR { 36 LIST_ELEMENT list; 37 ADDRESS cpuid; // cpuid leaf index 38 CPUID_FILTER_HANDLER handler; 39 } CPUID_FILTER_DESCRIPTOR; 40 41 static void vmexit_cpuid_filter_install( GUEST_HANDLE guest, 42 ADDRESS cpuid, CPUID_FILTER_HANDLER handler) 43 { 44 LIST_ELEMENT *filter_desc_list = guest_get_cpuid_list(guest); 45 CPUID_FILTER_DESCRIPTOR *p_filter_desc = vmm_malloc(sizeof(*p_filter_desc)); 46 47 VMM_ASSERT(NULL != p_filter_desc); 48 if (NULL != p_filter_desc) { 49 p_filter_desc->cpuid = cpuid; 50 p_filter_desc->handler = handler; 51 list_add(filter_desc_list, &p_filter_desc->list); 52 } 53 } 54 55 static VMEXIT_HANDLING_STATUS vmexit_cpuid_instruction(GUEST_CPU_HANDLE gcpu) 56 { 57 CPUID_PARAMS cpuid_params; 58 UINT32 req_id; 59 LIST_ELEMENT *filter_desc_list= guest_get_cpuid_list(gcpu_guest_handle(gcpu)); 60 LIST_ELEMENT *list_iterator; 61 CPUID_FILTER_DESCRIPTOR *p_filter_desc; 62 63 cpuid_params.m_rax = gcpu_get_native_gp_reg(gcpu, IA32_REG_RAX); 64 cpuid_params.m_rbx = gcpu_get_native_gp_reg(gcpu, IA32_REG_RBX); 65 cpuid_params.m_rcx = gcpu_get_native_gp_reg(gcpu, IA32_REG_RCX); 66 cpuid_params.m_rdx = gcpu_get_native_gp_reg(gcpu, IA32_REG_RDX); 67 req_id = (UINT32)cpuid_params.m_rax; 68 // get the real h/w values 69 hw_cpuid(&cpuid_params); 70 // pass to filters for virtualization 71 LIST_FOR_EACH(filter_desc_list, list_iterator) { 72 p_filter_desc = LIST_ENTRY(list_iterator, CPUID_FILTER_DESCRIPTOR, list); 73 if (p_filter_desc->cpuid == req_id) { 74 p_filter_desc->handler(gcpu, &cpuid_params); 75 } 76 } 77 // write back to guest OS 78 gcpu_set_native_gp_reg(gcpu, IA32_REG_RAX, cpuid_params.m_rax); 79 gcpu_set_native_gp_reg(gcpu, IA32_REG_RBX, cpuid_params.m_rbx); 80 gcpu_set_native_gp_reg(gcpu, IA32_REG_RCX, cpuid_params.m_rcx); 81 gcpu_set_native_gp_reg(gcpu, IA32_REG_RDX, cpuid_params.m_rdx); 82 #ifdef JLMDEBUG1 83 bprint("vmexit_cpuid_instruction\n"); 84 bprint("rax: %016lx, rbx: %016lx, rcx: %016lx, rdx: %016lx\n", 85 cpuid_params.m_rax, cpuid_params.m_rbx, 86 cpuid_params.m_rcx, cpuid_params.m_rdx); 87 #endif 88 // increment IP to skip executed CPUID instruction 89 gcpu_skip_guest_instruction(gcpu); 90 return VMEXIT_HANDLED; 91 } 92 93 static void cpuid_leaf_1h_filter( GUEST_CPU_HANDLE gcpu UNUSED, CPUID_PARAMS *p_cpuid UNUSED ) 94 { 95 VMM_ASSERT(p_cpuid); 96 97 // hide SMX support 98 BIT_CLR64(p_cpuid->m_rcx, CPUID_LEAF_1H_ECX_SMX_SUPPORT); 99 100 // hide VMX support 101 BIT_CLR64(p_cpuid->m_rcx, CPUID_LEAF_1H_ECX_VMX_SUPPORT); 102 } 103 104 static void cpuid_leaf_3h_filter( GUEST_CPU_HANDLE gcpu UNUSED, CPUID_PARAMS *p_cpuid ) 105 { 106 VMM_ASSERT(p_cpuid); 107 108 // use PSN index 3 to indicate whether eVmm is running or not. 109 p_cpuid->m_rcx = EVMM_RUNNING_SIGNATURE_VMM; //"EVMM" 110 p_cpuid->m_rdx = EVMM_RUNNING_SIGNATURE_CORP; //"INTC" 111 } 112 113 114 static 115 void cpuid_leaf_ext_1h_filter( 116 GUEST_CPU_HANDLE gcpu, 117 CPUID_PARAMS *p_cpuid ) 118 { 119 VMCS_OBJECT* vmcs = gcpu_get_vmcs(gcpu); 120 UINT64 guest_cs_ar= vmcs_read(vmcs, VMCS_GUEST_CS_AR); 121 122 VMM_ASSERT(p_cpuid); 123 if (BITMAP_GET(guest_cs_ar,DESCRIPTOR_L_BIT) == 0) { 124 //Guest is not in 64 bit mode, the bit 11 of EDX should be 125 //cleared since this bit indicates syscall/sysret available 126 //in 64 bit mode. See the Intel Software Programmer Manual vol 2A 127 //CPUID instruction 128 129 BIT_CLR64(p_cpuid->m_rdx, CPUID_EXT_LEAF_1H_EDX_SYSCALL_SYSRET); 130 } 131 } 132 133 134 135 #pragma warning( pop ) 136 137 138 void vmexit_cpuid_guest_intialize( GUEST_ID guest_id) 139 { 140 GUEST_HANDLE guest = guest_handle(guest_id); 141 142 VMM_ASSERT(guest); 143 // install CPUID vmexit handler 144 vmexit_install_handler( guest_id, vmexit_cpuid_instruction, 145 Ia32VmxExitBasicReasonCpuidInstruction); 146 147 // register cpuid(leaf 0x1) filter handler 148 vmexit_cpuid_filter_install(guest, CPUID_LEAF_1H,cpuid_leaf_1h_filter); 149 150 // register cpuid(leaf 0x3) filter handler 151 vmexit_cpuid_filter_install(guest, CPUID_LEAF_3H,cpuid_leaf_3h_filter); 152 153 // register cpuid(ext leaf 0x80000001) filter handler 154 vmexit_cpuid_filter_install(guest, CPUID_EXT_LEAF_1H,cpuid_leaf_ext_1h_filter); 155 156 VMM_LOG(mask_uvmm, level_trace,"finish vmexit_cpuid_guest_intialize\r\n"); 157 158 return; 159 } 160