github.com/grailbio/base@v0.0.11/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 */