github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/memory/ept/ept_hw_layer.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 "vmm_defs.h"
    16  #include "vmcs_init.h"
    17  #include "ept_hw_layer.h"
    18  #include "hw_utils.h"
    19  #include "guest_cpu.h"
    20  #include "vmcs_api.h"
    21  #include "vmm_phys_mem_types.h"
    22  #include "libc.h"
    23  #include "scheduler.h"
    24  #include "guest_cpu_internal.h"
    25  #include "file_codes.h"
    26  #define VMM_DEADLOOP()          VMM_DEADLOOP_LOG(EPT_HW_LAYER_C)
    27  #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(EPT_HW_LAYER_C, __condition)
    28  #ifdef JLMDEBUG
    29  #include "jlmdebug.h"
    30  #endif
    31  
    32  #define ENABLE_VPID
    33  
    34  BOOLEAN ept_hw_is_ept_supported(void)
    35  {
    36      const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints();
    37  
    38      return (hw_constraints->may1_processor_based_exec_ctrl.Bits.SecondaryControls
    39              && hw_constraints->may1_processor_based_exec_ctrl2.Bits.EnableEPT);
    40  }
    41  
    42  void ept_hw_set_pdtprs(GUEST_CPU_HANDLE gcpu, UINT64 pdptr[])
    43  {
    44      VMCS_OBJECT *vmcs = gcpu_get_vmcs(gcpu);
    45  
    46      CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu);
    47      vmcs_write(vmcs, VMCS_GUEST_PDPTR0, pdptr[0]);
    48      vmcs_write(vmcs, VMCS_GUEST_PDPTR1, pdptr[1]);
    49      vmcs_write(vmcs, VMCS_GUEST_PDPTR2, pdptr[2]);
    50      vmcs_write(vmcs, VMCS_GUEST_PDPTR3, pdptr[3]);
    51  }
    52  #ifdef INCLUDE_UNUSED_CODE
    53  void ept_hw_get_pdtprs(GUEST_CPU_HANDLE gcpu, UINT64 pdptr[])
    54  {
    55      VMCS_OBJECT *vmcs = gcpu_get_vmcs(gcpu);
    56  
    57      CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu);
    58      pdptr[0] = vmcs_read(vmcs, VMCS_GUEST_PDPTR0);
    59      pdptr[1] = vmcs_read(vmcs, VMCS_GUEST_PDPTR1);
    60      pdptr[2] = vmcs_read(vmcs, VMCS_GUEST_PDPTR2);
    61      pdptr[3] = vmcs_read(vmcs, VMCS_GUEST_PDPTR3);
    62  }
    63  #endif
    64  
    65  UINT32 ept_hw_get_guest_address_width(UINT32 actual_gaw)
    66  {
    67      const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints();
    68      if(actual_gaw <= 21 && hw_constraints->ept_vpid_capabilities.Bits.GAW_21_bit) {
    69          return 21;
    70      }
    71      if(actual_gaw <= 30 && hw_constraints->ept_vpid_capabilities.Bits.GAW_30_bit) {
    72          return 30;
    73      }
    74      if(actual_gaw <= 39 && hw_constraints->ept_vpid_capabilities.Bits.GAW_39_bit) {
    75          return 39;
    76      }
    77      if(actual_gaw <= 48 && hw_constraints->ept_vpid_capabilities.Bits.GAW_48_bit) {
    78          return 48;
    79      }
    80      if(actual_gaw <= 57 && hw_constraints->ept_vpid_capabilities.Bits.GAW_57_bit) {
    81          return 57;
    82      }
    83      VMM_ASSERT(0);
    84      return (UINT32) -1;
    85  }
    86  
    87  UINT32 ept_hw_get_guest_address_width_encoding(UINT32 width)
    88  {
    89      UINT32 gaw_encoding = (UINT32) -1;
    90  
    91      VMM_ASSERT(width == 21 || width == 30 || width == 39 || width == 48 || width == 57);
    92      gaw_encoding = (width - 21) / 9;
    93      return gaw_encoding;
    94  }
    95  
    96  UINT32 ept_hw_get_guest_address_width_from_encoding(UINT32 gaw_encoding)
    97  {
    98      VMM_ASSERT(gaw_encoding <= 4);
    99      return 21 + (gaw_encoding * 9);
   100  }
   101  
   102  VMM_PHYS_MEM_TYPE ept_hw_get_ept_memory_type(void)
   103  {
   104      const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints();
   105  
   106      if(hw_constraints->ept_vpid_capabilities.Bits.WB) {
   107          return VMM_PHYS_MEM_WRITE_BACK;
   108      }
   109      if(hw_constraints->ept_vpid_capabilities.Bits.WP) {
   110          return VMM_PHYS_MEM_WRITE_PROTECTED;
   111      }
   112      if(hw_constraints->ept_vpid_capabilities.Bits.WT) {
   113          return VMM_PHYS_MEM_WRITE_THROUGH;
   114      }
   115      if(hw_constraints->ept_vpid_capabilities.Bits.WC) {
   116          return VMM_PHYS_MEM_WRITE_COMBINING;
   117      }
   118      if(hw_constraints->ept_vpid_capabilities.Bits.UC) {
   119          return VMM_PHYS_MEM_UNCACHABLE;
   120      }
   121      VMM_ASSERT(0);
   122      return VMM_PHYS_MEM_UNDEFINED;
   123  }
   124  
   125  UINT64 ept_hw_get_eptp(GUEST_CPU_HANDLE gcpu)
   126  {
   127      VMCS_OBJECT* vmcs = gcpu_get_vmcs(gcpu);
   128      UINT64 eptp = 0;
   129  
   130      VMM_ASSERT(gcpu);
   131      CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu);
   132      if(! ept_hw_is_ept_supported()) {
   133          return eptp;
   134      }
   135      eptp = vmcs_read( vmcs, VMCS_EPTP_ADDRESS);
   136      return eptp;
   137  }
   138  
   139  BOOLEAN ept_hw_set_eptp(GUEST_CPU_HANDLE gcpu, HPA ept_root_hpa, UINT32 gaw)
   140  {
   141      VMCS_OBJECT* vmcs = gcpu_get_vmcs(gcpu);
   142      EPTP eptp;
   143      UINT32 ept_gaw = 0;
   144  
   145      VMM_ASSERT(gcpu);
   146      VMM_ASSERT(vmcs);
   147      CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu);
   148      if(! ept_hw_is_ept_supported() || ept_root_hpa == 0) {
   149          return FALSE;
   150      }
   151      ept_gaw = ept_hw_get_guest_address_width(gaw);
   152      if(ept_gaw == (UINT32) -1) {
   153          return FALSE;
   154      }
   155      eptp.Uint64 = ept_root_hpa;
   156      eptp.Bits.ETMT = ept_hw_get_ept_memory_type();
   157      eptp.Bits.GAW = ept_hw_get_guest_address_width_encoding(ept_gaw);
   158      eptp.Bits.Reserved = 0;
   159      vmcs_write( vmcs, VMCS_EPTP_ADDRESS, eptp.Uint64);
   160      return TRUE;
   161  }
   162  
   163  BOOLEAN ept_hw_is_ept_enabled(GUEST_CPU_HANDLE gcpu)
   164  {
   165      PROCESSOR_BASED_VM_EXECUTION_CONTROLS2 proc_ctrls2;
   166  
   167      CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu);
   168      proc_ctrls2.Uint32 = (UINT32) vmcs_read(gcpu_get_vmcs(gcpu), VMCS_CONTROL2_VECTOR_PROCESSOR_EVENTS);
   169      return proc_ctrls2.Bits.EnableEPT;
   170  }
   171  
   172  // invalidate EPT
   173  BOOLEAN ept_hw_is_invept_supported(void)
   174  {
   175      const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints();
   176  
   177      if(ept_hw_is_ept_supported() && hw_constraints->ept_vpid_capabilities.Bits.InveptSupported) {
   178          return TRUE;
   179      }
   180      return FALSE;
   181  }
   182  
   183  // invalidate VPID
   184  BOOLEAN ept_hw_is_invvpid_supported(void)
   185  {
   186      const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints();
   187  
   188      if(ept_hw_is_ept_supported() && hw_constraints->ept_vpid_capabilities.Bits.InvvpidSupported) {
   189          return TRUE;
   190      }
   191  #ifdef JLMDEBUG
   192      bprint("ept_hw_is_invvpid_supported is returning false\n");
   193  #endif
   194      return FALSE;
   195  }
   196  
   197  BOOLEAN ept_hw_invept_all_contexts(void)
   198  {
   199      INVEPT_ARG arg;
   200      UINT64 rflags;
   201      const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints();
   202      BOOLEAN status = FALSE;
   203  
   204      if(! ept_hw_is_invept_supported()) {
   205          return TRUE;
   206      }
   207      vmm_zeromem(&arg, sizeof(arg));
   208      if(hw_constraints->ept_vpid_capabilities.Bits.InveptAllContexts) {
   209          vmm_asm_invept(&arg, INVEPT_ALL_CONTEXTS, &rflags);
   210          status = ((rflags & 0x8d5) == 0);
   211          if(! status) {
   212              VMM_LOG(mask_anonymous, level_trace,"ept_hw_invept_all_contexts ERROR: rflags = %p\r\n", rflags);
   213          }
   214      }
   215      return status;
   216  }
   217  
   218  BOOLEAN ept_hw_invept_context(UINT64 eptp)
   219  {
   220      INVEPT_ARG arg;
   221      UINT64 rflags;
   222      const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints();
   223      BOOLEAN status = FALSE;
   224  
   225      if(! ept_hw_is_invept_supported()) {
   226          return TRUE;
   227      }
   228      vmm_zeromem(&arg, sizeof(arg));
   229      VMM_ASSERT(eptp != 0);
   230      arg.eptp = eptp;
   231      if(hw_constraints->ept_vpid_capabilities.Bits.InveptContextWide) {
   232          vmm_asm_invept(&arg, INVEPT_CONTEXT_WIDE, &rflags);
   233          status = ((rflags & 0x8d5) == 0);
   234          if(! status) {
   235              VMM_LOG(mask_anonymous, level_trace,"ept_hw_invept_context ERROR: eptp = %p rflags = %p\r\n", eptp, rflags);
   236          }
   237      }
   238      else {
   239          ept_hw_invept_all_contexts();
   240      }
   241      return status;
   242  }
   243  
   244  BOOLEAN ept_hw_invept_individual_address(UINT64 eptp, ADDRESS gpa)
   245  {
   246      INVEPT_ARG arg;
   247      const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints();
   248      UINT64 rflags;
   249      BOOLEAN status = FALSE;
   250  
   251      if(! ept_hw_is_invept_supported()) {
   252          return TRUE;
   253      }
   254      vmm_zeromem(&arg, sizeof(arg));
   255      VMM_ASSERT((eptp != 0) && (gpa != 0));
   256      arg.eptp = eptp;
   257      arg.gpa = gpa;
   258      if(hw_constraints->ept_vpid_capabilities.Bits.InveptIndividualAddress) {
   259          vmm_asm_invept(&arg, INVEPT_INDIVIDUAL_ADDRESS, &rflags);
   260          status = ((rflags & 0x8d5) == 0);
   261          if(! status) {
   262              VMM_LOG(mask_anonymous, level_trace,
   263                      "ept_hw_invept_individual_address ERROR: eptp = %p gpa = %p rflags = %p\r\n", 
   264                      eptp, gpa, rflags);
   265          }
   266      }
   267      else {
   268          ept_hw_invept_context(eptp);
   269      }
   270      return status;
   271  }
   272  
   273  BOOLEAN ept_hw_invvpid_individual_address(UINT64 vpid, ADDRESS gva)
   274  {
   275      INVVPID_ARG arg;
   276      const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints();
   277      UINT64 rflags;
   278      BOOLEAN status = FALSE;
   279  
   280      if(!ept_hw_is_invvpid_supported()) {
   281          VMM_ASSERT(0);
   282          return TRUE;
   283      }
   284      arg.vpid = vpid;
   285      arg.gva = gva;
   286      if(hw_constraints->ept_vpid_capabilities.Bits.InvvpidIndividualAddress) {
   287          vmm_asm_invvpid(&arg, INVVPID_INDIVIDUAL_ADDRESS, &rflags);
   288          status = ((rflags & 0x8d5) == 0);
   289          if(! status) {
   290              VMM_LOG(mask_anonymous, level_trace,
   291                      "ept_hw_invvpid_individual_address ERROR: vpid = %d gva = %p rflags = %p\r\n", 
   292                      vpid, gva, rflags);
   293                      VMM_ASSERT(0);
   294          }
   295      }
   296      return status;
   297  }
   298  
   299  BOOLEAN ept_hw_invvpid_all_contexts(void)
   300  {
   301      INVVPID_ARG arg;
   302      const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints();
   303      UINT64 rflags;
   304      BOOLEAN status = FALSE;
   305  
   306      if(! ept_hw_is_invvpid_supported()) {
   307                  VMM_ASSERT(0);
   308          return TRUE;
   309      }
   310      arg.vpid = 0; // vpid;
   311      //arg.gva = gva;
   312  
   313      if(hw_constraints->ept_vpid_capabilities.Bits.InvvpidAllContexts) {
   314          vmm_asm_invvpid(&arg, INVVPID_ALL_CONTEXTS, &rflags);
   315          status = ((rflags & 0x8d5) == 0);
   316          if(! status) {
   317              VMM_LOG(mask_anonymous, level_trace,"ept_hw_invvpid_all_contexts ERROR: rflags = %p\r\n", rflags);
   318                          VMM_ASSERT(0);
   319          }
   320      }
   321      return status;
   322  }
   323  
   324  
   325  BOOLEAN ept_hw_invvpid_single_context(UINT64 vpid)
   326  {
   327      INVVPID_ARG arg;
   328      const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints();
   329      UINT64 rflags;
   330      BOOLEAN status = FALSE;
   331  
   332  #ifdef JLMDEBUG1
   333      bprint("ept_hw_invvpid_single_context\n");
   334  #endif
   335      if(!ept_hw_is_invvpid_supported()) {
   336          VMM_ASSERT(0);
   337          return TRUE;
   338      }
   339      arg.vpid = vpid;
   340      if(hw_constraints->ept_vpid_capabilities.Bits.InvvpidContextWide) {
   341          vmm_asm_invvpid(&arg, INVVPID_SINGLE_CONTEXT, &rflags);
   342          status = ((rflags & 0x8d5) == 0);
   343          if(!status) {
   344  #ifdef JLMDEBUG
   345              bprint("vmm_asm_invvpid failed\n");
   346  #endif
   347              VMM_LOG(mask_anonymous, level_trace,
   348              "ept_hw_invvpid_all_contexts ERROR: rflags = %p\r\n", rflags);
   349              VMM_ASSERT(0);
   350          }
   351      }
   352      return status;
   353  }
   354  
   355  BOOLEAN ept_hw_enable_ept(GUEST_CPU_HANDLE gcpu)
   356  {
   357      PROCESSOR_BASED_VM_EXECUTION_CONTROLS2 proc_ctrls2;
   358      VMEXIT_CONTROL vmexit_request;
   359  
   360      CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu);
   361      VMM_ASSERT(gcpu);
   362      if(! ept_hw_is_ept_supported()) {
   363          return FALSE;
   364      }
   365      proc_ctrls2.Uint32 = 0;
   366      vmm_zeromem(&vmexit_request, sizeof(vmexit_request));
   367  
   368      proc_ctrls2.Bits.EnableEPT = 1;
   369  #ifdef ENABLE_VPID
   370      proc_ctrls2.Bits.EnableVPID = 1;
   371      vmcs_write(gcpu_get_vmcs(gcpu), VMCS_VPID, 1 + gcpu->vcpu.guest_id); 
   372  #endif
   373      vmexit_request.proc_ctrls2.bit_mask    = proc_ctrls2.Uint32;
   374      vmexit_request.proc_ctrls2.bit_request = UINT64_ALL_ONES;
   375      // FIXME
   376      gcpu_control_setup( gcpu, &vmexit_request );
   377      return TRUE;
   378  }
   379  
   380  void ept_hw_disable_ept(GUEST_CPU_HANDLE gcpu)
   381  {
   382      PROCESSOR_BASED_VM_EXECUTION_CONTROLS2 proc_ctrls2;
   383      VMEXIT_CONTROL vmexit_request;
   384      CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu);
   385      ept_hw_invvpid_single_context(1 + gcpu->vcpu.guest_id);
   386      proc_ctrls2.Uint32 = 0;
   387      vmm_zeromem(&vmexit_request, sizeof(vmexit_request));
   388      proc_ctrls2.Bits.EnableEPT = 1;
   389  #ifdef ENABLE_VPID
   390      proc_ctrls2.Bits.EnableVPID = 1;
   391      vmcs_write(gcpu_get_vmcs(gcpu), VMCS_VPID, 0);
   392  #endif
   393      vmexit_request.proc_ctrls2.bit_mask    = proc_ctrls2.Uint32;
   394      vmexit_request.proc_ctrls2.bit_request = 0;
   395      // FIXME
   396      gcpu_control_setup( gcpu, &vmexit_request );
   397  }