iPXE
hyperv.c File Reference

Hyper-V driver. More...

#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <byteswap.h>
#include <pic8259.h>
#include <ipxe/malloc.h>
#include <ipxe/device.h>
#include <ipxe/timer.h>
#include <ipxe/quiesce.h>
#include <ipxe/cpuid.h>
#include <ipxe/msr.h>
#include <ipxe/hyperv.h>
#include <ipxe/vmbus.h>
#include "hyperv.h"

Go to the source code of this file.

Macros

#define HV_MESSAGE_MAX_WAIT_MS   1000
 Maximum time to wait for a message response.
#define HV_TIMER_HZ   10000000
 Hyper-V timer frequency (fixed 10Mhz)
#define HV_TIMER_SHIFT   18
 Hyper-V timer scale factor (used to avoid 64-bit division)
#define EHV(status)
 Convert a Hyper-V status code to an iPXE status code.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
int hv_alloc_pages (struct hv_hypervisor *hv,...)
 Allocate zeroed pages.
void hv_free_pages (struct hv_hypervisor *hv,...)
 Free pages.
static int hv_alloc_message (struct hv_hypervisor *hv)
 Allocate message buffer.
static void hv_free_message (struct hv_hypervisor *hv)
 Free message buffer.
static int hv_check_hv (void)
 Check whether or not we are running in Hyper-V.
static int hv_check_features (struct hv_hypervisor *hv)
 Check required features.
static int hv_check_uefi (struct hv_hypervisor *hv)
 Check that Gen 2 UEFI firmware is not running.
static void hv_map_hypercall (struct hv_hypervisor *hv)
 Map hypercall page.
static void hv_unmap_hypercall (struct hv_hypervisor *hv)
 Unmap hypercall page.
static void hv_map_synic (struct hv_hypervisor *hv)
 Map synthetic interrupt controller.
static void hv_unmap_synic_no_scontrol (struct hv_hypervisor *hv)
 Unmap synthetic interrupt controller, leaving SCONTROL untouched.
static void hv_unmap_synic (struct hv_hypervisor *hv)
 Unmap synthetic interrupt controller.
void hv_enable_sint (struct hv_hypervisor *hv, unsigned int sintx)
 Enable synthetic interrupt.
void hv_disable_sint (struct hv_hypervisor *hv, unsigned int sintx)
 Disable synthetic interrupt.
int hv_post_message (struct hv_hypervisor *hv, unsigned int id, unsigned int type, const void *data, size_t len)
 Post message.
int hv_wait_for_message (struct hv_hypervisor *hv, unsigned int sintx)
 Wait for received message.
int hv_signal_event (struct hv_hypervisor *hv, unsigned int id, unsigned int flag)
 Signal event.
static int hv_probe (struct root_device *rootdev)
 Probe root device.
static void hv_remove (struct root_device *rootdev)
 Remove root device.
static void hv_quiesce (void)
 Quiesce system.
static void hv_unquiesce (void)
 Unquiesce system.
static int hv_timer_probe (void)
 Probe timer.
static unsigned long hv_currticks (void)
 Get current system time in ticks.
static void hv_udelay (unsigned long usecs)
 Delay for a fixed number of microseconds.
struct timer hv_timer __timer (TIMER_PREFERRED)
 Hyper-V timer.
 REQUIRING_SYMBOL (hv_root_device)
 REQUIRE_OBJECT (netvsc)

Variables

static struct root_driver hv_root_driver
 Hyper-V root device driver.
struct root_device hv_root_device __root_device
 Hyper-V root device.
struct quiescer hv_quiescer __quiescer
 Hyper-V quiescer.

Detailed Description

Hyper-V driver.

Definition in file hyperv.c.

Macro Definition Documentation

◆ HV_MESSAGE_MAX_WAIT_MS

#define HV_MESSAGE_MAX_WAIT_MS   1000

Maximum time to wait for a message response.

This is a policy decision.

Definition at line 54 of file hyperv.c.

Referenced by hv_wait_for_message().

◆ HV_TIMER_HZ

#define HV_TIMER_HZ   10000000

Hyper-V timer frequency (fixed 10Mhz)

Definition at line 57 of file hyperv.c.

Referenced by hv_currticks(), and hv_udelay().

◆ HV_TIMER_SHIFT

#define HV_TIMER_SHIFT   18

Hyper-V timer scale factor (used to avoid 64-bit division)

Definition at line 60 of file hyperv.c.

Referenced by hv_currticks().

◆ EHV

#define EHV ( status)
Value:
uint8_t status
Status.
Definition ena.h:5
#define EPLATFORM(einfo_base, platform,...)
Generate an error based on an external platform error code.
Definition errno.h:249
#define EINFO_EPLATFORM
Platform-generated base error.
Definition errno.h:692

Convert a Hyper-V status code to an iPXE status code.

Parameters
statusHyper-V status code
Return values
rciPXE status code (before negation)

Definition at line 68 of file hyperv.c.

Referenced by hv_post_message(), and hv_signal_event().

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ hv_alloc_pages()

int hv_alloc_pages ( struct hv_hypervisor * hv,
... )

Allocate zeroed pages.

Parameters
hvHyper-V hypervisor
...Page addresses to fill in, terminated by NULL
Return values
rcReturn status code

Definition at line 78 of file hyperv.c.

78 {
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}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
#define ENOMEM
Not enough space.
Definition errno.h:535
#define PAGE_SIZE
Page size.
Definition io.h:28
void * memset(void *dest, int character, size_t len) __nonnull
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
#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

References ENOMEM, free_phys(), malloc_phys(), memset(), NULL, PAGE_SIZE, va_arg, va_end, and va_start.

Referenced by hv_probe(), and vmbus_probe().

◆ hv_free_pages()

void hv_free_pages ( struct hv_hypervisor * hv,
... )

Free pages.

Parameters
hvHyper-V hypervisor
...Page addresses, terminated by NULL

Definition at line 113 of file hyperv.c.

113 {
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}

References free_phys(), NULL, PAGE_SIZE, va_arg, va_end, and va_start.

Referenced by hv_probe(), hv_remove(), vmbus_probe(), and vmbus_remove().

◆ hv_alloc_message()

int hv_alloc_message ( struct hv_hypervisor * hv)
static

Allocate message buffer.

Parameters
hvHyper-V hypervisor
Return values
rcReturn status code

Definition at line 129 of file hyperv.c.

129 {
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}
union hv_message_buffer * message
Message buffer.
Definition hyperv.h:209

References ENOMEM, malloc_phys(), and hv_hypervisor::message.

Referenced by hv_probe().

◆ hv_free_message()

void hv_free_message ( struct hv_hypervisor * hv)
static

Free message buffer.

Parameters
hvHyper-V hypervisor

Definition at line 147 of file hyperv.c.

147 {
148
149 /* Free buffer */
150 free_phys ( hv->message, sizeof ( *hv->message ) );
151}

References free_phys(), and hv_hypervisor::message.

Referenced by hv_probe(), and hv_remove().

◆ hv_check_hv()

int hv_check_hv ( void )
static

Check whether or not we are running in Hyper-V.

Return values
rcReturn status code

Definition at line 158 of file hyperv.c.

158 {
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}
uint32_t discard_edx
Definition hyperv.h:32
uint32_t discard_ecx
Definition hyperv.h:31
unsigned int uint32_t
Definition stdint.h:12
#define HV_CPUID_INTERFACE_ID
Get interface identification.
Definition hyperv.h:16
void x86_features(struct x86_features *features)
Get x86 CPU features.
Definition cpuid.c:164
#define CPUID_FEATURES_INTEL_ECX_HYPERVISOR
Hypervisor is present.
Definition cpuid.h:50
uint32_t features
Supported features.
Definition ena.h:5
#define DBGC(...)
Definition compiler.h:505
#define ENODEV
No such device.
Definition errno.h:510
#define HV_INTERFACE_ID
Hyper-V interface identification.
Definition hyperv.h:16
x86 CPU features
Definition cpuid.h:24

References CPUID_FEATURES_INTEL_ECX_HYPERVISOR, DBGC, discard_ecx, discard_edx, ENODEV, features, HV_CPUID_INTERFACE_ID, HV_INTERFACE_ID, and x86_features().

Referenced by hv_probe(), and hv_timer_probe().

◆ hv_check_features()

int hv_check_features ( struct hv_hypervisor * hv)
static

Check required features.

Parameters
hvHyper-V hypervisor
Return values
rcReturn status code

Definition at line 190 of file hyperv.c.

190 {
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}
#define HV_CPUID_FEATURES
Get hypervisor features.
Definition hyperv.h:22
#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_SYNIC_MSR
SynIC MSRs are available.
Definition hyperv.h:28
#define HV_FEATURES_PERM_SIGNAL_EVENTS
Guest may signal events.
Definition hyperv.h:37
#define EACCES
Permission denied.
Definition errno.h:299

References DBGC, discard_ecx, discard_edx, EACCES, ENODEV, HV_CPUID_FEATURES, HV_FEATURES_AVAIL_HYPERCALL_MSR, HV_FEATURES_AVAIL_SYNIC_MSR, HV_FEATURES_PERM_POST_MESSAGES, and HV_FEATURES_PERM_SIGNAL_EVENTS.

Referenced by hv_probe().

◆ hv_check_uefi()

int hv_check_uefi ( struct hv_hypervisor * hv)
static

Check that Gen 2 UEFI firmware is not running.

Parameters
hvHyper-V hypervisor
Return values
rcReturn status code

We must not steal ownership from the Gen 2 UEFI firmware, since doing so will cause an immediate crash. Avoid this by checking for the guest OS identity known to be used by the Gen 2 UEFI firmware.

Definition at line 233 of file hyperv.c.

233 {
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}
unsigned long long uint64_t
Definition stdint.h:13
#define HV_X64_MSR_GUEST_OS_ID
Guest OS identity MSR.
Definition hyperv.h:40
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define HV_GUEST_OS_ID_UEFI
Guest OS identity for Gen 2 UEFI firmware.
Definition hyperv.h:45

References DBGC, ENOTSUP, HV_GUEST_OS_ID_UEFI, and HV_X64_MSR_GUEST_OS_ID.

Referenced by hv_probe().

◆ hv_map_hypercall()

void hv_map_hypercall ( struct hv_hypervisor * hv)
static

Map hypercall page.

Parameters
hvHyper-V hypervisor

Definition at line 251 of file hyperv.c.

251 {
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}
#define HV_CPUID_VENDOR_ID
Get vendor identification.
Definition hyperv.h:13
#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 unsigned int hypercall
Definition xen.h:43
u32 version
Driver version.
Definition ath9k_hw.c:1985
static uint32_t uint32_t uint32_t * ebx
Definition cpuid.h:90
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
#define DBGC2(...)
Definition compiler.h:522
uint8_t vendor_id[3]
Definition ib_mad.h:11
#define __attribute__(x)
Definition compiler.h:10
#define HV_GUEST_OS_ID_IPXE
Guest OS identity for iPXE.
Definition hyperv.h:38
#define HV_HYPERCALL_ENABLE
Enable hypercall page.
Definition hyperv.h:48
void * hypercall
Hypercall page.
Definition hyperv.h:205

References __attribute__, DBGC, DBGC2, discard_ecx, discard_edx, ebx, ecx, edx, HV_CPUID_HYPERVISOR_ID, HV_CPUID_VENDOR_ID, HV_GUEST_OS_ID_IPXE, HV_HYPERCALL_ENABLE, HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL, hv_hypervisor::hypercall, hypercall, PAGE_SIZE, vendor_id, and version.

Referenced by hv_probe(), and hv_unquiesce().

◆ hv_unmap_hypercall()

void hv_unmap_hypercall ( struct hv_hypervisor * hv)
static

Unmap hypercall page.

Parameters
hvHyper-V hypervisor

Definition at line 300 of file hyperv.c.

300 {
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}

References DBGC2, HV_HYPERCALL_ENABLE, HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL, hypercall, and PAGE_SIZE.

Referenced by hv_probe(), hv_quiesce(), and hv_remove().

◆ hv_map_synic()

void hv_map_synic ( struct hv_hypervisor * hv)
static

Map synthetic interrupt controller.

Parameters
hvHyper-V hypervisor

Definition at line 321 of file hyperv.c.

321 {
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}
#define HV_X64_MSR_SIMP
SynIC message page MSR.
Definition hyperv.h:55
#define HV_X64_MSR_SCONTROL
SynIC control MSR.
Definition hyperv.h:49
#define HV_X64_MSR_SIEFP
SynIC event flags page MSR.
Definition hyperv.h:52
#define HV_SIEFP_ENABLE
Enable SynIC event flags.
Definition hyperv.h:54
#define HV_SCONTROL_ENABLE
Enable SynIC.
Definition hyperv.h:51
#define HV_SIMP_ENABLE
Enable SynIC messages.
Definition hyperv.h:57
struct hv_synic synic
Synthetic interrupt controller (SynIC)
Definition hyperv.h:207
struct hv_event * event
Event flag page.
Definition hyperv.h:189
struct hv_message * message
Message page.
Definition hyperv.h:187

References DBGC2, hv_synic::event, HV_SCONTROL_ENABLE, HV_SIEFP_ENABLE, HV_SIMP_ENABLE, HV_X64_MSR_SCONTROL, HV_X64_MSR_SIEFP, HV_X64_MSR_SIMP, memset(), hv_synic::message, PAGE_SIZE, and hv_hypervisor::synic.

Referenced by hv_probe(), and hv_unquiesce().

◆ hv_unmap_synic_no_scontrol()

void hv_unmap_synic_no_scontrol ( struct hv_hypervisor * hv)
static

Unmap synthetic interrupt controller, leaving SCONTROL untouched.

Parameters
hvHyper-V hypervisor

Definition at line 356 of file hyperv.c.

356 {
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}

References DBGC2, HV_SIEFP_ENABLE, HV_SIMP_ENABLE, HV_X64_MSR_SIEFP, HV_X64_MSR_SIMP, and PAGE_SIZE.

Referenced by hv_quiesce(), and hv_unmap_synic().

◆ hv_unmap_synic()

void hv_unmap_synic ( struct hv_hypervisor * hv)
static

Unmap synthetic interrupt controller.

Parameters
hvHyper-V hypervisor

Definition at line 378 of file hyperv.c.

378 {
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}
static void hv_unmap_synic_no_scontrol(struct hv_hypervisor *hv)
Unmap synthetic interrupt controller, leaving SCONTROL untouched.
Definition hyperv.c:356

References DBGC2, HV_SCONTROL_ENABLE, hv_unmap_synic_no_scontrol(), and HV_X64_MSR_SCONTROL.

Referenced by hv_probe(), and hv_remove().

◆ hv_enable_sint()

void hv_enable_sint ( struct hv_hypervisor * hv,
unsigned int sintx )

Enable synthetic interrupt.

Parameters
hvHyper-V hypervisor
sintxSynthetic interrupt number

Definition at line 397 of file hyperv.c.

397 {
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}
#define HV_X64_MSR_SINT(x)
SynIC interrupt source MSRs.
Definition hyperv.h:61
#define HV_SINT_VECTOR_MASK
Synthetic interrupt vector mask.
Definition hyperv.h:69
#define HV_SINT_AUTO_EOI
Perform implicit EOI upon synthetic interrupt delivery.
Definition hyperv.h:60
#define HV_SINT_VECTOR(x)
Synthetic interrupt vector.
Definition hyperv.h:66
#define HV_SINT_MASKED
Mask synthetic interrupt.
Definition hyperv.h:63
#define IRQ_INT(irq)
Definition pic8259.h:57

References DBGC2, HV_SINT_AUTO_EOI, HV_SINT_MASKED, HV_SINT_VECTOR, HV_SINT_VECTOR_MASK, HV_X64_MSR_SINT, and IRQ_INT.

Referenced by vmbus_probe(), and vmbus_reset().

◆ hv_disable_sint()

void hv_disable_sint ( struct hv_hypervisor * hv,
unsigned int sintx )

Disable synthetic interrupt.

Parameters
hvHyper-V hypervisor
sintxSynthetic interrupt number

Definition at line 423 of file hyperv.c.

423 {
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}

References DBGC2, HV_SINT_AUTO_EOI, HV_SINT_MASKED, and HV_X64_MSR_SINT.

Referenced by hv_quiesce(), vmbus_probe(), and vmbus_remove().

◆ hv_post_message()

int hv_post_message ( struct hv_hypervisor * hv,
unsigned int id,
unsigned int type,
const void * data,
size_t len )

Post message.

Parameters
hvHyper-V hypervisor
idConnection ID
typeMessage type
dataMessage
lenLength of message
Return values
rcReturn status code

Definition at line 449 of file hyperv.c.

450 {
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}
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
ring len
Length.
Definition dwmac.h:226
uint32_t type
Operating system type.
Definition ena.h:1
uint8_t data[48]
Additional event data.
Definition ena.h:11
#define DBGC2_HDA(...)
Definition compiler.h:523
#define EHV(status)
Convert a Hyper-V status code to an iPXE status code.
Definition hyperv.c:68
#define cpu_to_le32(value)
Definition byteswap.h:108
#define HV_POST_MESSAGE
Post message.
Definition hyperv.h:75
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void msg(unsigned int row, const char *fmt,...)
Print message centred on specified row.
Definition message.c:62
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
A posted message.
Definition hyperv.h:81
struct hv_post_message posted
Posted message.
Definition hyperv.h:195

References assert, cpu_to_le32, data, DBGC, DBGC2, DBGC2_HDA, EHV, HV_POST_MESSAGE, len, memcpy(), memset(), hv_hypervisor::message, msg(), NULL, hv_message_buffer::posted, rc, status, strerror(), and type.

◆ hv_wait_for_message()

int hv_wait_for_message ( struct hv_hypervisor * hv,
unsigned int sintx )

Wait for received message.

Parameters
hvHyper-V hypervisor
sintxSynthetic interrupt number
Return values
rcReturn status code

Definition at line 486 of file hyperv.c.

486 {
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}
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition acpi.c:48
#define HV_X64_MSR_EOM
SynIC end of message MSR.
Definition hyperv.h:58
static const void * src
Definition string.h:48
#define ETIMEDOUT
Connection timed out.
Definition errno.h:670
#define HV_MESSAGE_MAX_WAIT_MS
Maximum time to wait for a message response.
Definition hyperv.c:54
#define le32_to_cpu(value)
Definition byteswap.h:114
#define offsetof(type, field)
Get offset of a field within a structure.
Definition stddef.h:25
A received message.
Definition hyperv.h:100
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

References assert, data, DBGC, DBGC2, DBGC2_HDA, ETIMEDOUT, HV_MESSAGE_MAX_WAIT_MS, HV_X64_MSR_EOM, le32_to_cpu, len, mdelay(), memcpy(), memset(), hv_hypervisor::message, hv_synic::message, msg(), offsetof, hv_message_buffer::received, src, hv_hypervisor::synic, and typeof().

Referenced by vmbus_wait_for_any_message().

◆ hv_signal_event()

int hv_signal_event ( struct hv_hypervisor * hv,
unsigned int id,
unsigned int flag )

Signal event.

Parameters
hvHyper-V hypervisor
idConnection ID
flagFlag number
Return values
rcReturn status code

Definition at line 535 of file hyperv.c.

536 {
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}
uint32_t flag
Flag number.
Definition aqc1xx.h:2
#define cpu_to_le16(value)
Definition byteswap.h:107
#define HV_SIGNAL_EVENT
Signal event.
Definition hyperv.h:116
A signalled event.
Definition hyperv.h:119
struct hv_signal_event signalled
Signalled event.
Definition hyperv.h:199

References cpu_to_le16, cpu_to_le32, DBGC, EHV, flag, HV_SIGNAL_EVENT, memset(), hv_hypervisor::message, NULL, rc, hv_message_buffer::signalled, status, and strerror().

◆ hv_probe()

int hv_probe ( struct root_device * rootdev)
static

Probe root device.

Parameters
rootdevRoot device
Return values
rcReturn status code

Definition at line 563 of file hyperv.c.

563 {
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}
static void rootdev_set_drvdata(struct root_device *rootdev, void *priv)
Set root device driver-private data.
Definition device.h:144
static void hv_map_hypercall(struct hv_hypervisor *hv)
Map hypercall page.
Definition hyperv.c:251
static int hv_alloc_message(struct hv_hypervisor *hv)
Allocate message buffer.
Definition hyperv.c:129
static void hv_free_message(struct hv_hypervisor *hv)
Free message buffer.
Definition hyperv.c:147
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
static void hv_map_synic(struct hv_hypervisor *hv)
Map synthetic interrupt controller.
Definition hyperv.c:321
static void hv_unmap_hypercall(struct hv_hypervisor *hv)
Unmap hypercall page.
Definition hyperv.c:300
void hv_free_pages(struct hv_hypervisor *hv,...)
Free pages.
Definition hyperv.c:113
int hv_alloc_pages(struct hv_hypervisor *hv,...)
Allocate zeroed pages.
Definition hyperv.c:78
static void hv_unmap_synic(struct hv_hypervisor *hv)
Unmap synthetic interrupt controller.
Definition hyperv.c:378
static int hv_check_hv(void)
Check whether or not we are running in Hyper-V.
Definition hyperv.c:158
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
A Hyper-V hypervisor.
Definition hyperv.h:203
struct device dev
Device chain.
Definition device.h:103
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

References root_device::dev, ENOMEM, hv_synic::event, free, hv_alloc_message(), hv_alloc_pages(), hv_check_features(), hv_check_hv(), hv_check_uefi(), hv_free_message(), hv_free_pages(), hv_map_hypercall(), hv_map_synic(), hv_unmap_hypercall(), hv_unmap_synic(), hv_hypervisor::hypercall, hv_synic::message, NULL, rc, rootdev_set_drvdata(), hv_hypervisor::synic, vmbus_probe(), vmbus_remove(), and zalloc().

◆ hv_remove()

void hv_remove ( struct root_device * rootdev)
static

Remove root device.

Parameters
rootdevRoot device

Definition at line 630 of file hyperv.c.

630 {
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}
static void * rootdev_get_drvdata(struct root_device *rootdev)
Get root device driver-private data.
Definition device.h:155

References root_device::dev, hv_synic::event, free, hv_free_message(), hv_free_pages(), hv_unmap_hypercall(), hv_unmap_synic(), hv_hypervisor::hypercall, hv_synic::message, NULL, rootdev_get_drvdata(), rootdev_set_drvdata(), hv_hypervisor::synic, and vmbus_remove().

◆ hv_quiesce()

void hv_quiesce ( void )
static

Quiesce system.

Definition at line 659 of file hyperv.c.

659 {
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}
void hv_disable_sint(struct hv_hypervisor *hv, unsigned int sintx)
Disable synthetic interrupt.
Definition hyperv.c:423
#define HV_SINT_MAX
Maximum synthetic interrupt number.
Definition hyperv.h:72

References DBGC, hv_disable_sint(), HV_SINT_MAX, hv_unmap_hypercall(), hv_unmap_synic_no_scontrol(), and rootdev_get_drvdata().

◆ hv_unquiesce()

void hv_unquiesce ( void )
static

Unquiesce system.

Definition at line 704 of file hyperv.c.

704 {
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}
int vmbus_reset(struct hv_hypervisor *hv, struct device *parent)
Reset Hyper-V virtual machine bus.
Definition vmbus.c:1426

References DBGC, hv_map_hypercall(), hv_map_synic(), HV_SIMP_ENABLE, HV_X64_MSR_SIMP, rc, rootdev_get_drvdata(), strerror(), and vmbus_reset().

◆ hv_timer_probe()

int hv_timer_probe ( void )
static

Probe timer.

Return values
rcReturn status code

Definition at line 754 of file hyperv.c.

754 {
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}
#define HV_FEATURES_AVAIL_TIME_REF_COUNT_MSR
Time reference counter MSR is available.
Definition hyperv.h:25

References DBGC, discard_ecx, discard_edx, ENODEV, hv_check_hv(), HV_CPUID_FEATURES, HV_FEATURES_AVAIL_TIME_REF_COUNT_MSR, HV_INTERFACE_ID, and rc.

Referenced by __timer().

◆ hv_currticks()

unsigned long hv_currticks ( void )
static

Get current system time in ticks.

Return values
ticksCurrent time, in ticks

Definition at line 781 of file hyperv.c.

781 {
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}
#define HV_X64_MSR_TIME_REF_COUNT
Time reference MSR.
Definition hyperv.h:46
#define HV_TIMER_SHIFT
Hyper-V timer scale factor (used to avoid 64-bit division)
Definition hyperv.c:60
#define HV_TIMER_HZ
Hyper-V timer frequency (fixed 10Mhz)
Definition hyperv.c:57
#define TICKS_PER_SEC
Number of ticks per second.
Definition timer.h:16

References HV_TIMER_HZ, HV_TIMER_SHIFT, HV_X64_MSR_TIME_REF_COUNT, and TICKS_PER_SEC.

Referenced by __timer().

◆ hv_udelay()

void hv_udelay ( unsigned long usecs)
static

Delay for a fixed number of microseconds.

Parameters
usecsNumber of microseconds for which to delay

Definition at line 795 of file hyperv.c.

795 {
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}
uint32_t start
Starting offset.
Definition netvsc.h:1

References HV_TIMER_HZ, HV_X64_MSR_TIME_REF_COUNT, and start.

Referenced by __timer().

◆ __timer()

struct timer hv_timer __timer ( TIMER_PREFERRED )

◆ REQUIRING_SYMBOL()

REQUIRING_SYMBOL ( hv_root_device )

◆ REQUIRE_OBJECT()

REQUIRE_OBJECT ( netvsc )

Variable Documentation

◆ hv_root_driver

struct root_driver hv_root_driver
static
Initial value:
= {
.probe = hv_probe,
.remove = hv_remove,
}
static void hv_remove(struct root_device *rootdev)
Remove root device.
Definition hyperv.c:630
static int hv_probe(struct root_device *rootdev)
Probe root device.
Definition hyperv.c:563

Hyper-V root device driver.

Definition at line 644 of file hyperv.c.

644 {
645 .probe = hv_probe,
646 .remove = hv_remove,
647};

◆ __root_device

struct root_device hv_root_device __root_device
Initial value:
= {
.dev = { .name = "Hyper-V" },
.driver = &hv_root_driver,
}
static struct root_driver hv_root_driver
Hyper-V root device driver.
Definition hyperv.c:644

Hyper-V root device.

Definition at line 650 of file hyperv.c.

650 {
651 .dev = { .name = "Hyper-V" },
652 .driver = &hv_root_driver,
653};

◆ __quiescer

struct quiescer hv_quiescer __quiescer
Initial value:
= {
.quiesce = hv_quiesce,
.unquiesce = hv_unquiesce,
}
static void hv_quiesce(void)
Quiesce system.
Definition hyperv.c:659
static void hv_unquiesce(void)
Unquiesce system.
Definition hyperv.c:704

Hyper-V quiescer.

Definition at line 744 of file hyperv.c.

744 {
745 .quiesce = hv_quiesce,
746 .unquiesce = hv_unquiesce,
747};