8222825: ARM32 SIGILL issue on single core CPU (not supported PLDW instruction)
authorbulasevich
Thu, 16 May 2019 18:45:30 -0400
changeset 54915 278600885731
parent 54914 9feb4852536f
child 54916 7136c9ac56a7
8222825: ARM32 SIGILL issue on single core CPU (not supported PLDW instruction) Reviewed-by: dholmes, dlong
src/hotspot/cpu/arm/arm.ad
src/hotspot/cpu/arm/assembler_arm_32.hpp
src/hotspot/cpu/arm/vm_version_arm.hpp
src/hotspot/cpu/arm/vm_version_arm_32.cpp
src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp
--- a/src/hotspot/cpu/arm/arm.ad	Fri May 17 00:21:10 2019 +0200
+++ b/src/hotspot/cpu/arm/arm.ad	Thu May 16 18:45:30 2019 -0400
@@ -4348,7 +4348,8 @@
 // Prefetch instructions.
 // Must be safe to execute with invalid address (cannot fault).
 
-instruct prefetchAlloc( memoryP mem ) %{
+instruct prefetchAlloc_mp( memoryP mem ) %{
+  predicate(VM_Version::has_multiprocessing_extensions());
   match( PrefetchAllocation mem );
   ins_cost(MEMORY_REF_COST);
   size(4);
@@ -4360,6 +4361,20 @@
   ins_pipe(iload_mem);
 %}
 
+instruct prefetchAlloc_sp( memoryP mem ) %{
+  predicate(!VM_Version::has_multiprocessing_extensions());
+  match( PrefetchAllocation mem );
+  ins_cost(MEMORY_REF_COST);
+  size(4);
+
+  format %{ "PLD $mem\t! Prefetch allocation" %}
+  ins_encode %{
+    __ pld($mem$$Address);
+  %}
+  ins_pipe(iload_mem);
+%}
+
+
 //----------Store Instructions-------------------------------------------------
 // Store Byte
 instruct storeB(memoryB mem, store_RegI src) %{
--- a/src/hotspot/cpu/arm/assembler_arm_32.hpp	Fri May 17 00:21:10 2019 +0200
+++ b/src/hotspot/cpu/arm/assembler_arm_32.hpp	Thu May 16 18:45:30 2019 -0400
@@ -434,7 +434,9 @@
   }
 
   void pldw(Address addr) {
-    assert(VM_Version::arm_arch() >= 7 && os::is_MP(), "no pldw on this processor");
+    assert(!VM_Version::is_initialized() ||
+           (VM_Version::arm_arch() >= 7 && VM_Version::has_multiprocessing_extensions()),
+           "PLDW is available on ARMv7 with Multiprocessing Extensions only");
     emit_int32(0xf510f000 | addr.encoding2());
   }
 
--- a/src/hotspot/cpu/arm/vm_version_arm.hpp	Fri May 17 00:21:10 2019 +0200
+++ b/src/hotspot/cpu/arm/vm_version_arm.hpp	Thu May 16 18:45:30 2019 -0400
@@ -32,6 +32,7 @@
   friend class JVMCIVMStructs;
 
   static bool _has_simd;
+  static bool _has_mp_ext;
 
  protected:
   // Are we done with vm version initialization
@@ -47,6 +48,7 @@
     vfp = 0,
     vfp3_32 = 1,
     simd = 2,
+    mp_ext = 3
   };
 
   enum Feature_Flag_Set {
@@ -56,6 +58,7 @@
     vfp_m     = 1 << vfp,
     vfp3_32_m = 1 << vfp3_32,
     simd_m    = 1 << simd,
+    mp_ext_m  = 1 << mp_ext
   };
 
   // The value stored by "STR PC, [addr]" instruction can be either
@@ -97,6 +100,7 @@
   static bool has_vfp()             { return (_features & vfp_m) != 0; }
   static bool has_vfp3_32()         { return (_features & vfp3_32_m) != 0; }
   static bool has_simd()            { return (_features & simd_m) != 0; }
+  static bool has_multiprocessing_extensions() { return (_features & mp_ext_m) != 0; }
 
   static bool simd_math_is_compliant() { return false; }
 
--- a/src/hotspot/cpu/arm/vm_version_arm_32.cpp	Fri May 17 00:21:10 2019 +0200
+++ b/src/hotspot/cpu/arm/vm_version_arm_32.cpp	Thu May 16 18:45:30 2019 -0400
@@ -40,6 +40,7 @@
   typedef int (*get_cpu_info_t)();
   typedef bool (*check_vfp_t)(double *d);
   typedef bool (*check_simd_t)();
+  typedef bool (*check_mp_ext_t)(int *addr);
 }
 
 #define __ _masm->
@@ -95,6 +96,20 @@
 
     return start;
   };
+
+  address generate_check_mp_ext() {
+    StubCodeMark mark(this, "VM_Version", "check_mp_ext");
+    address start = __ pc();
+
+    // PLDW is available with Multiprocessing Extensions only
+    __ pldw(Address(R0));
+    // Return true if instruction caused no signals
+    __ mov(R0, 1);
+    // JVM_handle_linux_signal moves PC here if SIGILL happens
+    __ bx(LR);
+
+    return start;
+  };
 };
 
 #undef __
@@ -103,6 +118,7 @@
 extern "C" address check_vfp3_32_fault_instr;
 extern "C" address check_vfp_fault_instr;
 extern "C" address check_simd_fault_instr;
+extern "C" address check_mp_ext_fault_instr;
 
 void VM_Version::early_initialize() {
 
@@ -165,6 +181,13 @@
 #endif
 #endif
 
+  address check_mp_ext_pc = g.generate_check_mp_ext();
+  check_mp_ext_t check_mp_ext = CAST_TO_FN_PTR(check_mp_ext_t, check_mp_ext_pc);
+  check_mp_ext_fault_instr = (address)check_mp_ext;
+  int dummy_local_variable;
+  if (check_mp_ext(&dummy_local_variable)) {
+    _features |= mp_ext_m;
+  }
 
   if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
     warning("AES intrinsics are not available on this CPU");
@@ -247,11 +270,12 @@
          && _supports_atomic_getset8 && _supports_atomic_getadd8, "C2: atomic operations must be supported");
 #endif
   char buf[512];
-  jio_snprintf(buf, sizeof(buf), "(ARMv%d)%s%s%s",
+  jio_snprintf(buf, sizeof(buf), "(ARMv%d)%s%s%s%s",
                _arm_arch,
                (has_vfp() ? ", vfp" : ""),
                (has_vfp3_32() ? ", vfp3-32" : ""),
-               (has_simd() ? ", simd" : ""));
+               (has_simd() ? ", simd" : ""),
+               (has_multiprocessing_extensions() ? ", mp_ext" : ""));
 
   // buf is started with ", " or is empty
   _features_string = os::strdup(buf);
--- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp	Fri May 17 00:21:10 2019 +0200
+++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp	Thu May 16 18:45:30 2019 -0400
@@ -248,11 +248,13 @@
 
 extern "C" address check_vfp_fault_instr;
 extern "C" address check_vfp3_32_fault_instr;
+extern "C" address check_simd_fault_instr;
+extern "C" address check_mp_ext_fault_instr;
 
 address check_vfp_fault_instr = NULL;
 address check_vfp3_32_fault_instr = NULL;
-extern "C" address check_simd_fault_instr;
 address check_simd_fault_instr = NULL;
+address check_mp_ext_fault_instr = NULL;
 
 // Utility functions
 
@@ -271,7 +273,8 @@
   if (sig == SIGILL &&
       ((info->si_addr == (caddr_t)check_simd_fault_instr)
        || info->si_addr == (caddr_t)check_vfp_fault_instr
-       || info->si_addr == (caddr_t)check_vfp3_32_fault_instr)) {
+       || info->si_addr == (caddr_t)check_vfp3_32_fault_instr
+       || info->si_addr == (caddr_t)check_mp_ext_fault_instr)) {
     // skip faulty instruction + instruction that sets return value to
     // success and set return value to failure.
     os::Linux::ucontext_set_pc(uc, (address)info->si_addr + 8);