2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
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.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
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>
46 #include <ipxe/hyperv.h>
47 #include <ipxe/vmbus.h>
50 /** Maximum time to wait for a message response
52 * This is a policy decision.
54 #define HV_MESSAGE_MAX_WAIT_MS 1000
56 /** Hyper-V timer frequency (fixed 10Mhz) */
57 #define HV_TIMER_HZ 10000000
59 /** Hyper-V timer scale factor (used to avoid 64-bit division) */
60 #define HV_TIMER_SHIFT 18
63 * Convert a Hyper-V status code to an iPXE status code
65 * @v status Hyper-V status code
66 * @ret rc iPXE status code (before negation)
68 #define EHV( status ) EPLATFORM ( EINFO_EPLATFORM, (status) )
71 * Allocate zeroed pages
73 * @v hv Hyper-V hypervisor
74 * @v ... Page addresses to fill in, terminated by NULL
75 * @ret rc Return status code
77 __attribute__ (( sentinel
)) int
78 hv_alloc_pages ( struct hv_hypervisor
*hv
, ... ) {
83 /* Allocate and zero pages */
84 va_start ( args
, hv
);
85 for ( i
= 0 ; ( ( page
= va_arg ( args
, void ** ) ) != NULL
); i
++ ) {
86 *page
= malloc_dma ( PAGE_SIZE
, PAGE_SIZE
);
89 memset ( *page
, 0, PAGE_SIZE
);
97 va_start ( args
, hv
);
98 for ( ; i
>= 0 ; i
-- ) {
99 page
= va_arg ( args
, void ** );
100 free_dma ( *page
, PAGE_SIZE
);
109 * @v hv Hyper-V hypervisor
110 * @v ... Page addresses, terminated by NULL
112 __attribute__ (( sentinel
)) void
113 hv_free_pages ( struct hv_hypervisor
*hv
, ... ) {
117 va_start ( args
, hv
);
118 while ( ( page
= va_arg ( args
, void * ) ) != NULL
)
119 free_dma ( page
, PAGE_SIZE
);
124 * Allocate message buffer
126 * @v hv Hyper-V hypervisor
127 * @ret rc Return status code
129 static int hv_alloc_message ( struct hv_hypervisor
*hv
) {
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.
134 hv
->message
= malloc_dma ( sizeof ( *hv
->message
),
135 sizeof ( *hv
->message
) );
143 * Free message buffer
145 * @v hv Hyper-V hypervisor
147 static void hv_free_message ( struct hv_hypervisor
*hv
) {
150 free_dma ( hv
->message
, sizeof ( *hv
->message
) );
154 * Check whether or not we are running in Hyper-V
156 * @ret rc Return status code
158 static int hv_check_hv ( void ) {
159 struct x86_features features
;
160 uint32_t interface_id
;
161 uint32_t discard_ebx
;
162 uint32_t discard_ecx
;
163 uint32_t discard_edx
;
165 /* Check for presence of a hypervisor (not necessarily Hyper-V) */
166 x86_features ( &features
);
167 if ( ! ( features
.intel
.ecx
& CPUID_FEATURES_INTEL_ECX_HYPERVISOR
) ) {
168 DBGC ( HV_INTERFACE_ID
, "HV not running in a hypervisor\n" );
172 /* Check that hypervisor is Hyper-V */
173 cpuid ( HV_CPUID_INTERFACE_ID
, 0, &interface_id
, &discard_ebx
,
174 &discard_ecx
, &discard_edx
);
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
);
185 * Check required features
187 * @v hv Hyper-V hypervisor
188 * @ret rc Return status code
190 static int hv_check_features ( struct hv_hypervisor
*hv
) {
192 uint32_t permissions
;
193 uint32_t discard_ecx
;
194 uint32_t discard_edx
;
196 /* Check that required features and privileges are available */
197 cpuid ( HV_CPUID_FEATURES
, 0, &available
, &permissions
, &discard_ecx
,
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
);
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
);
209 if ( ! ( permissions
& HV_FEATURES_PERM_POST_MESSAGES
) ) {
210 DBGC ( hv
, "HV %p cannot post messages (features %08x:%08x)\n",
211 hv
, available
, permissions
);
214 if ( ! ( permissions
& HV_FEATURES_PERM_SIGNAL_EVENTS
) ) {
215 DBGC ( hv
, "HV %p cannot signal events (features %08x:%08x)",
216 hv
, available
, permissions
);
224 * Check that Gen 2 UEFI firmware is not running
226 * @v hv Hyper-V hypervisor
227 * @ret rc Return status code
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.
233 static int hv_check_uefi ( struct hv_hypervisor
*hv
) {
234 uint64_t guest_os_id
;
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
);
249 * @v hv Hyper-V hypervisor
251 static void hv_map_hypercall ( struct hv_hypervisor
*hv
) {
257 } __attribute__ (( packed
));
258 char text
[ 13 /* "bbbbccccdddd" + NUL */ ];
262 uint32_t discard_eax
;
263 uint32_t discard_ecx
;
264 uint32_t discard_edx
;
265 uint64_t guest_os_id
;
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",
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
);
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
,
284 DBGC ( hv
, "HV %p detected \"%s\" version %d.%d build %d\n", hv
,
285 vendor_id
.text
, ( version
>> 16 ), ( version
& 0xffff ), build
);
287 /* Map hypercall page */
288 hypercall
= rdmsr ( HV_X64_MSR_HYPERCALL
);
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
);
292 wrmsr ( HV_X64_MSR_HYPERCALL
, hypercall
);
296 * Unmap hypercall page
298 * @v hv Hyper-V hypervisor
300 static void hv_unmap_hypercall ( struct hv_hypervisor
*hv
) {
302 uint64_t guest_os_id
;
304 /* Unmap the hypercall page */
305 hypercall
= rdmsr ( HV_X64_MSR_HYPERCALL
);
306 hypercall
&= ( ( PAGE_SIZE
- 1 ) & ~HV_HYPERCALL_ENABLE
);
307 DBGC2 ( hv
, "HV %p hypercall MSR is %#08llx\n", hv
, hypercall
);
308 wrmsr ( HV_X64_MSR_HYPERCALL
, hypercall
);
310 /* Reset the guest OS identity */
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
);
317 * Map synthetic interrupt controller
319 * @v hv Hyper-V hypervisor
321 static void hv_map_synic ( struct hv_hypervisor
*hv
) {
326 /* Zero SynIC message and event pages */
327 memset ( hv
->synic
.message
, 0, PAGE_SIZE
);
328 memset ( hv
->synic
.event
, 0, PAGE_SIZE
);
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
);
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
);
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
);
352 * Unmap synthetic interrupt controller, leaving SCONTROL untouched
354 * @v hv Hyper-V hypervisor
356 static void hv_unmap_synic_no_scontrol ( struct hv_hypervisor
*hv
) {
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
);
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
);
374 * Unmap synthetic interrupt controller
376 * @v hv Hyper-V hypervisor
378 static void hv_unmap_synic ( struct hv_hypervisor
*hv
) {
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
);
387 /* Unmap SynIC event and message pages */
388 hv_unmap_synic_no_scontrol ( hv
);
392 * Enable synthetic interrupt
394 * @v hv Hyper-V hypervisor
395 * @v sintx Synthetic interrupt number
397 void hv_enable_sint ( struct hv_hypervisor
*hv
, unsigned int sintx
) {
398 unsigned long msr
= HV_X64_MSR_SINT ( sintx
);
401 /* Enable synthetic interrupt
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.
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
);
418 * Disable synthetic interrupt
420 * @v hv Hyper-V hypervisor
421 * @v sintx Synthetic interrupt number
423 void hv_disable_sint ( struct hv_hypervisor
*hv
, unsigned int sintx
) {
424 unsigned long msr
= HV_X64_MSR_SINT ( sintx
);
427 /* Do nothing if interrupt is already disabled */
428 sint
= rdmsr ( msr
);
429 if ( sint
& HV_SINT_MASKED
)
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
);
442 * @v hv Hyper-V hypervisor
443 * @v id Connection ID
444 * @v type Message type
446 * @v len Length of message
447 * @ret rc Return status code
449 int 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
;
456 assert ( len
<= sizeof ( msg
->data
) );
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",
466 DBGC2_HDA ( hv
, 0, msg
->data
, len
);
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
) );
480 * Wait for received message
482 * @v hv Hyper-V hypervisor
483 * @v sintx Synthetic interrupt number
484 * @ret rc Return status code
486 int 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
;
492 /* Wait for message to arrive */
493 for ( retries
= 0 ; retries
< HV_MESSAGE_MAX_WAIT_MS
; retries
++ ) {
495 /* Check for message */
499 memset ( msg
, 0, sizeof ( *msg
) );
501 assert ( len
<= sizeof ( *msg
) );
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
);
509 /* Consume message */
515 /* Trigger message delivery */
516 wrmsr ( HV_X64_MSR_EOM
, 0 );
522 DBGC ( hv
, "HV %p SINT%d timed out waiting for message\n",
530 * @v hv Hyper-V hypervisor
531 * @v id Connection ID
532 * @v flag Flag number
533 * @ret rc Return status code
535 int hv_signal_event ( struct hv_hypervisor
*hv
, unsigned int id
,
536 unsigned int flag
) {
537 struct hv_signal_event
*event
= &hv
->message
->signalled
;
541 /* Construct event */
542 memset ( event
, 0, sizeof ( *event
) );
543 event
->id
= cpu_to_le32 ( id
);
544 event
->flag
= cpu_to_le16 ( flag
);
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
) );
560 * @v rootdev Root device
561 * @ret rc Return status code
563 static int hv_probe ( struct root_device
*rootdev
) {
564 struct hv_hypervisor
*hv
;
567 /* Check we are running in Hyper-V */
568 if ( ( rc
= hv_check_hv() ) != 0 )
571 /* Allocate and initialise structure */
572 hv
= zalloc ( sizeof ( *hv
) );
579 if ( ( rc
= hv_check_features ( hv
) ) != 0 )
580 goto err_check_features
;
582 /* Check that Gen 2 UEFI firmware is not running */
583 if ( ( rc
= hv_check_uefi ( hv
) ) != 0 )
587 if ( ( rc
= hv_alloc_pages ( hv
, &hv
->hypercall
, &hv
->synic
.message
,
588 &hv
->synic
.event
, NULL
) ) != 0 )
589 goto err_alloc_pages
;
591 /* Allocate message buffer */
592 if ( ( rc
= hv_alloc_message ( hv
) ) != 0 )
593 goto err_alloc_message
;
595 /* Map hypercall page */
596 hv_map_hypercall ( hv
);
598 /* Map synthetic interrupt controller */
601 /* Probe Hyper-V devices */
602 if ( ( rc
= vmbus_probe ( hv
, &rootdev
->dev
) ) != 0 )
603 goto err_vmbus_probe
;
605 rootdev_set_drvdata ( rootdev
, hv
);
608 vmbus_remove ( hv
, &rootdev
->dev
);
610 hv_unmap_synic ( hv
);
611 hv_unmap_hypercall ( hv
);
612 hv_free_message ( hv
);
614 hv_free_pages ( hv
, hv
->hypercall
, hv
->synic
.message
, hv
->synic
.event
,
628 * @v rootdev Root device
630 static void hv_remove ( struct root_device
*rootdev
) {
631 struct hv_hypervisor
*hv
= rootdev_get_drvdata ( rootdev
);
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
,
640 rootdev_set_drvdata ( rootdev
, NULL
);
643 /** Hyper-V root device driver */
644 static struct root_driver hv_root_driver
= {
649 /** Hyper-V root device */
650 struct root_device hv_root_device __root_device
= {
651 .dev
= { .name
= "Hyper-V" },
652 .driver
= &hv_root_driver
,
659 static void hv_quiesce ( void ) {
660 struct hv_hypervisor
*hv
= rootdev_get_drvdata ( &hv_root_device
);
663 /* Do nothing if we are not running in Hyper-V */
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).
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.
678 * Attempt to create a safe handover environment by resetting
679 * all MSRs except for SCONTROL.
681 * Note that we do not shut down our VMBus devices, since we
682 * may need to unquiesce the system and continue operation.
685 /* Disable all synthetic interrupts */
686 for ( i
= 0 ; i
<= HV_SINT_MAX
; i
++ )
687 hv_disable_sint ( hv
, i
);
689 /* Unmap synthetic interrupt controller, leaving SCONTROL
690 * enabled (see above).
692 hv_unmap_synic_no_scontrol ( hv
);
694 /* Unmap hypercall page */
695 hv_unmap_hypercall ( hv
);
697 DBGC ( hv
, "HV %p quiesced\n", hv
);
704 static void hv_unquiesce ( void ) {
705 struct hv_hypervisor
*hv
= rootdev_get_drvdata ( &hv_root_device
);
709 /* Do nothing if we are not running in Hyper-V */
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.
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.
724 simp
= rdmsr ( HV_X64_MSR_SIMP
);
725 if ( simp
& HV_SIMP_ENABLE
)
728 /* Remap hypercall page */
729 hv_map_hypercall ( hv
);
731 /* Remap synthetic interrupt controller */
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 */
743 /** Hyper-V quiescer */
744 struct quiescer hv_quiescer __quiescer
= {
745 .quiesce
= hv_quiesce
,
746 .unquiesce
= hv_unquiesce
,
752 * @ret rc Return status code
754 static int hv_timer_probe ( void ) {
756 uint32_t discard_ebx
;
757 uint32_t discard_ecx
;
758 uint32_t discard_edx
;
761 /* Check we are running in Hyper-V */
762 if ( ( rc
= hv_check_hv() ) != 0 )
765 /* Check for available reference counter */
766 cpuid ( HV_CPUID_FEATURES
, 0, &available
, &discard_ebx
, &discard_ecx
,
768 if ( ! ( available
& HV_FEATURES_AVAIL_TIME_REF_COUNT_MSR
) ) {
769 DBGC ( HV_INTERFACE_ID
, "HV has no time reference counter\n" );
777 * Get current system time in ticks
779 * @ret ticks Current time, in ticks
781 static unsigned long hv_currticks ( void ) {
783 /* Calculate time using a combination of bit shifts and
784 * multiplication (to avoid a 64-bit division).
786 return ( ( rdmsr ( HV_X64_MSR_TIME_REF_COUNT
) >> HV_TIMER_SHIFT
) *
787 ( TICKS_PER_SEC
/ ( HV_TIMER_HZ
>> HV_TIMER_SHIFT
) ) );
791 * Delay for a fixed number of microseconds
793 * @v usecs Number of microseconds for which to delay
795 static void hv_udelay ( unsigned long usecs
) {
800 /* Spin until specified number of 10MHz ticks have elapsed */
801 start
= rdmsr ( HV_X64_MSR_TIME_REF_COUNT
);
802 threshold
= ( usecs
* ( HV_TIMER_HZ
/ 1000000 ) );
804 elapsed
= ( rdmsr ( HV_X64_MSR_TIME_REF_COUNT
) - start
);
805 } while ( elapsed
< threshold
);
809 struct timer hv_timer
__timer ( TIMER_PREFERRED
) = {
811 .probe
= hv_timer_probe
,
812 .currticks
= hv_currticks
,
816 /* Drag in objects via hv_root_device */
817 REQUIRING_SYMBOL ( hv_root_device
);
819 /* Drag in netvsc driver */
820 //REQUIRE_OBJECT ( netvsc );