File size: 7,320 Bytes
8df6da4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#ifndef __HYPERV_H
#define __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_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

#define HV_STIMER_ENABLE                (1ULL << 0)
#define HV_STIMER_PERIODIC              (1ULL << 1)
#define HV_STIMER_LAZY                  (1ULL << 2)
#define HV_STIMER_AUTOENABLE            (1ULL << 3)
#define HV_STIMER_SINT(config)          (__u8)(((config) >> 16) & 0x0F)

#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 synic_supported(void)
{
   return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_SYNIC_AVAILABLE;
}

static inline bool stimer_supported(void)
{
    return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_SYNIC_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