1 /*
  2  * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  *
 24  */
 25 
 26 #ifndef CPU_AARCH64_VM_VERSION_AARCH64_HPP
 27 #define CPU_AARCH64_VM_VERSION_AARCH64_HPP
 28 
 29 #include "spin_wait_aarch64.hpp"
 30 #include "runtime/abstract_vm_version.hpp"
 31 #include "utilities/sizes.hpp"
 32 
 33 #include <initializer_list>
 34 
 35 class stringStream;
 36 
 37 #define BIT_MASK(flag) (1ULL<<(flag))
 38 
 39 class VM_Version : public Abstract_VM_Version {
 40   friend class VMStructs;
 41   friend class JVMCIVMStructs;
 42 
 43 protected:
 44   static int _cpu;
 45   static int _model;
 46   static int _model2;
 47   static int _variant;
 48   static int _revision;
 49   static int _stepping;
 50 
 51   static int _zva_length;
 52   static int _dcache_line_size;
 53   static int _icache_line_size;
 54   static int _initial_sve_vector_length;
 55   static int _max_supported_sve_vector_length;
 56   static bool _rop_protection;
 57   static uintptr_t _pac_mask;
 58   // When _prefer_sve_merging_mode_cpy is true, `cpy (imm, zeroing)` is
 59   // implemented as `movi; cpy(imm, merging)`.
 60   static constexpr bool _prefer_sve_merging_mode_cpy = true;
 61 
 62   static SpinWait _spin_wait;
 63 
 64   // Read additional info using OS-specific interfaces
 65   static void get_os_cpu_info();
 66 
 67   // Sets the SVE length and returns a new actual value or negative on error.
 68   // If the len is larger than the system largest supported SVE vector length,
 69   // the function sets the largest supported value.
 70   static int set_and_get_current_sve_vector_length(int len);
 71   static int get_current_sve_vector_length();
 72 
 73   static void insert_features_names(uint64_t features, stringStream& ss);
 74 
 75 public:
 76   // Initialization
 77   static void initialize();
 78   static void check_virtualizations();
 79 
 80   static void print_platform_virtualization_info(outputStream*);
 81 
 82   // Asserts
 83   static void assert_is_initialized() {
 84   }
 85 
 86   static bool expensive_load(int ld_size, int scale) {
 87     if (cpu_family() == CPU_ARM) {
 88       // Half-word load with index shift by 1 (aka scale is 2) has
 89       // extra cycle latency, e.g. ldrsh w0, [x1,w2,sxtw #1].
 90       if (ld_size == 2 && scale == 2) {
 91         return true;
 92       }
 93     }
 94     return false;
 95   }
 96 
 97   // The CPU implementer codes can be found in
 98   // ARM Architecture Reference Manual ARMv8, for ARMv8-A architecture profile
 99   // https://developer.arm.com/docs/ddi0487/latest
100   // Arm can assign codes that are not published in the manual.
101   // Apple's code is defined in
102   // https://github.com/apple/darwin-xnu/blob/33eb983/osfmk/arm/cpuid.h#L62
103   enum Family {
104     CPU_AMPERE    = 0xC0,
105     CPU_ARM       = 'A',
106     CPU_BROADCOM  = 'B',
107     CPU_CAVIUM    = 'C',
108     CPU_DEC       = 'D',
109     CPU_HISILICON = 'H',
110     CPU_INFINEON  = 'I',
111     CPU_MOTOROLA  = 'M',
112     CPU_NVIDIA    = 'N',
113     CPU_AMCC      = 'P',
114     CPU_QUALCOMM  = 'Q',
115     CPU_MARVELL   = 'V',
116     CPU_INTEL     = 'i',
117     CPU_APPLE     = 'a',
118   };
119 
120   enum Ampere_CPU_Model {
121     CPU_MODEL_EMAG      = 0x0,   /* CPU implementer is CPU_AMCC */
122     CPU_MODEL_ALTRA     = 0xd0c, /* CPU implementer is CPU_ARM, Neoverse N1 */
123     CPU_MODEL_ALTRAMAX  = 0xd0c, /* CPU implementer is CPU_ARM, Neoverse N1 */
124     CPU_MODEL_AMPERE_1  = 0xac3, /* CPU implementer is CPU_AMPERE */
125     CPU_MODEL_AMPERE_1A = 0xac4, /* CPU implementer is CPU_AMPERE */
126     CPU_MODEL_AMPERE_1B = 0xac5  /* AMPERE_1B core Implements ARMv8.7 with CSSC, MTE, SM3/SM4 extensions */
127   };
128 
129   enum ARM_CPU_Model {
130     CPU_MODEL_ARM_CORTEX_A53    = 0xd03,
131     CPU_MODEL_ARM_CORTEX_A73    = 0xd09,
132     CPU_MODEL_ARM_NEOVERSE_N1   = 0xd0c,
133     CPU_MODEL_ARM_NEOVERSE_V1   = 0xd40,
134     CPU_MODEL_ARM_NEOVERSE_N2   = 0xd49,
135     CPU_MODEL_ARM_NEOVERSE_V2   = 0xd4f,
136     CPU_MODEL_ARM_NEOVERSE_V3AE = 0xd83,
137     CPU_MODEL_ARM_NEOVERSE_V3   = 0xd84,
138     CPU_MODEL_ARM_NEOVERSE_N3   = 0xd8e,
139   };
140 
141 #define CPU_FEATURE_FLAGS(decl)               \
142     decl(FP,            fp,            0)     \
143     decl(ASIMD,         asimd,         1)     \
144     decl(EVTSTRM,       evtstrm,       2)     \
145     decl(AES,           aes,           3)     \
146     decl(PMULL,         pmull,         4)     \
147     decl(SHA1,          sha1,          5)     \
148     decl(SHA2,          sha256,        6)     \
149     decl(CRC32,         crc32,         7)     \
150     decl(LSE,           lse,           8)     \
151     decl(FPHP,          fphp,          9)     \
152     decl(ASIMDHP,       asimdhp,       10)    \
153     decl(DCPOP,         dcpop,         16)    \
154     decl(SHA3,          sha3,          17)    \
155     decl(SHA512,        sha512,        21)    \
156     decl(SVE,           sve,           22)    \
157     decl(SB,            sb,            29)    \
158     decl(PACA,          paca,          30)    \
159     /* flags above must follow Linux HWCAP */ \
160     decl(SVEBITPERM,    svebitperm,    27)    \
161     decl(SVE2,          sve2,          28)    \
162     decl(A53MAC,        a53mac,        31)
163 
164   enum Feature_Flag {
165 #define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = bit,
166     CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG)
167 #undef DECLARE_CPU_FEATURE_FLAG
168     MAX_CPU_FEATURES
169   };
170 
171   STATIC_ASSERT(sizeof(_features) * BitsPerByte >= MAX_CPU_FEATURES);
172 
173   static const char* _features_names[MAX_CPU_FEATURES];
174 
175   // Feature identification
176 #define CPU_FEATURE_DETECTION(id, name, bit) \
177   static bool supports_##name() { return supports_feature(CPU_##id); }
178   CPU_FEATURE_FLAGS(CPU_FEATURE_DETECTION)
179 #undef CPU_FEATURE_DETECTION
180 
181   static void set_feature(Feature_Flag flag) {
182     _features |= BIT_MASK(flag);
183   }
184   static void clear_feature(Feature_Flag flag) {
185     _features &= (~BIT_MASK(flag));
186   }
187   static bool supports_feature(Feature_Flag flag) {
188     return (_features & BIT_MASK(flag)) != 0;
189   }
190   static bool supports_feature(uint64_t features, Feature_Flag flag) {
191     return (features & BIT_MASK(flag)) != 0;
192   }
193 
194   static int cpu_family()                     { return _cpu; }
195   static int cpu_model()                      { return _model; }
196   static int cpu_model2()                     { return _model2; }
197   static int cpu_variant()                    { return _variant; }
198   static int cpu_revision()                   { return _revision; }
199 
200   static bool model_is(int cpu_model) {
201     return _model == cpu_model || _model2 == cpu_model;
202   }
203 
204   static bool model_is_in(std::initializer_list<int> cpu_models) {
205     for (const int& cpu_model : cpu_models) {
206       if (_model == cpu_model || _model2 == cpu_model) {
207         return true;
208       }
209     }
210     return false;
211   }
212 
213   static bool is_zva_enabled() { return 0 < _zva_length; }
214   static int zva_length() {
215     assert(is_zva_enabled(), "ZVA not available");
216     return _zva_length;
217   }
218 
219   static int icache_line_size() { return _icache_line_size; }
220   static int dcache_line_size() { return _dcache_line_size; }
221   static int get_initial_sve_vector_length()        { return _initial_sve_vector_length; };
222   static int get_max_supported_sve_vector_length()  { return _max_supported_sve_vector_length; };
223 
224   // Aarch64 supports fast class initialization checks
225   static bool supports_fast_class_init_checks() { return true; }
226   constexpr static bool supports_stack_watermark_barrier() { return true; }
227   constexpr static bool supports_recursive_fast_locking() { return true; }
228 
229   constexpr static bool supports_secondary_supers_table() { return true; }
230 
231   static void get_compatible_board(char *buf, int buflen);
232 
233   static const SpinWait& spin_wait_desc() { return _spin_wait; }
234 
235   static bool supports_on_spin_wait() { return _spin_wait.inst() != SpinWait::NONE; }
236 
237   static bool supports_float16() { return true; }
238 
239 #ifdef __APPLE__
240   // Is the CPU running emulated (for example macOS Rosetta running x86_64 code on M1 ARM (aarch64)
241   static bool is_cpu_emulated();
242 #endif
243 
244   static void initialize_cpu_information(void);
245 
246   static bool use_rop_protection() { return _rop_protection; }
247 
248   static bool prefer_sve_merging_mode_cpy() { return _prefer_sve_merging_mode_cpy; }
249 
250   // For common 64/128-bit unpredicated vector operations, we may prefer
251   // emitting NEON instructions rather than the corresponding SVE instructions.
252   static bool use_neon_for_vector(int vector_length_in_bytes) {
253     return vector_length_in_bytes <= 16;
254   }
255 
256   static void get_cpu_features_name(void* features_buffer, stringStream& ss);
257 
258   // Returns names of features present in features_set1 but not in features_set2
259   static void get_missing_features_name(void* features_set1, void* features_set2, stringStream& ss);
260 
261   // Returns number of bytes required to store cpu features representation
262   static int cpu_features_size();
263 
264   // Stores cpu features representation in the provided buffer. This representation is arch dependent.
265   // Size of the buffer must be same as returned by cpu_features_size()
266   static void store_cpu_features(void* buf);
267 
268   static bool supports_features(void* features_to_test);
269 };
270 
271 #endif // CPU_AARCH64_VM_VERSION_AARCH64_HPP