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