1  /* Copyright (C) 2020-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library.  If not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <unistd.h>
      20  #include <sys/auxv.h>
      21  #include <stdbool.h>
      22  
      23  static long int linux_sysconf (int name);
      24  
      25  static inline bool
      26  getauxval2_einval (unsigned long int type, unsigned long int *result)
      27  {
      28    if (__getauxval2 (type, result))
      29      return true;
      30  
      31    __set_errno (EINVAL);
      32  
      33    return false;
      34  }
      35  
      36  static inline long int
      37  sysconf_get_cache_associativity (unsigned long type)
      38  {
      39    unsigned long int result;
      40  
      41    if (getauxval2_einval (type, &result))
      42      return (result & 0xffff0000) >> 16;
      43  
      44    return -1;
      45  }
      46  
      47  static inline long int
      48  sysconf_get_cache_linesize (unsigned long type)
      49  {
      50    unsigned long int result;
      51  
      52    if (getauxval2_einval (type, &result))
      53      return result & 0xffff;
      54  
      55    return -1;
      56  }
      57  
      58  static inline long int
      59  sysconf_get_cache_size (unsigned long type)
      60  {
      61    unsigned long int result;
      62  
      63    if (getauxval2_einval (type, &result))
      64      return result;
      65  
      66    return -1;
      67  }
      68  
      69  /* Get the value of the system variable NAME.  */
      70  long int
      71  __sysconf (int name)
      72  {
      73    switch (name)
      74      {
      75        case _SC_LEVEL1_ICACHE_SIZE:
      76  	return sysconf_get_cache_size (AT_L1I_CACHESIZE);
      77        case _SC_LEVEL1_ICACHE_ASSOC:
      78  	return sysconf_get_cache_associativity (AT_L1I_CACHEGEOMETRY);
      79        case _SC_LEVEL1_ICACHE_LINESIZE:
      80  	return sysconf_get_cache_linesize (AT_L1I_CACHEGEOMETRY);
      81        case _SC_LEVEL1_DCACHE_SIZE:
      82  	return sysconf_get_cache_size (AT_L1D_CACHESIZE);
      83        case _SC_LEVEL1_DCACHE_ASSOC:
      84  	return sysconf_get_cache_associativity (AT_L1D_CACHEGEOMETRY);
      85        case _SC_LEVEL1_DCACHE_LINESIZE:
      86  	return sysconf_get_cache_linesize (AT_L1D_CACHEGEOMETRY);
      87        case _SC_LEVEL2_CACHE_SIZE:
      88  	return sysconf_get_cache_size (AT_L2_CACHESIZE);
      89        case _SC_LEVEL2_CACHE_ASSOC:
      90  	return sysconf_get_cache_associativity (AT_L2_CACHEGEOMETRY);
      91        case _SC_LEVEL2_CACHE_LINESIZE:
      92  	return sysconf_get_cache_linesize (AT_L2_CACHEGEOMETRY);
      93        case _SC_LEVEL3_CACHE_SIZE:
      94         return sysconf_get_cache_size (AT_L3_CACHESIZE);
      95        case _SC_LEVEL3_CACHE_ASSOC:
      96         return sysconf_get_cache_associativity (AT_L3_CACHEGEOMETRY);
      97        case _SC_LEVEL3_CACHE_LINESIZE:
      98         return sysconf_get_cache_linesize (AT_L3_CACHEGEOMETRY);
      99        default:
     100  	return linux_sysconf (name);
     101      }
     102  }
     103  
     104  /* Now the generic Linux version.  */
     105  #undef __sysconf
     106  #define __sysconf static linux_sysconf
     107  #include <sysdeps/unix/sysv/linux/sysconf.c>