cpu_arm64_hwcap.mx raw

   1  // Copyright 2020 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  //go:build arm64 && linux
   6  
   7  package cpu
   8  
   9  import _ "unsafe" // for linkname
  10  
  11  // HWCap may be initialized by archauxv and
  12  // should not be changed after it was initialized.
  13  //
  14  // Other widely used packages
  15  // access HWCap using linkname as well, most notably:
  16  //   - github.com/klauspost/cpuid/v2
  17  //
  18  // Do not remove or change the type signature.
  19  // See go.dev/issue/67401.
  20  //
  21  //go:linkname HWCap
  22  var HWCap uint
  23  
  24  // HWCAP bits. These are exposed by Linux.
  25  // See arch/arm64/include/uapi/asm/hwcap.h.
  26  const (
  27  	hwcap_AES     = 1 << 3
  28  	hwcap_PMULL   = 1 << 4
  29  	hwcap_SHA1    = 1 << 5
  30  	hwcap_SHA2    = 1 << 6
  31  	hwcap_CRC32   = 1 << 7
  32  	hwcap_ATOMICS = 1 << 8
  33  	hwcap_CPUID   = 1 << 11
  34  	hwcap_SHA3    = 1 << 17
  35  	hwcap_SHA512  = 1 << 21
  36  	hwcap_DIT     = 1 << 24
  37  )
  38  
  39  func hwcapInit(os []byte) {
  40  	// HWCap was populated by the runtime from the auxiliary vector.
  41  	// See https://docs.kernel.org/arch/arm64/elf_hwcaps.html.
  42  	// Use HWCap information since reading aarch64 system registers
  43  	// is not supported in user space on older linux kernels.
  44  	ARM64.HasAES = isSet(HWCap, hwcap_AES)
  45  	ARM64.HasPMULL = isSet(HWCap, hwcap_PMULL)
  46  	ARM64.HasSHA1 = isSet(HWCap, hwcap_SHA1)
  47  	ARM64.HasSHA2 = isSet(HWCap, hwcap_SHA2)
  48  	ARM64.HasSHA3 = isSet(HWCap, hwcap_SHA3)
  49  	ARM64.HasCRC32 = isSet(HWCap, hwcap_CRC32)
  50  	ARM64.HasCPUID = isSet(HWCap, hwcap_CPUID)
  51  	ARM64.HasSHA512 = isSet(HWCap, hwcap_SHA512)
  52  	ARM64.HasDIT = isSet(HWCap, hwcap_DIT)
  53  
  54  	// The Samsung S9+ kernel reports support for atomics, but not all cores
  55  	// actually support them, resulting in SIGILL. See issue #28431.
  56  	// TODO(elias.naur): Only disable the optimization on bad chipsets on android.
  57  	ARM64.HasATOMICS = isSet(HWCap, hwcap_ATOMICS) && os != "android"
  58  
  59  	// Check to see if executing on a Neoverse core and in order to do that,
  60  	// check the AUXV for the CPUID bit. The getMIDR function executes an
  61  	// instruction which would normally be an illegal instruction, but it's
  62  	// trapped by the kernel, the value sanitized and then returned.
  63  	// Without the CPUID bit the kernel will not trap the instruction and the
  64  	// process will be terminated with SIGILL.
  65  	if ARM64.HasCPUID {
  66  		midr := getMIDR()
  67  		part_num := uint16((midr >> 4) & 0xfff)
  68  		implementer := byte((midr >> 24) & 0xff)
  69  
  70  		// d0c - NeoverseN1
  71  		// d40 - NeoverseV1
  72  		// d49 - NeoverseN2
  73  		// d4f - NeoverseV2
  74  		// d8e - NeoverseN3
  75  		// d84 - NeoverseV3
  76  		// d83 - NeoverseV3ae
  77  		if implementer == 'A' {
  78  			switch part_num {
  79  			case 0xd0c, 0xd40, 0xd49, 0xd4f, 0xd8e, 0xd84, 0xd83:
  80  				ARM64.IsNeoverse = true
  81  			}
  82  		}
  83  	}
  84  }
  85  
  86  func isSet(hwc uint, value uint) bool {
  87  	return hwc&value != 0
  88  }
  89