text: /* 
   * 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) 2011, Jack Lange <jarusl@cs.northwestern.edu> 
   * Copyright (c) 2011, 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_lowlevel.h>
  #include <palacios/vmx_hw_info.h>
  #include <palacios/vmm_msr.h>
  
  // Intel VMX Feature MSRs
  
  
  
  static int 
  get_ex_ctrl_caps(struct vmx_hw_info    * hw_info, 
  		 struct vmx_ctrl_field * field, 
  		 uint32_t                old_msr, 
  		 uint32_t                true_msr) 
  {
      uint32_t old_0  = 0;  /* Bit is 1 => MB1 */
      uint32_t old_1  = 0;  /* Bit is 0 => MBZ */
      uint32_t true_0 = 0;  /* Bit is 1 => MB1 */
      uint32_t true_1 = 0;  /* Bit is 0 => MBZ */
  
      v3_get_msr(old_msr, &old_1, &old_0);
      field->def_val = old_0;
  
      if (hw_info->basic_info.def1_maybe_0) {
  	v3_get_msr(true_msr, &true_1, &true_0);
      } else {
  	true_0 = old_0;
  	true_1 = old_1;
      }
      
      field->req_val  = true_0;
      field->req_mask = ~(true_1 ^ true_0);
  
      return 0;
  }
  
  
  static int 
  get_ctrl_caps(struct vmx_ctrl_field * field, 
  	      uint32_t                msr)
  {
      uint32_t mbz = 0; /* (32-64) Bit is 0 => MBZ */
      uint32_t mb1 = 0; /* (0-31) Bit is 1 => MB1 */
      
      v3_get_msr(msr, &mbz, &mb1);
      
      field->def_val  = mb1;
      field->req_val  = mb1;
      field->req_mask = ~(mbz ^ mb1);
  
      return 0;
  }
  
  
  
  static int 
  get_cr_fields(struct vmx_cr_field * field, 
  	      uint32_t              fixed_1_msr, 
  	      uint32_t              fixed_0_msr) 
  {
      struct v3_msr mbz; /* Bit is 0 => MBZ */
      struct v3_msr mb1; /* Bit is 0 => MBZ */
  
      v3_get_msr(fixed_1_msr, &(mbz.hi), &(mbz.lo));
      v3_get_msr(fixed_0_msr, &(mb1.hi), &(mb1.lo));
       
      field->def_val  = mb1.value;
      field->req_val  = mb1.value;
      field->req_mask = ~(mbz.value ^ mb1.value);
  
      return 0;
  }
  
  
  
  
  int 
  v3_init_vmx_hw(struct vmx_hw_info * hw_info) 
  {
      //  extern v3_cpu_arch_t v3_cpu_types[];
  
      memset(hw_info, 0, sizeof(struct vmx_hw_info));
  
      v3_get_msr(VMX_BASIC_MSR, &(hw_info->basic_info.hi), &(hw_info->basic_info.lo));
      v3_get_msr(VMX_MISC_MSR,  &(hw_info->misc_info.hi),  &(hw_info->misc_info.lo));
  
      PrintError("BASIC_MSR: Lo: %x, Hi: %x\n", hw_info->basic_info.lo, hw_info->basic_info.hi);
  
      get_ex_ctrl_caps(hw_info, &(hw_info->pin_ctrls),   VMX_PINBASED_CTLS_MSR,  VMX_TRUE_PINBASED_CTLS_MSR);
      get_ex_ctrl_caps(hw_info, &(hw_info->proc_ctrls),  VMX_PROCBASED_CTLS_MSR, VMX_TRUE_PROCBASED_CTLS_MSR);
      get_ex_ctrl_caps(hw_info, &(hw_info->exit_ctrls),  VMX_EXIT_CTLS_MSR,      VMX_TRUE_EXIT_CTLS_MSR);
      get_ex_ctrl_caps(hw_info, &(hw_info->entry_ctrls), VMX_ENTRY_CTLS_MSR,     VMX_TRUE_ENTRY_CTLS_MSR);
  
      get_cr_fields(&(hw_info->cr0), VMX_CR0_FIXED1_MSR, VMX_CR0_FIXED0_MSR);
      get_cr_fields(&(hw_info->cr4), VMX_CR4_FIXED1_MSR, VMX_CR4_FIXED0_MSR);
  
  
      /* 
       * Check whether Secondary Controls are available 
       * 
       * Get secondary PROCBASED controls if secondary controls are available (optional or required)
       * Intel Manual 3B. Sect. G.3.3
       */
      if ( ((hw_info->proc_ctrls.req_mask & 0x80000000) == 0) || 
  	 ((hw_info->proc_ctrls.req_val  & 0x80000000) != 0) ) {
  
  	hw_info->caps.sec_proc_ctrls = 1;
  
  	get_ctrl_caps(&(hw_info->sec_proc_ctrls), VMX_PROCBASED_CTLS2_MSR);
  
  	/*
  	 * Check For Nested Paging (EPT) Support 
  	 */
  	// Grab the EPT info MSR if either EPT or VPIDs are available in Secondary proc ctrls
  	if ( ((hw_info->sec_proc_ctrls.req_mask & 0x00000002) == 0) || 
  	     ((hw_info->sec_proc_ctrls.req_val  & 0x00000002) != 0) ) {
  	    V3_Print("Intel VMX: EPT supported\n");
  
  	    hw_info->caps.ept = 1;
  	    v3_get_msr(VMX_EPT_VPID_CAP_MSR, &(hw_info->ept_info.hi), &(hw_info->ept_info.lo)); 
  
  	} else if ( ((hw_info->sec_proc_ctrls.req_mask & 0x00000002) == 0) || 
  		    ((hw_info->sec_proc_ctrls.req_val  & 0x00000002) != 0) ) {
  	    v3_get_msr(VMX_EPT_VPID_CAP_MSR, &(hw_info->ept_info.hi), &(hw_info->ept_info.lo)); 
  	}
  
  
  	/* 
  	 * Check for Unrestricted Guest Support
  	 */
  	if ( ((hw_info->sec_proc_ctrls.req_mask & 0x00000080) == 0) ||
  	     ((hw_info->sec_proc_ctrls.req_val  & 0x00000080) != 0)) {
  	    V3_Print("Intel VMX: Unrestricted Guest supported\n");
  	    hw_info->caps.unrestricted_guest = 1;
  
  	    // Intel has a bug(?) in the CR0 fixed bits detection with UG support
  	    // We have to manually remove the PG and PE flags from the mask
  	    hw_info->cr0.req_mask &= ~(0x80000001);
  	    hw_info->cr0.req_val  &= ~(0x80000001);
  	}
      }
  
      /* 
       *  Check for Preemption Timer 
       */
      if ( ((hw_info->pin_ctrls.req_mask & 0x00000040) == 0) ||
  	 ((hw_info->pin_ctrls.req_val  & 0x00000040) != 0)) {
          V3_Print("Intel VMX: Preemption Timer supported\n");
  	hw_info->caps.preempt_timer = 1;
      }
  
      /*
       *  Check if we can virtualize the PAT
       *
       *  There are 3 fields (2 exit ctrls, 1 entry ctrl) but we only check one
       */
      if ( ((hw_info->exit_ctrls.req_mask & 0x00040000) == 0) ||
  	 ((hw_info->exit_ctrls.req_val  & 0x00040000) != 0)) {
          V3_Print("Intel VMX: Virtualized PAT supported\n");
  	hw_info->caps.virt_pat = 1;
      }
  
      /* 
       * Check for virtualized EFER 
       */
      if ( ((hw_info->exit_ctrls.req_mask & 0x00100000) == 0) ||
  	 ((hw_info->exit_ctrls.req_val  & 0x00100000) != 0)) {
          V3_Print("Intel VMX: Virtualized EFER supported\n");
  	hw_info->caps.virt_efer = 1;
      }
  
      return 0;
  }
  