|  | /* | 
|  | * vmx.h: VMX Architecture related definitions | 
|  | * Copyright (c) 2004, Intel Corporation. | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or modify it | 
|  | * under the terms and conditions of the GNU General Public License, | 
|  | * version 2, as published by the Free Software Foundation. | 
|  | * | 
|  | * This program is distributed in the hope it will be useful, but WITHOUT | 
|  | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|  | * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | 
|  | * more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License along with | 
|  | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 
|  | * Place - Suite 330, Boston, MA 02111-1307 USA. | 
|  | * | 
|  | * A few random additions are: | 
|  | * Copyright (C) 2006 Qumranet | 
|  | *    Avi Kivity <avi@qumranet.com> | 
|  | *    Yaniv Kamay <yaniv@qumranet.com> | 
|  | * | 
|  | */ | 
|  |  | 
|  | #pragma once | 
|  |  | 
|  | #include <ros/arch/vmx.h> | 
|  |  | 
|  | /* Additional bits for VMMCPs, originally from the Dune version of kvm. */ | 
|  | /* | 
|  | * vmx.h - header file for USM VMX driver. | 
|  | */ | 
|  |  | 
|  | /* This is per-guest per-core, and the implementation specific area | 
|  | * should be assumed to have hidden fields. | 
|  | */ | 
|  | struct vmcs { | 
|  | uint32_t revision_id; | 
|  | uint32_t abort_code; | 
|  | char _impl_specific[PGSIZE - sizeof(uint32_t) * 2]; | 
|  | }; | 
|  |  | 
|  | typedef uint64_t gpa_t; | 
|  | typedef uint64_t gva_t; | 
|  |  | 
|  | struct vmx_capability { | 
|  | uint32_t ept; | 
|  | uint32_t vpid; | 
|  | }; | 
|  |  | 
|  | struct vmcs_config { | 
|  | int size; | 
|  | uint32_t revision_id; | 
|  | uint32_t pin_based_exec_ctrl; | 
|  | uint32_t cpu_based_exec_ctrl; | 
|  | uint32_t cpu_based_2nd_exec_ctrl; | 
|  | uint32_t vmexit_ctrl; | 
|  | uint32_t vmentry_ctrl; | 
|  | }; | 
|  |  | 
|  | struct guest_pcore { | 
|  | int cpu; | 
|  | struct proc *proc; | 
|  | unsigned long *posted_irq_desc; | 
|  | struct vmcs *vmcs; | 
|  | int vmcs_core_id; | 
|  | bool should_vmresume; | 
|  | uint64_t xcr0; | 
|  | uint64_t msr_kern_gs_base; | 
|  | uint64_t msr_star; | 
|  | uint64_t msr_lstar; | 
|  | uint64_t msr_sfmask; | 
|  | }; | 
|  |  | 
|  | #define NR_AUTOLOAD_MSRS 8 | 
|  |  | 
|  | /* the horror. */ | 
|  | struct desc_struct { | 
|  | union { | 
|  | struct { | 
|  | unsigned int a; | 
|  | unsigned int b; | 
|  | }; | 
|  | struct { | 
|  | uint16_t limit0; | 
|  | uint16_t base0; | 
|  | unsigned base1: 8, type: 4, s: 1, dpl: 2, p: 1; | 
|  | unsigned limit: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8; | 
|  | }; | 
|  | }; | 
|  | } __attribute__((packed)); | 
|  |  | 
|  | /* LDT or TSS descriptor in the GDT. 16 bytes. */ | 
|  | struct ldttss_desc64 { | 
|  | uint16_t limit0; | 
|  | uint16_t base0; | 
|  | unsigned base1 : 8, type : 5, dpl : 2, p : 1; | 
|  | unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8; | 
|  | uint32_t base3; | 
|  | uint32_t zero1; | 
|  | } __attribute__((packed)); | 
|  |  | 
|  | #define INTEL_MSR_WRITE_OFFSET			2048 | 
|  |  | 
|  | #define INTEL_X2APIC_MSR_START			0x100 | 
|  | #define INTEL_X2APIC_MSR_LENGTH			(0x40/8) | 
|  |  | 
|  | #define MSR_IA32_VMX_BASIC_MSR			0x480 | 
|  | #define MSR_IA32_VMX_PINBASED_CTLS_MSR	0x481 | 
|  | #define MSR_IA32_VMX_PROCBASED_CTLS_MSR	0x482 | 
|  | #define MSR_IA32_VMX_EXIT_CTLS_MSR		0x483 | 
|  | #define MSR_IA32_VMX_ENTRY_CTLS_MSR		0x484 | 
|  |  | 
|  | extern char * const VMX_EXIT_REASON_NAMES[]; | 
|  |  | 
|  | static inline void native_store_idt(pseudodesc_t *dtr); | 
|  | static inline unsigned long get_desc_base(const struct desc_struct *desc); | 
|  | static inline void native_store_gdt(pseudodesc_t *dtr); | 
|  | static inline bool cpu_has_secondary_exec_ctrls(void); | 
|  | static inline bool cpu_has_vmx_vpid(void); | 
|  | static inline bool cpu_has_vmx_invpcid(void); | 
|  | static inline bool cpu_has_vmx_invvpid_single(void); | 
|  | static inline bool cpu_has_vmx_invvpid_global(void); | 
|  | static inline bool cpu_has_vmx_ept(void); | 
|  | static inline bool cpu_has_vmx_invept(void); | 
|  | static inline bool cpu_has_vmx_invept_individual_addr(void); | 
|  | static inline bool cpu_has_vmx_invept_context(void); | 
|  | static inline bool cpu_has_vmx_invept_global(void); | 
|  | static inline bool cpu_has_vmx_ept_ad_bits(void); | 
|  | static inline bool cpu_has_vmx_ept_execute_only(void); | 
|  | static inline bool cpu_has_vmx_eptp_uncacheable(void); | 
|  | static inline bool cpu_has_vmx_eptp_writeback(void); | 
|  | static inline bool cpu_has_vmx_ept_2m_page(void); | 
|  | static inline bool cpu_has_vmx_ept_1g_page(void); | 
|  | static inline bool cpu_has_vmx_ept_4levels(void); | 
|  | static inline void __invept(int ext, uint64_t eptp, gpa_t gpa); | 
|  | static inline void ept_sync_global(void); | 
|  | static inline void ept_sync_context(uint64_t eptp); | 
|  | static inline void ept_sync_individual_addr(uint64_t eptp, gpa_t gpa); | 
|  | static inline void __vmxon(uint64_t addr); | 
|  | static inline void __vmxoff(void); | 
|  | static inline void __invvpid(int ext, uint16_t vpid, gva_t gva); | 
|  | static inline void vpid_sync_gpc_single(uint16_t vpid); | 
|  | static inline void vpid_sync_gpc_global(void); | 
|  | static inline void vpid_sync_context(uint16_t vpid); | 
|  |  | 
|  | /* no way to get around some of this stuff. */ | 
|  | /* we will do the bare minimum required. */ | 
|  | static inline void native_store_idt(pseudodesc_t *dtr) | 
|  | { | 
|  | asm volatile("sidt %0":"=m" (*dtr)); | 
|  | } | 
|  |  | 
|  | static inline unsigned long get_desc_base(const struct desc_struct *desc) | 
|  | { | 
|  | return (unsigned)(desc->base0 | ((desc->base1) << 16) | | 
|  | ((desc->base2) << 24)); | 
|  | } | 
|  |  | 
|  | #define store_gdt(dtr) native_store_gdt(dtr) | 
|  | static inline void native_store_gdt(pseudodesc_t *dtr) | 
|  | { | 
|  | asm volatile("sgdt %0":"=m" (*dtr)); | 
|  | } | 
|  |  | 
|  | /* TODO: somewhat nasty - two structs, only used by the helpers.  Maybe use cpu | 
|  | * features. */ | 
|  | extern struct vmcs_config vmcs_config; | 
|  | extern struct vmx_capability vmx_capability; | 
|  |  | 
|  | static inline bool cpu_has_secondary_exec_ctrls(void) | 
|  | { | 
|  | return vmcs_config.cpu_based_exec_ctrl & | 
|  | CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_vpid(void) | 
|  | { | 
|  | return vmcs_config.cpu_based_2nd_exec_ctrl & | 
|  | SECONDARY_EXEC_ENABLE_VPID; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_invpcid(void) | 
|  | { | 
|  | return vmcs_config.cpu_based_2nd_exec_ctrl & | 
|  | SECONDARY_EXEC_ENABLE_INVPCID; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_invvpid_single(void) | 
|  | { | 
|  | return vmx_capability.vpid & VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_invvpid_global(void) | 
|  | { | 
|  | return vmx_capability.vpid & VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_ept(void) | 
|  | { | 
|  | return vmcs_config.cpu_based_2nd_exec_ctrl & | 
|  | SECONDARY_EXEC_ENABLE_EPT; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_invept(void) | 
|  | { | 
|  | return vmx_capability.ept & VMX_EPT_INVEPT_BIT; | 
|  | } | 
|  |  | 
|  | /* the SDM (2015-01) doesn't mention this ability (still?) */ | 
|  | static inline bool cpu_has_vmx_invept_individual_addr(void) | 
|  | { | 
|  | return vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_invept_context(void) | 
|  | { | 
|  | return vmx_capability.ept & VMX_EPT_EXTENT_CONTEXT_BIT; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_invept_global(void) | 
|  | { | 
|  | return vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_ept_ad_bits(void) | 
|  | { | 
|  | return vmx_capability.ept & VMX_EPT_AD_BIT; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_ept_execute_only(void) | 
|  | { | 
|  | return vmx_capability.ept & VMX_EPT_EXECUTE_ONLY_BIT; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_eptp_uncacheable(void) | 
|  | { | 
|  | return vmx_capability.ept & VMX_EPTP_UC_BIT; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_eptp_writeback(void) | 
|  | { | 
|  | return vmx_capability.ept & VMX_EPTP_WB_BIT; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_ept_2m_page(void) | 
|  | { | 
|  | return vmx_capability.ept & VMX_EPT_2MB_PAGE_BIT; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_ept_1g_page(void) | 
|  | { | 
|  | return vmx_capability.ept & VMX_EPT_1GB_PAGE_BIT; | 
|  | } | 
|  |  | 
|  | static inline bool cpu_has_vmx_ept_4levels(void) | 
|  | { | 
|  | return vmx_capability.ept & VMX_EPT_PAGE_WALK_4_BIT; | 
|  | } | 
|  |  | 
|  | static inline void __invept(int ext, uint64_t eptp, gpa_t gpa) | 
|  | { | 
|  | struct { | 
|  | uint64_t eptp, gpa; | 
|  | } operand = {eptp, gpa}; | 
|  |  | 
|  | asm volatile (ASM_VMX_INVEPT | 
|  | /* CF==1 or ZF==1 --> rc = -1 */ | 
|  | "; ja 1f ; ud2 ; 1:\n" | 
|  | : : "a" (&operand), "c" (ext) : "cc", "memory"); | 
|  | } | 
|  |  | 
|  | /* We assert support for the global flush during ept_init() */ | 
|  | static inline void ept_sync_global(void) | 
|  | { | 
|  | __invept(VMX_EPT_EXTENT_GLOBAL, 0, 0); | 
|  | } | 
|  |  | 
|  | static inline void ept_sync_context(uint64_t eptp) | 
|  | { | 
|  | if (cpu_has_vmx_invept_context()) | 
|  | __invept(VMX_EPT_EXTENT_CONTEXT, eptp, 0); | 
|  | else | 
|  | ept_sync_global(); | 
|  | } | 
|  |  | 
|  | static inline void ept_sync_individual_addr(uint64_t eptp, gpa_t gpa) | 
|  | { | 
|  | if (cpu_has_vmx_invept_individual_addr()) | 
|  | __invept(VMX_EPT_EXTENT_INDIVIDUAL_ADDR, | 
|  | eptp, gpa); | 
|  | else | 
|  | ept_sync_context(eptp); | 
|  | } | 
|  |  | 
|  | static inline void __vmxon(uint64_t addr) | 
|  | { | 
|  | asm volatile (ASM_VMX_VMXON_RAX | 
|  | : : "a"(&addr), "m"(addr) | 
|  | : "memory", "cc"); | 
|  | } | 
|  |  | 
|  | static inline void __vmxoff(void) | 
|  | { | 
|  | asm volatile (ASM_VMX_VMXOFF : : : "cc"); | 
|  | } | 
|  |  | 
|  | static inline void __invvpid(int ext, uint16_t vpid, gva_t gva) | 
|  | { | 
|  | struct { | 
|  | uint64_t vpid : 16; | 
|  | uint64_t rsvd : 48; | 
|  | uint64_t gva; | 
|  | } operand = { vpid, 0, gva }; | 
|  |  | 
|  | asm volatile (ASM_VMX_INVVPID | 
|  | /* CF==1 or ZF==1 --> rc = -1 */ | 
|  | "; ja 1f ; ud2 ; 1:" | 
|  | : : "a"(&operand), "c"(ext) : "cc", "memory"); | 
|  | } | 
|  |  | 
|  | static inline void vpid_sync_gpc_single(uint16_t vpid) | 
|  | { | 
|  | if (vpid == 0) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (cpu_has_vmx_invvpid_single()) | 
|  | __invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vpid, 0); | 
|  | } | 
|  |  | 
|  | static inline void vpid_sync_gpc_global(void) | 
|  | { | 
|  | if (cpu_has_vmx_invvpid_global()) | 
|  | __invvpid(VMX_VPID_EXTENT_ALL_CONTEXT, 0, 0); | 
|  | } | 
|  |  | 
|  | static inline void vpid_sync_context(uint16_t vpid) | 
|  | { | 
|  | if (cpu_has_vmx_invvpid_single()) | 
|  | vpid_sync_gpc_single(vpid); | 
|  | else | 
|  | vpid_sync_gpc_global(); | 
|  | } | 
|  |  | 
|  | static inline unsigned long vmcs_read(unsigned long field) | 
|  | { | 
|  | unsigned long value; | 
|  |  | 
|  | asm volatile (ASM_VMX_VMREAD_RDX_RAX : "=a"(value) : "d"(field) : "cc"); | 
|  | return value; | 
|  | } | 
|  |  | 
|  | /* Returns true if the op succeeded.  It can fail if the field is unsupported */ | 
|  | static inline bool vmcs_write(unsigned long field, unsigned long value) | 
|  | { | 
|  | uint8_t error; | 
|  |  | 
|  | asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0" | 
|  | : "=q"(error) : "a"(value), "d"(field) : "cc"); | 
|  | return error ? FALSE : TRUE; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * VMX Execution Controls (vmxec) | 
|  | * Some bits can be set, others can not (i.e. they are reserved). | 
|  | * | 
|  | * o all bits listed in here must set or clear all the bits in a word | 
|  | *   that are not reserved (coverage). | 
|  | * o no bits listed in one of these elements is listed in | 
|  | *   another element (conflict) | 
|  | * o you are allowed to specify a bit that matches a reserved value | 
|  | *   (because it might be settable at some future time). | 
|  | * o do your best to find symbolic names for the set_to_1 and set_to_0 values. | 
|  | *   In the one case we could not find a name, it turned out to be an | 
|  | *   error in kvm constants that went back to the earliest days. | 
|  | * We're hoping you almost never have to change this. It's painful. | 
|  | * The assumption going in is that the 5 MSRs that define the vmxec | 
|  | * values are relatively static. This has been the case for a while. | 
|  | */ | 
|  | struct vmxec { | 
|  | char *name; | 
|  | uint32_t msr; | 
|  | uint32_t truemsr; | 
|  | uint32_t must_be_1; | 
|  | uint32_t must_be_0; | 
|  | uint32_t try_set_1; | 
|  | uint32_t try_set_0; | 
|  | uint32_t hw_changeable; | 
|  | uint32_t policy_changeable; | 
|  | }; | 
|  |  | 
|  | /* Per-VM VMX info */ | 
|  | struct vmx_vmm { | 
|  | uint32_t			pin_exec_ctls; | 
|  | uint32_t			cpu_exec_ctls; | 
|  | uint32_t			cpu2_exec_ctls; | 
|  | }; | 
|  |  | 
|  | int intel_vmm_init(void); | 
|  | int intel_vmm_pcpu_init(void); | 
|  | void vmx_load_guest_pcore(struct guest_pcore *gpc); | 
|  | void vmx_unload_guest_pcore(struct guest_pcore *gpc); | 
|  | uint64_t gpc_get_eptp(struct guest_pcore *gpc); | 
|  | void vmx_clear_vmcs(void); | 
|  | void vmx_setup_vmx_vmm(struct vmx_vmm *vmx); | 
|  | int vmx_ctl_get_exits(struct vmx_vmm *vmx); | 
|  | int vmx_ctl_set_exits(struct vmx_vmm *vmx, int vmm_exits); |