github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/compress/libdeflate/arm/cpu_features.c (about) 1 /* 2 * arm/cpu_features.c - feature detection for ARM processors 3 * 4 * Copyright 2018 Eric Biggers 5 * 6 * Permission is hereby granted, free of charge, to any person 7 * obtaining a copy of this software and associated documentation 8 * files (the "Software"), to deal in the Software without 9 * restriction, including without limitation the rights to use, 10 * copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following 13 * conditions: 14 * 15 * The above copyright notice and this permission notice shall be 16 * included in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 * OTHER DEALINGS IN THE SOFTWARE. 26 */ 27 28 /* 29 * ARM processors don't have a standard way for unprivileged programs to detect 30 * processor features. But, on Linux we can read the AT_HWCAP and AT_HWCAP2 31 * values from /proc/self/auxv. 32 * 33 * Ideally we'd use the C library function getauxval(), but it's not guaranteed 34 * to be available: it was only added to glibc in 2.16, and in Android it was 35 * added to API level 18 for ARM and level 21 for AArch64. 36 */ 37 38 #include "cpu_features.h" 39 40 #if ARM_CPU_FEATURES_ENABLED 41 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #define AT_HWCAP 16 48 #define AT_HWCAP2 26 49 50 volatile u32 _cpu_features = 0; 51 52 static void scan_auxv(unsigned long *hwcap, unsigned long *hwcap2) 53 { 54 int fd; 55 unsigned long auxbuf[32]; 56 int filled = 0; 57 int i; 58 59 fd = open("/proc/self/auxv", O_RDONLY); 60 if (fd < 0) 61 return; 62 63 for (;;) { 64 do { 65 int ret = read(fd, &((char *)auxbuf)[filled], 66 sizeof(auxbuf) - filled); 67 if (ret <= 0) { 68 if (ret < 0 && errno == EINTR) 69 continue; 70 goto out; 71 } 72 filled += ret; 73 } while (filled < 2 * sizeof(long)); 74 75 i = 0; 76 do { 77 unsigned long type = auxbuf[i]; 78 unsigned long value = auxbuf[i + 1]; 79 80 if (type == AT_HWCAP) 81 *hwcap = value; 82 else if (type == AT_HWCAP2) 83 *hwcap2 = value; 84 i += 2; 85 filled -= 2 * sizeof(long); 86 } while (filled >= 2 * sizeof(long)); 87 88 memmove(auxbuf, &auxbuf[i], filled); 89 } 90 out: 91 close(fd); 92 } 93 94 void setup_cpu_features(void) 95 { 96 u32 features = 0; 97 unsigned long hwcap = 0; 98 unsigned long hwcap2 = 0; 99 100 scan_auxv(&hwcap, &hwcap2); 101 102 #ifdef __arm__ 103 STATIC_ASSERT(sizeof(long) == 4); 104 if (hwcap & (1 << 12)) /* HWCAP_NEON */ 105 features |= ARM_CPU_FEATURE_NEON; 106 if (hwcap2 & (1 << 1)) /* HWCAP2_PMULL */ 107 features |= ARM_CPU_FEATURE_PMULL; 108 #else 109 STATIC_ASSERT(sizeof(long) == 8); 110 if (hwcap & (1 << 1)) /* HWCAP_ASIMD */ 111 features |= ARM_CPU_FEATURE_NEON; 112 if (hwcap & (1 << 4)) /* HWCAP_PMULL */ 113 features |= ARM_CPU_FEATURE_PMULL; 114 #endif 115 116 _cpu_features = features | ARM_CPU_FEATURES_KNOWN; 117 } 118 119 #endif /* ARM_CPU_FEATURES_ENABLED */