mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
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
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;
|
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, ®isters[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.
|
||||||
if (strncmp("KVMKVMKVM", signature, 9) == 0) {
|
// 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;
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue