8188857: [s390]: CPU feature detection incomplete
authorlucy
Mon, 09 Oct 2017 11:51:20 +0200
changeset 47607 c2ff34932cbd
parent 47606 660175b829e8
child 47608 9d337e48b178
8188857: [s390]: CPU feature detection incomplete Reviewed-by: mdoerr
src/hotspot/cpu/s390/vm_version_s390.cpp
src/hotspot/cpu/s390/vm_version_s390.hpp
src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp
--- a/src/hotspot/cpu/s390/vm_version_s390.cpp	Mon Oct 09 11:43:42 2017 +0200
+++ b/src/hotspot/cpu/s390/vm_version_s390.cpp	Mon Oct 09 11:51:20 2017 +0200
@@ -706,12 +706,13 @@
   Label    getCPUFEATURES;                   // fcode = -1 (cache)
   Label    getCIPHERFEATURES;                // fcode = -2 (cipher)
   Label    getMSGDIGESTFEATURES;             // fcode = -3 (SHA)
+  Label    getVECTORFEATURES;                // fcode = -4 (OS support for vector instructions)
   Label    checkLongDispFast;
   Label    noLongDisp;
   Label    posDisp, negDisp;
   Label    errRTN;
   a->z_ltgfr(Z_R0, Z_ARG2);                  // Buf len to r0 and test.
-  a->z_brl(getFEATURES);                     // negative -> Get machine features.
+  a->z_brl(getFEATURES);                     // negative -> Get machine features not covered by facility list.
   a->z_brz(checkLongDispFast);               // zero -> Check for high-speed Long Displacement Facility.
   a->z_aghi(Z_R0, -1);
   a->z_stfle(0, Z_ARG1);
@@ -736,6 +737,8 @@
   a->z_bre(getCIPHERFEATURES);
   a->z_cghi(Z_R0, -3);                       // -3: Extract detailed crypto capabilities (msg digest instructions).
   a->z_bre(getMSGDIGESTFEATURES);
+  a->z_cghi(Z_R0, -4);                       // -4: Verify vector instruction availability (OS support).
+  a->z_bre(getVECTORFEATURES);
 
   a->z_xgr(Z_RET, Z_RET);                    // Not a valid function code.
   a->z_br(Z_R14);                            // Return "operation aborted".
@@ -766,6 +769,11 @@
   a->z_ecag(Z_RET,Z_R0,0,Z_ARG3);            // Extract information as requested by Z_ARG1 contents.
   a->z_br(Z_R14);
 
+  // Use a vector instruction to verify OS support. Will fail with SIGFPE if OS support is missing.
+  a->bind(getVECTORFEATURES);
+  a->z_vtm(Z_V0,Z_V0);                       // non-destructive vector instruction. Will cause SIGFPE if not supported.
+  a->z_br(Z_R14);
+
   // Check the performance of the Long Displacement Facility, i.e. find out if we are running on z900 or newer.
   a->bind(checkLongDispFast);
   a->z_llill(Z_R0, 0xffff);                  // preset #iterations
@@ -962,6 +970,19 @@
     _nfeatures = 0;
   }
 
+  if (has_VectorFacility()) {
+    // Verify that feature can actually be used. OS support required.
+    call_getFeatures(buffer, -4, 0);
+    if (printVerbose) {
+      ttyLocker ttyl;
+      if (has_VectorFacility()) {
+        tty->print_cr("  Vector Facility has been verified to be supported by OS");
+      } else {
+        tty->print_cr("  Vector Facility has been disabled - not supported by OS");
+      }
+    }
+  }
+
   // Extract Crypto Facility details.
   if (has_Crypto()) {
     // Get cipher features.
--- a/src/hotspot/cpu/s390/vm_version_s390.hpp	Mon Oct 09 11:43:42 2017 +0200
+++ b/src/hotspot/cpu/s390/vm_version_s390.hpp	Mon Oct 09 11:51:20 2017 +0200
@@ -473,6 +473,8 @@
   static void set_has_CryptoExt5()                { _features[0] |= CryptoExtension5Mask; }
   static void set_has_VectorFacility()            { _features[2] |= VectorFacilityMask; }
 
+  static void reset_has_VectorFacility()          { _features[2] &= ~VectorFacilityMask; }
+
   // Assembler testing.
   static void allow_all();
   static void revert();
--- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp	Mon Oct 09 11:43:42 2017 +0200
+++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp	Mon Oct 09 11:51:20 2017 +0200
@@ -448,11 +448,17 @@
     }
 
     else { // thread->thread_state() != _thread_in_Java
-      if (sig == SIGILL && VM_Version::is_determine_features_test_running()) {
-        // SIGILL must be caused by VM_Version::determine_features().
+      if ((sig == SIGILL) && VM_Version::is_determine_features_test_running()) {
+        // SIGILL must be caused by VM_Version::determine_features()
+        // when attempting to execute a non-existing instruction.
         //*(int *) (pc-6)=0; // Patch instruction to 0 to indicate that it causes a SIGILL.
                              // Flushing of icache is not necessary.
         stub = pc; // Continue with next instruction.
+      } else if ((sig == SIGFPE) && VM_Version::is_determine_features_test_running()) {
+        // SIGFPE is known to be caused by trying to execute a vector instruction
+        // when the vector facility is installed, but operating system support is missing.
+        VM_Version::reset_has_VectorFacility();
+        stub = pc; // Continue with next instruction.
       } else if (thread->thread_state() == _thread_in_vm &&
                  sig == SIGBUS && thread->doing_unsafe_access()) {
         // We don't really need a stub here! Just set the pending exeption and
@@ -510,7 +516,7 @@
   // Note: this should be combined with the trap_pc handling above,
   // because it handles the same issue.
   if (sig == SIGILL || sig == SIGFPE) {
-    pc = (address) info->si_addr;
+    pc = (address)info->si_addr;
   }
 
   VMError::report_and_die(t, sig, pc, info, ucVoid);