Kaynağa Gözat

[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 yıl önce
ebeveyn
işleme
936657832f

+ 28
- 0
src/arch/x86/drivers/hyperv/hyperv.c Dosyayı Görüntüle

@@ -220,6 +220,29 @@ static int hv_check_features ( struct hv_hypervisor *hv ) {
220 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 247
  * Map hypercall page
225 248
  *
@@ -556,6 +579,10 @@ static int hv_probe ( struct root_device *rootdev ) {
556 579
 	if ( ( rc = hv_check_features ( hv ) ) != 0 )
557 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 586
 	/* Allocate pages */
560 587
 	if ( ( rc = hv_alloc_pages ( hv, &hv->hypercall, &hv->synic.message,
561 588
 				     &hv->synic.event, NULL ) ) != 0 )
@@ -587,6 +614,7 @@ static int hv_probe ( struct root_device *rootdev ) {
587 614
 	hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event,
588 615
 			NULL );
589 616
  err_alloc_pages:
617
+ err_check_uefi:
590 618
  err_check_features:
591 619
 	free ( hv );
592 620
  err_alloc:

+ 7
- 0
src/include/ipxe/hyperv.h Dosyayı Görüntüle

@@ -37,6 +37,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
37 37
  */
38 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 47
 /** Enable hypercall page */
41 48
 #define HV_HYPERCALL_ENABLE 0x00000001UL
42 49
 

Loading…
İptal
Kaydet