diff --git a/src/arch/x86/drivers/hyperv/hyperv.c b/src/arch/x86/drivers/hyperv/hyperv.c index 4e687687..1903d1db 100644 --- a/src/arch/x86/drivers/hyperv/hyperv.c +++ b/src/arch/x86/drivers/hyperv/hyperv.c @@ -220,6 +220,29 @@ static int hv_check_features ( struct hv_hypervisor *hv ) { return 0; } +/** + * Check that Gen 2 UEFI firmware is not running + * + * @v hv Hyper-V hypervisor + * @ret rc Return 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. + */ +static int hv_check_uefi ( struct hv_hypervisor *hv ) { + uint64_t guest_os_id; + + /* Check for UEFI firmware's guest OS identity */ + guest_os_id = rdmsr ( HV_X64_MSR_GUEST_OS_ID ); + if ( guest_os_id == HV_GUEST_OS_ID_UEFI ) { + DBGC ( hv, "HV %p is owned by UEFI firmware\n", hv ); + return -ENOTSUP; + } + + return 0; +} + /** * Map hypercall page * @@ -556,6 +579,10 @@ static int hv_probe ( struct root_device *rootdev ) { if ( ( rc = hv_check_features ( hv ) ) != 0 ) goto err_check_features; + /* Check that Gen 2 UEFI firmware is not running */ + if ( ( rc = hv_check_uefi ( hv ) ) != 0 ) + goto err_check_uefi; + /* Allocate pages */ if ( ( rc = hv_alloc_pages ( hv, &hv->hypercall, &hv->synic.message, &hv->synic.event, NULL ) ) != 0 ) @@ -587,6 +614,7 @@ static int hv_probe ( struct root_device *rootdev ) { hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event, NULL ); err_alloc_pages: + err_check_uefi: err_check_features: free ( hv ); err_alloc: diff --git a/src/include/ipxe/hyperv.h b/src/include/ipxe/hyperv.h index 9194a976..9b7e54a5 100644 --- a/src/include/ipxe/hyperv.h +++ b/src/include/ipxe/hyperv.h @@ -37,6 +37,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #define HV_GUEST_OS_ID_IPXE ( ( 1ULL << 63 ) | ( 0x18aeULL << 48 ) ) +/** Guest OS identity for Gen 2 UEFI firmware + * + * This does not conform to the documented structure for guest OS + * identities. + */ +#define HV_GUEST_OS_ID_UEFI ( 1ULL << 40 ) + /** Enable hypercall page */ #define HV_HYPERCALL_ENABLE 0x00000001UL