[hyperv] Check for required features
[ipxe.git] / src / arch / x86 / drivers / hyperv / hyperv.c
1 /*
2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 /** @file
23 *
24 * Hyper-V driver
25 *
26 */
27
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <assert.h>
33 #include <errno.h>
34 #include <byteswap.h>
35 #include <pic8259.h>
36 #include <ipxe/malloc.h>
37 #include <ipxe/device.h>
38 #include <ipxe/cpuid.h>
39 #include <ipxe/msr.h>
40 #include <ipxe/hyperv.h>
41 #include <ipxe/vmbus.h>
42 #include "hyperv.h"
43
44 /** Maximum time to wait for a message response
45 *
46 * This is a policy decision.
47 */
48 #define HV_MESSAGE_MAX_WAIT_MS 1000
49
50 /**
51 * Convert a Hyper-V status code to an iPXE status code
52 *
53 * @v status Hyper-V status code
54 * @ret rc iPXE status code (before negation)
55 */
56 #define EHV( status ) EPLATFORM ( EINFO_EPLATFORM, (status) )
57
58 /**
59 * Allocate zeroed pages
60 *
61 * @v hv Hyper-V hypervisor
62 * @v ... Page addresses to fill in, terminated by NULL
63 * @ret rc Return status code
64 */
65 __attribute__ (( sentinel )) int
66 hv_alloc_pages ( struct hv_hypervisor *hv, ... ) {
67 va_list args;
68 void **page;
69 int i;
70
71 /* Allocate and zero pages */
72 va_start ( args, hv );
73 for ( i = 0 ; ( ( page = va_arg ( args, void ** ) ) != NULL ); i++ ) {
74 *page = malloc_dma ( PAGE_SIZE, PAGE_SIZE );
75 if ( ! *page )
76 goto err_alloc;
77 memset ( *page, 0, PAGE_SIZE );
78 }
79 va_end ( args );
80
81 return 0;
82
83 err_alloc:
84 va_end ( args );
85 va_start ( args, hv );
86 for ( ; i >= 0 ; i-- ) {
87 page = va_arg ( args, void ** );
88 free_dma ( *page, PAGE_SIZE );
89 }
90 va_end ( args );
91 return -ENOMEM;
92 }
93
94 /**
95 * Free pages
96 *
97 * @v hv Hyper-V hypervisor
98 * @v ... Page addresses, terminated by NULL
99 */
100 __attribute__ (( sentinel )) void
101 hv_free_pages ( struct hv_hypervisor *hv, ... ) {
102 va_list args;
103 void *page;
104
105 va_start ( args, hv );
106 while ( ( page = va_arg ( args, void * ) ) != NULL )
107 free_dma ( page, PAGE_SIZE );
108 va_end ( args );
109 }
110
111 /**
112 * Allocate message buffer
113 *
114 * @v hv Hyper-V hypervisor
115 * @ret rc Return status code
116 */
117 static int hv_alloc_message ( struct hv_hypervisor *hv ) {
118
119 /* Allocate buffer. Must be aligned to at least 8 bytes and
120 * must not cross a page boundary, so align on its own size.
121 */
122 hv->message = malloc_dma ( sizeof ( *hv->message ),
123 sizeof ( *hv->message ) );
124 if ( ! hv->message )
125 return -ENOMEM;
126
127 return 0;
128 }
129
130 /**
131 * Free message buffer
132 *
133 * @v hv Hyper-V hypervisor
134 */
135 static void hv_free_message ( struct hv_hypervisor *hv ) {
136
137 /* Free buffer */
138 free_dma ( hv->message, sizeof ( *hv->message ) );
139 }
140
141 /**
142 * Check whether or not we are running in Hyper-V
143 *
144 * @v hv Hyper-V hypervisor
145 * @ret rc Return status code
146 */
147 static int hv_check_hv ( struct hv_hypervisor *hv ) {
148 struct x86_features features;
149 uint32_t interface_id;
150 uint32_t discard_ebx;
151 uint32_t discard_ecx;
152 uint32_t discard_edx;
153 uint32_t available;
154 uint32_t permissions;
155
156 /* Check for presence of a hypervisor (not necessarily Hyper-V) */
157 x86_features ( &features );
158 if ( ! ( features.intel.ecx & CPUID_FEATURES_INTEL_ECX_HYPERVISOR ) ) {
159 DBGC ( hv, "HV %p not running in a hypervisor\n", hv );
160 return -ENODEV;
161 }
162
163 /* Check that hypervisor is Hyper-V */
164 cpuid ( HV_CPUID_INTERFACE_ID, &interface_id, &discard_ebx,
165 &discard_ecx, &discard_edx );
166 if ( interface_id != HV_INTERFACE_ID ) {
167 DBGC ( hv, "HV %p not running in Hyper-V (interface ID "
168 "%#08x)\n", hv, interface_id );
169 return -ENODEV;
170 }
171
172 /* Check that required features and privileges are available */
173 cpuid ( HV_CPUID_FEATURES, &available, &permissions, &discard_ecx,
174 &discard_edx );
175 if ( ! ( available & HV_FEATURES_AVAIL_HYPERCALL_MSR ) ) {
176 DBGC ( hv, "HV %p has no hypercall MSRs (features %08x:%08x)\n",
177 hv, available, permissions );
178 return -ENODEV;
179 }
180 if ( ! ( available & HV_FEATURES_AVAIL_SYNIC_MSR ) ) {
181 DBGC ( hv, "HV %p has no SynIC MSRs (features %08x:%08x)\n",
182 hv, available, permissions );
183 return -ENODEV;
184 }
185 if ( ! ( permissions & HV_FEATURES_PERM_POST_MESSAGES ) ) {
186 DBGC ( hv, "HV %p cannot post messages (features %08x:%08x)\n",
187 hv, available, permissions );
188 return -EACCES;
189 }
190 if ( ! ( permissions & HV_FEATURES_PERM_SIGNAL_EVENTS ) ) {
191 DBGC ( hv, "HV %p cannot signal events (features %08x:%08x)",
192 hv, available, permissions );
193 return -EACCES;
194 }
195
196 return 0;
197 }
198
199 /**
200 * Map hypercall page
201 *
202 * @v hv Hyper-V hypervisor
203 * @ret rc Return status code
204 */
205 static int hv_map_hypercall ( struct hv_hypervisor *hv ) {
206 union {
207 struct {
208 uint32_t ebx;
209 uint32_t ecx;
210 uint32_t edx;
211 } __attribute__ (( packed ));
212 char text[ 13 /* "bbbbccccdddd" + NUL */ ];
213 } vendor_id;
214 uint32_t build;
215 uint32_t version;
216 uint32_t discard_eax;
217 uint32_t discard_ecx;
218 uint32_t discard_edx;
219 uint64_t guest_os_id;
220 uint64_t hypercall;
221
222 /* Report guest OS identity */
223 guest_os_id = rdmsr ( HV_X64_MSR_GUEST_OS_ID );
224 if ( guest_os_id != 0 ) {
225 DBGC ( hv, "HV %p guest OS ID MSR already set to %#08llx\n",
226 hv, guest_os_id );
227 return -EBUSY;
228 }
229 guest_os_id = HV_GUEST_OS_ID_IPXE;
230 DBGC2 ( hv, "HV %p guest OS ID MSR is %#08llx\n", hv, guest_os_id );
231 wrmsr ( HV_X64_MSR_GUEST_OS_ID, guest_os_id );
232
233 /* Get hypervisor system identity (for debugging) */
234 cpuid ( HV_CPUID_VENDOR_ID, &discard_eax, &vendor_id.ebx,
235 &vendor_id.ecx, &vendor_id.edx );
236 vendor_id.text[ sizeof ( vendor_id.text ) - 1 ] = '\0';
237 cpuid ( HV_CPUID_HYPERVISOR_ID, &build, &version, &discard_ecx,
238 &discard_edx );
239 DBGC ( hv, "HV %p detected \"%s\" version %d.%d build %d\n", hv,
240 vendor_id.text, ( version >> 16 ), ( version & 0xffff ), build );
241
242 /* Map hypercall page */
243 hypercall = rdmsr ( HV_X64_MSR_HYPERCALL );
244 hypercall &= ( PAGE_SIZE - 1 );
245 hypercall |= ( virt_to_phys ( hv->hypercall ) | HV_HYPERCALL_ENABLE );
246 DBGC2 ( hv, "HV %p hypercall MSR is %#08llx\n", hv, hypercall );
247 wrmsr ( HV_X64_MSR_HYPERCALL, hypercall );
248
249 return 0;
250 }
251
252 /**
253 * Unmap hypercall page
254 *
255 * @v hv Hyper-V hypervisor
256 */
257 static void hv_unmap_hypercall ( struct hv_hypervisor *hv ) {
258 uint64_t hypercall;
259 uint64_t guest_os_id;
260
261 /* Unmap the hypercall page */
262 hypercall = rdmsr ( HV_X64_MSR_HYPERCALL );
263 hypercall &= ( ( PAGE_SIZE - 1 ) & ~HV_HYPERCALL_ENABLE );
264 DBGC2 ( hv, "HV %p hypercall MSR is %#08llx\n", hv, hypercall );
265 wrmsr ( HV_X64_MSR_HYPERCALL, hypercall );
266
267 /* Reset the guest OS identity */
268 guest_os_id = 0;
269 DBGC2 ( hv, "HV %p guest OS ID MSR is %#08llx\n", hv, guest_os_id );
270 wrmsr ( HV_X64_MSR_GUEST_OS_ID, guest_os_id );
271 }
272
273 /**
274 * Map synthetic interrupt controller
275 *
276 * @v hv Hyper-V hypervisor
277 * @ret rc Return status code
278 */
279 static int hv_map_synic ( struct hv_hypervisor *hv ) {
280 uint64_t simp;
281 uint64_t siefp;
282 uint64_t scontrol;
283
284 /* Map SynIC message page */
285 simp = rdmsr ( HV_X64_MSR_SIMP );
286 simp &= ( PAGE_SIZE - 1 );
287 simp |= ( virt_to_phys ( hv->synic.message ) | HV_SIMP_ENABLE );
288 DBGC2 ( hv, "HV %p SIMP MSR is %#08llx\n", hv, simp );
289 wrmsr ( HV_X64_MSR_SIMP, simp );
290
291 /* Map SynIC event page */
292 siefp = rdmsr ( HV_X64_MSR_SIEFP );
293 siefp &= ( PAGE_SIZE - 1 );
294 siefp |= ( virt_to_phys ( hv->synic.event ) | HV_SIEFP_ENABLE );
295 DBGC2 ( hv, "HV %p SIEFP MSR is %#08llx\n", hv, siefp );
296 wrmsr ( HV_X64_MSR_SIEFP, siefp );
297
298 /* Enable SynIC */
299 scontrol = rdmsr ( HV_X64_MSR_SCONTROL );
300 scontrol |= HV_SCONTROL_ENABLE;
301 DBGC2 ( hv, "HV %p SCONTROL MSR is %#08llx\n", hv, scontrol );
302 wrmsr ( HV_X64_MSR_SCONTROL, scontrol );
303
304 return 0;
305 }
306
307 /**
308 * Unmap synthetic interrupt controller
309 *
310 * @v hv Hyper-V hypervisor
311 */
312 static void hv_unmap_synic ( struct hv_hypervisor *hv ) {
313 uint64_t scontrol;
314 uint64_t siefp;
315 uint64_t simp;
316
317 /* Disable SynIC */
318 scontrol = rdmsr ( HV_X64_MSR_SCONTROL );
319 scontrol &= ~HV_SCONTROL_ENABLE;
320 DBGC2 ( hv, "HV %p SCONTROL MSR is %#08llx\n", hv, scontrol );
321 wrmsr ( HV_X64_MSR_SCONTROL, scontrol );
322
323 /* Unmap SynIC event page */
324 siefp = rdmsr ( HV_X64_MSR_SIEFP );
325 siefp &= ( ( PAGE_SIZE - 1 ) & ~HV_SIEFP_ENABLE );
326 DBGC2 ( hv, "HV %p SIEFP MSR is %#08llx\n", hv, siefp );
327 wrmsr ( HV_X64_MSR_SIEFP, siefp );
328
329 /* Unmap SynIC message page */
330 simp = rdmsr ( HV_X64_MSR_SIMP );
331 simp &= ( ( PAGE_SIZE - 1 ) & ~HV_SIMP_ENABLE );
332 DBGC2 ( hv, "HV %p SIMP MSR is %#08llx\n", hv, simp );
333 wrmsr ( HV_X64_MSR_SIMP, simp );
334 }
335
336 /**
337 * Enable synthetic interrupt
338 *
339 * @v hv Hyper-V hypervisor
340 * @v sintx Synthetic interrupt number
341 */
342 void hv_enable_sint ( struct hv_hypervisor *hv, unsigned int sintx ) {
343 unsigned long msr = HV_X64_MSR_SINT ( sintx );
344 uint64_t sint;
345
346 /* Enable synthetic interrupt
347 *
348 * We have to enable the interrupt, otherwise messages will
349 * not be delivered (even though the documentation implies
350 * that polling for messages is possible). We enable AutoEOI
351 * and hook the interrupt to the obsolete IRQ13 (FPU
352 * exception) vector, which will be implemented as a no-op.
353 */
354 sint = rdmsr ( msr );
355 sint &= ~( HV_SINT_MASKED | HV_SINT_VECTOR_MASK );
356 sint |= ( HV_SINT_AUTO_EOI |
357 HV_SINT_VECTOR ( IRQ_INT ( 13 /* See comment above */ ) ) );
358 DBGC2 ( hv, "HV %p SINT%d MSR is %#08llx\n", hv, sintx, sint );
359 wrmsr ( msr, sint );
360 }
361
362 /**
363 * Disable synthetic interrupt
364 *
365 * @v hv Hyper-V hypervisor
366 * @v sintx Synthetic interrupt number
367 */
368 void hv_disable_sint ( struct hv_hypervisor *hv, unsigned int sintx ) {
369 unsigned long msr = HV_X64_MSR_SINT ( sintx );
370 uint64_t sint;
371
372 /* Disable synthetic interrupt */
373 sint = rdmsr ( msr );
374 sint &= ~HV_SINT_AUTO_EOI;
375 sint |= HV_SINT_MASKED;
376 DBGC2 ( hv, "HV %p SINT%d MSR is %#08llx\n", hv, sintx, sint );
377 wrmsr ( msr, sint );
378 }
379
380 /**
381 * Post message
382 *
383 * @v hv Hyper-V hypervisor
384 * @v id Connection ID
385 * @v type Message type
386 * @v data Message
387 * @v len Length of message
388 * @ret rc Return status code
389 */
390 int hv_post_message ( struct hv_hypervisor *hv, unsigned int id,
391 unsigned int type, const void *data, size_t len ) {
392 struct hv_post_message *msg = &hv->message->posted;
393 int status;
394 int rc;
395
396 /* Sanity check */
397 assert ( len <= sizeof ( msg->data ) );
398
399 /* Construct message */
400 memset ( msg, 0, sizeof ( *msg ) );
401 msg->id = cpu_to_le32 ( id );
402 msg->type = cpu_to_le32 ( type );
403 msg->len = cpu_to_le32 ( len );
404 memcpy ( msg->data, data, len );
405 DBGC2 ( hv, "HV %p connection %d posting message type %#08x:\n",
406 hv, id, type );
407 DBGC2_HDA ( hv, 0, msg->data, len );
408
409 /* Post message */
410 if ( ( status = hv_call ( hv, HV_POST_MESSAGE, msg, NULL ) ) != 0 ) {
411 rc = -EHV ( status );
412 DBGC ( hv, "HV %p could not post message to %#08x: %s\n",
413 hv, id, strerror ( rc ) );
414 return rc;
415 }
416
417 return 0;
418 }
419
420 /**
421 * Wait for received message
422 *
423 * @v hv Hyper-V hypervisor
424 * @v sintx Synthetic interrupt number
425 * @ret rc Return status code
426 */
427 int hv_wait_for_message ( struct hv_hypervisor *hv, unsigned int sintx ) {
428 struct hv_message *msg = &hv->message->received;
429 struct hv_message *src = &hv->synic.message[sintx];
430 unsigned int retries;
431 size_t len;
432
433 /* Wait for message to arrive */
434 for ( retries = 0 ; retries < HV_MESSAGE_MAX_WAIT_MS ; retries++ ) {
435
436 /* Check for message */
437 if ( src->type ) {
438
439 /* Copy message */
440 memset ( msg, 0, sizeof ( *msg ) );
441 len = src->len;
442 assert ( len <= sizeof ( *msg ) );
443 memcpy ( msg, src,
444 ( offsetof ( typeof ( *msg ), data ) + len ) );
445 DBGC2 ( hv, "HV %p SINT%d received message type "
446 "%#08x:\n", hv, sintx,
447 le32_to_cpu ( msg->type ) );
448 DBGC2_HDA ( hv, 0, msg->data, len );
449
450 /* Consume message */
451 src->type = 0;
452
453 return 0;
454 }
455
456 /* Trigger message delivery */
457 wrmsr ( HV_X64_MSR_EOM, 0 );
458
459 /* Delay */
460 mdelay ( 1 );
461 }
462
463 DBGC ( hv, "HV %p SINT%d timed out waiting for message\n",
464 hv, sintx );
465 return -ETIMEDOUT;
466 }
467
468 /**
469 * Signal event
470 *
471 * @v hv Hyper-V hypervisor
472 * @v id Connection ID
473 * @v flag Flag number
474 * @ret rc Return status code
475 */
476 int hv_signal_event ( struct hv_hypervisor *hv, unsigned int id,
477 unsigned int flag ) {
478 struct hv_signal_event *event = &hv->message->signalled;
479 int status;
480 int rc;
481
482 /* Construct event */
483 memset ( event, 0, sizeof ( *event ) );
484 event->id = cpu_to_le32 ( id );
485 event->flag = cpu_to_le16 ( flag );
486
487 /* Signal event */
488 if ( ( status = hv_call ( hv, HV_SIGNAL_EVENT, event, NULL ) ) != 0 ) {
489 rc = -EHV ( status );
490 DBGC ( hv, "HV %p could not signal event to %#08x: %s\n",
491 hv, id, strerror ( rc ) );
492 return rc;
493 }
494
495 return 0;
496 }
497
498 /**
499 * Probe root device
500 *
501 * @v rootdev Root device
502 * @ret rc Return status code
503 */
504 static int hv_probe ( struct root_device *rootdev ) {
505 struct hv_hypervisor *hv;
506 int rc;
507
508 /* Allocate and initialise structure */
509 hv = zalloc ( sizeof ( *hv ) );
510 if ( ! hv ) {
511 rc = -ENOMEM;
512 goto err_alloc;
513 }
514
515 /* Check we are running in Hyper-V */
516 if ( ( rc = hv_check_hv ( hv ) ) != 0 )
517 goto err_check_hv;
518
519 /* Allocate pages */
520 if ( ( rc = hv_alloc_pages ( hv, &hv->hypercall, &hv->synic.message,
521 &hv->synic.event, NULL ) ) != 0 )
522 goto err_alloc_pages;
523
524 /* Allocate message buffer */
525 if ( ( rc = hv_alloc_message ( hv ) ) != 0 )
526 goto err_alloc_message;
527
528 /* Map hypercall page */
529 if ( ( rc = hv_map_hypercall ( hv ) ) != 0 )
530 goto err_map_hypercall;
531
532 /* Map synthetic interrupt controller */
533 if ( ( rc = hv_map_synic ( hv ) ) != 0 )
534 goto err_map_synic;
535
536 /* Probe Hyper-V devices */
537 if ( ( rc = vmbus_probe ( hv, &rootdev->dev ) ) != 0 )
538 goto err_vmbus_probe;
539
540 rootdev_set_drvdata ( rootdev, hv );
541 return 0;
542
543 vmbus_remove ( hv, &rootdev->dev );
544 err_vmbus_probe:
545 hv_unmap_synic ( hv );
546 err_map_synic:
547 hv_unmap_hypercall ( hv );
548 err_map_hypercall:
549 hv_free_message ( hv );
550 err_alloc_message:
551 hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event,
552 NULL );
553 err_alloc_pages:
554 err_check_hv:
555 free ( hv );
556 err_alloc:
557 return rc;
558 }
559
560 /**
561 * Remove root device
562 *
563 * @v rootdev Root device
564 */
565 static void hv_remove ( struct root_device *rootdev ) {
566 struct hv_hypervisor *hv = rootdev_get_drvdata ( rootdev );
567
568 vmbus_remove ( hv, &rootdev->dev );
569 hv_unmap_synic ( hv );
570 hv_unmap_hypercall ( hv );
571 hv_free_message ( hv );
572 hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event,
573 NULL );
574 free ( hv );
575 }
576
577 /** Hyper-V root device driver */
578 static struct root_driver hv_root_driver = {
579 .probe = hv_probe,
580 .remove = hv_remove,
581 };
582
583 /** Hyper-V root device */
584 struct root_device hv_root_device __root_device = {
585 .dev = { .name = "Hyper-V" },
586 .driver = &hv_root_driver,
587 };
588
589 /* Drag in netvsc driver */
590 REQUIRE_OBJECT ( netvsc );