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   set_feature(CPU_FP);
 71   set_feature(CPU_ASIMD);
 72 
 73   // All Apple-darwin Arm processors have AES, PMULL, SHA1 and SHA2.
 74   // See https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/arm/commpage/commpage.c#L412
 75   // Note that we ought to add assertions to check sysctlbyname parameters for
 76   // these four CPU features, e.g., "hw.optional.arm.FEAT_AES", but the
 77   // corresponding string names are not available before xnu-8019 version.
 78   // Hence, assertions are omitted considering backward compatibility.
 79   set_feature(CPU_AES);
 80   set_feature(CPU_PMULL);
 81   set_feature(CPU_SHA1);
 82   set_feature(CPU_SHA2);
 83 
 84   if (cpu_has("hw.optional.armv8_crc32")) {
 85     set_feature(CPU_CRC32);
 86   }
 87   if (cpu_has("hw.optional.arm.FEAT_LSE") ||
 88       cpu_has("hw.optional.armv8_1_atomics")) {
 89     set_feature(CPU_LSE);
 90   }
 91   if (cpu_has("hw.optional.arm.FEAT_SHA512") ||
 92       cpu_has("hw.optional.armv8_2_sha512")) {
 93     set_feature(CPU_SHA512);
 94   }
 95   if (cpu_has("hw.optional.arm.FEAT_SHA3") ||
 96       cpu_has("hw.optional.armv8_2_sha3")) {
 97     set_feature(CPU_SHA3);
 98   }
 99 
100   int cache_line_size;
101   int hw_conf_cache_line[] = { CTL_HW, HW_CACHELINE };
102   sysctllen = sizeof(cache_line_size);
103   if (sysctl(hw_conf_cache_line, 2, &cache_line_size, &sysctllen, nullptr, 0)) {
104     cache_line_size = 16;
105   }
106   _icache_line_size = 16; // minimal line length CCSIDR_EL1 can hold
107   _dcache_line_size = cache_line_size;
108 
109   uint64_t dczid_el0;
110   __asm__ (
111     "mrs %0, DCZID_EL0\n"
112     : "=r"(dczid_el0)
113   );
114   if (!(dczid_el0 & 0x10)) {
115     _zva_length = 4 << (dczid_el0 & 0xf);
116   }
117 
118   int family;
119   sysctllen = sizeof(family);
120   if (sysctlbyname("hw.cpufamily", &family, &sysctllen, nullptr, 0)) {
121     family = 0;
122   }
123 
124   _model = family;
125   _cpu = CPU_APPLE;
126 }
127 
128 void VM_Version::get_compatible_board(char *buf, int buflen) {
129   assert(buf != nullptr, "invalid argument");
130   assert(buflen >= 1, "invalid argument");
131   *buf = '\0';
132 }
133 
134 #ifdef __APPLE__
135 
136 bool VM_Version::is_cpu_emulated() {
137   return false;
138 }
139 
140 #endif