1 #ifndef X86_HYPERV_H
2 #define X86_HYPERV_H
3
4 #include "libcflat.h"
5 #include "processor.h"
6
7 #define HYPERV_CPUID_FEATURES 0x40000003
8
9 #define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1)
10 #define HV_X64_MSR_SYNIC_AVAILABLE (1 << 2)
11 #define HV_X64_MSR_SYNTIMER_AVAILABLE (1 << 3)
12
13 #define HV_STIMER_DIRECT_MODE_AVAILABLE (1 << 19)
14
15 #define HV_X64_MSR_GUEST_OS_ID 0x40000000
16 #define HV_X64_MSR_HYPERCALL 0x40000001
17
18 #define HV_X64_MSR_TIME_REF_COUNT 0x40000020
19 #define HV_X64_MSR_REFERENCE_TSC 0x40000021
20
21 /* Define synthetic interrupt controller model specific registers. */
22 #define HV_X64_MSR_SCONTROL 0x40000080
23 #define HV_X64_MSR_SVERSION 0x40000081
24 #define HV_X64_MSR_SIEFP 0x40000082
25 #define HV_X64_MSR_SIMP 0x40000083
26 #define HV_X64_MSR_EOM 0x40000084
27 #define HV_X64_MSR_SINT0 0x40000090
28 #define HV_X64_MSR_SINT1 0x40000091
29 #define HV_X64_MSR_SINT2 0x40000092
30 #define HV_X64_MSR_SINT3 0x40000093
31 #define HV_X64_MSR_SINT4 0x40000094
32 #define HV_X64_MSR_SINT5 0x40000095
33 #define HV_X64_MSR_SINT6 0x40000096
34 #define HV_X64_MSR_SINT7 0x40000097
35 #define HV_X64_MSR_SINT8 0x40000098
36 #define HV_X64_MSR_SINT9 0x40000099
37 #define HV_X64_MSR_SINT10 0x4000009A
38 #define HV_X64_MSR_SINT11 0x4000009B
39 #define HV_X64_MSR_SINT12 0x4000009C
40 #define HV_X64_MSR_SINT13 0x4000009D
41 #define HV_X64_MSR_SINT14 0x4000009E
42 #define HV_X64_MSR_SINT15 0x4000009F
43
44 /*
45 * Synthetic Timer MSRs. Four timers per vcpu.
46 */
47
48 #define HV_X64_MSR_STIMER0_CONFIG 0x400000B0
49 #define HV_X64_MSR_STIMER0_COUNT 0x400000B1
50 #define HV_X64_MSR_STIMER1_CONFIG 0x400000B2
51 #define HV_X64_MSR_STIMER1_COUNT 0x400000B3
52 #define HV_X64_MSR_STIMER2_CONFIG 0x400000B4
53 #define HV_X64_MSR_STIMER2_COUNT 0x400000B5
54 #define HV_X64_MSR_STIMER3_CONFIG 0x400000B6
55 #define HV_X64_MSR_STIMER3_COUNT 0x400000B7
56
57 #define HV_SYNIC_CONTROL_ENABLE (1ULL << 0)
58 #define HV_SYNIC_SIMP_ENABLE (1ULL << 0)
59 #define HV_SYNIC_SIEFP_ENABLE (1ULL << 0)
60 #define HV_SYNIC_SINT_MASKED (1ULL << 16)
61 #define HV_SYNIC_SINT_AUTO_EOI (1ULL << 17)
62 #define HV_SYNIC_SINT_VECTOR_MASK (0xFF)
63 #define HV_SYNIC_SINT_COUNT 16
64
65 /*
66 * Synthetic timer configuration.
67 */
68 union hv_stimer_config {
69 u64 as_uint64;
70 struct {
71 u64 enable:1;
72 u64 periodic:1;
73 u64 lazy:1;
74 u64 auto_enable:1;
75 u64 apic_vector:8;
76 u64 direct_mode:1;
77 u64 reserved_z0:3;
78 u64 sintx:4;
79 u64 reserved_z1:44;
80 };
81 };
82
83 #define HV_SYNIC_STIMER_COUNT (4)
84
85 /* Define synthetic interrupt controller message constants. */
86 #define HV_MESSAGE_SIZE (256)
87 #define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240)
88 #define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30)
89
90 /* Define hypervisor message types. */
91 enum hv_message_type {
92 HVMSG_NONE = 0x00000000,
93
94 /* Memory access messages. */
95 HVMSG_UNMAPPED_GPA = 0x80000000,
96 HVMSG_GPA_INTERCEPT = 0x80000001,
97
98 /* Timer notification messages. */
99 HVMSG_TIMER_EXPIRED = 0x80000010,
100
101 /* Error messages. */
102 HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020,
103 HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021,
104 HVMSG_UNSUPPORTED_FEATURE = 0x80000022,
105
106 /* Trace buffer complete messages. */
107 HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040,
108
109 /* Platform-specific processor intercept messages. */
110 HVMSG_X64_IOPORT_INTERCEPT = 0x80010000,
111 HVMSG_X64_MSR_INTERCEPT = 0x80010001,
112 HVMSG_X64_CPUID_INTERCEPT = 0x80010002,
113 HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003,
114 HVMSG_X64_APIC_EOI = 0x80010004,
115 HVMSG_X64_LEGACY_FP_ERROR = 0x80010005
116 };
117
118 /* Define synthetic interrupt controller message flags. */
119 union hv_message_flags {
120 uint8_t asu8;
121 struct {
122 uint8_t msg_pending:1;
123 uint8_t reserved:7;
124 };
125 };
126
127 union hv_port_id {
128 uint32_t asu32;
129 struct {
130 uint32_t id:24;
131 uint32_t reserved:8;
132 } u;
133 };
134
135 /* Define port type. */
136 enum hv_port_type {
137 HVPORT_MSG = 1,
138 HVPORT_EVENT = 2,
139 HVPORT_MONITOR = 3
140 };
141
142 /* Define synthetic interrupt controller message header. */
143 struct hv_message_header {
144 uint32_t message_type;
145 uint8_t payload_size;
146 union hv_message_flags message_flags;
147 uint8_t reserved[2];
148 union {
149 uint64_t sender;
150 union hv_port_id port;
151 };
152 };
153
154 /* Define timer message payload structure. */
155 struct hv_timer_message_payload {
156 uint32_t timer_index;
157 uint32_t reserved;
158 uint64_t expiration_time; /* When the timer expired */
159 uint64_t delivery_time; /* When the message was delivered */
160 };
161
162 /* Define synthetic interrupt controller message format. */
163 struct hv_message {
164 struct hv_message_header header;
165 union {
166 uint64_t payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
167 } u;
168 };
169
170 /* Define the synthetic interrupt message page layout. */
171 struct hv_message_page {
172 struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
173 };
174
175 #define HV_EVENT_FLAGS_COUNT (256 * 8)
176
177 struct hv_event_flags {
178 ulong flags[HV_EVENT_FLAGS_COUNT / (8 * sizeof(ulong))];
179 };
180
181 struct hv_event_flags_page {
182 struct hv_event_flags slot[HV_SYNIC_SINT_COUNT];
183 };
184
185 #define HV_X64_MSR_HYPERCALL_ENABLE 0x1
186
187 #define HV_HYPERCALL_FAST (1u << 16)
188
189 #define HVCALL_POST_MESSAGE 0x5c
190 #define HVCALL_SIGNAL_EVENT 0x5d
191
192 struct hv_input_post_message {
193 u32 connectionid;
194 u32 reserved;
195 u32 message_type;
196 u32 payload_size;
197 u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
198 };
199
hv_synic_supported(void)200 static inline bool hv_synic_supported(void)
201 {
202 return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_SYNIC_AVAILABLE;
203 }
204
hv_stimer_supported(void)205 static inline bool hv_stimer_supported(void)
206 {
207 return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_SYNTIMER_AVAILABLE;
208 }
209
stimer_direct_supported(void)210 static inline bool stimer_direct_supported(void)
211 {
212 return cpuid(HYPERV_CPUID_FEATURES).d & HV_STIMER_DIRECT_MODE_AVAILABLE;
213 }
214
hv_time_ref_counter_supported(void)215 static inline bool hv_time_ref_counter_supported(void)
216 {
217 return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE;
218 }
219
220 void synic_sint_create(u8 sint, u8 vec, bool auto_eoi);
221 void synic_sint_set(u8 vcpu, u8 sint);
222 void synic_sint_destroy(u8 sint);
223 void msg_conn_create(u8 sint, u8 vec, u8 conn_id);
224 void msg_conn_destroy(u8 sint, u8 conn_id);
225 void evt_conn_create(u8 sint, u8 vec, u8 conn_id);
226 void evt_conn_destroy(u8 sint, u8 conn_id);
227
228 struct hv_reference_tsc_page {
229 uint32_t tsc_sequence;
230 uint32_t res1;
231 uint64_t tsc_scale;
232 int64_t tsc_offset;
233 };
234
235
236 #endif
237