Geoff Chappell - Software Analyst
The HviGetHypervisorVendorAndMaxFunction function obtains the output of a hypervisor’s cpuid leaf 0x40000000.
VOID HviGetHypervisorVendorAndMaxFunction (HV_VENDOR_AND_MAX_FUNCTION *);
The one argument provides the address of a structure that is to receive the cpuid output.
The HviGetHypervisorVendorAndMaxFunction function is exported by name from the kernel in version 10.0 and higher.
The version 6.3 kernel has an inline routine that is coded very similarly to the version 10.0 HviGetHypervisorVendorAndMaxFunction. Public symbol files for the version 6.3 kernel confirm that this earlier kernel has an inline routine that was already named HviGetHypervisorVendorAndMaxFunction and had as its one argument a pointer to an HV_VENDOR_AND_MAX_FUNCTION. That the inline routine in the binary is the same as named in the symbol files which is in turn the origin of the exported function must be all but certain.
The HviGetHypervisorVendorAndMaxFunction function is not documented.
If a hypervisor is present—see HviIsAnyHypervisorPresent—then the function copies to the given address whatever cpuid leaf 0x40000000 produces in the eax, ebx, ecx and edx registers.
Otherwise, the structure at the given address is zeroed. This, in effect, is the function’s indication of failure.
The kernel is largely unconcerned with the Vendor. This is consistent with the Hypervisor Top-Level Functional Specification (TLFS), which advises that “The vendor ID signature should be used only for reporting and diagnostic purposes” and recommends “that software only base compatibility decisions on the interface signature reported through leaf 0x40000001.” The MaxFunction, by contrast, is important to the kernel and surely also to external callers, for assurance that output from a given cpuid leaf is meaningful. The kernel never executes any cpuid leaf beyond 0x40000005 without checking that the leaf is no greater than MaxFunction.
In practice, then, the primary purpose of HviGetHypervisorVendorAndMaxFunction is to get the MaxFunction. Public symbol files for the version 6.3 kernel confirm that Microsoft’s programmers had an inline routine that extracts just the MaxFunction:
UINT32 HvipGetMaxFunction (VOID);
This looks like it exists solely as a convenience. The only coding that looks plausible for it in the binary is that it calls the inline routine HviGetHypervisorVendorAndMaxFunction, returns the MaxFunction and discards the Vendor. This then would be a use (if not the use) that gets HviGetHypervisorVendorAndMaxFunction into the public symbol files. That HvipGetMaxFunction is also in the public symbol files would follow from its use by the inline routine HviGetHardwareFeatures. This coding all continues to Windows 10. That it doesn’t show in the public symbol files for any Windows 10 kernel pretty much proves that even though HviGetHypervisorVendorAndMaxFunction does still get inlined, it is no longer defined in a header, e.g., hvgdk_mini.h, that gets included by the source file (ntsym.c) that’s used for merging type information into the public symbols.