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 public:
74 // Initialization
75 static void initialize();
76 static void check_virtualizations();
77
78 static void insert_features_names(uint64_t features, stringStream& ss);
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