1 #ifndef _IPXE_HYPERV_H
2 #define _IPXE_HYPERV_H
3 
4 /** @file
5  *
6  * Hyper-V interface
7  *
8  */
9 
10 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11 
12 #include <stdint.h>
13 #include <ipxe/io.h>
14 
15 /** Hyper-V interface identification */
16 #define HV_INTERFACE_ID 0x31237648 /* "Hv#1" */
17 
18 /** Guest OS identity for iPXE
19  *
20  * This field comprises:
21  *
22  * Bit  63    : set to 1 to indicate an open source OS
23  * Bits 62:56 : OS Type
24  * Bits 55:48 : OS ID
25  * Bits 47:16 : Version
26  * Bits 15:0  : Build number
27  *
28  * There appears to be no central registry for the "OS Type".  The
29  * specification states that "Linux is 0x100", and the FreeBSD source
30  * states that "FreeBSD is 0x200".  Both of these statements are
31  * actually referring to the combined "OS Type" and "OS ID" field.
32  *
33  * We choose to use 0x98ae: this is generated by setting bit 63 (to
34  * indicate an open source OS) and setting the OS Type+ID equal to the
35  * PnP vendor ID used in romprefix.S.  No version information or build
36  * number is included.
37  */
38 #define HV_GUEST_OS_ID_IPXE ( ( 1ULL << 63 ) | ( 0x18aeULL << 48 ) )
39 
40 /** Guest OS identity for Gen 2 UEFI firmware
41  *
42  * This does not conform to the documented structure for guest OS
43  * identities.
44  */
45 #define HV_GUEST_OS_ID_UEFI ( 1ULL << 40 )
46 
47 /** Enable hypercall page */
48 #define HV_HYPERCALL_ENABLE 0x00000001UL
49 
50 /** Enable SynIC */
51 #define HV_SCONTROL_ENABLE 0x00000001UL
52 
53 /** Enable SynIC event flags */
54 #define HV_SIEFP_ENABLE 0x00000001UL
55 
56 /** Enable SynIC messages */
57 #define HV_SIMP_ENABLE 0x00000001UL
58 
59 /** Perform implicit EOI upon synthetic interrupt delivery */
60 #define HV_SINT_AUTO_EOI 0x00020000UL
61 
62 /** Mask synthetic interrupt */
63 #define HV_SINT_MASKED 0x00010000UL
64 
65 /** Synthetic interrupt vector */
66 #define HV_SINT_VECTOR(x) ( (x) << 0 )
67 
68 /** Synthetic interrupt vector mask */
69 #define HV_SINT_VECTOR_MASK HV_SINT_VECTOR ( 0xff )
70 
71 /** Maximum synthetic interrupt number */
72 #define HV_SINT_MAX 15
73 
74 /** Post message */
75 #define HV_POST_MESSAGE 0x005c
76 
77 /** A posted message
78  *
79  * This is the input parameter list for the HvPostMessage hypercall.
80  */
81 struct hv_post_message {
82 	/** Connection ID */
83 	uint32_t id;
84 	/** Padding */
85 	uint32_t reserved;
86 	/** Type */
87 	uint32_t type;
88 	/** Length of message */
89 	uint32_t len;
90 	/** Message */
91 	uint8_t data[240];
92 } __attribute__ (( packed ));
93 
94 /** A received message
95  *
96  * This is the HV_MESSAGE structure from the Hypervisor Top-Level
97  * Functional Specification.  The field order given in the
98  * documentation is incorrect.
99  */
100 struct hv_message {
101 	/** Type */
102 	uint32_t type;
103 	/** Length of message */
104 	uint8_t len;
105 	/** Flags */
106 	uint8_t flags;
107 	/** Padding */
108 	uint16_t reserved;
109 	/** Origin */
110 	uint64_t origin;
111 	/** Message */
112 	uint8_t data[240];
113 } __attribute__ (( packed ));
114 
115 /** Signal event */
116 #define HV_SIGNAL_EVENT 0x005d
117 
118 /** A signalled event */
119 struct hv_signal_event {
120 	/** Connection ID */
121 	uint32_t id;
122 	/** Flag number */
123 	uint16_t flag;
124 	/** Reserved */
125 	uint16_t reserved;
126 } __attribute__ (( packed ));
127 
128 /** A received event */
129 struct hv_event {
130 	/** Event flags */
131 	uint8_t flags[256];
132 } __attribute__ (( packed ));
133 
134 /** A monitor trigger group
135  *
136  * This is the HV_MONITOR_TRIGGER_GROUP structure from the Hypervisor
137  * Top-Level Functional Specification.
138  */
139 struct hv_monitor_trigger {
140 	/** Pending events */
141 	uint32_t pending;
142 	/** Armed events */
143 	uint32_t armed;
144 } __attribute__ (( packed ));
145 
146 /** A monitor parameter set
147  *
148  * This is the HV_MONITOR_PARAMETER structure from the Hypervisor
149  * Top-Level Functional Specification.
150  */
151 struct hv_monitor_parameter {
152 	/** Connection ID */
153 	uint32_t id;
154 	/** Flag number */
155 	uint16_t flag;
156 	/** Reserved */
157 	uint16_t reserved;
158 } __attribute__ (( packed ));
159 
160 /** A monitor page
161  *
162  * This is the HV_MONITOR_PAGE structure from the Hypervisor Top-Level
163  * Functional Specification.
164  */
165 struct hv_monitor {
166 	/** Flags */
167 	uint32_t flags;
168 	/** Reserved */
169 	uint8_t reserved_a[4];
170 	/** Trigger groups */
171 	struct hv_monitor_trigger trigger[4];
172 	/** Reserved */
173 	uint8_t reserved_b[536];
174 	/** Latencies */
175 	uint16 latency[4][32];
176 	/** Reserved */
177 	uint8_t reserved_c[256];
178 	/** Parameters */
179 	struct hv_monitor_parameter param[4][32];
180 	/** Reserved */
181 	uint8_t reserved_d[1984];
182 } __attribute__ (( packed ));
183 
184 /** A synthetic interrupt controller */
185 struct hv_synic {
186 	/** Message page */
187 	struct hv_message *message;
188 	/** Event flag page */
189 	struct hv_event *event;
190 };
191 
192 /** A message buffer */
193 union hv_message_buffer {
194 	/** Posted message */
195 	struct hv_post_message posted;
196 	/** Received message */
197 	struct hv_message received;
198 	/** Signalled event */
199 	struct hv_signal_event signalled;
200 };
201 
202 /** A Hyper-V hypervisor */
203 struct hv_hypervisor {
204 	/** Hypercall page */
205 	void *hypercall;
206 	/** Synthetic interrupt controller (SynIC) */
207 	struct hv_synic synic;
208 	/** Message buffer */
209 	union hv_message_buffer *message;
210 	/** Virtual machine bus */
211 	struct vmbus *vmbus;
212 };
213 
214 #include <bits/hyperv.h>
215 
216 /**
217  * Calculate the number of pages covering an address range
218  *
219  * @v data		Start of data
220  * @v len		Length of data (must be non-zero)
221  * @ret pfn_count	Number of pages covered
222  */
hv_pfn_count(physaddr_t data,size_t len)223 static inline unsigned int hv_pfn_count ( physaddr_t data, size_t len ) {
224 	unsigned int first_pfn = ( data / PAGE_SIZE );
225 	unsigned int last_pfn = ( ( data + len - 1 ) / PAGE_SIZE );
226 
227 	return ( last_pfn - first_pfn + 1 );
228 }
229 
230 extern __attribute__ (( sentinel )) int
231 hv_alloc_pages ( struct hv_hypervisor *hv, ... );
232 extern __attribute__ (( sentinel )) void
233 hv_free_pages ( struct hv_hypervisor *hv, ... );
234 extern void hv_enable_sint ( struct hv_hypervisor *hv, unsigned int sintx );
235 extern void hv_disable_sint ( struct hv_hypervisor *hv, unsigned int sintx );
236 extern int hv_post_message ( struct hv_hypervisor *hv, unsigned int id,
237 			     unsigned int type, const void *data, size_t len );
238 extern int hv_wait_for_message ( struct hv_hypervisor *hv, unsigned int sintx );
239 extern int hv_signal_event ( struct hv_hypervisor *hv, unsigned int id,
240 			     unsigned int flag );
241 
242 #endif /* _IPXE_HYPERV_H */
243