< prev index next >

src/cpu/x86/vm/vm_version_x86.cpp

Print this page
rev 9054 : 8219241: Provide basic virtualization related info in the hs_error file on linux/windows x86_64
Reviewed-by: dholmes, mdoerr

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.

@@ -1090,10 +1090,69 @@
     }
   }
 #endif // !PRODUCT
 }
 
+void VM_Version::print_platform_virtualization_info(outputStream* st) {
+  VirtualizationType vrt = VM_Version::get_detected_virtualization();
+  if (vrt == XenHVM) {
+    st->print_cr("Xen hardware-assisted virtualization detected");
+  } else if (vrt == KVM) {
+    st->print_cr("KVM virtualization detected");
+  } else if (vrt == VMWare) {
+    st->print_cr("VMWare virtualization detected");
+  } else if (vrt == HyperV) {
+    st->print_cr("HyperV virtualization 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
   // low data contention.  With high lock contention the lock is usually
   // inflated and biased locking is not suitable for that case.

@@ -1111,10 +1170,58 @@
   }
 #endif
   return UseBiasedLocking;
 }
 
+// On Xen, the cpuid instruction returns
+//  eax / registers[0]: Version of Xen
+//  ebx / registers[1]: chars 'XenV'
+//  ecx / registers[2]: chars 'MMXe'
+//  edx / registers[3]: chars 'nVMM'
+//
+// On KVM / VMWare / MS Hyper-V, the cpuid instruction returns
+//  ebx / registers[1]: chars 'KVMK' / 'VMwa' / 'Micr'
+//  ecx / registers[2]: chars 'VMKV' / 'reVM' / 'osof'
+//  edx / registers[3]: chars 'M'    / 'ware' / 't Hv'
+//
+// more information :
+// 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));
+
+  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];
+
+    if (strncmp("VMwareVMware", signature, 12) == 0) {
+      Abstract_VM_Version::_detected_virtualization = VMWare;
+    }
+
+    if (strncmp("Microsoft Hv", signature, 12) == 0) {
+      Abstract_VM_Version::_detected_virtualization = HyperV;
+    }
+
+    if (strncmp("KVMKVMKVM", signature, 9) == 0) {
+      Abstract_VM_Version::_detected_virtualization = KVM;
+    }
+
+    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);

@@ -1125,6 +1232,9 @@
   VM_Version_StubGenerator g(&c);
   get_cpu_info_stub = CAST_TO_FN_PTR(get_cpu_info_stub_t,
                                      g.generate_get_cpu_info());
 
   get_processor_features();
+  if (cpu_family() > 4) { // it supports CPUID
+    check_virtualizations();
+  }
 }
< prev index next >