git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/cpuinfo/os_linux_arm64.go (about)

     1  // Copyright (c) 2020 Klaus Post, released under MIT License. See LICENSE file.
     2  
     3  // Copyright 2018 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file located
     6  // here https://github.com/golang/sys/blob/master/LICENSE
     7  
     8  package cpuinfo
     9  
    10  import (
    11  	"encoding/binary"
    12  	"io/ioutil"
    13  	"runtime"
    14  )
    15  
    16  // HWCAP bits.
    17  const (
    18  	hwcap_FP       = 1 << 0
    19  	hwcap_ASIMD    = 1 << 1
    20  	hwcap_EVTSTRM  = 1 << 2
    21  	hwcap_AES      = 1 << 3
    22  	hwcap_PMULL    = 1 << 4
    23  	hwcap_SHA1     = 1 << 5
    24  	hwcap_SHA2     = 1 << 6
    25  	hwcap_CRC32    = 1 << 7
    26  	hwcap_ATOMICS  = 1 << 8
    27  	hwcap_FPHP     = 1 << 9
    28  	hwcap_ASIMDHP  = 1 << 10
    29  	hwcap_CPUID    = 1 << 11
    30  	hwcap_ASIMDRDM = 1 << 12
    31  	hwcap_JSCVT    = 1 << 13
    32  	hwcap_FCMA     = 1 << 14
    33  	hwcap_LRCPC    = 1 << 15
    34  	hwcap_DCPOP    = 1 << 16
    35  	hwcap_SHA3     = 1 << 17
    36  	hwcap_SM3      = 1 << 18
    37  	hwcap_SM4      = 1 << 19
    38  	hwcap_ASIMDDP  = 1 << 20
    39  	hwcap_SHA512   = 1 << 21
    40  	hwcap_SVE      = 1 << 22
    41  	hwcap_ASIMDFHM = 1 << 23
    42  )
    43  
    44  func detectOS(c *CPUInfo) bool {
    45  	// For now assuming no hyperthreading is reasonable.
    46  	c.LogicalCores = runtime.NumCPU()
    47  	c.PhysicalCores = c.LogicalCores
    48  	c.ThreadsPerCore = 1
    49  	if hwcap == 0 {
    50  		// We did not get values from the runtime.
    51  		// Try reading /proc/self/auxv
    52  
    53  		// From https://github.com/golang/sys
    54  		const (
    55  			_AT_HWCAP  = 16
    56  			_AT_HWCAP2 = 26
    57  
    58  			uintSize = int(32 << (^uint(0) >> 63))
    59  		)
    60  
    61  		buf, err := ioutil.ReadFile("/proc/self/auxv")
    62  		if err != nil {
    63  			// e.g. on android /proc/self/auxv is not accessible, so silently
    64  			// ignore the error and leave Initialized = false. On some
    65  			// architectures (e.g. arm64) doinit() implements a fallback
    66  			// readout and will set Initialized = true again.
    67  			return false
    68  		}
    69  		bo := binary.LittleEndian
    70  		for len(buf) >= 2*(uintSize/8) {
    71  			var tag, val uint
    72  			switch uintSize {
    73  			case 32:
    74  				tag = uint(bo.Uint32(buf[0:]))
    75  				val = uint(bo.Uint32(buf[4:]))
    76  				buf = buf[8:]
    77  			case 64:
    78  				tag = uint(bo.Uint64(buf[0:]))
    79  				val = uint(bo.Uint64(buf[8:]))
    80  				buf = buf[16:]
    81  			}
    82  			switch tag {
    83  			case _AT_HWCAP:
    84  				hwcap = val
    85  			case _AT_HWCAP2:
    86  				// Not used
    87  			}
    88  		}
    89  		if hwcap == 0 {
    90  			return false
    91  		}
    92  	}
    93  
    94  	// HWCap was populated by the runtime from the auxiliary vector.
    95  	// Use HWCap information since reading aarch64 system registers
    96  	// is not supported in user space on older linux kernels.
    97  	c.featureSet.setIf(isSet(hwcap, hwcap_AES), AESARM)
    98  	c.featureSet.setIf(isSet(hwcap, hwcap_ASIMD), ASIMD)
    99  	c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDDP), ASIMDDP)
   100  	c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDHP), ASIMDHP)
   101  	c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDRDM), ASIMDRDM)
   102  	c.featureSet.setIf(isSet(hwcap, hwcap_CPUID), ARMCPUID)
   103  	c.featureSet.setIf(isSet(hwcap, hwcap_CRC32), CRC32)
   104  	c.featureSet.setIf(isSet(hwcap, hwcap_DCPOP), DCPOP)
   105  	c.featureSet.setIf(isSet(hwcap, hwcap_EVTSTRM), EVTSTRM)
   106  	c.featureSet.setIf(isSet(hwcap, hwcap_FCMA), FCMA)
   107  	c.featureSet.setIf(isSet(hwcap, hwcap_FP), FP)
   108  	c.featureSet.setIf(isSet(hwcap, hwcap_FPHP), FPHP)
   109  	c.featureSet.setIf(isSet(hwcap, hwcap_JSCVT), JSCVT)
   110  	c.featureSet.setIf(isSet(hwcap, hwcap_LRCPC), LRCPC)
   111  	c.featureSet.setIf(isSet(hwcap, hwcap_PMULL), PMULL)
   112  	c.featureSet.setIf(isSet(hwcap, hwcap_SHA1), SHA1)
   113  	c.featureSet.setIf(isSet(hwcap, hwcap_SHA2), SHA2)
   114  	c.featureSet.setIf(isSet(hwcap, hwcap_SHA3), SHA3)
   115  	c.featureSet.setIf(isSet(hwcap, hwcap_SHA512), SHA512)
   116  	c.featureSet.setIf(isSet(hwcap, hwcap_SM3), SM3)
   117  	c.featureSet.setIf(isSet(hwcap, hwcap_SM4), SM4)
   118  	c.featureSet.setIf(isSet(hwcap, hwcap_SVE), SVE)
   119  
   120  	// The Samsung S9+ kernel reports support for atomics, but not all cores
   121  	// actually support them, resulting in SIGILL. See issue #28431.
   122  	// TODO(elias.naur): Only disable the optimization on bad chipsets on android.
   123  	c.featureSet.setIf(isSet(hwcap, hwcap_ATOMICS) && runtime.GOOS != "android", ATOMICS)
   124  
   125  	return true
   126  }
   127  
   128  func isSet(hwc uint, value uint) bool {
   129  	return hwc&value != 0
   130  }