8250598: Hyper-V is detected in spite of running on host OS

Reviewed-by: mbaesken, mdoerr, dholmes
This commit is contained in:
Yasumasa Suenaga 2020-08-26 19:21:09 +09:00
parent b4787e6c3f
commit 0c20de1954
5 changed files with 84 additions and 81 deletions

View file

@ -50,12 +50,14 @@ address VM_Version::_cpuinfo_segv_addr = 0;
address VM_Version::_cpuinfo_cont_addr = 0; address VM_Version::_cpuinfo_cont_addr = 0;
static BufferBlob* stub_blob; static BufferBlob* stub_blob;
static const int stub_size = 1100; static const int stub_size = 2000;
extern "C" { extern "C" {
typedef void (*get_cpu_info_stub_t)(void*); typedef void (*get_cpu_info_stub_t)(void*);
typedef void (*detect_virt_stub_t)(uint32_t, uint32_t*);
} }
static get_cpu_info_stub_t get_cpu_info_stub = NULL; static get_cpu_info_stub_t get_cpu_info_stub = NULL;
static detect_virt_stub_t detect_virt_stub = NULL;
class VM_Version_StubGenerator: public StubCodeGenerator { class VM_Version_StubGenerator: public StubCodeGenerator {
@ -568,6 +570,43 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ vzeroupper_uncached(); __ vzeroupper_uncached();
# undef __ # undef __
} }
address generate_detect_virt() {
StubCodeMark mark(this, "VM_Version", "detect_virt_stub");
# define __ _masm->
address start = __ pc();
// Evacuate callee-saved registers
__ push(rbp);
__ push(rbx);
__ push(rsi); // for Windows
#ifdef _LP64
__ mov(rax, c_rarg0); // CPUID leaf
__ mov(rsi, c_rarg1); // register array address (eax, ebx, ecx, edx)
#else
__ movptr(rax, Address(rsp, 16)); // CPUID leaf
__ movptr(rsi, Address(rsp, 20)); // register array address
#endif
__ cpuid();
// Store result to register array
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi, 12), rdx);
// Epilogue
__ pop(rsi);
__ pop(rbx);
__ pop(rbp);
__ ret(0);
# undef __
return start;
};
}; };
void VM_Version::get_processor_features() { void VM_Version::get_processor_features() {
@ -1671,56 +1710,12 @@ void VM_Version::print_platform_virtualization_info(outputStream* st) {
st->print_cr("VMWare virtualization detected"); st->print_cr("VMWare virtualization detected");
VirtualizationSupport::print_virtualization_info(st); VirtualizationSupport::print_virtualization_info(st);
} else if (vrt == HyperV) { } else if (vrt == HyperV) {
st->print_cr("HyperV virtualization detected"); st->print_cr("Hyper-V virtualization detected");
} else if (vrt == HyperVRole) {
st->print_cr("Hyper-V role detected");
} }
} }
void VM_Version::check_virt_cpuid(uint32_t idx, uint32_t *regs) {
// TODO support 32 bit
#if defined(_LP64)
#if defined(_MSC_VER)
// Allocate space for the code
const int code_size = 100;
ResourceMark rm;
CodeBuffer cb("detect_virt", code_size, 0);
MacroAssembler* a = new MacroAssembler(&cb);
address code = a->pc();
void (*test)(uint32_t idx, uint32_t *regs) = (void(*)(uint32_t idx, uint32_t *regs))code;
a->movq(r9, rbx); // save nonvolatile register
// next line would not work on 32-bit
a->movq(rax, c_rarg0 /* rcx */);
a->movq(r8, c_rarg1 /* rdx */);
a->cpuid();
a->movl(Address(r8, 0), rax);
a->movl(Address(r8, 4), rbx);
a->movl(Address(r8, 8), rcx);
a->movl(Address(r8, 12), rdx);
a->movq(rbx, r9); // restore nonvolatile register
a->ret(0);
uint32_t *code_end = (uint32_t *)a->pc();
a->flush();
// execute code
(*test)(idx, regs);
#elif defined(__GNUC__)
__asm__ volatile (
" cpuid;"
" mov %%eax,(%1);"
" mov %%ebx,4(%1);"
" mov %%ecx,8(%1);"
" mov %%edx,12(%1);"
: "+a" (idx)
: "S" (regs)
: "ebx", "ecx", "edx", "memory" );
#endif
#endif
}
bool VM_Version::use_biased_locking() { bool VM_Version::use_biased_locking() {
#if INCLUDE_RTM_OPT #if INCLUDE_RTM_OPT
// RTM locking is most useful when there is high lock contention and // RTM locking is most useful when there is high lock contention and
@ -1821,59 +1816,62 @@ bool VM_Version::compute_has_intel_jcc_erratum() {
// https://kb.vmware.com/s/article/1009458 // https://kb.vmware.com/s/article/1009458
// //
void VM_Version::check_virtualizations() { void VM_Version::check_virtualizations() {
#if defined(_LP64) uint32_t registers[4] = {0};
uint32_t registers[4]; char signature[13] = {0};
char signature[13];
uint32_t base;
signature[12] = '\0';
memset((void*)registers, 0, 4*sizeof(uint32_t));
for (base = 0x40000000; base < 0x40010000; base += 0x100) { // Xen cpuid leaves can be found 0x100 aligned boundary starting
check_virt_cpuid(base, registers); // from 0x40000000 until 0x40010000.
// https://lists.linuxfoundation.org/pipermail/virtualization/2012-May/019974.html
*(uint32_t *)(signature + 0) = registers[1]; for (int leaf = 0x40000000; leaf < 0x40010000; leaf += 0x100) {
*(uint32_t *)(signature + 4) = registers[2]; detect_virt_stub(leaf, registers);
*(uint32_t *)(signature + 8) = registers[3]; memcpy(signature, &registers[1], 12);
if (strncmp("VMwareVMware", signature, 12) == 0) { if (strncmp("VMwareVMware", signature, 12) == 0) {
Abstract_VM_Version::_detected_virtualization = VMWare; Abstract_VM_Version::_detected_virtualization = VMWare;
// check for extended metrics from guestlib // check for extended metrics from guestlib
VirtualizationSupport::initialize(); VirtualizationSupport::initialize();
} } else if (strncmp("Microsoft Hv", signature, 12) == 0) {
if (strncmp("Microsoft Hv", signature, 12) == 0) {
Abstract_VM_Version::_detected_virtualization = HyperV; Abstract_VM_Version::_detected_virtualization = HyperV;
#ifdef _WINDOWS
// CPUID leaf 0x40000007 is available to the root partition only.
// See Hypervisor Top Level Functional Specification section 2.4.8 for more details.
// https://github.com/MicrosoftDocs/Virtualization-Documentation/raw/master/tlfs/Hypervisor%20Top%20Level%20Functional%20Specification%20v6.0b.pdf
detect_virt_stub(0x40000007, registers);
if ((registers[0] != 0x0) ||
(registers[1] != 0x0) ||
(registers[2] != 0x0) ||
(registers[3] != 0x0)) {
Abstract_VM_Version::_detected_virtualization = HyperVRole;
} }
#endif
if (strncmp("KVMKVMKVM", signature, 9) == 0) { } else if (strncmp("KVMKVMKVM", signature, 9) == 0) {
Abstract_VM_Version::_detected_virtualization = KVM; Abstract_VM_Version::_detected_virtualization = KVM;
} } else if (strncmp("XenVMMXenVMM", signature, 12) == 0) {
if (strncmp("XenVMMXenVMM", signature, 12) == 0) {
Abstract_VM_Version::_detected_virtualization = XenHVM; Abstract_VM_Version::_detected_virtualization = XenHVM;
} }
} }
#endif
} }
void VM_Version::initialize() { void VM_Version::initialize() {
ResourceMark rm; ResourceMark rm;
// Making this stub must be FIRST use of assembler // Making this stub must be FIRST use of assembler
stub_blob = BufferBlob::create("VM_Version stub", stub_size);
stub_blob = BufferBlob::create("get_cpu_info_stub", stub_size);
if (stub_blob == NULL) { if (stub_blob == NULL) {
vm_exit_during_initialization("Unable to allocate get_cpu_info_stub"); vm_exit_during_initialization("Unable to allocate stub for VM_Version");
} }
CodeBuffer c(stub_blob); CodeBuffer c(stub_blob);
VM_Version_StubGenerator g(&c); VM_Version_StubGenerator g(&c);
get_cpu_info_stub = CAST_TO_FN_PTR(get_cpu_info_stub_t, get_cpu_info_stub = CAST_TO_FN_PTR(get_cpu_info_stub_t,
g.generate_get_cpu_info()); g.generate_get_cpu_info());
detect_virt_stub = CAST_TO_FN_PTR(detect_virt_stub_t,
g.generate_detect_virt());
get_processor_features(); get_processor_features();
LP64_ONLY(Assembler::precompute_instructions();) LP64_ONLY(Assembler::precompute_instructions();)
if (cpu_family() > 4) { // it supports CPUID if (VM_Version::supports_hv()) { // Supports hypervisor
check_virtualizations(); check_virtualizations();
} }
} }

View file

@ -89,7 +89,8 @@ class VM_Version : public Abstract_VM_Version {
: 1, : 1,
osxsave : 1, osxsave : 1,
avx : 1, avx : 1,
: 3; : 2,
hv : 1;
} bits; } bits;
}; };
@ -348,6 +349,7 @@ protected:
#define CPU_CLWB ((uint64_t)UCONST64( 0x80000000000)) // clwb instruction #define CPU_CLWB ((uint64_t)UCONST64( 0x80000000000)) // clwb instruction
#define CPU_AVX512_VBMI2 ((uint64_t)UCONST64(0x100000000000)) // VBMI2 shift left double instructions #define CPU_AVX512_VBMI2 ((uint64_t)UCONST64(0x100000000000)) // VBMI2 shift left double instructions
#define CPU_AVX512_VBMI ((uint64_t)UCONST64(0x200000000000)) // Vector BMI instructions #define CPU_AVX512_VBMI ((uint64_t)UCONST64(0x200000000000)) // Vector BMI instructions
#define CPU_HV_PRESENT ((uint64_t)UCONST64(0x400000000000)) // for hypervisor detection
// NB! When adding new CPU feature detection consider updating vmStructs_x86.hpp, vmStructs_jvmci.hpp, and VM_Version::get_processor_features(). // NB! When adding new CPU feature detection consider updating vmStructs_x86.hpp, vmStructs_jvmci.hpp, and VM_Version::get_processor_features().
@ -580,6 +582,8 @@ enum Extended_Family {
result |= CPU_AVX512_VBMI2; result |= CPU_AVX512_VBMI2;
} }
} }
if (_cpuid_info.std_cpuid1_ecx.bits.hv != 0)
result |= CPU_HV_PRESENT;
if (_cpuid_info.sef_cpuid7_ebx.bits.bmi1 != 0) if (_cpuid_info.sef_cpuid7_ebx.bits.bmi1 != 0)
result |= CPU_BMI1; result |= CPU_BMI1;
if (_cpuid_info.std_cpuid1_edx.bits.tsc != 0) if (_cpuid_info.std_cpuid1_edx.bits.tsc != 0)
@ -871,6 +875,7 @@ public:
static bool supports_avx512_vnni() { return (_features & CPU_AVX512_VNNI) != 0; } static bool supports_avx512_vnni() { return (_features & CPU_AVX512_VNNI) != 0; }
static bool supports_avx512_vbmi() { return (_features & CPU_AVX512_VBMI) != 0; } static bool supports_avx512_vbmi() { return (_features & CPU_AVX512_VBMI) != 0; }
static bool supports_avx512_vbmi2() { return (_features & CPU_AVX512_VBMI2) != 0; } static bool supports_avx512_vbmi2() { return (_features & CPU_AVX512_VBMI2) != 0; }
static bool supports_hv() { return (_features & CPU_HV_PRESENT) != 0; }
// Intel features // Intel features
static bool is_intel_family_core() { return is_intel() && static bool is_intel_family_core() { return is_intel() &&
@ -1023,7 +1028,6 @@ public:
// support functions for virtualization detection // support functions for virtualization detection
private: private:
static void check_virt_cpuid(uint32_t idx, uint32_t *regs);
static void check_virtualizations(); static void check_virtualizations();
}; };

View file

@ -1609,9 +1609,7 @@ void os::print_os_info(outputStream* st) {
os::win32::print_uptime_info(st); os::win32::print_uptime_info(st);
#ifdef _LP64
VM_Version::print_platform_virtualization_info(st); VM_Version::print_platform_virtualization_info(st);
#endif
} }
void os::win32::print_windows_version(outputStream* st) { void os::win32::print_windows_version(outputStream* st) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -265,7 +265,9 @@ const char* JfrOSInterface::virtualization_name() {
} else if (vrt == VMWare) { } else if (vrt == VMWare) {
return "VMWare virtualization"; return "VMWare virtualization";
} else if (vrt == HyperV) { } else if (vrt == HyperV) {
return "HyperV virtualization"; return "Hyper-V virtualization";
} else if (vrt == HyperVRole) {
return "Hyper-V role";
} else if (vrt == PowerVM) { } else if (vrt == PowerVM) {
return "PowerVM virtualization"; return "PowerVM virtualization";
} else if (vrt == PowerKVM) { } else if (vrt == PowerKVM) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -34,6 +34,7 @@ typedef enum {
KVM, KVM,
VMWare, VMWare,
HyperV, HyperV,
HyperVRole,
PowerVM, // on AIX or Linux ppc64(le) PowerVM, // on AIX or Linux ppc64(le)
PowerFullPartitionMode, // on Linux ppc64(le) PowerFullPartitionMode, // on Linux ppc64(le)
PowerKVM PowerKVM