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