github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/memory/ept/ept.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(EPT_C)
    17  #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(EPT_C, __condition)
    18  #include "vmm_callback.h"
    19  #include "vmcs_init.h"
    20  #include "guest_cpu.h"
    21  #include "event_mgr.h"
    22  #include "vmm_events_data.h"
    23  #include "vmcs_api.h"
    24  #include "guest.h"
    25  #include "ept.h"
    26  #include "policy_manager.h"
    27  #include "memory_allocator.h"
    28  #include "memory_address_mapper_api.h"
    29  #include "gpm_api.h"
    30  #include "hw_utils.h"
    31  #include "mtrrs_abstraction.h"
    32  #include "libc.h"
    33  #include "host_memory_manager_api.h"
    34  #include "ept_hw_layer.h"
    35  #include "ipc.h"
    36  #include "guest_cpu_vmenter_event.h"
    37  #include "lock.h"
    38  #include "scheduler.h"
    39  #include "page_walker.h"
    40  #include "guest_cpu_internal.h"
    41  #include "unrestricted_guest.h"
    42  #include "fvs.h"
    43  #include "ve.h"
    44  #ifdef JLMDEBUG
    45  #include "jlmdebug.h"
    46  #endif
    47  
    48  EPT_STATE ept;
    49  HPA redirect_physical_addr = 0;
    50  
    51  #pragma warning( disable : 4214 ) // enables UINT64 bitfield
    52  #pragma warning (disable : 4100)  // Supress warnings about unreferenced formal parameter
    53  
    54  // macro #define's
    55  #define PDPTR_NXE_DISABLED_RESERVED_BITS_MASK        (UINT64) 0xffffff00000001e6
    56  #define PDPTR_NXE_ENABLED_RESERVED_BITS_MASK         (UINT64) 0x7fffff00000001e6
    57  #define PRESENT_BIT                                  (UINT64) 0x1
    58  
    59  // static functions
    60  static BOOLEAN ept_guest_cpu_initialize(GUEST_CPU_HANDLE gcpu);
    61  BOOLEAN ept_page_walk(UINT64 first_table, UINT64 addr, UINT32 gaw);
    62  void ept_set_remote_eptp(CPU_ID from, void* arg);
    63  
    64  
    65  #ifdef INCLUDE_UNUSED_CODE
    66  static
    67  BOOLEAN ept_check_pdpt_reserved_bits(UINT64 pdptr, UINT64 efer)
    68  {
    69      if((efer & EFER_NXE) == 0) {
    70          return (pdptr & PDPTR_NXE_DISABLED_RESERVED_BITS_MASK) == 0;
    71      }
    72      return (pdptr & PDPTR_NXE_ENABLED_RESERVED_BITS_MASK) == 0;
    73  }
    74  #endif
    75  
    76  void ept_set_pdtprs(GUEST_CPU_HANDLE gcpu, UINT64 cr4_value)
    77  {
    78      UINT64 pdpt[4];
    79      BOOLEAN status = TRUE;
    80      BOOLEAN pdptr_required = FALSE;
    81  
    82      if (cr4_value & CR4_PAE) { // PAE mode
    83          UINT64 efer = gcpu_get_msr_reg(gcpu, IA32_VMM_MSR_EFER);
    84          if (0 == (efer & EFER_LME)) { // 32-bit mode
    85              status = gcpu_get_32_bit_pdpt(gcpu, pdpt)
    86                    && pw_is_pdpt_in_32_bit_pae_mode_valid(gcpu, pdpt);
    87              if (TRUE == status) {
    88                  pdptr_required = TRUE;
    89                  ept_hw_set_pdtprs(gcpu, pdpt);
    90              }
    91          }
    92      }
    93      if (FALSE == pdptr_required) {
    94          vmm_zeromem(pdpt, sizeof(pdpt));
    95          ept_hw_set_pdtprs(gcpu, pdpt);
    96      }
    97  }
    98  
    99  void ept_acquire_lock(void)
   100  {
   101  #ifdef JLMDEBUG1
   102      bprint("(ept_acquire_lock %d)", ept.lock_count);
   103  #endif
   104      if (ept.lock.owner_cpu_id == hw_cpu_id()) {
   105          ept.lock_count++;
   106          return;
   107      }
   108      interruptible_lock_acquire(&ept.lock);
   109      ept.lock_count = 1;
   110  }
   111  
   112  void ept_release_lock(void)
   113  {
   114      ept.lock_count--;
   115      if (ept.lock_count == 0) {
   116          lock_release(&ept.lock);
   117      }
   118  }
   119  
   120  BOOLEAN ept_is_cpu_in_non_paged_mode(GUEST_ID guest_id)
   121  {
   122      EPT_GUEST_STATE *ept_guest = NULL;
   123      EPT_GUEST_CPU_STATE *ept_guest_cpu = NULL;
   124      UINT32 i = 0;
   125      GUEST_CPU_HANDLE gcpu = scheduler_get_current_gcpu_for_guest(guest_id);
   126  
   127      //for UG system, flat page table will never be used, so, this function should always return FALSE.
   128      if(is_unrestricted_guest_enabled(gcpu))
   129          return FALSE;
   130      ept_guest = ept_find_guest_state(guest_id);
   131      VMM_ASSERT(ept_guest);
   132      for (i = 0; i < ept.num_of_cpus; i++) {
   133          ept_guest_cpu = ept_guest->gcpu_state[i];
   134          VMM_ASSERT(ept_guest_cpu);
   135          if (ept_guest_cpu->is_initialized && (ept_guest_cpu->cr0 & CR0_PG) == 0) {
   136              // cannot change perms - another gcpu not paged and uses flat page tables
   137              return TRUE;
   138          }
   139      }
   140      return FALSE;
   141  }
   142  
   143  
   144  #ifdef INCLUDE_UNUSED_CODE
   145  void dbg_print_ept_violation(GUEST_CPU_HANDLE gcpu, EPTP eptp, EVENT_GCPU_EPT_VIOLATION_DATA *data)
   146  {
   147      EPT_PRINTERROR("\r\n****EPT violation:****\n");
   148      EPT_PRINTERROR("R=%d W=%d X=%d EptR=%d EptW=%d EptX=%d\n",
   149          data->qualification.EptViolation.R, data->qualification.EptViolation.W, data->qualification.EptViolation.X,
   150          data->qualification.EptViolation.EptR, data->qualification.EptViolation.EptW, data->qualification.EptViolation.EptX);
   151      EPT_PRINTERROR("GawViolation=%d GlaValidity=%d NMIunblocking=%d\n", 
   152          data->qualification.EptViolation.GawViolation, data->qualification.EptViolation.GlaValidity,data->qualification.EptViolation.NMIunblocking);
   153      EPT_PRINTERROR("GPA: %p\n", data->guest_physical_address);
   154      if(data->qualification.EptViolation.GlaValidity)
   155      {
   156          EPT_PRINTERROR("GVA: %p\n", data->guest_linear_address);
   157      }
   158      EPT_PRINTERROR("EPTP.ETMT: 0x%X EPTP.GAW: 0x%X EPTP.ASR: 0x%X\n", eptp.Bits.ETMT, eptp.Bits.GAW, eptp.Uint64 & ~PAGE_4KB_MASK);
   159      EPT_PRINTERROR("Is native %p\r\n", gcpu_is_native_execution(gcpu));
   160      ept_page_walk((UINT64) eptp.Uint64 & ~PAGE_4KB_MASK, data->guest_physical_address, ept_hw_get_guest_address_width_from_encoding((UINT32)eptp.Bits.GAW));
   161  }
   162  #endif
   163  
   164  // EPT vmexits
   165  /*
   166   *  Function name: ept_violation_vmexit
   167   *  Parameters: Function does not validate gcpu. Assumes valid.
   168   */
   169  BOOLEAN ept_violation_vmexit(GUEST_CPU_HANDLE gcpu, void *pv)
   170  {
   171      REPORT_EPT_VIOLATION_DATA violation_data;
   172      EVENT_GCPU_EPT_VIOLATION_DATA *data = (EVENT_GCPU_EPT_VIOLATION_DATA *) pv;
   173      const VIRTUAL_CPU_ID *vcpu_id=NULL;
   174      IA32_VMX_EXIT_QUALIFICATION ept_violation_qualification;
   175  
   176      vcpu_id= guest_vcpu(gcpu);
   177      VMM_ASSERT(vcpu_id);
   178      // Report EPT violation to the VIEW module
   179      violation_data.qualification = data->qualification.Uint64;
   180      violation_data.guest_linear_address = data->guest_linear_address;
   181      violation_data.guest_physical_address = data->guest_physical_address;
   182  
   183      ept_violation_qualification.Uint64 = violation_data.qualification;
   184      if( ept_violation_qualification.EptViolation.NMIunblocking ) {
   185          VMCS_OBJECT *vmcs = gcpu_get_vmcs(gcpu);
   186          IA32_VMX_VMCS_VM_EXIT_INFO_IDT_VECTORING    idt_vectoring_info;
   187  
   188          idt_vectoring_info.Uint32 = (UINT32)vmcs_read(vmcs,VMCS_EXIT_INFO_IDT_VECTORING);
   189  
   190          if(!idt_vectoring_info.Bits.Valid) {
   191              IA32_VMX_VMCS_GUEST_INTERRUPTIBILITY guest_interruptibility;
   192  
   193              guest_interruptibility.Uint32 = (UINT32) vmcs_read(vmcs, VMCS_GUEST_INTERRUPTIBILITY);
   194              guest_interruptibility.Bits.BlockNmi = 1;
   195              vmcs_write(vmcs,VMCS_GUEST_INTERRUPTIBILITY,(UINT64)guest_interruptibility.Uint32);
   196          }
   197      }
   198  
   199      if (!report_uvmm_event(UVMM_EVENT_EPT_VIOLATION, (VMM_IDENTIFICATION_DATA)gcpu, (const GUEST_VCPU*)vcpu_id, (void *)&violation_data)) {
   200          VMM_LOG(mask_anonymous, level_trace, "report_ept_violation failed\n");
   201      }
   202  
   203      data->processed = TRUE;
   204      return TRUE;
   205  }
   206  
   207  #pragma warning (disable:4189)
   208  #pragma warning (disable:4101)
   209  
   210  BOOLEAN ept_misconfiguration_vmexit(GUEST_CPU_HANDLE gcpu UNUSED, void *pv)
   211  {
   212      EPTP eptp;
   213      EVENT_GCPU_EPT_MISCONFIGURATION_DATA *data = (EVENT_GCPU_EPT_MISCONFIGURATION_DATA *) pv;
   214  
   215      EPT_PRINTERROR("\r\n****EPT Misconfiguration:****\n");
   216      EPT_PRINTERROR("GPA=%p\n", data->guest_physical_address);
   217  
   218      eptp.Uint64 = ept_get_eptp(gcpu);
   219      VMM_LOG(mask_anonymous, level_trace,"EPTP.ETMT: 0x%X EPTP.GAW: 0x%X EPTP.ASR: 0x%X\n", eptp.Bits.ETMT, eptp.Bits.GAW, eptp.Uint64 & ~PAGE_4KB_MASK);
   220      VMM_LOG(mask_anonymous, level_trace,"Is native %p\r\n", gcpu_is_native_execution(gcpu));
   221      ept_page_walk((UINT64) eptp.Uint64 & ~PAGE_4KB_MASK, data->guest_physical_address, ept_hw_get_guest_address_width_from_encoding((UINT32)eptp.Bits.GAW));
   222      VMM_DEADLOOP();
   223      data->processed = TRUE;
   224      return TRUE;
   225  }
   226  
   227  MAM_EPT_SUPER_PAGE_SUPPORT ept_get_mam_super_page_support(void)
   228  {
   229      const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints();
   230      IA32_VMX_EPT_VPID_CAP ept_cap = hw_constraints->ept_vpid_capabilities;
   231      MAM_EPT_SUPER_PAGE_SUPPORT sp_support = MAM_EPT_NO_SUPER_PAGE_SUPPORT;
   232  
   233  // Currently we support 2MB pages in implementation
   234      if(ept_cap.Bits.SP_21_bit) {
   235          sp_support |= MAM_EPT_SUPPORT_2MB_PAGE;
   236      }
   237  #if 0  // Support for different memory page sizes
   238      if(ept_cap.Bits.SP_30_bit) {
   239          sp_support |= MAM_EPT_SUPPORT_1GB_PAGE;
   240      }
   241      if(ept_cap.Bits.SP_39_bit)
   242      {
   243          sp_support |= MAM_EPT_SUPPORT_512_GB_PAGE;
   244      }
   245  #endif
   246      return sp_support;
   247  }
   248  
   249  void ept_get_current_ept(GUEST_CPU_HANDLE gcpu, UINT64 *ept_root_table_hpa, UINT32 *ept_gaw)
   250  {
   251      const VIRTUAL_CPU_ID* vcpu_id = NULL;
   252      EPT_GUEST_STATE *ept_guest = NULL;
   253      EPT_GUEST_CPU_STATE *ept_guest_cpu = NULL;
   254      VMM_ASSERT(gcpu);
   255      vcpu_id = guest_vcpu(gcpu);
   256      //paranoid check. If assertion fails, possible memory corruption.
   257      VMM_ASSERT(vcpu_id);
   258      ept_guest = ept_find_guest_state(vcpu_id->guest_id);
   259      VMM_ASSERT(ept_guest);
   260      ept_guest_cpu = ept_guest->gcpu_state[vcpu_id->guest_cpu_id];
   261      VMM_ASSERT(ept_guest_cpu);
   262      *ept_root_table_hpa = ept_guest_cpu->active_ept_root_table_hpa;
   263      *ept_gaw = ept_guest_cpu->active_ept_gaw;
   264  }
   265  
   266  void ept_set_current_ept(GUEST_CPU_HANDLE gcpu, UINT64 ept_root_table_hpa, UINT32 ept_gaw)
   267  {
   268      const VIRTUAL_CPU_ID* vcpu_id = NULL;
   269      EPT_GUEST_STATE *ept_guest = NULL;
   270      EPT_GUEST_CPU_STATE *ept_guest_cpu = NULL;
   271  
   272      VMM_ASSERT(gcpu);
   273      vcpu_id = guest_vcpu(gcpu);
   274      //paranoid check. If assertion fails, possible memory corruption.
   275      VMM_ASSERT(vcpu_id);
   276      ept_guest = ept_find_guest_state(vcpu_id->guest_id);
   277      VMM_ASSERT(ept_guest);
   278      ept_guest_cpu = ept_guest->gcpu_state[vcpu_id->guest_cpu_id];
   279      VMM_ASSERT(ept_guest_cpu);
   280      ept_guest_cpu->active_ept_root_table_hpa = ept_root_table_hpa;
   281      ept_guest_cpu->active_ept_gaw = ept_gaw;
   282  }
   283  
   284  void ept_get_default_ept(GUEST_HANDLE guest, UINT64 *ept_root_table_hpa, UINT32 *ept_gaw)
   285  {
   286      EPT_GUEST_STATE *ept_guest = NULL;
   287  
   288      VMM_ASSERT(guest);
   289  
   290      ept_guest = ept_find_guest_state(guest_get_id(guest));
   291      VMM_ASSERT(ept_guest);
   292  
   293      *ept_root_table_hpa = ept_guest->ept_root_table_hpa;
   294      *ept_gaw = ept_guest->gaw;
   295  }
   296  
   297  void ept_create_default_ept(GUEST_HANDLE guest, GPM_HANDLE gpm)
   298  {
   299      EPT_GUEST_STATE *ept_guest = NULL;
   300  
   301      VMM_ASSERT(guest);
   302      VMM_ASSERT(gpm);
   303      ept_guest = ept_find_guest_state(guest_get_id(guest));
   304      VMM_ASSERT(ept_guest);
   305  
   306      if (ept_guest->address_space != MAM_INVALID_HANDLE) {
   307          mam_destroy_mapping(ept_guest->address_space);
   308          ept_guest->address_space = MAM_INVALID_HANDLE;
   309      }
   310      ept_guest->gaw = ept_hw_get_guest_address_width(ept_get_guest_address_width(gpm));
   311      VMM_ASSERT(ept_guest->gaw != (UINT32) -1);
   312      ept_guest->address_space = ept_create_guest_address_space(gpm, TRUE);
   313      VMM_ASSERT(mam_convert_to_ept(ept_guest->address_space, ept_get_mam_super_page_support(),
   314                                    ept_get_mam_supported_gaw(ept_guest->gaw), ve_is_hw_supported(),
   315                                    &(ept_guest->ept_root_table_hpa)));
   316  }
   317  
   318  MAM_EPT_SUPPORTED_GAW ept_get_mam_supported_gaw(UINT32 gaw)
   319  {
   320      return (MAM_EPT_SUPPORTED_GAW)ept_hw_get_guest_address_width_encoding(gaw);
   321  }
   322  
   323  static
   324  BOOLEAN ept_begin_gpm_modification_before_cpus_stop( GUEST_CPU_HANDLE gcpu UNUSED,
   325                                                       void* pv UNUSED )
   326  {
   327      ept_acquire_lock();
   328      return TRUE;
   329  }
   330  
   331  static
   332  BOOLEAN ept_end_gpm_modification_before_cpus_resume( GUEST_CPU_HANDLE gcpu, void* pv )
   333  {
   334      GUEST_HANDLE guest = NULL;
   335      EPT_SET_EPTP_CMD set_eptp_cmd;
   336      EPT_INVEPT_CMD invept_cmd;
   337      IPC_DESTINATION ipc_dest;
   338      EVENT_GPM_MODIFICATION_DATA *gpm_modification_data = (EVENT_GPM_MODIFICATION_DATA *) pv;
   339      UINT64 default_ept_root_table_hpa;
   340      UINT32 default_ept_gaw;
   341      VMM_ASSERT(pv);
   342  
   343      guest = guest_handle(gpm_modification_data->guest_id);
   344      if (gpm_modification_data->operation == VMM_MEM_OP_UPDATE)
   345      {
   346          ept_get_default_ept(guest, &default_ept_root_table_hpa, &default_ept_gaw);
   347          invept_cmd.host_cpu_id = ANY_CPU_ID;
   348          invept_cmd.cmd = INVEPT_CONTEXT_WIDE;
   349          invept_cmd.eptp = ept_compute_eptp(guest, default_ept_root_table_hpa, default_ept_gaw);
   350  
   351          ept_invalidate_ept(ANY_CPU_ID, &invept_cmd);
   352  
   353          ipc_dest.addr_shorthand = IPI_DST_ALL_EXCLUDING_SELF;
   354          ipc_execute_handler_sync(ipc_dest, ept_invalidate_ept, (void *) &invept_cmd);
   355      } else if (gpm_modification_data->operation == VMM_MEM_OP_RECREATE) {
   356          // Recreate Default EPT
   357          ept_create_default_ept(guest, guest_get_startup_gpm(guest));
   358          ept_get_default_ept(guest, &default_ept_root_table_hpa, &default_ept_gaw);
   359  
   360          // Reset the Default EPT on current CPU
   361          ept_set_eptp(gcpu, default_ept_root_table_hpa, default_ept_gaw);
   362  
   363          invept_cmd.host_cpu_id = ANY_CPU_ID;
   364          invept_cmd.cmd = INVEPT_CONTEXT_WIDE;
   365          invept_cmd.eptp = ept_compute_eptp(guest, default_ept_root_table_hpa, default_ept_gaw);
   366          ept_invalidate_ept(ANY_CPU_ID, &invept_cmd);
   367  
   368          set_eptp_cmd.guest_id = gpm_modification_data->guest_id;
   369          set_eptp_cmd.ept_root_table_hpa = default_ept_root_table_hpa;
   370          set_eptp_cmd.gaw = default_ept_gaw;
   371          set_eptp_cmd.invept_cmd = &invept_cmd;
   372  
   373          ipc_dest.addr_shorthand = IPI_DST_ALL_EXCLUDING_SELF;
   374          ipc_execute_handler_sync(ipc_dest, ept_set_remote_eptp, (void *) &set_eptp_cmd);
   375      } else { // switch
   376          VMM_ASSERT(gpm_modification_data->operation == VMM_MEM_OP_SWITCH);
   377          //only switch ept if the active view is not the same as switchto handle
   378  //        if (ept_guest_get_active_view(gcpu) != gpm_modification_data->handle) {
   379  //            VMM_ASSERT(ept_set_eptp(gcpu, gpm_modification_data->handle));
   380  //        }
   381      }
   382  
   383      return TRUE;
   384  }
   385  
   386  
   387  static BOOLEAN ept_end_gpm_modification_after_cpus_resume(GUEST_CPU_HANDLE gcpu UNUSED, void* pv UNUSED)
   388  {
   389      ept_release_lock();
   390      return TRUE;
   391  }
   392  
   393  
   394  static BOOLEAN ept_cr0_update(GUEST_CPU_HANDLE gcpu, void* pv)
   395  {
   396      UINT64 value = ((EVENT_GCPU_GUEST_CR_WRITE_DATA*) pv)->new_guest_visible_value;
   397      BOOLEAN pg;
   398      BOOLEAN prev_pg = 0;
   399      const VIRTUAL_CPU_ID* vcpu_id = NULL;
   400      EPT_GUEST_STATE *ept_guest = NULL;
   401      EPT_GUEST_CPU_STATE *ept_guest_cpu = NULL;
   402      UINT64 cr4;
   403      IA32_EFER_S efer;
   404      VM_ENTRY_CONTROLS entry_ctrl_mask;
   405      VMCS_OBJECT* vmcs = gcpu_get_vmcs(gcpu);
   406  
   407  #ifdef JLMDEBUG
   408      bprint("ept_cr0_update, ");
   409  #endif
   410      ept_acquire_lock();
   411      vcpu_id = guest_vcpu(gcpu);
   412      VMM_ASSERT(vcpu_id);
   413      ept_guest = ept_find_guest_state(vcpu_id->guest_id);
   414      VMM_ASSERT(ept_guest);
   415      ept_guest_cpu = ept_guest->gcpu_state[vcpu_id->guest_cpu_id];
   416      prev_pg = (ept_guest_cpu->cr0 & CR0_PG) != 0;
   417      ept_guest_cpu->cr0 = value;
   418      pg = (ept_guest_cpu->cr0 & CR0_PG) != 0;
   419      if(is_unrestricted_guest_supported()) {
   420          /* IA Manual 3B: 27.9.4: IA32_EFER.LMA is always set by the processor
   421           * to equal IA32_EFER.LME & CR0.PG
   422           * Update LMA and IA32e bits based on LME and PG bit on systems with UG
   423           * Set VMCS.GUEST.EFER_MSR.LMA = (GUEST.CR0.PG & GUEST.EFER.LME)
   424           * Set VMCS.ENTRY_CONTROL.IA32e = (GUEST.CR0.PG & GUEST.EFER.LME)
   425           *
   426           * On systems w/o UG, LMA and IA32e are updated when EFER.LME is updated,
   427           * since PG is always 1
   428           */
   429          efer.Uint64 = gcpu_get_msr_reg(gcpu, IA32_VMM_MSR_EFER);
   430          efer.Bits.LMA = (pg & efer.Bits.LME);
   431          gcpu_set_msr_reg(gcpu, IA32_VMM_MSR_EFER, efer.Uint64);
   432          entry_ctrl_mask.Uint32 = 0;
   433          entry_ctrl_mask.Bits.Ia32eModeGuest = 1;
   434          vmcs_update(vmcs, VMCS_ENTER_CONTROL_VECTOR,
   435                  (efer.Bits.LMA) ? UINT64_ALL_ONES : 0,
   436                  (UINT64) entry_ctrl_mask.Uint32);
   437      }
   438      if(pg != prev_pg) {
   439          /* INVVPID for this guest */
   440          ept_hw_invvpid_single_context(1 + gcpu->vcpu.guest_id);
   441      }
   442      if((pg) && (pg != prev_pg)) {
   443          // Enable EPT on systems w/o UG, when PG is turned on
   444          if(!is_unrestricted_guest_supported() && !ept_is_ept_enabled(gcpu))
   445              ept_enable(gcpu);
   446          cr4 = gcpu_get_guest_visible_control_reg(gcpu, IA32_CTRL_CR4);
   447          ept_set_pdtprs(gcpu, cr4);
   448      }
   449      // Disable EPT on systems without UG, when PG is turned off
   450      if(!pg && !is_unrestricted_guest_supported() && ept_is_ept_enabled(gcpu))
   451          ept_disable(gcpu);
   452      ept_release_lock();
   453  #ifdef JLMDEBUG
   454      bprint("ept_cr0_update complete\n");
   455  #endif
   456      return TRUE;
   457  }
   458  
   459  static BOOLEAN ept_cr3_update( GUEST_CPU_HANDLE gcpu, void* pv UNUSED )
   460  {
   461      const VIRTUAL_CPU_ID* vcpu_id = NULL;
   462      EPT_GUEST_STATE *ept_guest = NULL;
   463      EPT_GUEST_CPU_STATE *ept_guest_cpu = NULL;
   464  
   465  #ifdef JLMDEBUG
   466      bprint("ept_cr3_update\n");
   467  #endif
   468      ept_acquire_lock();
   469      vcpu_id = guest_vcpu( gcpu );
   470      VMM_ASSERT(vcpu_id);
   471      ept_guest = ept_find_guest_state(vcpu_id->guest_id);
   472      VMM_ASSERT(ept_guest);
   473      ept_guest_cpu = ept_guest->gcpu_state[vcpu_id->guest_cpu_id];
   474      if ((ept_guest_cpu->cr0 & CR0_PG) &&    // if paging is enabled
   475          (ept_guest_cpu->cr4 & CR4_PAE)) {    // and PAE mode is active
   476          ept_set_pdtprs(gcpu, ept_guest_cpu->cr4);
   477      }
   478      // Flush TLB
   479      ept_hw_invvpid_single_context(1 + gcpu->vcpu.guest_id);
   480      ept_release_lock();
   481      //    EPT_LOG("EPT CPU#%d: %s\n", hw_cpu_id(), __FUNCTION__);
   482      return TRUE;
   483  }
   484  
   485  
   486  static BOOLEAN ept_cr4_update(GUEST_CPU_HANDLE gcpu, void* pv)
   487  {
   488      UINT64 new_cr4 = ((EVENT_GCPU_GUEST_CR_WRITE_DATA*) pv)->new_guest_visible_value;
   489      BOOLEAN pg;
   490      BOOLEAN pae = 0;
   491      BOOLEAN prev_pae = 0;
   492      const VIRTUAL_CPU_ID* vcpu_id = NULL;
   493      EPT_GUEST_STATE *ept_guest = NULL;
   494      EPT_GUEST_CPU_STATE *ept_guest_cpu = NULL;
   495      UINT64 cr4;
   496  
   497      (void)pg;
   498  #ifdef JLMDEBUG
   499      bprint("ept_cr4_update, \n");
   500  #endif
   501      ept_acquire_lock();
   502      vcpu_id = guest_vcpu(gcpu);
   503      VMM_ASSERT(vcpu_id);
   504      ept_guest = ept_find_guest_state(vcpu_id->guest_id);
   505      VMM_ASSERT(ept_guest);
   506      ept_guest_cpu = ept_guest->gcpu_state[vcpu_id->guest_cpu_id];
   507      prev_pae = (ept_guest_cpu->cr4 & CR4_PAE) != 0;
   508      ept_guest_cpu->cr4 = new_cr4;
   509      pg = (ept_guest_cpu->cr0 & CR0_PG) != 0;
   510      pae = (ept_guest_cpu->cr4 & CR4_PAE) != 0;
   511      if(ept_is_ept_enabled(gcpu) && pae != prev_pae) {
   512          cr4 = ept_guest_cpu->cr4;
   513          ept_set_pdtprs(gcpu, cr4);
   514      }
   515      // Flush TLB
   516      ept_hw_invvpid_single_context(1+gcpu->vcpu.guest_id);
   517      ept_release_lock();
   518  #ifdef JLMDEBUG
   519      bprint("ept_cr4_update complete\n");
   520  #endif
   521      return TRUE;
   522  }
   523  
   524  static BOOLEAN ept_emulator_enter(GUEST_CPU_HANDLE gcpu, void* pv UNUSED)
   525  {
   526      const VIRTUAL_CPU_ID* vcpu_id = NULL;
   527      EPT_GUEST_CPU_STATE *ept_guest_cpu = NULL;
   528      EPT_GUEST_STATE *ept_guest_state = NULL;
   529  
   530      vcpu_id = guest_vcpu( gcpu );
   531      VMM_ASSERT(vcpu_id);
   532      ept_guest_state = ept_find_guest_state(vcpu_id->guest_id);
   533      VMM_ASSERT(ept_guest_state);
   534      ept_guest_cpu = ept_guest_state->gcpu_state[vcpu_id->guest_cpu_id];
   535  
   536      ept_guest_cpu->cr0 = gcpu_get_guest_visible_control_reg(gcpu, IA32_CTRL_CR0);
   537      ept_guest_cpu->cr4 = gcpu_get_guest_visible_control_reg(gcpu, IA32_CTRL_CR4);
   538      ept_guest_cpu->ept_enabled_save = FALSE;
   539      if(ept_is_ept_enabled(gcpu)) {
   540          ept_guest_cpu->ept_enabled_save = TRUE;
   541          ept_disable(gcpu);
   542      }
   543      return TRUE;
   544  }
   545  
   546  static BOOLEAN ept_emulator_exit(GUEST_CPU_HANDLE gcpu, void* pv UNUSED)
   547  {
   548      const VIRTUAL_CPU_ID* vcpu_id = NULL;
   549      EPT_GUEST_STATE *ept_guest = NULL;
   550      EPT_GUEST_CPU_STATE *ept_guest_cpu = NULL;
   551      EVENT_GCPU_GUEST_CR_WRITE_DATA write_data = {0};
   552      UINT64 cr0, cr4;
   553  
   554  #ifdef JLMDEBUG
   555      bprint("ept_emulator exit\n");
   556  #endif
   557      ept_acquire_lock();
   558      vcpu_id = guest_vcpu(gcpu);
   559      VMM_ASSERT(vcpu_id);
   560      ept_guest = ept_find_guest_state(vcpu_id->guest_id);
   561      VMM_ASSERT(ept_guest);
   562      ept_guest_cpu = ept_guest->gcpu_state[vcpu_id->guest_cpu_id];
   563      if(ept_guest_cpu->ept_enabled_save) {
   564          ept_enable(gcpu);
   565      }
   566      cr0 = gcpu_get_guest_visible_control_reg(gcpu, IA32_CTRL_CR0);
   567      cr4 = gcpu_get_guest_visible_control_reg(gcpu, IA32_CTRL_CR4);
   568      // Do not assume that the CR0 must be changed when emulator exits.
   569      // comment out this line to fix the issue "ETP disabled after S3 in ThinkCentre desktop". 
   570      if(cr0 != ept_guest_cpu->cr0) {
   571          write_data.new_guest_visible_value = cr0;
   572          ept_cr0_update(gcpu, &write_data);
   573      }
   574      if(cr4 != ept_guest_cpu->cr4) {
   575          write_data.new_guest_visible_value = cr4;
   576          ept_cr4_update(gcpu, &write_data);
   577      }
   578      ept_release_lock();
   579      return TRUE;
   580  }
   581  
   582  static void ept_register_events(GUEST_CPU_HANDLE gcpu)
   583  {
   584      event_gcpu_register(EVENT_GCPU_AFTER_GUEST_CR0_WRITE, gcpu, ept_cr0_update);
   585      event_gcpu_register(EVENT_GCPU_AFTER_GUEST_CR3_WRITE, gcpu, ept_cr3_update);
   586      event_gcpu_register(EVENT_GCPU_AFTER_GUEST_CR4_WRITE, gcpu, ept_cr4_update);
   587      event_gcpu_register(EVENT_EMULATOR_AS_GUEST_ENTER, gcpu, ept_emulator_enter);
   588      event_gcpu_register(EVENT_EMULATOR_AS_GUEST_LEAVE, gcpu, ept_emulator_exit);
   589      event_gcpu_register(EVENT_GCPU_EPT_MISCONFIGURATION, gcpu, 
   590                          ept_misconfiguration_vmexit);
   591      event_gcpu_register(EVENT_GCPU_EPT_VIOLATION, gcpu, ept_violation_vmexit);
   592  }
   593  
   594  INLINE BOOLEAN ept_is_gcpu_active(IA32_VMX_VMCS_GUEST_SLEEP_STATE activity_state)
   595  {
   596      return ((Ia32VmxVmcsGuestSleepStateWaitForSipi != activity_state) &&
   597              ((Ia32VmxVmcsGuestSleepStateTripleFaultShutdown != activity_state)));
   598  }
   599  
   600  static void ept_gcpu_activity_state_change(GUEST_CPU_HANDLE gcpu, 
   601                      EVENT_GCPU_ACTIVITY_STATE_CHANGE_DATA* pv)
   602  {
   603      const VIRTUAL_CPU_ID* vcpu_id = NULL;
   604      EPT_GUEST_STATE *ept_guest = NULL;
   605  
   606  #ifdef JLMDEBUG
   607      bprint("ept_gcpu_activity_state_change\n");
   608  #endif
   609      VMM_ASSERT( gcpu );
   610      VMM_ASSERT( pv );
   611      EPT_LOG("ept CPU#%d: activity state change: new state %d\r\n", 
   612              hw_cpu_id(), pv->new_state);
   613      vcpu_id = guest_vcpu( gcpu );
   614      VMM_ASSERT(vcpu_id);
   615      ept_guest = ept_find_guest_state(vcpu_id->guest_id);
   616      VMM_ASSERT(ept_guest);
   617      if (ept_is_gcpu_active(pv->new_state)) {
   618          ept_guest_cpu_initialize(gcpu);
   619      }
   620  }
   621  
   622  UINT32 ept_get_guest_address_width(GPM_HANDLE gpm)
   623  {
   624      GPM_RANGES_ITERATOR gpm_iter = 0;
   625      GPA guest_range_addr = 0;
   626      UINT64 guest_range_size = 0;
   627      GPA guest_highest_range_addr = 0;
   628      UINT64 guest_highest_range_size = 0;
   629      UINT64 guest_address_limit = 0;
   630      UINT32 guest_address_limit_msb_index = 0;
   631  
   632      VMM_ASSERT(gpm);
   633      gpm_iter = gpm_get_ranges_iterator(gpm);
   634      while(GPM_INVALID_RANGES_ITERATOR != gpm_iter) { // for each range in GPM
   635          gpm_iter = gpm_get_range_details_from_iterator(gpm, gpm_iter,
   636                                                &guest_range_addr, &guest_range_size);
   637          if(guest_range_addr > guest_highest_range_addr) {
   638              guest_highest_range_addr = guest_range_addr;
   639              guest_highest_range_size = guest_range_size;
   640          }
   641      }
   642      guest_address_limit = guest_highest_range_addr + guest_highest_range_size;
   643      hw_scan_bit_backward64(&guest_address_limit_msb_index, guest_address_limit);
   644      return guest_address_limit_msb_index + 1;
   645  }
   646  
   647  MAM_HANDLE ept_create_guest_address_space(GPM_HANDLE gpm, BOOLEAN original_perms)
   648  {
   649      MAM_HANDLE address_space = NULL;
   650      MAM_ATTRIBUTES attributes = {0}, hpa_attrs;
   651      GPM_RANGES_ITERATOR gpm_iter = 0;
   652      GPA guest_range_addr = 0;
   653      UINT64 guest_range_size = 0;
   654      HPA host_range_addr = 0;
   655      BOOLEAN status = FALSE;
   656      UINT64 same_memory_type_range_size = 0, covered_guest_range_size = 0;
   657      VMM_PHYS_MEM_TYPE mem_type;
   658  
   659      VMM_ASSERT(gpm);
   660  
   661      // if (original_perms == FALSE) then permissions = RWX (default)
   662      attributes.ept_attr.readable = 1;
   663      attributes.ept_attr.writable = 1;
   664      attributes.ept_attr.executable = 1;
   665  
   666      address_space = mam_create_mapping(attributes);
   667      VMM_ASSERT(address_space);
   668      gpm_iter = gpm_get_ranges_iterator(gpm);
   669      while(GPM_INVALID_RANGES_ITERATOR != gpm_iter) { // for each range in GPM
   670          gpm_iter = gpm_get_range_details_from_iterator(gpm, gpm_iter, 
   671                                      &guest_range_addr, &guest_range_size);
   672          status = gpm_gpa_to_hpa(gpm, guest_range_addr, &host_range_addr, &hpa_attrs);
   673          if (original_perms) {
   674              attributes.ept_attr.readable = hpa_attrs.ept_attr.readable;
   675              attributes.ept_attr.writable = hpa_attrs.ept_attr.writable;
   676              attributes.ept_attr.executable = hpa_attrs.ept_attr.executable;
   677          }
   678          if(status) {
   679              covered_guest_range_size = 0;
   680              do { // add separate mapping per memory type
   681                  mem_type = mtrrs_abstraction_get_range_memory_type(
   682                                  host_range_addr + covered_guest_range_size, 
   683                                  &same_memory_type_range_size,
   684                                  guest_range_size - covered_guest_range_size);
   685                  if (VMM_PHYS_MEM_UNDEFINED == mem_type) {
   686                      EPT_LOG("  EPT %s:  Undefined mem-type for region %P. Use Uncached\n",
   687                      guest_range_addr + covered_guest_range_size);
   688                      mem_type = VMM_PHYS_MEM_UNCACHED;
   689                  }
   690                  attributes.ept_attr.emt = mem_type;
   691                  if(covered_guest_range_size + same_memory_type_range_size > guest_range_size) {
   692                      same_memory_type_range_size = guest_range_size - covered_guest_range_size;
   693                  }
   694                  mam_insert_range(address_space, guest_range_addr + covered_guest_range_size,
   695                                   host_range_addr + covered_guest_range_size, same_memory_type_range_size,
   696                                   attributes);
   697                  covered_guest_range_size += same_memory_type_range_size;
   698              } while(covered_guest_range_size < guest_range_size);
   699          }
   700      }
   701      return address_space;
   702  }
   703  
   704  void ept_invalidate_ept(CPU_ID from UNUSED, void* arg)
   705  {
   706      EPT_INVEPT_CMD *invept_cmd = (EPT_INVEPT_CMD *) arg;
   707  
   708  #ifdef JLMDEBUG
   709      bprint("ept_invalidate_ept\n");
   710  #endif
   711      if (invept_cmd->host_cpu_id != ANY_CPU_ID &&
   712          invept_cmd->host_cpu_id != hw_cpu_id()) {
   713          // not for this CPU -- ignore command
   714          return;
   715      }
   716      switch(invept_cmd->cmd) {
   717        case INVEPT_ALL_CONTEXTS: // Not being used currently
   718          ept_hw_invept_all_contexts();
   719          break;
   720        case INVEPT_CONTEXT_WIDE:
   721          ept_hw_invept_context(invept_cmd->eptp);
   722          break;
   723        case INVEPT_INDIVIDUAL_ADDRESS: // Not being used currently
   724          ept_hw_invept_individual_address(invept_cmd->eptp, invept_cmd->gpa);
   725          break;
   726        default:
   727          VMM_ASSERT(0);
   728      }
   729  }
   730  
   731  BOOLEAN ept_is_ept_supported(void)
   732  {
   733      return ept_hw_is_ept_supported();
   734  }
   735  
   736  BOOLEAN ept_is_ept_enabled(GUEST_CPU_HANDLE gcpu)
   737  {
   738      return ept_hw_is_ept_enabled(gcpu);
   739  }
   740  
   741  UINT64 ept_compute_eptp(GUEST_HANDLE guest, UINT64 ept_root_table_hpa, UINT32 gaw)
   742  {
   743      EPTP eptp;
   744  
   745      VMM_ASSERT(guest);
   746      VMM_ASSERT(ept_root_table_hpa);
   747      VMM_ASSERT(gaw);
   748      eptp.Uint64 = ept_root_table_hpa;
   749      eptp.Bits.GAW = ept_hw_get_guest_address_width_encoding(gaw);
   750      eptp.Bits.ETMT = ept_hw_get_ept_memory_type();
   751      eptp.Bits.Reserved = 0;
   752      return eptp.Uint64;
   753  }
   754  
   755  //NOTE: This function is expected to be always called with the lock acquired
   756  BOOLEAN ept_enable(GUEST_CPU_HANDLE gcpu)
   757  {
   758      UINT64 ept_root_table_hpa = 0;
   759      UINT32 gaw = 0;
   760  
   761      VMM_ASSERT(gcpu);
   762      ept_get_current_ept(gcpu, &ept_root_table_hpa, &gaw);
   763      if (!ept_set_eptp(gcpu, ept_root_table_hpa, gaw)) {
   764          EPT_PRINTERROR("EPT: failed to set eptp\r\n");
   765          goto failure;
   766      }
   767      if (!ept_hw_enable_ept(gcpu)) {
   768          EPT_PRINTERROR("EPT: failed to enable ept\r\n");
   769          goto failure;
   770      }
   771      return TRUE;
   772  
   773  failure:
   774      return FALSE;
   775  }
   776  
   777  //NOTE: This function is expected to be always called with the lock acquired
   778  void ept_disable(GUEST_CPU_HANDLE gcpu)
   779  {
   780      //ept_acquire_lock();
   781      ept_hw_disable_ept(gcpu);
   782      //ept_release_lock();
   783  }
   784  
   785  UINT64 ept_get_eptp(GUEST_CPU_HANDLE gcpu)
   786  {
   787      VMM_ASSERT(gcpu);
   788      return ept_hw_get_eptp(gcpu);
   789  }
   790  
   791  BOOLEAN ept_set_eptp(GUEST_CPU_HANDLE gcpu, UINT64 ept_root_table_hpa, UINT32 gaw)
   792  {
   793      VMM_ASSERT(gcpu);
   794      return ept_hw_set_eptp(gcpu, ept_root_table_hpa, gaw);
   795  }
   796  
   797  void ept_set_remote_eptp(CPU_ID from, void* arg)
   798  {
   799      EPT_SET_EPTP_CMD *set_eptp_cmd = arg;
   800      GUEST_CPU_HANDLE gcpu;
   801      (void)from;
   802      gcpu = scheduler_get_current_gcpu_for_guest(set_eptp_cmd->guest_id);
   803      if(gcpu == NULL || !ept_is_ept_enabled(gcpu)) {
   804          return;
   805      }
   806      ept_set_eptp(gcpu, set_eptp_cmd->ept_root_table_hpa, set_eptp_cmd->gaw);
   807      ept_invalidate_ept(ANY_CPU_ID, set_eptp_cmd->invept_cmd);
   808  }
   809  
   810  EPT_GUEST_STATE *ept_find_guest_state(GUEST_ID guest_id)
   811  {
   812      EPT_GUEST_STATE *ept_guest_state = NULL;
   813      LIST_ELEMENT *iter = NULL;
   814      BOOLEAN found = FALSE;
   815  
   816      LIST_FOR_EACH(ept.guest_state, iter) {
   817          ept_guest_state = LIST_ENTRY(iter, EPT_GUEST_STATE, list);
   818          if(ept_guest_state->guest_id == guest_id) {
   819              found = TRUE;
   820              break;
   821          }
   822      }
   823      if(found) {
   824          return ept_guest_state;
   825      }
   826      return NULL;
   827  }
   828  
   829  static BOOLEAN ept_guest_initialize(GUEST_HANDLE guest)
   830  {
   831      UINT32 i;
   832      EPT_GUEST_STATE *ept_guest = NULL;
   833  
   834  #ifdef JLMDEBUG
   835      bprint("ept_guest_initialize\n");
   836  #endif
   837      ept_guest = (EPT_GUEST_STATE *) vmm_malloc(sizeof(EPT_GUEST_STATE));
   838      VMM_ASSERT(ept_guest);
   839      ept_guest->guest_id = guest_get_id(guest);
   840      list_add(ept.guest_state, ept_guest->list);
   841      ept_guest->gcpu_state = (EPT_GUEST_CPU_STATE **) vmm_malloc(ept.num_of_cpus * sizeof(EPT_GUEST_CPU_STATE*));
   842      VMM_ASSERT(ept_guest->gcpu_state);
   843      for (i = 0; i < ept.num_of_cpus; i++) {
   844          ept_guest->gcpu_state[i] = (EPT_GUEST_CPU_STATE *) vmm_malloc(sizeof(EPT_GUEST_CPU_STATE));
   845          VMM_ASSERT(ept_guest->gcpu_state[i]);
   846      }
   847      event_global_register( EVENT_BEGIN_GPM_MODIFICATION_BEFORE_CPUS_STOPPED,
   848                              ept_begin_gpm_modification_before_cpus_stop);
   849      event_global_register( EVENT_END_GPM_MODIFICATION_BEFORE_CPUS_RESUMED,
   850                              ept_end_gpm_modification_before_cpus_resume);
   851      event_global_register( EVENT_END_GPM_MODIFICATION_AFTER_CPUS_RESUMED,
   852                              ept_end_gpm_modification_after_cpus_resume);
   853  
   854      return TRUE;
   855  }
   856  
   857  static BOOLEAN ept_guest_cpu_initialize(GUEST_CPU_HANDLE gcpu)
   858  {
   859      const VIRTUAL_CPU_ID* vcpu_id = NULL;
   860      EPT_GUEST_CPU_STATE *ept_guest_cpu = NULL;
   861      EPT_GUEST_STATE *ept_guest_state = NULL;
   862  
   863      EPT_LOG("EPT: CPU#%d ept_guest_cpu_initialize\r\n", hw_cpu_id());
   864      vcpu_id = guest_vcpu( gcpu );
   865      VMM_ASSERT(vcpu_id);
   866      ept_guest_state = ept_find_guest_state(vcpu_id->guest_id);
   867      VMM_ASSERT(ept_guest_state);
   868      ept_guest_cpu = ept_guest_state->gcpu_state[vcpu_id->guest_cpu_id];
   869      //During S3 resume, these values need to be updated
   870      ept_guest_cpu->cr0 = gcpu_get_guest_visible_control_reg(gcpu, IA32_CTRL_CR0);
   871      ept_guest_cpu->cr4 = gcpu_get_guest_visible_control_reg(gcpu, IA32_CTRL_CR4);
   872      if (!ept_guest_cpu->is_initialized) {
   873          ept_register_events(gcpu);
   874          ept_guest_cpu->is_initialized = TRUE;
   875      }
   876      return TRUE;
   877  }
   878  
   879  static void ept_fill_vmexit_request(VMEXIT_CONTROL *vmexit_request)
   880  {
   881  #ifdef JLMDEBUG
   882      bprint("ept_fill_vmexit_request\n");
   883  #endif
   884      vmm_zeromem(vmexit_request, sizeof(VMEXIT_CONTROL));
   885      if(!is_unrestricted_guest_supported()) {
   886          vmexit_request->cr0.bit_request = CR0_PG;
   887          vmexit_request->cr0.bit_mask    = CR0_PG;
   888          vmexit_request->cr4.bit_request = CR4_PAE;
   889          vmexit_request->cr4.bit_mask    = CR4_PAE;
   890      }
   891  }
   892  
   893  static BOOLEAN ept_add_gcpu(GUEST_CPU_HANDLE gcpu, void *pv UNUSED)
   894  {
   895      EVENT_GCPU_ACTIVITY_STATE_CHANGE_DATA activity_state;
   896      VMEXIT_CONTROL vmexit_request;
   897  
   898  #ifdef JLMDEBUG
   899      bprint("ept_add_gcpu\n");
   900  #endif
   901      vmm_zeromem(&activity_state, sizeof(activity_state));
   902      vmm_zeromem(&vmexit_request, sizeof(vmexit_request));
   903      event_gcpu_register(EVENT_GCPU_ACTIVITY_STATE_CHANGE, gcpu, 
   904                          (event_callback) ept_gcpu_activity_state_change);
   905      activity_state.new_state = gcpu_get_activity_state(gcpu);
   906      if(ept_is_gcpu_active(activity_state.new_state))
   907      {// if gcpu already active, fire manually
   908          ept_gcpu_activity_state_change(gcpu, &activity_state);
   909      }
   910      // setup control only if gcpu is added on this host CPU
   911      if(hw_cpu_id() == scheduler_get_host_cpu_id(gcpu))
   912      {
   913          ept_fill_vmexit_request(&vmexit_request);
   914          gcpu_control_setup(gcpu, &vmexit_request);
   915      }
   916      return TRUE;
   917  }
   918  
   919  static void ept_add_static_guest(GUEST_HANDLE guest)
   920  {
   921      GUEST_CPU_HANDLE gcpu;
   922      GUEST_GCPU_ECONTEXT gcpu_context;
   923      VMEXIT_CONTROL vmexit_request;
   924      UINT64 ept_root_table_hpa = 0;
   925      UINT32 ept_gaw = 0;
   926  
   927  #ifdef JLMDEBUG
   928      bprint("ept_add_static_guest\n");
   929  #endif
   930      EPT_LOG("ept CPU#%d: activate ept\r\n", hw_cpu_id());
   931      ept_fill_vmexit_request(&vmexit_request);
   932      // request needed vmexits
   933      guest_control_setup(guest, &vmexit_request);
   934      ept_guest_initialize(guest);
   935      // Initialize default EPT
   936      ept_create_default_ept(guest, guest_get_startup_gpm(guest));
   937      // Get default EPT
   938      ept_get_default_ept(guest, &ept_root_table_hpa, &ept_gaw);
   939      for(gcpu = guest_gcpu_first(guest, &gcpu_context); gcpu; gcpu = guest_gcpu_next(&gcpu_context)) {
   940          ept_add_gcpu(gcpu, NULL);
   941          // Set EPT pointer (of each GCPU) to default EPT
   942          ept_set_current_ept(gcpu, ept_root_table_hpa, ept_gaw);
   943      }
   944  }
   945  
   946  static BOOLEAN ept_add_dynamic_guest(GUEST_CPU_HANDLE gcpu UNUSED, void *pv)
   947  {
   948      EVENT_GUEST_CREATE_DATA *guest_create_event_data = (EVENT_GUEST_CREATE_DATA *) pv;
   949      GUEST_HANDLE            guest = guest_handle(guest_create_event_data->guest_id);
   950      VMM_PAGING_POLICY       pg_policy;
   951      POL_RETVAL              policy_status;
   952  
   953  #ifdef JLMDEBUG
   954      bprint("ept_add_dynamic_guest\n");
   955  #endif
   956      policy_status = get_paging_policy(guest_policy(guest), &pg_policy);
   957      VMM_ASSERT(POL_RETVAL_SUCCESS == policy_status);
   958      if (POL_PG_EPT == pg_policy) {
   959          ept_guest_initialize(guest_handle(guest_create_event_data->guest_id));
   960      }
   961      return TRUE;
   962  }
   963  
   964  void init_ept_addon(UINT32 num_of_cpus)
   965  {
   966      GUEST_HANDLE   guest;
   967      GUEST_ECONTEXT guest_ctx;
   968  
   969      if (!global_policy_uses_ept()) {
   970          return;
   971      }
   972      vmm_zeromem(&ept, sizeof(ept));
   973      ept.num_of_cpus = num_of_cpus;
   974      EPT_LOG("init_ept_addon: Initialize EPT num_cpus %d\n", num_of_cpus);
   975      list_init(ept.guest_state);
   976      lock_initialize(&ept.lock);
   977      event_global_register(EVENT_GUEST_CREATE, ept_add_dynamic_guest);
   978      event_global_register(EVENT_GCPU_ADD, (event_callback) ept_add_gcpu);
   979      for(guest = guest_first(&guest_ctx); guest; guest = guest_next(&guest_ctx)) {
   980          ept_add_static_guest(guest);
   981      }
   982  }
   983  
   984  BOOLEAN ept_page_walk(UINT64 first_table, UINT64 addr, UINT32 gaw)
   985  {
   986      UINT64 *table = (UINT64 *) first_table;
   987      UINT64 *entry = NULL;
   988  
   989      EPT_LOG("EPT page walk addr %p\r\n", addr);
   990      if(gaw > 39) {
   991          entry = &table[(addr & 0xFF8000000000) >> 39];
   992          EPT_LOG("Level 4: table %p entry %p\r\n", table, *entry);
   993          table = (UINT64 *) ((*entry) & ~0xfff);
   994          if(((*entry) & 0x1) == 0) {
   995              EPT_LOG("Entry not present\r\n");
   996              return FALSE;
   997          }
   998      }
   999      entry = &table[(addr & 0x7fc0000000) >> 30];
  1000      EPT_LOG("Level 3: table %p entry %p\r\n", table, *entry);
  1001      if(((*entry) & 0x1) == 0) {
  1002          EPT_LOG("Entry not present\r\n");
  1003          return FALSE;
  1004      }
  1005      table = (UINT64 *) ((*entry) & ~0xfff);
  1006      entry = &table[(addr & 0x3FE00000) >> 21];
  1007      EPT_LOG("Level 2: table %p entry %p\r\n", table, *entry);
  1008      table = (UINT64 *) ((*entry) & ~0xfff);
  1009      if(((*entry) & 0x1) == 0) {
  1010          EPT_LOG("Entry not present\r\n");
  1011          return FALSE;
  1012      }
  1013      entry = &table[(addr & 0x1ff000) >> 12];
  1014      EPT_LOG("Level 1: table %p entry %p\r\n", table, *entry);
  1015      return TRUE;
  1016  }
  1017  
  1018  #ifdef DEBUG
  1019  void ept_print(IN GUEST_HANDLE guest, IN MAM_HANDLE address_space)
  1020  {
  1021      MAM_MEMORY_RANGES_ITERATOR iter;
  1022      MAM_MAPPING_RESULT res;
  1023  
  1024      iter = mam_get_memory_ranges_iterator(address_space);
  1025  
  1026      while (iter != MAM_INVALID_MEMORY_RANGES_ITERATOR) {
  1027          GPA curr_gpa;
  1028          UINT64 curr_size;
  1029          HPA curr_hpa;
  1030          MAM_ATTRIBUTES attrs;
  1031          iter = mam_get_range_details_from_iterator(address_space, iter,
  1032                                                     (UINT64*)&curr_gpa, &curr_size);
  1033          VMM_ASSERT(curr_size != 0);
  1034  
  1035          res = mam_get_mapping(address_space, curr_gpa, &curr_hpa, &attrs);
  1036          if (res == MAM_MAPPING_SUCCESSFUL) {
  1037              EPT_LOG("EPT guest#%d: GPA %p -> HPA %p\r\n", curr_gpa, curr_hpa);
  1038          }
  1039      }
  1040  }
  1041  #endif
  1042  
  1043  #ifdef INCLUDE_UNUSED_CODE
  1044  static
  1045  void ept_reset_initiate(GUEST_HANDLE guest)
  1046  {
  1047      GUEST_CPU_HANDLE gcpu;
  1048  
  1049      VMM_ASSERT(guest);
  1050      gcpu = scheduler_get_current_gcpu_for_guest(guest_get_id(guest));
  1051  
  1052      if(gcpu != NULL && ept_is_ept_enabled(gcpu)) {
  1053          ept_disable(gcpu);
  1054          ept_enable(gcpu);
  1055      }
  1056  }
  1057  
  1058  void ept_single_cpu_update(GUEST_HANDLE guest, TMSL_MEM_VIEW_HANDLE handle)
  1059  {
  1060      EPT_INVEPT_CMD invept_cmd;
  1061  
  1062  #ifdef JLMDEBUG
  1063      bprint("ept_single_cpu_update\n");
  1064  #endif
  1065      invept_cmd.host_cpu_id = ANY_CPU_ID;
  1066      invept_cmd.cmd = INVEPT_CONTEXT_WIDE;
  1067      invept_cmd.eptp = ept_compute_eptp(guest, handle);
  1068      ept_invalidate_ept(ANY_CPU_ID, &invept_cmd);
  1069  }
  1070  
  1071  static void ept_reset_local(CPU_ID from UNUSED, void* arg)
  1072  {
  1073      GUEST_HANDLE guest = (GUEST_HANDLE) arg;
  1074      GUEST_CPU_HANDLE gcpu;
  1075  
  1076      VMM_ASSERT(guest);
  1077      gcpu = scheduler_get_current_gcpu_for_guest(guest_get_id(guest));
  1078      if(gcpu != NULL && ept_is_ept_enabled(gcpu)) {
  1079          ept_disable(gcpu);
  1080          ept_enable(gcpu);
  1081      }
  1082  }
  1083  
  1084  #endif
  1085  
  1086  #ifdef INCLUDE_UNUSED_CODE
  1087  static void ept_exec_invept(CPU_ID dest, INVEPT_CMD_TYPE cmd,
  1088                       UINT64 eptp, UINT64 gpa)
  1089  {
  1090      IPC_DESTINATION ipc_dest;
  1091      EPT_INVEPT_CMD invept_cmd;
  1092  
  1093      vmm_zeromem(&ipc_dest, sizeof(ipc_dest));
  1094      vmm_zeromem(&invept_cmd, sizeof(invept_cmd));
  1095  
  1096      invept_cmd.host_cpu_id = dest;
  1097      invept_cmd.cmd = cmd;
  1098      invept_cmd.eptp = eptp;
  1099      invept_cmd.gpa = gpa;
  1100      ipc_dest.addr_shorthand = LOCAL_APIC_BROADCAST_MODE_ALL_EXCLUDING_SELF;
  1101      ipc_execute_handler_sync(ipc_dest, ept_invalidate_ept, (void *) &invept_cmd);
  1102  }
  1103  
  1104  void ept_invalidate_guest_ept_on_all_cpus(IN GUEST_HANDLE guest)
  1105  {
  1106      UINT64 eptp = 0;
  1107  
  1108      ept_acquire_lock();
  1109      eptp = ept_compute_eptp(guest);
  1110      ept_exec_invept(ANY_CPU_ID, INVEPT_CONTEXT_WIDE, eptp, 0);
  1111      EPT_LOG("Invalidate eptp %p on CPU#%d\r\n", eptp, hw_cpu_id());
  1112      ept_hw_invept_context(eptp);
  1113      ept_release_lock();
  1114  }
  1115  
  1116  BOOLEAN ept_invept_all_contexts(IN CPU_ID host_cpu_id)
  1117  {
  1118      BOOLEAN res = FALSE;
  1119  
  1120      ept_acquire_lock();
  1121      if(host_cpu_id == hw_cpu_id()) {
  1122          res = ept_hw_invept_all_contexts();
  1123      }
  1124      else {
  1125          ept_exec_invept(ANY_CPU_ID, INVEPT_ALL_CONTEXTS, 0, 0);
  1126      }
  1127      ept_release_lock();
  1128      return res;
  1129  }
  1130  
  1131  BOOLEAN ept_invept_context(IN CPU_ID host_cpu_id, UINT64 eptp)
  1132  {
  1133      BOOLEAN res = FALSE;
  1134  
  1135      ept_acquire_lock();
  1136      if(host_cpu_id == hw_cpu_id()) {
  1137          res = ept_hw_invept_context(eptp);
  1138      }
  1139      else {
  1140          ept_exec_invept(ANY_CPU_ID, INVEPT_CONTEXT_WIDE, eptp, 0);
  1141      }
  1142      ept_release_lock();
  1143      return res;
  1144  }
  1145  
  1146  BOOLEAN ept_invept_individual_address(IN CPU_ID host_cpu_id, UINT64 eptp, ADDRESS gpa)
  1147  {
  1148      BOOLEAN res = FALSE;
  1149  
  1150      ept_acquire_lock();
  1151      if(host_cpu_id == hw_cpu_id()) {
  1152          res = ept_hw_invept_individual_address(eptp, gpa);
  1153      }
  1154      else {
  1155          ept_exec_invept(ANY_CPU_ID, INVEPT_INDIVIDUAL_ADDRESS, eptp, gpa);
  1156      }
  1157      ept_release_lock();
  1158      return res;
  1159  }
  1160  #endif
  1161  
  1162  #ifdef INCLUDE_UNUSED_CODE
  1163  BOOLEAN ept_add_mapping(IN GUEST_HANDLE guest, IN GPA src, IN HPA dest, IN UINT64 size,
  1164                          IN BOOLEAN readable, IN BOOLEAN writable, IN BOOLEAN executable)
  1165  {
  1166      EPT_GUEST_STATE *ept_guest = NULL;
  1167      UINT64 eptp = 0;
  1168      GUEST_ID guest_id = guest_get_id(guest);
  1169      MAM_ATTRIBUTES attrs;
  1170      BOOLEAN status = FALSE;
  1171      EPT_INVEPT_CMD invept_cmd;
  1172  
  1173      VMM_ASSERT( guest );
  1174      vmm_zeromem(&invept_cmd, sizeof(invept_cmd));
  1175      ept_guest = ept_find_guest_state(guest_id);
  1176      VMM_ASSERT(ept_guest);
  1177      ept_acquire_lock();
  1178      stop_all_cpus();
  1179      attrs.uint32 = 0;
  1180      attrs.ept_attr.readable = readable;
  1181      attrs.ept_attr.writable = writable;
  1182      attrs.ept_attr.executable = executable;
  1183      status = mam_insert_range(ept_guest->address_space, src, dest, size, attrs);
  1184      eptp = ept_compute_eptp(guest);
  1185      invept_cmd.host_cpu_id = ANY_CPU_ID;
  1186      invept_cmd.cmd = INVEPT_CONTEXT_WIDE;
  1187      invept_cmd.eptp = eptp;
  1188      start_all_cpus(ept_invalidate_ept, (void *) &invept_cmd);
  1189      ept_hw_invept_context(eptp);
  1190      ept_release_lock();
  1191      return status;
  1192  }
  1193  
  1194  BOOLEAN ept_remove_mapping(IN GUEST_HANDLE guest, IN GPA src,
  1195                             IN UINT64 size, IN MAM_MAPPING_RESULT reason)
  1196  {
  1197      EPT_GUEST_STATE *ept_guest = NULL;
  1198      UINT64 eptp = 0;
  1199      GUEST_ID guest_id = guest_get_id(guest);
  1200      BOOLEAN status = FALSE;
  1201      EPT_INVEPT_CMD invept_cmd;
  1202  
  1203      VMM_ASSERT( guest );
  1204      ept_guest = ept_find_guest_state(guest_id);
  1205      VMM_ASSERT(ept_guest);
  1206      ept_acquire_lock();
  1207      stop_all_cpus();
  1208      status = mam_insert_not_existing_range(ept_guest->address_space, src, size, reason);
  1209      eptp = ept_compute_eptp(guest);
  1210      vmm_zeromem(&invept_cmd, sizeof(invept_cmd));
  1211      invept_cmd.host_cpu_id = ANY_CPU_ID;
  1212      invept_cmd.cmd = INVEPT_CONTEXT_WIDE;
  1213      invept_cmd.eptp = eptp;
  1214      start_all_cpus(ept_invalidate_ept, (void *) &invept_cmd);
  1215      ept_hw_invept_context(eptp);
  1216      ept_release_lock();
  1217      return status;
  1218  }
  1219  
  1220  MAM_MAPPING_RESULT ept_get_mapping(IN GUEST_HANDLE guest, IN GPA src,
  1221                                     OUT HPA *dest, OUT MAM_ATTRIBUTES *attrs)
  1222  {
  1223      EPT_GUEST_STATE *ept_guest = NULL;
  1224      GUEST_ID guest_id = guest_get_id(guest);
  1225      MAM_MAPPING_RESULT res;
  1226  
  1227      ept_guest = ept_find_guest_state(guest_id);
  1228      VMM_ASSERT(ept_guest);
  1229      ept_acquire_lock();
  1230      res = mam_get_mapping(ept_guest, src, dest, attrs);
  1231      ept_release_lock();
  1232      return res;
  1233  }
  1234  
  1235  static BOOLEAN ept_allow_uvmm_heap_access(GUEST_CPU_HANDLE gcpu)
  1236  {
  1237      GUEST_HANDLE guest = NULL;
  1238      HVA heap_base_hva = 0;
  1239      HPA heap_base_hpa = 0;
  1240      UINT32 heap_size = 0;
  1241      VMM_PHYS_MEM_TYPE mem_type;
  1242      BOOLEAN status = FALSE;
  1243      UINT64 same_memory_type_range_size = 0, covered_heap_range_size = 0;
  1244      MAM_ATTRIBUTES attributes = {0};
  1245      EPT_GUEST_STATE *ept_guest = NULL;
  1246  
  1247      guest = gcpu_guest_handle(gcpu);
  1248      ept_guest = ept_find_guest_state(guest_get_id(guest));
  1249      VMM_ASSERT(ept_guest);
  1250      vmm_heap_get_details(&heap_base_hva, &heap_size);
  1251      status = hmm_hva_to_hpa(heap_base_hva, &heap_base_hpa);
  1252      VMM_ASSERT(status);
  1253      attributes.ept_attr.readable = 1;
  1254      attributes.ept_attr.writable = 1;
  1255      while(covered_heap_range_size < heap_size) {
  1256          mem_type = mtrrs_abstraction_get_range_memory_type(
  1257                                 heap_base_hpa + covered_heap_range_size,
  1258                                 &same_memory_type_range_size);
  1259          attributes.ept_attr.emt = mem_type;
  1260          EPT_LOG("  EPT add uvmm heap range: gpa %p -> hpa %p; size %p; mem_type %d\r\n",
  1261              heap_base_hpa, heap_base_hpa, same_memory_type_range_size, mem_type);
  1262  
  1263          if(covered_heap_range_size + same_memory_type_range_size > heap_size) { // normalize
  1264              same_memory_type_range_size = heap_size - covered_heap_range_size;
  1265          }
  1266          ept_add_mapping(guest, heap_base_hpa + covered_heap_range_size,
  1267              heap_base_hpa + covered_heap_range_size, same_memory_type_range_size,
  1268              TRUE, // readable
  1269              TRUE, // writable
  1270              FALSE // executable
  1271              );
  1272          covered_heap_range_size += same_memory_type_range_size;
  1273          if(covered_heap_range_size > heap_size) { // normalize
  1274              covered_heap_range_size = heap_size;
  1275          }
  1276      }
  1277      return TRUE;
  1278  }
  1279  
  1280  static BOOLEAN ept_deny_uvmm_heap_access(GUEST_CPU_HANDLE gcpu)
  1281  {
  1282      GUEST_HANDLE guest = NULL;
  1283      HVA heap_base_hva = 0;
  1284      HPA heap_base_hpa = 0;
  1285      UINT32 heap_size = 0;
  1286      BOOLEAN status = FALSE;
  1287      UINT32 i = 0;
  1288      EPT_GUEST_STATE *ept_guest = NULL;
  1289      EPT_GUEST_CPU_STATE *ept_guest_cpu = NULL;
  1290      const VIRTUAL_CPU_ID* vcpu_id = NULL;
  1291  
  1292      VMM_ASSERT( gcpu );
  1293      vcpu_id = guest_vcpu( gcpu );
  1294      ept_guest = ept_find_guest_state(vcpu_id->guest_id);
  1295      VMM_ASSERT(ept_guest);
  1296  
  1297      for(i = 0; i < ept.num_of_cpus; i++) {
  1298          ept_guest_cpu = ept_guest->gcpu_state[i];
  1299          if(ept_guest_cpu->is_initialized
  1300             && (ept_guest_cpu->cr0 & CR0_PG) == 0) { // cannot deny access - another gcpu not paged and uses flat page tables
  1301              return FALSE;
  1302          }
  1303      }
  1304      guest = gcpu_guest_handle(gcpu);
  1305      vmm_heap_get_details(&heap_base_hva, &heap_size);
  1306      status = hmm_hva_to_hpa(heap_base_hva, &heap_base_hpa);
  1307      VMM_ASSERT(status);
  1308      EPT_LOG("  EPT remove uvmm heap range: gpa %p -> hpa %p; size %p;\r\n",
  1309          heap_base_hpa, heap_base_hpa, heap_size);
  1310      ept_remove_mapping(guest, heap_base_hpa, heap_size, 0);
  1311      return TRUE;
  1312  }
  1313  #endif