162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef __KVM_X86_VMX_VMCS_H 362306a36Sopenharmony_ci#define __KVM_X86_VMX_VMCS_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/ktime.h> 662306a36Sopenharmony_ci#include <linux/list.h> 762306a36Sopenharmony_ci#include <linux/nospec.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/kvm.h> 1062306a36Sopenharmony_ci#include <asm/vmx.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "capabilities.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define ROL16(val, n) ((u16)(((u16)(val) << (n)) | ((u16)(val) >> (16 - (n))))) 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct vmcs_hdr { 1762306a36Sopenharmony_ci u32 revision_id:31; 1862306a36Sopenharmony_ci u32 shadow_vmcs:1; 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct vmcs { 2262306a36Sopenharmony_ci struct vmcs_hdr hdr; 2362306a36Sopenharmony_ci u32 abort; 2462306a36Sopenharmony_ci char data[]; 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ciDECLARE_PER_CPU(struct vmcs *, current_vmcs); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * vmcs_host_state tracks registers that are loaded from the VMCS on VMEXIT 3162306a36Sopenharmony_ci * and whose values change infrequently, but are not constant. I.e. this is 3262306a36Sopenharmony_ci * used as a write-through cache of the corresponding VMCS fields. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_cistruct vmcs_host_state { 3562306a36Sopenharmony_ci unsigned long cr3; /* May not match real cr3 */ 3662306a36Sopenharmony_ci unsigned long cr4; /* May not match real cr4 */ 3762306a36Sopenharmony_ci unsigned long gs_base; 3862306a36Sopenharmony_ci unsigned long fs_base; 3962306a36Sopenharmony_ci unsigned long rsp; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci u16 fs_sel, gs_sel, ldt_sel; 4262306a36Sopenharmony_ci#ifdef CONFIG_X86_64 4362306a36Sopenharmony_ci u16 ds_sel, es_sel; 4462306a36Sopenharmony_ci#endif 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct vmcs_controls_shadow { 4862306a36Sopenharmony_ci u32 vm_entry; 4962306a36Sopenharmony_ci u32 vm_exit; 5062306a36Sopenharmony_ci u32 pin; 5162306a36Sopenharmony_ci u32 exec; 5262306a36Sopenharmony_ci u32 secondary_exec; 5362306a36Sopenharmony_ci u64 tertiary_exec; 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * Track a VMCS that may be loaded on a certain CPU. If it is (cpu!=-1), also 5862306a36Sopenharmony_ci * remember whether it was VMLAUNCHed, and maintain a linked list of all VMCSs 5962306a36Sopenharmony_ci * loaded on this CPU (so we can clear them if the CPU goes down). 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_cistruct loaded_vmcs { 6262306a36Sopenharmony_ci struct vmcs *vmcs; 6362306a36Sopenharmony_ci struct vmcs *shadow_vmcs; 6462306a36Sopenharmony_ci int cpu; 6562306a36Sopenharmony_ci bool launched; 6662306a36Sopenharmony_ci bool nmi_known_unmasked; 6762306a36Sopenharmony_ci bool hv_timer_soft_disabled; 6862306a36Sopenharmony_ci /* Support for vnmi-less CPUs */ 6962306a36Sopenharmony_ci int soft_vnmi_blocked; 7062306a36Sopenharmony_ci ktime_t entry_time; 7162306a36Sopenharmony_ci s64 vnmi_blocked_time; 7262306a36Sopenharmony_ci unsigned long *msr_bitmap; 7362306a36Sopenharmony_ci struct list_head loaded_vmcss_on_cpu_link; 7462306a36Sopenharmony_ci struct vmcs_host_state host_state; 7562306a36Sopenharmony_ci struct vmcs_controls_shadow controls_shadow; 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic __always_inline bool is_intr_type(u32 intr_info, u32 type) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci const u32 mask = INTR_INFO_VALID_MASK | INTR_INFO_INTR_TYPE_MASK; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return (intr_info & mask) == (INTR_INFO_VALID_MASK | type); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic inline bool is_intr_type_n(u32 intr_info, u32 type, u8 vector) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci const u32 mask = INTR_INFO_VALID_MASK | INTR_INFO_INTR_TYPE_MASK | 8862306a36Sopenharmony_ci INTR_INFO_VECTOR_MASK; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return (intr_info & mask) == (INTR_INFO_VALID_MASK | type | vector); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic inline bool is_exception_n(u32 intr_info, u8 vector) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci return is_intr_type_n(intr_info, INTR_TYPE_HARD_EXCEPTION, vector); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic inline bool is_debug(u32 intr_info) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci return is_exception_n(intr_info, DB_VECTOR); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic inline bool is_breakpoint(u32 intr_info) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci return is_exception_n(intr_info, BP_VECTOR); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic inline bool is_double_fault(u32 intr_info) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci return is_exception_n(intr_info, DF_VECTOR); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic inline bool is_page_fault(u32 intr_info) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci return is_exception_n(intr_info, PF_VECTOR); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic inline bool is_invalid_opcode(u32 intr_info) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci return is_exception_n(intr_info, UD_VECTOR); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic inline bool is_gp_fault(u32 intr_info) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci return is_exception_n(intr_info, GP_VECTOR); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic inline bool is_alignment_check(u32 intr_info) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci return is_exception_n(intr_info, AC_VECTOR); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic inline bool is_machine_check(u32 intr_info) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci return is_exception_n(intr_info, MC_VECTOR); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic inline bool is_nm_fault(u32 intr_info) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci return is_exception_n(intr_info, NM_VECTOR); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* Undocumented: icebp/int1 */ 14462306a36Sopenharmony_cistatic inline bool is_icebp(u32 intr_info) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci return is_intr_type(intr_info, INTR_TYPE_PRIV_SW_EXCEPTION); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic __always_inline bool is_nmi(u32 intr_info) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci return is_intr_type(intr_info, INTR_TYPE_NMI_INTR); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic inline bool is_external_intr(u32 intr_info) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci return is_intr_type(intr_info, INTR_TYPE_EXT_INTR); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic inline bool is_exception_with_error_code(u32 intr_info) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci const u32 mask = INTR_INFO_VALID_MASK | INTR_INFO_DELIVER_CODE_MASK; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return (intr_info & mask) == mask; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cienum vmcs_field_width { 16762306a36Sopenharmony_ci VMCS_FIELD_WIDTH_U16 = 0, 16862306a36Sopenharmony_ci VMCS_FIELD_WIDTH_U64 = 1, 16962306a36Sopenharmony_ci VMCS_FIELD_WIDTH_U32 = 2, 17062306a36Sopenharmony_ci VMCS_FIELD_WIDTH_NATURAL_WIDTH = 3 17162306a36Sopenharmony_ci}; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic inline int vmcs_field_width(unsigned long field) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci if (0x1 & field) /* the *_HIGH fields are all 32 bit */ 17662306a36Sopenharmony_ci return VMCS_FIELD_WIDTH_U32; 17762306a36Sopenharmony_ci return (field >> 13) & 0x3; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic inline int vmcs_field_readonly(unsigned long field) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci return (((field >> 10) & 0x3) == 1); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci#define VMCS_FIELD_INDEX_SHIFT (1) 18662306a36Sopenharmony_ci#define VMCS_FIELD_INDEX_MASK GENMASK(9, 1) 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic inline unsigned int vmcs_field_index(unsigned long field) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci return (field & VMCS_FIELD_INDEX_MASK) >> VMCS_FIELD_INDEX_SHIFT; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci#endif /* __KVM_X86_VMX_VMCS_H */ 194