blob: a1443842ed0b28cb6f1c7d2787b6319edebd4a54 [file] [log] [blame]
#ifndef X86_HYPERV_H
#define X86_HYPERV_H
#include "libcflat.h"
#include "processor.h"
#define HYPERV_CPUID_FEATURES 0x40000003
#define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1)
#define HV_X64_MSR_SYNIC_AVAILABLE (1 << 2)
#define HV_X64_MSR_SYNTIMER_AVAILABLE (1 << 3)
#define HV_STIMER_DIRECT_MODE_AVAILABLE (1 << 19)
#define HV_X64_MSR_GUEST_OS_ID 0x40000000
#define HV_X64_MSR_HYPERCALL 0x40000001
#define HV_X64_MSR_TIME_REF_COUNT 0x40000020
#define HV_X64_MSR_REFERENCE_TSC 0x40000021
/* Define synthetic interrupt controller model specific registers. */
#define HV_X64_MSR_SCONTROL 0x40000080
#define HV_X64_MSR_SVERSION 0x40000081
#define HV_X64_MSR_SIEFP 0x40000082
#define HV_X64_MSR_SIMP 0x40000083
#define HV_X64_MSR_EOM 0x40000084
#define HV_X64_MSR_SINT0 0x40000090
#define HV_X64_MSR_SINT1 0x40000091
#define HV_X64_MSR_SINT2 0x40000092
#define HV_X64_MSR_SINT3 0x40000093
#define HV_X64_MSR_SINT4 0x40000094
#define HV_X64_MSR_SINT5 0x40000095
#define HV_X64_MSR_SINT6 0x40000096
#define HV_X64_MSR_SINT7 0x40000097
#define HV_X64_MSR_SINT8 0x40000098
#define HV_X64_MSR_SINT9 0x40000099
#define HV_X64_MSR_SINT10 0x4000009A
#define HV_X64_MSR_SINT11 0x4000009B
#define HV_X64_MSR_SINT12 0x4000009C
#define HV_X64_MSR_SINT13 0x4000009D
#define HV_X64_MSR_SINT14 0x4000009E
#define HV_X64_MSR_SINT15 0x4000009F
/*
* Synthetic Timer MSRs. Four timers per vcpu.
*/
#define HV_X64_MSR_STIMER0_CONFIG 0x400000B0
#define HV_X64_MSR_STIMER0_COUNT 0x400000B1
#define HV_X64_MSR_STIMER1_CONFIG 0x400000B2
#define HV_X64_MSR_STIMER1_COUNT 0x400000B3
#define HV_X64_MSR_STIMER2_CONFIG 0x400000B4
#define HV_X64_MSR_STIMER2_COUNT 0x400000B5
#define HV_X64_MSR_STIMER3_CONFIG 0x400000B6
#define HV_X64_MSR_STIMER3_COUNT 0x400000B7
#define HV_SYNIC_CONTROL_ENABLE (1ULL << 0)
#define HV_SYNIC_SIMP_ENABLE (1ULL << 0)
#define HV_SYNIC_SIEFP_ENABLE (1ULL << 0)
#define HV_SYNIC_SINT_MASKED (1ULL << 16)
#define HV_SYNIC_SINT_AUTO_EOI (1ULL << 17)
#define HV_SYNIC_SINT_VECTOR_MASK (0xFF)
#define HV_SYNIC_SINT_COUNT 16
/*
* Synthetic timer configuration.
*/
union hv_stimer_config {
u64 as_uint64;
struct {
u64 enable:1;
u64 periodic:1;
u64 lazy:1;
u64 auto_enable:1;
u64 apic_vector:8;
u64 direct_mode:1;
u64 reserved_z0:3;
u64 sintx:4;
u64 reserved_z1:44;
};
};
#define HV_SYNIC_STIMER_COUNT (4)
/* Define synthetic interrupt controller message constants. */
#define HV_MESSAGE_SIZE (256)
#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240)
#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30)
/* Define hypervisor message types. */
enum hv_message_type {
HVMSG_NONE = 0x00000000,
/* Memory access messages. */
HVMSG_UNMAPPED_GPA = 0x80000000,
HVMSG_GPA_INTERCEPT = 0x80000001,
/* Timer notification messages. */
HVMSG_TIMER_EXPIRED = 0x80000010,
/* Error messages. */
HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020,
HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021,
HVMSG_UNSUPPORTED_FEATURE = 0x80000022,
/* Trace buffer complete messages. */
HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040,
/* Platform-specific processor intercept messages. */
HVMSG_X64_IOPORT_INTERCEPT = 0x80010000,
HVMSG_X64_MSR_INTERCEPT = 0x80010001,
HVMSG_X64_CPUID_INTERCEPT = 0x80010002,
HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003,
HVMSG_X64_APIC_EOI = 0x80010004,
HVMSG_X64_LEGACY_FP_ERROR = 0x80010005
};
/* Define synthetic interrupt controller message flags. */
union hv_message_flags {
uint8_t asu8;
struct {
uint8_t msg_pending:1;
uint8_t reserved:7;
};
};
union hv_port_id {
uint32_t asu32;
struct {
uint32_t id:24;
uint32_t reserved:8;
} u;
};
/* Define port type. */
enum hv_port_type {
HVPORT_MSG = 1,
HVPORT_EVENT = 2,
HVPORT_MONITOR = 3
};
/* Define synthetic interrupt controller message header. */
struct hv_message_header {
uint32_t message_type;
uint8_t payload_size;
union hv_message_flags message_flags;
uint8_t reserved[2];
union {
uint64_t sender;
union hv_port_id port;
};
};
/* Define timer message payload structure. */
struct hv_timer_message_payload {
uint32_t timer_index;
uint32_t reserved;
uint64_t expiration_time; /* When the timer expired */
uint64_t delivery_time; /* When the message was delivered */
};
/* Define synthetic interrupt controller message format. */
struct hv_message {
struct hv_message_header header;
union {
uint64_t payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
} u;
};
/* Define the synthetic interrupt message page layout. */
struct hv_message_page {
struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
};
#define HV_EVENT_FLAGS_COUNT (256 * 8)
struct hv_event_flags {
ulong flags[HV_EVENT_FLAGS_COUNT / (8 * sizeof(ulong))];
};
struct hv_event_flags_page {
struct hv_event_flags slot[HV_SYNIC_SINT_COUNT];
};
#define HV_X64_MSR_HYPERCALL_ENABLE 0x1
#define HV_HYPERCALL_FAST (1u << 16)
#define HVCALL_POST_MESSAGE 0x5c
#define HVCALL_SIGNAL_EVENT 0x5d
struct hv_input_post_message {
u32 connectionid;
u32 reserved;
u32 message_type;
u32 payload_size;
u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
};
static inline bool hv_synic_supported(void)
{
return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_SYNIC_AVAILABLE;
}
static inline bool hv_stimer_supported(void)
{
return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_SYNTIMER_AVAILABLE;
}
static inline bool stimer_direct_supported(void)
{
return cpuid(HYPERV_CPUID_FEATURES).d & HV_STIMER_DIRECT_MODE_AVAILABLE;
}
static inline bool hv_time_ref_counter_supported(void)
{
return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE;
}
void synic_sint_create(u8 sint, u8 vec, bool auto_eoi);
void synic_sint_set(u8 vcpu, u8 sint);
void synic_sint_destroy(u8 sint);
void msg_conn_create(u8 sint, u8 vec, u8 conn_id);
void msg_conn_destroy(u8 sint, u8 conn_id);
void evt_conn_create(u8 sint, u8 vec, u8 conn_id);
void evt_conn_destroy(u8 sint, u8 conn_id);
struct hv_reference_tsc_page {
uint32_t tsc_sequence;
uint32_t res1;
uint64_t tsc_scale;
int64_t tsc_offset;
};
#endif