8250598: Hyper-V is detected in spite of running on host OS
Reviewed-by: mbaesken, mdoerr, dholmes
This commit is contained in:
parent
b4787e6c3f
commit
0c20de1954
src/hotspot
cpu/x86
os/windows
share
@ -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, ®isters[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
|
||||
|
Loading…
x
Reference in New Issue
Block a user