1 /*
   2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2015, Red Hat Inc. All rights reserved.
   4  * Copyright (c) 2015, Linaro Ltd. All rights reserved.
   5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6  *
   7  * This code is free software; you can redistribute it and/or modify it
   8  * under the terms of the GNU General Public License version 2 only, as
   9  * published by the Free Software Foundation.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  *
  25  */
  26 
  27 #include "precompiled.hpp"
  28 #include "asm/macroAssembler.hpp"
  29 #include "asm/macroAssembler.inline.hpp"
  30 #include "memory/resourceArea.hpp"
  31 #include "runtime/java.hpp"
  32 #include "runtime/stubCodeGenerator.hpp"
  33 #include "vm_version_aarch32.hpp"
  34 #ifdef TARGET_OS_FAMILY_linux
  35 # include "os_linux.inline.hpp"
  36 #endif
  37 #include "compiler/disassembler.hpp"
  38 
  39 enum ProcessorFeatures VM_Version::_features = FT_NONE;
  40 const char* VM_Version::_cpu_features = "";
  41 
  42 static BufferBlob* stub_blob;
  43 static const int stub_size = 550;
  44 volatile bool VM_Version::_is_determine_features_test_running = false;
  45 
  46 extern "C" {
  47   typedef void (*getPsrInfo_stub_t)(void*);
  48 }
  49 static getPsrInfo_stub_t getPsrInfo_stub = NULL;
  50 
  51 
  52 bool VM_Version::identify_procline(const char *tag, char **line) {
  53   char *i = *line;
  54   const char EOT = '\t', EOT2 = ':'; // the longest has no tabs
  55   for(; '\0' != *i && EOT != *i && EOT2 != *i; i++);
  56   if(EOT == *i || EOT2 == *i) {
  57     if(!memcmp(*line, tag, i - *line)) {
  58       for(i++; (EOT == *i || EOT2 == *i || ' ' == *i) && '\0' != *i; i++);
  59       if('\0' != *i) {
  60         *line = i;
  61         return true;
  62       }
  63     }
  64   }
  65   return false;
  66 }
  67 
  68 void VM_Version::get_processor_features() {
  69   _supports_cx8 = true;
  70   _supports_atomic_getset4 = true;
  71   _supports_atomic_getadd4 = true;
  72   _supports_atomic_getset8 = true;
  73   _supports_atomic_getadd8 = true;
  74 
  75   if (FLAG_IS_DEFAULT(AllocatePrefetchDistance))
  76     FLAG_SET_DEFAULT(AllocatePrefetchDistance, 256);
  77   if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize))
  78     FLAG_SET_DEFAULT(AllocatePrefetchStepSize, 64);
  79   FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 256);
  80   FLAG_SET_DEFAULT(PrefetchFieldsAhead, 256);
  81   FLAG_SET_DEFAULT(PrefetchCopyIntervalInBytes, 256);
  82 
  83   enum ProcessorFeatures f = FT_NONE;
  84 
  85   // Allocate space for the code.
  86   const int code_size = 10 * Assembler::instruction_size;
  87   ResourceMark rm;
  88   CodeBuffer cb("detect_cpu_features", code_size, 0);
  89   MacroAssembler* a = new MacroAssembler(&cb);
  90   jlong test_area;
  91 
  92   // Must be set to true so we can generate the test code.
  93   _features = FT_ALL;
  94   // Emit code.
  95   uint32_t *const code = (uint32_t *)a->pc();
  96   void (*test)(address addr, uintptr_t offset)=(void(*)(address addr, uintptr_t nonzero))(void *)code;
  97 
  98   a->udiv(r3, r2, r1);     // FT_HW_DIVIDE
  99   a->bfc(r1, 1, 1);        // FT_ARMV6T2
 100   a->vneg_f64(d0, d0);     // FT_VFPV2
 101   a->vmov_f64(d0, 1.);     // FT_VFPV3
 102   a->dmb(Assembler::ISH);  // FT_ARMV7
 103   a->ldrexd(r2, r0);       // FT_ARMV6K
 104   a->vmov_f64(d0, 0.0);    // FT_AdvSIMD
 105   a->crc32b(r3, r2, r1);   // FT_CRC32
 106   a->b(lr);
 107 
 108   uint32_t *const code_end = (uint32_t *)a->pc();
 109   a->flush();
 110   _features = FT_NONE;
 111 
 112   // Print the detection code.
 113   if (PrintAssembly) {
 114     ttyLocker ttyl;
 115     tty->print_cr("Decoding cpu-feature detection stub at " INTPTR_FORMAT " before execution:", p2i(code));
 116     Disassembler::decode((u_char*)code, (u_char*)code_end, tty);
 117   }
 118   // Execute code. Illegal instructions will be replaced by 0 in the signal handler.
 119   VM_Version::_is_determine_features_test_running = true;
 120   (*test)((address)&test_area, 1);
 121   VM_Version::_is_determine_features_test_running = false;
 122 
 123   uint32_t *insn = code;
 124   if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_HW_DIVIDE);
 125   if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_ARMV6T2);
 126   if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_VFPV2);
 127   if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_VFPV3);
 128   if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_ARMV7);
 129   if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_ARMV6K);
 130   if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_AdvSIMD);
 131   if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_CRC32);
 132 
 133   int ncores = 0, cpu, variant, model, revision;
 134   char buf[2048], *i;
 135   if (FILE * fp = fopen("/proc/cpuinfo", "r")) {
 136     while ((i = fgets(buf, 2048, fp))) {
 137       if (identify_procline("processor", &i)) {
 138         ncores++;
 139       } else if (identify_procline("CPU implementer", &i)) {
 140         cpu = strtol(i, NULL, 0);
 141       } else if (identify_procline("CPU variant", &i)) {
 142         variant = strtol(i, NULL, 0);
 143       } else if (identify_procline("CPU part", &i)) {
 144         model = strtol(i, NULL, 0);
 145       } else if (identify_procline("CPU revision", &i)) {
 146         revision = strtol(i, NULL, 0);
 147       }
 148     }
 149     fclose(fp);
 150   }
 151   if (1 == ncores) {
 152     f = (ProcessorFeatures) (f | FT_SINGLE_CORE);
 153   }
 154   if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) {
 155     UseCRC32Intrinsics = true;
 156   }
 157   if ((f & FT_AdvSIMD) && FLAG_IS_DEFAULT(UseNeon) && (model & ~0x0f0) >= 0xc08) {
 158     UseNeon = true;
 159   }
 160   _features = f;
 161   sprintf(buf, "0x%02x:0x%x:0x%03x:%d", cpu, variant, model, revision);
 162   _cpu_features = os::strdup(buf);
 163 
 164 #ifdef COMPILER2
 165   if (UseMultiplyToLenIntrinsic) {
 166     if (!FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
 167       warning("multiplyToLen intrinsic is not available in 32-bit VM");
 168     }
 169     FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false);
 170   }
 171 #endif // COMPILER2
 172 
 173   if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps) && (f & (FT_VFPV2 | FT_AdvSIMD))) {
 174     FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true);
 175   }
 176 
 177 /*  if (FLAG_IS_DEFAULT(UseBarriersForVolatile)) {
 178     UseBarriersForVolatile = (_cpuFeatures & CPU_DMB_ATOMICS) != 0;
 179   }*/
 180 
 181   /*if(!(f & FT_ARMV7) && FLAG_IS_DEFAULT(UseMembar)) {
 182   UseMembar = false;
 183   } else if(UseMembar) {
 184   fprintf(stderr, "Unable to use memory barriers as not on ARMv7, disabling.\n");
 185   UseMembar = false;
 186   }*/
 187 
 188   if (UseAES) {
 189     warning("AES instructions are not implemented on this CPU");
 190     FLAG_SET_DEFAULT(UseAES, false);
 191   }
 192   if (UseAESIntrinsics) {
 193     warning("AES intrinsics are not implemented on this CPU");
 194     FLAG_SET_DEFAULT(UseAESIntrinsics, false);
 195   }
 196 
 197   if (UseSHA) {
 198     warning("SHA instructions are not available on this CPU");
 199     FLAG_SET_DEFAULT(UseSHA, false);
 200   }
 201   if (UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics) {
 202     warning("SHA intrinsics are not available on this CPU");
 203     FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
 204     FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
 205     FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
 206   }
 207 
 208 }
 209 
 210 void VM_Version::initialize() {
 211   ResourceMark rm;
 212 
 213   stub_blob = BufferBlob::create("getPsrInfo_stub", stub_size);
 214   if (stub_blob == NULL) {
 215     vm_exit_during_initialization("Unable to allocate getPsrInfo_stub");
 216   }
 217 
 218   get_processor_features();
 219 
 220 #ifndef HARD_FLOAT_CC
 221   if( !(VM_Version::features() & (FT_VFPV2 | FT_VFPV3)) ) {
 222       if(FLAG_IS_CMDLINE(UseFPU)) {
 223           warning("FPU is not present on this core");
 224       }
 225       FLAG_SET_DEFAULT(UseFPU, false);
 226   }
 227 #endif
 228 }