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

@ -50,12 +50,14 @@ address VM_Version::_cpuinfo_segv_addr = 0;
address VM_Version::_cpuinfo_cont_addr = 0;
static BufferBlob* stub_blob;
static const int stub_size = 1100;
static const int stub_size = 2000;
extern "C" {
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 detect_virt_stub_t detect_virt_stub = NULL;
class VM_Version_StubGenerator: public StubCodeGenerator {
@ -568,6 +570,43 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ vzeroupper_uncached();
# 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() {
@ -1671,56 +1710,12 @@ void VM_Version::print_platform_virtualization_info(outputStream* st) {
st->print_cr("VMWare virtualization detected");
VirtualizationSupport::print_virtualization_info(st);
} 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() {
#if INCLUDE_RTM_OPT
// 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
//
void VM_Version::check_virtualizations() {
#if defined(_LP64)
uint32_t registers[4];
char signature[13];
uint32_t base;
signature[12] = '\0';
memset((void*)registers, 0, 4*sizeof(uint32_t));
uint32_t registers[4] = {0};
char signature[13] = {0};
for (base = 0x40000000; base < 0x40010000; base += 0x100) {
check_virt_cpuid(base, registers);
*(uint32_t *)(signature + 0) = registers[1];
*(uint32_t *)(signature + 4) = registers[2];
*(uint32_t *)(signature + 8) = registers[3];
// Xen cpuid leaves can be found 0x100 aligned boundary starting
// from 0x40000000 until 0x40010000.
// https://lists.linuxfoundation.org/pipermail/virtualization/2012-May/019974.html
for (int leaf = 0x40000000; leaf < 0x40010000; leaf += 0x100) {
detect_virt_stub(leaf, registers);
memcpy(signature, &registers[1], 12);
if (strncmp("VMwareVMware", signature, 12) == 0) {
Abstract_VM_Version::_detected_virtualization = VMWare;
// check for extended metrics from guestlib
VirtualizationSupport::initialize();
}
if (strncmp("Microsoft Hv", signature, 12) == 0) {
} else if (strncmp("Microsoft Hv", signature, 12) == 0) {
Abstract_VM_Version::_detected_virtualization = HyperV;
}
if (strncmp("KVMKVMKVM", signature, 9) == 0) {
#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
} else if (strncmp("KVMKVMKVM", signature, 9) == 0) {
Abstract_VM_Version::_detected_virtualization = KVM;
}
if (strncmp("XenVMMXenVMM", signature, 12) == 0) {
} else if (strncmp("XenVMMXenVMM", signature, 12) == 0) {
Abstract_VM_Version::_detected_virtualization = XenHVM;
}
}
#endif
}
void VM_Version::initialize() {
ResourceMark rm;
// Making this stub must be FIRST use of assembler
stub_blob = BufferBlob::create("get_cpu_info_stub", stub_size);
stub_blob = BufferBlob::create("VM_Version stub", stub_size);
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);
VM_Version_StubGenerator g(&c);
get_cpu_info_stub = CAST_TO_FN_PTR(get_cpu_info_stub_t,
g.generate_get_cpu_info());
detect_virt_stub = CAST_TO_FN_PTR(detect_virt_stub_t,
g.generate_detect_virt());
get_processor_features();
LP64_ONLY(Assembler::precompute_instructions();)
if (cpu_family() > 4) { // it supports CPUID
if (VM_Version::supports_hv()) { // Supports hypervisor
check_virtualizations();
}
}

@ -89,7 +89,8 @@ class VM_Version : public Abstract_VM_Version {
: 1,
osxsave : 1,
avx : 1,
: 3;
: 2,
hv : 1;
} bits;
};
@ -348,6 +349,7 @@ protected:
#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_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().
@ -580,6 +582,8 @@ enum Extended_Family {
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)
result |= CPU_BMI1;
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_vbmi() { return (_features & CPU_AVX512_VBMI) != 0; }
static bool supports_avx512_vbmi2() { return (_features & CPU_AVX512_VBMI2) != 0; }
static bool supports_hv() { return (_features & CPU_HV_PRESENT) != 0; }
// Intel features
static bool is_intel_family_core() { return is_intel() &&
@ -1023,7 +1028,6 @@ public:
// support functions for virtualization detection
private:
static void check_virt_cpuid(uint32_t idx, uint32_t *regs);
static void check_virtualizations();
};

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

@ -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.
*
* 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) {
return "VMWare virtualization";
} else if (vrt == HyperV) {
return "HyperV virtualization";
return "Hyper-V virtualization";
} else if (vrt == HyperVRole) {
return "Hyper-V role";
} else if (vrt == PowerVM) {
return "PowerVM virtualization";
} else if (vrt == PowerKVM) {

@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,6 +34,7 @@ typedef enum {
KVM,
VMWare,
HyperV,
HyperVRole,
PowerVM, // on AIX or Linux ppc64(le)
PowerFullPartitionMode, // on Linux ppc64(le)
PowerKVM