1 /*
2 * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2014, 2019, Red Hat Inc. All rights reserved.
4 * Copyright (c) 2021, Azul Systems, Inc. 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 "runtime/java.hpp"
28 #include "runtime/os.hpp"
29 #include "runtime/vm_version.hpp"
30
31 #include <sys/sysctl.h>
32
33 int VM_Version::get_current_sve_vector_length() {
34 ShouldNotCallThis();
35 return -1;
36 }
37
38 int VM_Version::set_and_get_current_sve_vector_length(int length) {
39 ShouldNotCallThis();
40 return -1;
41 }
42
43 static bool cpu_has(const char* optional) {
44 uint32_t val;
45 size_t len = sizeof(val);
46 if (sysctlbyname(optional, &val, &len, nullptr, 0)) {
47 return false;
48 }
49 return val;
50 }
51
52 void VM_Version::get_os_cpu_info() {
53 size_t sysctllen;
54
55 // cpu_has() uses sysctlbyname function to check the existence of CPU
56 // features. References: Apple developer document [1] and XNU kernel [2].
57 // [1] https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
58 // [2] https://github.com/apple-oss-distributions/xnu/blob/main/bsd/kern/kern_mib.c
59 //
60 // Note that for some features (e.g., LSE, SHA512 and SHA3) there are two
61 // parameters for sysctlbyname, which are invented at different times.
62 // Considering backward compatibility, we check both here.
63 //
64 // Floating-point and Advance SIMD features are standard in Apple processors
65 // beginning with M1 and A7, and don't need to be checked [1].
66 // 1) hw.optional.floatingpoint always returns 1 [2].
67 // 2) ID_AA64PFR0_EL1 describes AdvSIMD always equals to FP field.
68 // See the Arm ARM, section "ID_AA64PFR0_EL1, AArch64 Processor Feature
69 // Register 0".
70 _features = CPU_FP | CPU_ASIMD;
71
72 // All Apple-darwin Arm processors have AES, PMULL, SHA1 and SHA2.
73 // See https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/arm/commpage/commpage.c#L412
74 // Note that we ought to add assertions to check sysctlbyname parameters for
75 // these four CPU features, e.g., "hw.optional.arm.FEAT_AES", but the
76 // corresponding string names are not available before xnu-8019 version.
77 // Hence, assertions are omitted considering backward compatibility.
78 _features |= CPU_AES | CPU_PMULL | CPU_SHA1 | CPU_SHA2;
79
80 if (cpu_has("hw.optional.armv8_crc32")) {
81 _features |= CPU_CRC32;
82 }
83 if (cpu_has("hw.optional.arm.FEAT_LSE") ||
84 cpu_has("hw.optional.armv8_1_atomics")) {
85 _features |= CPU_LSE;
86 }
87 if (cpu_has("hw.optional.arm.FEAT_SHA512") ||
88 cpu_has("hw.optional.armv8_2_sha512")) {
89 _features |= CPU_SHA512;
90 }
91 if (cpu_has("hw.optional.arm.FEAT_SHA3") ||
92 cpu_has("hw.optional.armv8_2_sha3")) {
93 _features |= CPU_SHA3;
94 }
95
96 int cache_line_size;
97 int hw_conf_cache_line[] = { CTL_HW, HW_CACHELINE };
98 sysctllen = sizeof(cache_line_size);
99 if (sysctl(hw_conf_cache_line, 2, &cache_line_size, &sysctllen, nullptr, 0)) {
100 cache_line_size = 16;
101 }
102 _icache_line_size = 16; // minimal line length CCSIDR_EL1 can hold
103 _dcache_line_size = cache_line_size;
104
105 uint64_t dczid_el0;
106 __asm__ (
107 "mrs %0, DCZID_EL0\n"
108 : "=r"(dczid_el0)
109 );
110 if (!(dczid_el0 & 0x10)) {
111 _zva_length = 4 << (dczid_el0 & 0xf);
112 }
113
114 int family;
115 sysctllen = sizeof(family);
116 if (sysctlbyname("hw.cpufamily", &family, &sysctllen, nullptr, 0)) {
117 family = 0;
118 }
119
120 _model = family;
121 _cpu = CPU_APPLE;
122 }
123
124 void VM_Version::get_compatible_board(char *buf, int buflen) {
125 assert(buf != nullptr, "invalid argument");
126 assert(buflen >= 1, "invalid argument");
127 *buf = '\0';
128 }
129
130 #ifdef __APPLE__
131
132 bool VM_Version::is_cpu_emulated() {
133 return false;
134 }
135
136 #endif