iPXE
hyperv.c
Go to the documentation of this file.
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 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26/** @file
27 *
28 * Hyper-V driver
29 *
30 */
31
32#include <stdlib.h>
33#include <stdarg.h>
34#include <string.h>
35#include <unistd.h>
36#include <assert.h>
37#include <errno.h>
38#include <byteswap.h>
39#include <pic8259.h>
40#include <ipxe/malloc.h>
41#include <ipxe/device.h>
42#include <ipxe/timer.h>
43#include <ipxe/quiesce.h>
44#include <ipxe/cpuid.h>
45#include <ipxe/msr.h>
46#include <ipxe/hyperv.h>
47#include <ipxe/vmbus.h>
48#include "hyperv.h"
49
50/** Maximum time to wait for a message response
51 *
52 * This is a policy decision.
53 */
54#define HV_MESSAGE_MAX_WAIT_MS 1000
55
56/** Hyper-V timer frequency (fixed 10Mhz) */
57#define HV_TIMER_HZ 10000000
58
59/** Hyper-V timer scale factor (used to avoid 64-bit division) */
60#define HV_TIMER_SHIFT 18
61
62/**
63 * Convert a Hyper-V status code to an iPXE status code
64 *
65 * @v status Hyper-V status code
66 * @ret rc iPXE status code (before negation)
67 */
68#define EHV( status ) EPLATFORM ( EINFO_EPLATFORM, (status) )
69
70/**
71 * Allocate zeroed pages
72 *
73 * @v hv Hyper-V hypervisor
74 * @v ... Page addresses to fill in, terminated by NULL
75 * @ret rc Return status code
76 */
77__attribute__ (( sentinel )) int
78hv_alloc_pages ( struct hv_hypervisor *hv, ... ) {
79 va_list args;
80 void **page;
81 int i;
82
83 /* Allocate and zero pages */
84 va_start ( args, hv );
85 for ( i = 0 ; ( ( page = va_arg ( args, void ** ) ) != NULL ); i++ ) {
86 *page = malloc_phys ( PAGE_SIZE, PAGE_SIZE );
87 if ( ! *page )
88 goto err_alloc;
89 memset ( *page, 0, PAGE_SIZE );
90 }
91 va_end ( args );
92
93 return 0;
94
95 err_alloc:
96 va_end ( args );
97 va_start ( args, hv );
98 for ( ; i >= 0 ; i-- ) {
99 page = va_arg ( args, void ** );
100 free_phys ( *page, PAGE_SIZE );
101 }
102 va_end ( args );
103 return -ENOMEM;
104}
105
106/**
107 * Free pages
108 *
109 * @v hv Hyper-V hypervisor
110 * @v ... Page addresses, terminated by NULL
111 */
112__attribute__ (( sentinel )) void
113hv_free_pages ( struct hv_hypervisor *hv, ... ) {
114 va_list args;
115 void *page;
116
117 va_start ( args, hv );
118 while ( ( page = va_arg ( args, void * ) ) != NULL )
119 free_phys ( page, PAGE_SIZE );
120 va_end ( args );
121}
122
123/**
124 * Allocate message buffer
125 *
126 * @v hv Hyper-V hypervisor
127 * @ret rc Return status code
128 */
129static int hv_alloc_message ( struct hv_hypervisor *hv ) {
130
131 /* Allocate buffer. Must be aligned to at least 8 bytes and
132 * must not cross a page boundary, so align on its own size.
133 */
134 hv->message = malloc_phys ( sizeof ( *hv->message ),
135 sizeof ( *hv->message ) );
136 if ( ! hv->message )
137 return -ENOMEM;
138
139 return 0;
140}
141
142/**
143 * Free message buffer
144 *
145 * @v hv Hyper-V hypervisor
146 */
147static void hv_free_message ( struct hv_hypervisor *hv ) {
148
149 /* Free buffer */
150 free_phys ( hv->message, sizeof ( *hv->message ) );
151}
152
153/**
154 * Check whether or not we are running in Hyper-V
155 *
156 * @ret rc Return status code
157 */
158static int hv_check_hv ( void ) {
159 struct x86_features features;
160 uint32_t interface_id;
161 uint32_t discard_ebx;
164
165 /* Check for presence of a hypervisor (not necessarily Hyper-V) */
167 if ( ! ( features.intel.ecx & CPUID_FEATURES_INTEL_ECX_HYPERVISOR ) ) {
168 DBGC ( HV_INTERFACE_ID, "HV not running in a hypervisor\n" );
169 return -ENODEV;
170 }
171
172 /* Check that hypervisor is Hyper-V */
173 cpuid ( HV_CPUID_INTERFACE_ID, 0, &interface_id, &discard_ebx,
175 if ( interface_id != HV_INTERFACE_ID ) {
176 DBGC ( HV_INTERFACE_ID, "HV not running in Hyper-V (interface "
177 "ID %#08x)\n", interface_id );
178 return -ENODEV;
179 }
180
181 return 0;
182}
183
184/**
185 * Check required features
186 *
187 * @v hv Hyper-V hypervisor
188 * @ret rc Return status code
189 */
190static int hv_check_features ( struct hv_hypervisor *hv ) {
191 uint32_t available;
192 uint32_t permissions;
195
196 /* Check that required features and privileges are available */
197 cpuid ( HV_CPUID_FEATURES, 0, &available, &permissions, &discard_ecx,
198 &discard_edx );
199 if ( ! ( available & HV_FEATURES_AVAIL_HYPERCALL_MSR ) ) {
200 DBGC ( hv, "HV %p has no hypercall MSRs (features %08x:%08x)\n",
201 hv, available, permissions );
202 return -ENODEV;
203 }
204 if ( ! ( available & HV_FEATURES_AVAIL_SYNIC_MSR ) ) {
205 DBGC ( hv, "HV %p has no SynIC MSRs (features %08x:%08x)\n",
206 hv, available, permissions );
207 return -ENODEV;
208 }
209 if ( ! ( permissions & HV_FEATURES_PERM_POST_MESSAGES ) ) {
210 DBGC ( hv, "HV %p cannot post messages (features %08x:%08x)\n",
211 hv, available, permissions );
212 return -EACCES;
213 }
214 if ( ! ( permissions & HV_FEATURES_PERM_SIGNAL_EVENTS ) ) {
215 DBGC ( hv, "HV %p cannot signal events (features %08x:%08x)",
216 hv, available, permissions );
217 return -EACCES;
218 }
219
220 return 0;
221}
222
223/**
224 * Check that Gen 2 UEFI firmware is not running
225 *
226 * @v hv Hyper-V hypervisor
227 * @ret rc Return status code
228 *
229 * We must not steal ownership from the Gen 2 UEFI firmware, since
230 * doing so will cause an immediate crash. Avoid this by checking for
231 * the guest OS identity known to be used by the Gen 2 UEFI firmware.
232 */
233static int hv_check_uefi ( struct hv_hypervisor *hv ) {
234 uint64_t guest_os_id;
235
236 /* Check for UEFI firmware's guest OS identity */
237 guest_os_id = rdmsr ( HV_X64_MSR_GUEST_OS_ID );
238 if ( guest_os_id == HV_GUEST_OS_ID_UEFI ) {
239 DBGC ( hv, "HV %p is owned by UEFI firmware\n", hv );
240 return -ENOTSUP;
241 }
242
243 return 0;
244}
245
246/**
247 * Map hypercall page
248 *
249 * @v hv Hyper-V hypervisor
250 */
251static void hv_map_hypercall ( struct hv_hypervisor *hv ) {
252 union {
253 struct {
257 } __attribute__ (( packed ));
258 char text[ 13 /* "bbbbccccdddd" + NUL */ ];
259 } vendor_id;
260 uint32_t build;
262 uint32_t discard_eax;
265 uint64_t guest_os_id;
267
268 /* Report guest OS identity */
269 guest_os_id = rdmsr ( HV_X64_MSR_GUEST_OS_ID );
270 if ( guest_os_id != 0 ) {
271 DBGC ( hv, "HV %p guest OS ID MSR was %#08llx\n",
272 hv, guest_os_id );
273 }
274 guest_os_id = HV_GUEST_OS_ID_IPXE;
275 DBGC2 ( hv, "HV %p guest OS ID MSR is %#08llx\n", hv, guest_os_id );
276 wrmsr ( HV_X64_MSR_GUEST_OS_ID, guest_os_id );
277
278 /* Get hypervisor system identity (for debugging) */
279 cpuid ( HV_CPUID_VENDOR_ID, 0, &discard_eax, &vendor_id.ebx,
280 &vendor_id.ecx, &vendor_id.edx );
281 vendor_id.text[ sizeof ( vendor_id.text ) - 1 ] = '\0';
282 cpuid ( HV_CPUID_HYPERVISOR_ID, 0, &build, &version, &discard_ecx,
283 &discard_edx );
284 DBGC ( hv, "HV %p detected \"%s\" version %d.%d build %d\n", hv,
285 vendor_id.text, ( version >> 16 ), ( version & 0xffff ), build );
286
287 /* Map hypercall page */
289 hypercall &= ( PAGE_SIZE - 1 );
290 hypercall |= ( virt_to_phys ( hv->hypercall ) | HV_HYPERCALL_ENABLE );
291 DBGC2 ( hv, "HV %p hypercall MSR is %#08llx\n", hv, hypercall );
293}
294
295/**
296 * Unmap hypercall page
297 *
298 * @v hv Hyper-V hypervisor
299 */
300static void hv_unmap_hypercall ( struct hv_hypervisor *hv ) {
302 uint64_t guest_os_id;
303
304 /* Unmap the hypercall page */
307 DBGC2 ( hv, "HV %p hypercall MSR is %#08llx\n", hv, hypercall );
309
310 /* Reset the guest OS identity */
311 guest_os_id = 0;
312 DBGC2 ( hv, "HV %p guest OS ID MSR is %#08llx\n", hv, guest_os_id );
313 wrmsr ( HV_X64_MSR_GUEST_OS_ID, guest_os_id );
314}
315
316/**
317 * Map synthetic interrupt controller
318 *
319 * @v hv Hyper-V hypervisor
320 */
321static void hv_map_synic ( struct hv_hypervisor *hv ) {
322 uint64_t simp;
323 uint64_t siefp;
324 uint64_t scontrol;
325
326 /* Zero SynIC message and event pages */
327 memset ( hv->synic.message, 0, PAGE_SIZE );
328 memset ( hv->synic.event, 0, PAGE_SIZE );
329
330 /* Map SynIC message page */
331 simp = rdmsr ( HV_X64_MSR_SIMP );
332 simp &= ( PAGE_SIZE - 1 );
333 simp |= ( virt_to_phys ( hv->synic.message ) | HV_SIMP_ENABLE );
334 DBGC2 ( hv, "HV %p SIMP MSR is %#08llx\n", hv, simp );
335 wrmsr ( HV_X64_MSR_SIMP, simp );
336
337 /* Map SynIC event page */
338 siefp = rdmsr ( HV_X64_MSR_SIEFP );
339 siefp &= ( PAGE_SIZE - 1 );
340 siefp |= ( virt_to_phys ( hv->synic.event ) | HV_SIEFP_ENABLE );
341 DBGC2 ( hv, "HV %p SIEFP MSR is %#08llx\n", hv, siefp );
342 wrmsr ( HV_X64_MSR_SIEFP, siefp );
343
344 /* Enable SynIC */
345 scontrol = rdmsr ( HV_X64_MSR_SCONTROL );
346 scontrol |= HV_SCONTROL_ENABLE;
347 DBGC2 ( hv, "HV %p SCONTROL MSR is %#08llx\n", hv, scontrol );
348 wrmsr ( HV_X64_MSR_SCONTROL, scontrol );
349}
350
351/**
352 * Unmap synthetic interrupt controller, leaving SCONTROL untouched
353 *
354 * @v hv Hyper-V hypervisor
355 */
356static void hv_unmap_synic_no_scontrol ( struct hv_hypervisor *hv ) {
357 uint64_t siefp;
358 uint64_t simp;
359
360 /* Unmap SynIC event page */
361 siefp = rdmsr ( HV_X64_MSR_SIEFP );
362 siefp &= ( ( PAGE_SIZE - 1 ) & ~HV_SIEFP_ENABLE );
363 DBGC2 ( hv, "HV %p SIEFP MSR is %#08llx\n", hv, siefp );
364 wrmsr ( HV_X64_MSR_SIEFP, siefp );
365
366 /* Unmap SynIC message page */
367 simp = rdmsr ( HV_X64_MSR_SIMP );
368 simp &= ( ( PAGE_SIZE - 1 ) & ~HV_SIMP_ENABLE );
369 DBGC2 ( hv, "HV %p SIMP MSR is %#08llx\n", hv, simp );
370 wrmsr ( HV_X64_MSR_SIMP, simp );
371}
372
373/**
374 * Unmap synthetic interrupt controller
375 *
376 * @v hv Hyper-V hypervisor
377 */
378static void hv_unmap_synic ( struct hv_hypervisor *hv ) {
379 uint64_t scontrol;
380
381 /* Disable SynIC */
382 scontrol = rdmsr ( HV_X64_MSR_SCONTROL );
383 scontrol &= ~HV_SCONTROL_ENABLE;
384 DBGC2 ( hv, "HV %p SCONTROL MSR is %#08llx\n", hv, scontrol );
385 wrmsr ( HV_X64_MSR_SCONTROL, scontrol );
386
387 /* Unmap SynIC event and message pages */
389}
390
391/**
392 * Enable synthetic interrupt
393 *
394 * @v hv Hyper-V hypervisor
395 * @v sintx Synthetic interrupt number
396 */
397void hv_enable_sint ( struct hv_hypervisor *hv, unsigned int sintx ) {
398 unsigned long msr = HV_X64_MSR_SINT ( sintx );
399 uint64_t sint;
400
401 /* Enable synthetic interrupt
402 *
403 * We have to enable the interrupt, otherwise messages will
404 * not be delivered (even though the documentation implies
405 * that polling for messages is possible). We enable AutoEOI
406 * and hook the interrupt to the obsolete IRQ13 (FPU
407 * exception) vector, which will be implemented as a no-op.
408 */
409 sint = rdmsr ( msr );
410 sint &= ~( HV_SINT_MASKED | HV_SINT_VECTOR_MASK );
411 sint |= ( HV_SINT_AUTO_EOI |
412 HV_SINT_VECTOR ( IRQ_INT ( 13 /* See comment above */ ) ) );
413 DBGC2 ( hv, "HV %p SINT%d MSR is %#08llx\n", hv, sintx, sint );
414 wrmsr ( msr, sint );
415}
416
417/**
418 * Disable synthetic interrupt
419 *
420 * @v hv Hyper-V hypervisor
421 * @v sintx Synthetic interrupt number
422 */
423void hv_disable_sint ( struct hv_hypervisor *hv, unsigned int sintx ) {
424 unsigned long msr = HV_X64_MSR_SINT ( sintx );
425 uint64_t sint;
426
427 /* Do nothing if interrupt is already disabled */
428 sint = rdmsr ( msr );
429 if ( sint & HV_SINT_MASKED )
430 return;
431
432 /* Disable synthetic interrupt */
433 sint &= ~HV_SINT_AUTO_EOI;
434 sint |= HV_SINT_MASKED;
435 DBGC2 ( hv, "HV %p SINT%d MSR is %#08llx\n", hv, sintx, sint );
436 wrmsr ( msr, sint );
437}
438
439/**
440 * Post message
441 *
442 * @v hv Hyper-V hypervisor
443 * @v id Connection ID
444 * @v type Message type
445 * @v data Message
446 * @v len Length of message
447 * @ret rc Return status code
448 */
449int hv_post_message ( struct hv_hypervisor *hv, unsigned int id,
450 unsigned int type, const void *data, size_t len ) {
451 struct hv_post_message *msg = &hv->message->posted;
452 int status;
453 int rc;
454
455 /* Sanity check */
456 assert ( len <= sizeof ( msg->data ) );
457
458 /* Construct message */
459 memset ( msg, 0, sizeof ( *msg ) );
460 msg->id = cpu_to_le32 ( id );
461 msg->type = cpu_to_le32 ( type );
462 msg->len = cpu_to_le32 ( len );
463 memcpy ( msg->data, data, len );
464 DBGC2 ( hv, "HV %p connection %d posting message type %#08x:\n",
465 hv, id, type );
466 DBGC2_HDA ( hv, 0, msg->data, len );
467
468 /* Post message */
469 if ( ( status = hv_call ( hv, HV_POST_MESSAGE, msg, NULL ) ) != 0 ) {
470 rc = -EHV ( status );
471 DBGC ( hv, "HV %p could not post message to %#08x: %s\n",
472 hv, id, strerror ( rc ) );
473 return rc;
474 }
475
476 return 0;
477}
478
479/**
480 * Wait for received message
481 *
482 * @v hv Hyper-V hypervisor
483 * @v sintx Synthetic interrupt number
484 * @ret rc Return status code
485 */
486int hv_wait_for_message ( struct hv_hypervisor *hv, unsigned int sintx ) {
487 struct hv_message *msg = &hv->message->received;
488 struct hv_message *src = &hv->synic.message[sintx];
489 unsigned int retries;
490 size_t len;
491
492 /* Wait for message to arrive */
493 for ( retries = 0 ; retries < HV_MESSAGE_MAX_WAIT_MS ; retries++ ) {
494
495 /* Check for message */
496 if ( src->type ) {
497
498 /* Copy message */
499 memset ( msg, 0, sizeof ( *msg ) );
500 len = src->len;
501 assert ( len <= sizeof ( *msg ) );
502 memcpy ( msg, src,
503 ( offsetof ( typeof ( *msg ), data ) + len ) );
504 DBGC2 ( hv, "HV %p SINT%d received message type "
505 "%#08x:\n", hv, sintx,
506 le32_to_cpu ( msg->type ) );
507 DBGC2_HDA ( hv, 0, msg->data, len );
508
509 /* Consume message */
510 src->type = 0;
511
512 return 0;
513 }
514
515 /* Trigger message delivery */
516 wrmsr ( HV_X64_MSR_EOM, 0 );
517
518 /* Delay */
519 mdelay ( 1 );
520 }
521
522 DBGC ( hv, "HV %p SINT%d timed out waiting for message\n",
523 hv, sintx );
524 return -ETIMEDOUT;
525}
526
527/**
528 * Signal event
529 *
530 * @v hv Hyper-V hypervisor
531 * @v id Connection ID
532 * @v flag Flag number
533 * @ret rc Return status code
534 */
535int hv_signal_event ( struct hv_hypervisor *hv, unsigned int id,
536 unsigned int flag ) {
537 struct hv_signal_event *event = &hv->message->signalled;
538 int status;
539 int rc;
540
541 /* Construct event */
542 memset ( event, 0, sizeof ( *event ) );
543 event->id = cpu_to_le32 ( id );
544 event->flag = cpu_to_le16 ( flag );
545
546 /* Signal event */
547 if ( ( status = hv_call ( hv, HV_SIGNAL_EVENT, event, NULL ) ) != 0 ) {
548 rc = -EHV ( status );
549 DBGC ( hv, "HV %p could not signal event to %#08x: %s\n",
550 hv, id, strerror ( rc ) );
551 return rc;
552 }
553
554 return 0;
555}
556
557/**
558 * Probe root device
559 *
560 * @v rootdev Root device
561 * @ret rc Return status code
562 */
563static int hv_probe ( struct root_device *rootdev ) {
564 struct hv_hypervisor *hv;
565 int rc;
566
567 /* Check we are running in Hyper-V */
568 if ( ( rc = hv_check_hv() ) != 0 )
569 goto err_check_hv;
570
571 /* Allocate and initialise structure */
572 hv = zalloc ( sizeof ( *hv ) );
573 if ( ! hv ) {
574 rc = -ENOMEM;
575 goto err_alloc;
576 }
577
578 /* Check features */
579 if ( ( rc = hv_check_features ( hv ) ) != 0 )
580 goto err_check_features;
581
582 /* Check that Gen 2 UEFI firmware is not running */
583 if ( ( rc = hv_check_uefi ( hv ) ) != 0 )
584 goto err_check_uefi;
585
586 /* Allocate pages */
587 if ( ( rc = hv_alloc_pages ( hv, &hv->hypercall, &hv->synic.message,
588 &hv->synic.event, NULL ) ) != 0 )
589 goto err_alloc_pages;
590
591 /* Allocate message buffer */
592 if ( ( rc = hv_alloc_message ( hv ) ) != 0 )
593 goto err_alloc_message;
594
595 /* Map hypercall page */
596 hv_map_hypercall ( hv );
597
598 /* Map synthetic interrupt controller */
599 hv_map_synic ( hv );
600
601 /* Probe Hyper-V devices */
602 if ( ( rc = vmbus_probe ( hv, &rootdev->dev ) ) != 0 )
603 goto err_vmbus_probe;
604
605 rootdev_set_drvdata ( rootdev, hv );
606 return 0;
607
608 vmbus_remove ( hv, &rootdev->dev );
609 err_vmbus_probe:
610 hv_unmap_synic ( hv );
611 hv_unmap_hypercall ( hv );
612 hv_free_message ( hv );
613 err_alloc_message:
614 hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event,
615 NULL );
616 err_alloc_pages:
617 err_check_uefi:
618 err_check_features:
619 free ( hv );
620 err_alloc:
621 err_check_hv:
622 return rc;
623}
624
625/**
626 * Remove root device
627 *
628 * @v rootdev Root device
629 */
630static void hv_remove ( struct root_device *rootdev ) {
631 struct hv_hypervisor *hv = rootdev_get_drvdata ( rootdev );
632
633 vmbus_remove ( hv, &rootdev->dev );
634 hv_unmap_synic ( hv );
635 hv_unmap_hypercall ( hv );
636 hv_free_message ( hv );
637 hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event,
638 NULL );
639 free ( hv );
640 rootdev_set_drvdata ( rootdev, NULL );
641}
642
643/** Hyper-V root device driver */
645 .probe = hv_probe,
646 .remove = hv_remove,
647};
648
649/** Hyper-V root device */
650struct root_device hv_root_device __root_device = {
651 .dev = { .name = "Hyper-V" },
652 .driver = &hv_root_driver,
653};
654
655/**
656 * Quiesce system
657 *
658 */
659static void hv_quiesce ( void ) {
660 struct hv_hypervisor *hv = rootdev_get_drvdata ( &hv_root_device );
661 unsigned int i;
662
663 /* Do nothing if we are not running in Hyper-V */
664 if ( ! hv )
665 return;
666
667 /* The "enlightened" portions of the Windows Server 2016 boot
668 * process will not cleanly take ownership of an active
669 * Hyper-V connection. Experimentation shows that the minimum
670 * requirement is that we disable the SynIC message page
671 * (i.e. zero the SIMP MSR).
672 *
673 * We cannot perform a full shutdown of the Hyper-V
674 * connection. Experimentation shows that if we disable the
675 * SynIC (i.e. zero the SCONTROL MSR) then Windows Server 2016
676 * will enter an indefinite wait loop.
677 *
678 * Attempt to create a safe handover environment by resetting
679 * all MSRs except for SCONTROL.
680 *
681 * Note that we do not shut down our VMBus devices, since we
682 * may need to unquiesce the system and continue operation.
683 */
684
685 /* Disable all synthetic interrupts */
686 for ( i = 0 ; i <= HV_SINT_MAX ; i++ )
687 hv_disable_sint ( hv, i );
688
689 /* Unmap synthetic interrupt controller, leaving SCONTROL
690 * enabled (see above).
691 */
693
694 /* Unmap hypercall page */
695 hv_unmap_hypercall ( hv );
696
697 DBGC ( hv, "HV %p quiesced\n", hv );
698}
699
700/**
701 * Unquiesce system
702 *
703 */
704static void hv_unquiesce ( void ) {
705 struct hv_hypervisor *hv = rootdev_get_drvdata ( &hv_root_device );
706 uint64_t simp;
707 int rc;
708
709 /* Do nothing if we are not running in Hyper-V */
710 if ( ! hv )
711 return;
712
713 /* Experimentation shows that the "enlightened" portions of
714 * Windows Server 2016 will break our Hyper-V connection at
715 * some point during a SAN boot. Surprisingly it does not
716 * change the guest OS ID MSR, but it does leave the SynIC
717 * message page disabled.
718 *
719 * Our own explicit quiescing procedure will also disable the
720 * SynIC message page. We can therefore use the SynIC message
721 * page enable bit as a heuristic to determine when we need to
722 * reestablish our Hyper-V connection.
723 */
724 simp = rdmsr ( HV_X64_MSR_SIMP );
725 if ( simp & HV_SIMP_ENABLE )
726 return;
727
728 /* Remap hypercall page */
729 hv_map_hypercall ( hv );
730
731 /* Remap synthetic interrupt controller */
732 hv_map_synic ( hv );
733
734 /* Reset Hyper-V devices */
735 if ( ( rc = vmbus_reset ( hv, &hv_root_device.dev ) ) != 0 ) {
736 DBGC ( hv, "HV %p could not unquiesce: %s\n",
737 hv, strerror ( rc ) );
738 /* Nothing we can do */
739 return;
740 }
741}
742
743/** Hyper-V quiescer */
744struct quiescer hv_quiescer __quiescer = {
745 .quiesce = hv_quiesce,
746 .unquiesce = hv_unquiesce,
747};
748
749/**
750 * Probe timer
751 *
752 * @ret rc Return status code
753 */
754static int hv_timer_probe ( void ) {
755 uint32_t available;
756 uint32_t discard_ebx;
759 int rc;
760
761 /* Check we are running in Hyper-V */
762 if ( ( rc = hv_check_hv() ) != 0 )
763 return rc;
764
765 /* Check for available reference counter */
766 cpuid ( HV_CPUID_FEATURES, 0, &available, &discard_ebx, &discard_ecx,
767 &discard_edx );
768 if ( ! ( available & HV_FEATURES_AVAIL_TIME_REF_COUNT_MSR ) ) {
769 DBGC ( HV_INTERFACE_ID, "HV has no time reference counter\n" );
770 return -ENODEV;
771 }
772
773 return 0;
774}
775
776/**
777 * Get current system time in ticks
778 *
779 * @ret ticks Current time, in ticks
780 */
781static unsigned long hv_currticks ( void ) {
782
783 /* Calculate time using a combination of bit shifts and
784 * multiplication (to avoid a 64-bit division).
785 */
786 return ( ( rdmsr ( HV_X64_MSR_TIME_REF_COUNT ) >> HV_TIMER_SHIFT ) *
788}
789
790/**
791 * Delay for a fixed number of microseconds
792 *
793 * @v usecs Number of microseconds for which to delay
794 */
795static void hv_udelay ( unsigned long usecs ) {
797 uint32_t elapsed;
798 uint32_t threshold;
799
800 /* Spin until specified number of 10MHz ticks have elapsed */
802 threshold = ( usecs * ( HV_TIMER_HZ / 1000000 ) );
803 do {
804 elapsed = ( rdmsr ( HV_X64_MSR_TIME_REF_COUNT ) - start );
805 } while ( elapsed < threshold );
806}
807
808/** Hyper-V timer */
809struct timer hv_timer __timer ( TIMER_PREFERRED ) = {
810 .name = "Hyper-V",
811 .probe = hv_timer_probe,
812 .currticks = hv_currticks,
813 .udelay = hv_udelay,
814};
815
816/* Drag in objects via hv_root_device */
817REQUIRING_SYMBOL ( hv_root_device );
818
819/* Drag in netvsc driver */
820REQUIRE_OBJECT ( netvsc );
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition acpi.c:48
uint32_t flag
Flag number.
Definition aqc1xx.h:2
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
uint32_t discard_edx
Definition hyperv.h:32
uint32_t discard_ecx
Definition hyperv.h:31
unsigned int uint32_t
Definition stdint.h:12
unsigned long long uint64_t
Definition stdint.h:13
Hyper-V driver.
#define HV_X64_MSR_SIMP
SynIC message page MSR.
Definition hyperv.h:55
#define HV_X64_MSR_TIME_REF_COUNT
Time reference MSR.
Definition hyperv.h:46
#define HV_X64_MSR_EOM
SynIC end of message MSR.
Definition hyperv.h:58
#define HV_X64_MSR_SCONTROL
SynIC control MSR.
Definition hyperv.h:49
#define HV_CPUID_FEATURES
Get hypervisor features.
Definition hyperv.h:22
#define HV_CPUID_INTERFACE_ID
Get interface identification.
Definition hyperv.h:16
#define HV_FEATURES_AVAIL_HYPERCALL_MSR
Hypercall MSRs are available.
Definition hyperv.h:31
#define HV_FEATURES_PERM_POST_MESSAGES
Guest may post messages.
Definition hyperv.h:34
#define HV_FEATURES_AVAIL_TIME_REF_COUNT_MSR
Time reference counter MSR is available.
Definition hyperv.h:25
#define HV_X64_MSR_GUEST_OS_ID
Guest OS identity MSR.
Definition hyperv.h:40
#define HV_CPUID_VENDOR_ID
Get vendor identification.
Definition hyperv.h:13
#define HV_X64_MSR_SIEFP
SynIC event flags page MSR.
Definition hyperv.h:52
#define HV_FEATURES_AVAIL_SYNIC_MSR
SynIC MSRs are available.
Definition hyperv.h:28
#define HV_X64_MSR_SINT(x)
SynIC interrupt source MSRs.
Definition hyperv.h:61
#define HV_FEATURES_PERM_SIGNAL_EVENTS
Guest may signal events.
Definition hyperv.h:37
#define HV_CPUID_HYPERVISOR_ID
Get hypervisor identification.
Definition hyperv.h:19
#define HV_X64_MSR_HYPERCALL
Hypercall page MSR.
Definition hyperv.h:43
static const void * src
Definition string.h:48
static unsigned int hypercall
Definition xen.h:43
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
u32 version
Driver version.
Definition ath9k_hw.c:1985
void x86_features(struct x86_features *features)
Get x86 CPU features.
Definition cpuid.c:164
x86 CPU feature detection
static uint32_t uint32_t uint32_t * ebx
Definition cpuid.h:90
#define CPUID_FEATURES_INTEL_ECX_HYPERVISOR
Hypervisor is present.
Definition cpuid.h:50
static uint32_t uint32_t uint32_t uint32_t * ecx
Definition cpuid.h:91
static uint32_t uint32_t uint32_t uint32_t uint32_t * edx
Definition cpuid.h:91
Device model.
#define __root_device
Declare a root device.
Definition device.h:136
static void * rootdev_get_drvdata(struct root_device *rootdev)
Get root device driver-private data.
Definition device.h:155
static void rootdev_set_drvdata(struct root_device *rootdev, void *priv)
Set root device driver-private data.
Definition device.h:144
ring len
Length.
Definition dwmac.h:226
uint32_t features
Supported features.
Definition ena.h:5
uint32_t type
Operating system type.
Definition ena.h:1
uint8_t data[48]
Additional event data.
Definition ena.h:11
uint8_t status
Status.
Definition ena.h:5
Error codes.
#define DBGC2(...)
Definition compiler.h:522
#define DBGC2_HDA(...)
Definition compiler.h:523
#define DBGC(...)
Definition compiler.h:505
uint32_t start
Starting offset.
Definition netvsc.h:1
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define REQUIRE_OBJECT(object)
Require an object.
Definition compiler.h:202
#define ETIMEDOUT
Connection timed out.
Definition errno.h:670
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define ENODEV
No such device.
Definition errno.h:510
#define EACCES
Permission denied.
Definition errno.h:299
#define REQUIRING_SYMBOL(symbol)
Specify the file's requiring symbol.
Definition compiler.h:140
#define TIMER_PREFERRED
Preferred timer.
Definition timer.h:63
int hv_wait_for_message(struct hv_hypervisor *hv, unsigned int sintx)
Wait for received message.
Definition hyperv.c:486
static void hv_map_hypercall(struct hv_hypervisor *hv)
Map hypercall page.
Definition hyperv.c:251
#define EHV(status)
Convert a Hyper-V status code to an iPXE status code.
Definition hyperv.c:68
static int hv_alloc_message(struct hv_hypervisor *hv)
Allocate message buffer.
Definition hyperv.c:129
static void hv_remove(struct root_device *rootdev)
Remove root device.
Definition hyperv.c:630
static struct root_driver hv_root_driver
Hyper-V root device driver.
Definition hyperv.c:644
static void hv_free_message(struct hv_hypervisor *hv)
Free message buffer.
Definition hyperv.c:147
static void hv_udelay(unsigned long usecs)
Delay for a fixed number of microseconds.
Definition hyperv.c:795
void hv_disable_sint(struct hv_hypervisor *hv, unsigned int sintx)
Disable synthetic interrupt.
Definition hyperv.c:423
static int hv_probe(struct root_device *rootdev)
Probe root device.
Definition hyperv.c:563
#define HV_TIMER_SHIFT
Hyper-V timer scale factor (used to avoid 64-bit division)
Definition hyperv.c:60
static int hv_check_features(struct hv_hypervisor *hv)
Check required features.
Definition hyperv.c:190
static int hv_check_uefi(struct hv_hypervisor *hv)
Check that Gen 2 UEFI firmware is not running.
Definition hyperv.c:233
#define HV_TIMER_HZ
Hyper-V timer frequency (fixed 10Mhz)
Definition hyperv.c:57
static void hv_map_synic(struct hv_hypervisor *hv)
Map synthetic interrupt controller.
Definition hyperv.c:321
static unsigned long hv_currticks(void)
Get current system time in ticks.
Definition hyperv.c:781
static void hv_unmap_hypercall(struct hv_hypervisor *hv)
Unmap hypercall page.
Definition hyperv.c:300
static void hv_unmap_synic_no_scontrol(struct hv_hypervisor *hv)
Unmap synthetic interrupt controller, leaving SCONTROL untouched.
Definition hyperv.c:356
void hv_free_pages(struct hv_hypervisor *hv,...)
Free pages.
Definition hyperv.c:113
int hv_post_message(struct hv_hypervisor *hv, unsigned int id, unsigned int type, const void *data, size_t len)
Post message.
Definition hyperv.c:449
int hv_alloc_pages(struct hv_hypervisor *hv,...)
Allocate zeroed pages.
Definition hyperv.c:78
static void hv_quiesce(void)
Quiesce system.
Definition hyperv.c:659
static void hv_unmap_synic(struct hv_hypervisor *hv)
Unmap synthetic interrupt controller.
Definition hyperv.c:378
int hv_signal_event(struct hv_hypervisor *hv, unsigned int id, unsigned int flag)
Signal event.
Definition hyperv.c:535
void hv_enable_sint(struct hv_hypervisor *hv, unsigned int sintx)
Enable synthetic interrupt.
Definition hyperv.c:397
static int hv_timer_probe(void)
Probe timer.
Definition hyperv.c:754
#define HV_MESSAGE_MAX_WAIT_MS
Maximum time to wait for a message response.
Definition hyperv.c:54
static void hv_unquiesce(void)
Unquiesce system.
Definition hyperv.c:704
static int hv_check_hv(void)
Check whether or not we are running in Hyper-V.
Definition hyperv.c:158
uint8_t vendor_id[3]
Definition ib_mad.h:11
#define le32_to_cpu(value)
Definition byteswap.h:114
#define cpu_to_le32(value)
Definition byteswap.h:108
#define cpu_to_le16(value)
Definition byteswap.h:107
#define __attribute__(x)
Definition compiler.h:10
Hyper-V interface.
#define HV_SINT_VECTOR_MASK
Synthetic interrupt vector mask.
Definition hyperv.h:69
#define HV_GUEST_OS_ID_IPXE
Guest OS identity for iPXE.
Definition hyperv.h:38
#define HV_INTERFACE_ID
Hyper-V interface identification.
Definition hyperv.h:16
#define HV_SINT_MAX
Maximum synthetic interrupt number.
Definition hyperv.h:72
#define HV_SINT_AUTO_EOI
Perform implicit EOI upon synthetic interrupt delivery.
Definition hyperv.h:60
#define HV_SIEFP_ENABLE
Enable SynIC event flags.
Definition hyperv.h:54
#define HV_SINT_VECTOR(x)
Synthetic interrupt vector.
Definition hyperv.h:66
#define HV_SCONTROL_ENABLE
Enable SynIC.
Definition hyperv.h:51
#define HV_POST_MESSAGE
Post message.
Definition hyperv.h:75
#define HV_GUEST_OS_ID_UEFI
Guest OS identity for Gen 2 UEFI firmware.
Definition hyperv.h:45
#define HV_SIGNAL_EVENT
Signal event.
Definition hyperv.h:116
#define HV_SIMP_ENABLE
Enable SynIC messages.
Definition hyperv.h:57
#define HV_HYPERCALL_ENABLE
Enable hypercall page.
Definition hyperv.h:48
#define HV_SINT_MASKED
Mask synthetic interrupt.
Definition hyperv.h:63
#define PAGE_SIZE
Page size.
Definition io.h:28
iPXE timers
#define TICKS_PER_SEC
Number of ticks per second.
Definition timer.h:16
#define __timer(order)
Declare a timer.
Definition timer.h:56
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
void * malloc_phys(size_t size, size_t phys_align)
Allocate memory with specified physical alignment.
Definition malloc.c:707
void free_phys(void *ptr, size_t size)
Free memory allocated with malloc_phys()
Definition malloc.c:723
Dynamic memory allocation.
void msg(unsigned int row, const char *fmt,...)
Print message centred on specified row.
Definition message.c:62
Model-specific registers.
#define IRQ_INT(irq)
Definition pic8259.h:57
Quiesce system.
#define __quiescer
Declare a quiescer.
Definition quiesce.h:27
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
#define va_arg(ap, type)
Definition stdarg.h:9
#define va_end(ap)
Definition stdarg.h:10
#define va_start(ap, last)
Definition stdarg.h:8
__builtin_va_list va_list
Definition stdarg.h:7
#define offsetof(type, field)
Get offset of a field within a structure.
Definition stddef.h:25
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
A Hyper-V hypervisor.
Definition hyperv.h:203
struct hv_synic synic
Synthetic interrupt controller (SynIC)
Definition hyperv.h:207
union hv_message_buffer * message
Message buffer.
Definition hyperv.h:209
void * hypercall
Hypercall page.
Definition hyperv.h:205
A received message.
Definition hyperv.h:100
A posted message.
Definition hyperv.h:81
A signalled event.
Definition hyperv.h:119
struct hv_event * event
Event flag page.
Definition hyperv.h:189
struct hv_message * message
Message page.
Definition hyperv.h:187
A quiescer.
Definition quiesce.h:16
A root device.
Definition device.h:98
struct device dev
Device chain.
Definition device.h:103
A root device driver.
Definition device.h:111
A timer.
Definition timer.h:29
x86 CPU features
Definition cpuid.h:24
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition timer.c:79
struct hv_message received
Received message.
Definition hyperv.h:197
struct hv_post_message posted
Posted message.
Definition hyperv.h:195
struct hv_signal_event signalled
Signalled event.
Definition hyperv.h:199
int vmbus_probe(struct hv_hypervisor *hv, struct device *parent)
Probe Hyper-V virtual machine bus.
Definition vmbus.c:1365
void vmbus_remove(struct hv_hypervisor *hv, struct device *parent)
Remove Hyper-V virtual machine bus.
Definition vmbus.c:1458
int vmbus_reset(struct hv_hypervisor *hv, struct device *parent)
Reset Hyper-V virtual machine bus.
Definition vmbus.c:1426
Hyper-V virtual machine bus.