2018-03-20 15:02:11 +01:00
/* SPDX-License-Identifier: GPL-2.0 */
2022-11-01 15:53:44 +01:00
# ifndef __KVM_X86_VMX_HYPERV_H
# define __KVM_X86_VMX_HYPERV_H
2018-03-20 15:02:11 +01:00
2018-12-03 13:53:06 -08:00
# include <linux/jump_label.h>
2018-03-20 15:02:11 +01:00
2018-12-03 13:53:06 -08:00
# include <asm/hyperv-tlfs.h>
# include <asm/mshyperv.h>
# include <asm/vmx.h>
2022-11-01 15:53:44 +01:00
# include "../hyperv.h"
2018-12-03 13:53:06 -08:00
# include "capabilities.h"
# include "vmcs.h"
2020-02-05 13:30:34 +01:00
# include "vmcs12.h"
2018-12-03 13:53:06 -08:00
struct vmcs_config ;
DECLARE_STATIC_KEY_FALSE ( enable_evmcs ) ;
# define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs))
# define KVM_EVMCS_VERSION 1
/*
* Enlightened VMCSv1 doesn ' t support these :
*
* POSTED_INTR_NV = 0x00000002 ,
* GUEST_INTR_STATUS = 0x00000810 ,
* APIC_ACCESS_ADDR = 0x00002014 ,
* POSTED_INTR_DESC_ADDR = 0x00002016 ,
* EOI_EXIT_BITMAP0 = 0x0000201c ,
* EOI_EXIT_BITMAP1 = 0x0000201e ,
* EOI_EXIT_BITMAP2 = 0x00002020 ,
* EOI_EXIT_BITMAP3 = 0x00002022 ,
* GUEST_PML_INDEX = 0x00000812 ,
* PML_ADDRESS = 0x0000200e ,
* VM_FUNCTION_CONTROL = 0x00002018 ,
* EPTP_LIST_ADDRESS = 0x00002024 ,
* VMREAD_BITMAP = 0x00002026 ,
* VMWRITE_BITMAP = 0x00002028 ,
*
* TSC_MULTIPLIER = 0x00002032 ,
* PLE_GAP = 0x00004020 ,
* PLE_WINDOW = 0x00004022 ,
* VMX_PREEMPTION_TIMER_VALUE = 0x0000482E ,
*
* Currently unsupported in KVM :
* GUEST_IA32_RTIT_CTL = 0x00002814 ,
*/
# define EVMCS1_UNSUPPORTED_PINCTRL (PIN_BASED_POSTED_INTR | \
PIN_BASED_VMX_PREEMPTION_TIMER )
2022-04-19 23:34:00 +08:00
# define EVMCS1_UNSUPPORTED_EXEC_CTRL (CPU_BASED_ACTIVATE_TERTIARY_CONTROLS)
2018-12-03 13:53:06 -08:00
# define EVMCS1_UNSUPPORTED_2NDEXEC \
( SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | \
SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | \
SECONDARY_EXEC_APIC_REGISTER_VIRT | \
SECONDARY_EXEC_ENABLE_PML | \
SECONDARY_EXEC_ENABLE_VMFUNC | \
SECONDARY_EXEC_SHADOW_VMCS | \
SECONDARY_EXEC_TSC_SCALING | \
SECONDARY_EXEC_PAUSE_LOOP_EXITING )
2022-01-12 18:01:31 +01:00
# define EVMCS1_UNSUPPORTED_VMEXIT_CTRL \
2022-08-30 15:37:19 +02:00
( VM_EXIT_SAVE_VMX_PREEMPTION_TIMER )
# define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (0)
2018-12-03 13:53:06 -08:00
# define EVMCS1_UNSUPPORTED_VMFUNC (VMX_VMFUNC_EPTP_SWITCHING)
2018-03-20 15:02:11 +01:00
struct evmcs_field {
u16 offset ;
u16 clean_field ;
} ;
2018-12-03 13:53:06 -08:00
extern const struct evmcs_field vmcs_field_to_evmcs_1 [ ] ;
extern const unsigned int nr_evmcs_1_fields ;
2022-01-12 18:01:33 +01:00
static __always_inline int evmcs_field_offset ( unsigned long field ,
u16 * clean_field )
2018-03-20 15:02:11 +01:00
{
unsigned int index = ROL16 ( field , 6 ) ;
const struct evmcs_field * evmcs_field ;
2022-01-12 18:01:33 +01:00
if ( unlikely ( index > = nr_evmcs_1_fields ) )
2018-03-20 15:02:11 +01:00
return - ENOENT ;
evmcs_field = & vmcs_field_to_evmcs_1 [ index ] ;
2022-01-12 18:01:33 +01:00
/*
* Use offset = 0 to detect holes in eVMCS . This offset belongs to
* ' revision_id ' but this field has no encoding and is supposed to
* be accessed directly .
*/
if ( unlikely ( ! evmcs_field - > offset ) )
return - ENOENT ;
2018-03-20 15:02:11 +01:00
if ( clean_field )
* clean_field = evmcs_field - > clean_field ;
return evmcs_field - > offset ;
}
2022-01-12 18:01:34 +01:00
static inline u64 evmcs_read_any ( struct hv_enlightened_vmcs * evmcs ,
unsigned long field , u16 offset )
{
/*
* vmcs12_read_any ( ) doesn ' t care whether the supplied structure
* is ' struct vmcs12 ' or ' struct hv_enlightened_vmcs ' as it takes
* the exact offset of the required field , use it for convenience
* here .
*/
return vmcs12_read_any ( ( void * ) evmcs , field , offset ) ;
}
2022-01-12 18:01:33 +01:00
# if IS_ENABLED(CONFIG_HYPERV)
static __always_inline int get_evmcs_offset ( unsigned long field ,
u16 * clean_field )
{
int offset = evmcs_field_offset ( field , clean_field ) ;
WARN_ONCE ( offset < 0 , " KVM: accessing unsupported EVMCS field %lx \n " ,
field ) ;
return offset ;
}
2021-06-24 11:41:07 +02:00
static __always_inline void evmcs_write64 ( unsigned long field , u64 value )
2018-12-03 13:53:06 -08:00
{
u16 clean_field ;
int offset = get_evmcs_offset ( field , & clean_field ) ;
if ( offset < 0 )
return ;
* ( u64 * ) ( ( char * ) current_evmcs + offset ) = value ;
current_evmcs - > hv_clean_fields & = ~ clean_field ;
}
static inline void evmcs_write32 ( unsigned long field , u32 value )
{
u16 clean_field ;
int offset = get_evmcs_offset ( field , & clean_field ) ;
if ( offset < 0 )
return ;
* ( u32 * ) ( ( char * ) current_evmcs + offset ) = value ;
current_evmcs - > hv_clean_fields & = ~ clean_field ;
}
static inline void evmcs_write16 ( unsigned long field , u16 value )
{
u16 clean_field ;
int offset = get_evmcs_offset ( field , & clean_field ) ;
if ( offset < 0 )
return ;
* ( u16 * ) ( ( char * ) current_evmcs + offset ) = value ;
current_evmcs - > hv_clean_fields & = ~ clean_field ;
}
static inline u64 evmcs_read64 ( unsigned long field )
{
int offset = get_evmcs_offset ( field , NULL ) ;
if ( offset < 0 )
return 0 ;
return * ( u64 * ) ( ( char * ) current_evmcs + offset ) ;
}
static inline u32 evmcs_read32 ( unsigned long field )
{
int offset = get_evmcs_offset ( field , NULL ) ;
if ( offset < 0 )
return 0 ;
return * ( u32 * ) ( ( char * ) current_evmcs + offset ) ;
}
static inline u16 evmcs_read16 ( unsigned long field )
{
int offset = get_evmcs_offset ( field , NULL ) ;
if ( offset < 0 )
return 0 ;
return * ( u16 * ) ( ( char * ) current_evmcs + offset ) ;
}
static inline void evmcs_touch_msr_bitmap ( void )
{
if ( unlikely ( ! current_evmcs ) )
return ;
if ( current_evmcs - > hv_enlightenments_control . msr_bitmap )
current_evmcs - > hv_clean_fields & =
~ HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP ;
}
static inline void evmcs_load ( u64 phys_addr )
{
struct hv_vp_assist_page * vp_ap =
hv_get_vp_assist_page ( smp_processor_id ( ) ) ;
2019-08-22 22:30:21 +08:00
if ( current_evmcs - > hv_enlightenments_control . nested_flush_hypercall )
vp_ap - > nested_control . features . directhypercall = 1 ;
2018-12-03 13:53:06 -08:00
vp_ap - > current_nested_vmcs = phys_addr ;
vp_ap - > enlighten_vmentry = 1 ;
}
# else /* !IS_ENABLED(CONFIG_HYPERV) */
2021-06-24 11:41:07 +02:00
static __always_inline void evmcs_write64 ( unsigned long field , u64 value ) { }
2018-12-03 13:53:06 -08:00
static inline void evmcs_write32 ( unsigned long field , u32 value ) { }
static inline void evmcs_write16 ( unsigned long field , u16 value ) { }
static inline u64 evmcs_read64 ( unsigned long field ) { return 0 ; }
static inline u32 evmcs_read32 ( unsigned long field ) { return 0 ; }
static inline u16 evmcs_read16 ( unsigned long field ) { return 0 ; }
static inline void evmcs_load ( u64 phys_addr ) { }
static inline void evmcs_touch_msr_bitmap ( void ) { }
# endif /* IS_ENABLED(CONFIG_HYPERV) */
2021-05-26 15:20:16 +02:00
# define EVMPTR_INVALID (-1ULL)
2021-05-26 15:20:20 +02:00
# define EVMPTR_MAP_PENDING (-2ULL)
2021-05-26 15:20:16 +02:00
static inline bool evmptr_is_valid ( u64 evmptr )
{
2021-05-26 15:20:20 +02:00
return evmptr ! = EVMPTR_INVALID & & evmptr ! = EVMPTR_MAP_PENDING ;
2021-05-26 15:20:16 +02:00
}
2020-03-09 16:52:13 +01:00
enum nested_evmptrld_status {
EVMPTRLD_DISABLED ,
EVMPTRLD_SUCCEEDED ,
EVMPTRLD_VMFAIL ,
EVMPTRLD_ERROR ,
} ;
2022-11-01 15:54:03 +01:00
u64 nested_get_evmptr ( struct kvm_vcpu * vcpu ) ;
2018-12-10 18:21:55 +01:00
uint16_t nested_get_evmcs_version ( struct kvm_vcpu * vcpu ) ;
2018-12-03 13:53:06 -08:00
int nested_enable_evmcs ( struct kvm_vcpu * vcpu ,
uint16_t * vmcs_version ) ;
2022-08-30 15:37:19 +02:00
void nested_evmcs_filter_control_msr ( struct kvm_vcpu * vcpu , u32 msr_index , u64 * pdata ) ;
2020-02-05 13:30:34 +01:00
int nested_evmcs_check_controls ( struct vmcs12 * vmcs12 ) ;
2022-11-01 15:53:59 +01:00
void vmx_hv_inject_synthetic_vmexit_post_tlb_flush ( struct kvm_vcpu * vcpu ) ;
2018-12-03 13:53:06 -08:00
2022-11-01 15:53:44 +01:00
# endif /* __KVM_X86_VMX_HYPERV_H */