Browse Source

[hyperv] Do not steal ownership from the Gen 2 UEFI firmware

We must not steal ownership from the Gen 2 UEFI firmware, since doing
so will cause an immediate system crash (most likely in the form of a
reboot).

This problem was masked before commit a0f6e75 ("[hyperv] Do not fail
if guest OS ID MSR is already set"), since prior to that commit we
would always fail if we found any non-zero guest OS identity.  We now
accept a non-zero previous guest OS identity in order to allow for
situations such as chainloading from iPXE to another iPXE, and as a
prerequisite for commit b91cc98 ("[hyperv] Cope with Windows Server
2016 enlightenments").

A proper fix would be to reverse engineer the UEFI protocols exposed
within the Hyper-V Gen 2 firmware and use these to bind to the VMBus
device representing the network connection, (with the native Hyper-V
driver moved to become a BIOS-only feature).

As an interim solution, fail to initialise the native Hyper-V driver
if we detect the guest OS identity known to be used by the Gen 2 UEFI
firmware.  This will cause the standard all-drivers build (ipxe.efi)
to fall back to using the SNP driver.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 7 years ago
parent
commit
936657832f
2 changed files with 35 additions and 0 deletions
  1. 28
    0
      src/arch/x86/drivers/hyperv/hyperv.c
  2. 7
    0
      src/include/ipxe/hyperv.h

+ 28
- 0
src/arch/x86/drivers/hyperv/hyperv.c View File

220
 	return 0;
220
 	return 0;
221
 }
221
 }
222
 
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
+ */
233
+static 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
+
223
 /**
246
 /**
224
  * Map hypercall page
247
  * Map hypercall page
225
  *
248
  *
556
 	if ( ( rc = hv_check_features ( hv ) ) != 0 )
579
 	if ( ( rc = hv_check_features ( hv ) ) != 0 )
557
 		goto err_check_features;
580
 		goto err_check_features;
558
 
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
+
559
 	/* Allocate pages */
586
 	/* Allocate pages */
560
 	if ( ( rc = hv_alloc_pages ( hv, &hv->hypercall, &hv->synic.message,
587
 	if ( ( rc = hv_alloc_pages ( hv, &hv->hypercall, &hv->synic.message,
561
 				     &hv->synic.event, NULL ) ) != 0 )
588
 				     &hv->synic.event, NULL ) ) != 0 )
587
 	hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event,
614
 	hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event,
588
 			NULL );
615
 			NULL );
589
  err_alloc_pages:
616
  err_alloc_pages:
617
+ err_check_uefi:
590
  err_check_features:
618
  err_check_features:
591
 	free ( hv );
619
 	free ( hv );
592
  err_alloc:
620
  err_alloc:

+ 7
- 0
src/include/ipxe/hyperv.h View File

37
  */
37
  */
38
 #define HV_GUEST_OS_ID_IPXE ( ( 1ULL << 63 ) | ( 0x18aeULL << 48 ) )
38
 #define HV_GUEST_OS_ID_IPXE ( ( 1ULL << 63 ) | ( 0x18aeULL << 48 ) )
39
 
39
 
40
+/** Guest OS identity for Gen 2 UEFI firmware
41
+ *
42
+ * This does not conform to the documented structure for guest OS
43
+ * identities.
44
+ */
45
+#define HV_GUEST_OS_ID_UEFI ( 1ULL << 40 )
46
+
40
 /** Enable hypercall page */
47
 /** Enable hypercall page */
41
 #define HV_HYPERCALL_ENABLE 0x00000001UL
48
 #define HV_HYPERCALL_ENABLE 0x00000001UL
42
 
49
 

Loading…
Cancel
Save