2019-10-25 03:09:59 +00:00
|
|
|
// Copyright 2020 The gVisor Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
// +build arm64
|
|
|
|
|
|
|
|
package cpuid
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"gvisor.dev/gvisor/pkg/log"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ARM64 doesn't have a 'cpuid' equivalent, which means it have no architected
|
|
|
|
// discovery mechanism for hardware features available to userspace code at EL0.
|
|
|
|
// The kernel exposes the presence of these features to userspace through a set
|
|
|
|
// of flags(HWCAP/HWCAP2) bits, exposed in the auxilliary vector.
|
|
|
|
// Ref Documentation/arm64/elf_hwcaps.rst for more info.
|
|
|
|
//
|
|
|
|
// Currently, only the HWCAP bits are supported.
|
|
|
|
|
|
|
|
const (
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureFP indicates support for single and double precision
|
|
|
|
// float point types.
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureFP Feature = iota
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureASIMD indicates support for Advanced SIMD with single
|
|
|
|
// and double precision float point arithmetic.
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureASIMD
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureEVTSTRM indicates support for the generic timer
|
|
|
|
// configured to generate events at a frequency of approximately
|
|
|
|
// 100KHz.
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureEVTSTRM
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureAES indicates support for AES instructions
|
|
|
|
// (AESE/AESD/AESMC/AESIMC).
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureAES
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeaturePMULL indicates support for AES instructions
|
|
|
|
// (PMULL/PMULL2).
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeaturePMULL
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureSHA1 indicates support for SHA1 instructions
|
|
|
|
// (SHA1C/SHA1P/SHA1M etc).
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureSHA1
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureSHA2 indicates support for SHA2 instructions
|
|
|
|
// (SHA256H/SHA256H2/SHA256SU0 etc).
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureSHA2
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureCRC32 indicates support for CRC32 instructions
|
|
|
|
// (CRC32B/CRC32H/CRC32W etc).
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureCRC32
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureATOMICS indicates support for atomic instructions
|
|
|
|
// (LDADD/LDCLR/LDEOR/LDSET etc).
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureATOMICS
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureFPHP indicates support for half precision float point
|
|
|
|
// arithmetic.
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureFPHP
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureASIMDHP indicates support for ASIMD with half precision
|
|
|
|
// float point arithmetic.
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureASIMDHP
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureCPUID indicates support for EL0 access to certain ID
|
|
|
|
// registers is available.
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureCPUID
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureASIMDRDM indicates support for SQRDMLAH and SQRDMLSH
|
|
|
|
// instructions.
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureASIMDRDM
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureJSCVT indicates support for the FJCVTZS instruction.
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureJSCVT
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureFCMA indicates support for the FCMLA and FCADD
|
|
|
|
// instructions.
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureFCMA
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureLRCPC indicates support for the LDAPRB/LDAPRH/LDAPR
|
|
|
|
// instructions.
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureLRCPC
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureDCPOP indicates support for DC instruction (DC CVAP).
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureDCPOP
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureSHA3 indicates support for SHA3 instructions
|
|
|
|
// (EOR3/RAX1/XAR/BCAX).
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureSHA3
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureSM3 indicates support for SM3 instructions
|
|
|
|
// (SM3SS1/SM3TT1A/SM3TT1B).
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureSM3
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureSM4 indicates support for SM4 instructions
|
|
|
|
// (SM4E/SM4EKEY).
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureSM4
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureASIMDDP indicates support for dot product instructions
|
|
|
|
// (UDOT/SDOT).
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureASIMDDP
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureSHA512 indicates support for SHA2 instructions
|
|
|
|
// (SHA512H/SHA512H2/SHA512SU0).
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureSHA512
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureSVE indicates support for Scalable Vector Extension.
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureSVE
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// ARM64FeatureASIMDFHM indicates support for FMLAL and FMLSL
|
|
|
|
// instructions.
|
2019-10-25 03:09:59 +00:00
|
|
|
ARM64FeatureASIMDFHM
|
|
|
|
)
|
|
|
|
|
|
|
|
// ELF auxiliary vector tags
|
|
|
|
const (
|
|
|
|
_AT_NULL = 0 // End of vector
|
|
|
|
_AT_HWCAP = 16 // hardware capability bit vector
|
|
|
|
_AT_HWCAP2 = 26 // hardware capability bit vector 2
|
|
|
|
)
|
|
|
|
|
|
|
|
// These should not be changed after they are initialized.
|
|
|
|
var hwCap uint
|
|
|
|
|
|
|
|
// To make emulation of /proc/cpuinfo easy, these names match the names of the
|
|
|
|
// basic features in Linux defined in arch/arm64/kernel/cpuinfo.c.
|
|
|
|
var arm64FeatureStrings = map[Feature]string{
|
|
|
|
ARM64FeatureFP: "fp",
|
|
|
|
ARM64FeatureASIMD: "asimd",
|
|
|
|
ARM64FeatureEVTSTRM: "evtstrm",
|
|
|
|
ARM64FeatureAES: "aes",
|
|
|
|
ARM64FeaturePMULL: "pmull",
|
|
|
|
ARM64FeatureSHA1: "sha1",
|
|
|
|
ARM64FeatureSHA2: "sha2",
|
|
|
|
ARM64FeatureCRC32: "crc32",
|
|
|
|
ARM64FeatureATOMICS: "atomics",
|
|
|
|
ARM64FeatureFPHP: "fphp",
|
|
|
|
ARM64FeatureASIMDHP: "asimdhp",
|
|
|
|
ARM64FeatureCPUID: "cpuid",
|
|
|
|
ARM64FeatureASIMDRDM: "asimdrdm",
|
|
|
|
ARM64FeatureJSCVT: "jscvt",
|
|
|
|
ARM64FeatureFCMA: "fcma",
|
|
|
|
ARM64FeatureLRCPC: "lrcpc",
|
|
|
|
ARM64FeatureDCPOP: "dcpop",
|
|
|
|
ARM64FeatureSHA3: "sha3",
|
|
|
|
ARM64FeatureSM3: "sm3",
|
|
|
|
ARM64FeatureSM4: "sm4",
|
|
|
|
ARM64FeatureASIMDDP: "asimddp",
|
|
|
|
ARM64FeatureSHA512: "sha512",
|
|
|
|
ARM64FeatureSVE: "sve",
|
|
|
|
ARM64FeatureASIMDFHM: "asimdfhm",
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
cpuFreqMHz float64
|
|
|
|
cpuImplHex uint64
|
|
|
|
cpuArchDec uint64
|
|
|
|
cpuVarHex uint64
|
|
|
|
cpuPartHex uint64
|
|
|
|
cpuRevDec uint64
|
|
|
|
)
|
|
|
|
|
|
|
|
// arm64FeaturesFromString includes features from arm64FeatureStrings.
|
|
|
|
var arm64FeaturesFromString = make(map[string]Feature)
|
|
|
|
|
|
|
|
// FeatureFromString returns the Feature associated with the given feature
|
|
|
|
// string plus a bool to indicate if it could find the feature.
|
|
|
|
func FeatureFromString(s string) (Feature, bool) {
|
|
|
|
f, b := arm64FeaturesFromString[s]
|
|
|
|
return f, b
|
|
|
|
}
|
|
|
|
|
|
|
|
// String implements fmt.Stringer.
|
|
|
|
func (f Feature) String() string {
|
|
|
|
if s := f.flagString(); s != "" {
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("<cpuflag %d>", f)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f Feature) flagString() string {
|
|
|
|
if s, ok := arm64FeatureStrings[f]; ok {
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// FeatureSet is a set of Features for a CPU.
|
|
|
|
//
|
|
|
|
// +stateify savable
|
|
|
|
type FeatureSet struct {
|
|
|
|
// Set is the set of features that are enabled in this FeatureSet.
|
|
|
|
Set map[Feature]bool
|
|
|
|
|
|
|
|
// CPUImplementer is part of the processor signature.
|
|
|
|
CPUImplementer uint8
|
|
|
|
|
|
|
|
// CPUArchitecture is part of the processor signature.
|
|
|
|
CPUArchitecture uint8
|
|
|
|
|
|
|
|
// CPUVariant is part of the processor signature.
|
|
|
|
CPUVariant uint8
|
|
|
|
|
|
|
|
// CPUPartnum is part of the processor signature.
|
|
|
|
CPUPartnum uint16
|
|
|
|
|
|
|
|
// CPURevision is part of the processor signature.
|
|
|
|
CPURevision uint8
|
|
|
|
}
|
|
|
|
|
|
|
|
// CheckHostCompatible returns nil if fs is a subset of the host feature set.
|
|
|
|
// Noop on arm64.
|
|
|
|
func (fs *FeatureSet) CheckHostCompatible() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExtendedStateSize returns the number of bytes needed to save the "extended
|
|
|
|
// state" for this processor and the boundary it must be aligned to. Extended
|
|
|
|
// state includes floating point(NEON) registers, and other cpu state that's not
|
|
|
|
// associated with the normal task context.
|
|
|
|
func (fs *FeatureSet) ExtendedStateSize() (size, align uint) {
|
|
|
|
// ARMv8 provide 32x128bits NEON registers.
|
|
|
|
//
|
|
|
|
// Ref arch/arm64/include/uapi/asm/ptrace.h
|
|
|
|
// struct user_fpsimd_state {
|
|
|
|
// __uint128_t vregs[32];
|
|
|
|
// __u32 fpsr;
|
|
|
|
// __u32 fpcr;
|
|
|
|
// __u32 __reserved[2];
|
|
|
|
// };
|
|
|
|
return 528, 16
|
|
|
|
}
|
|
|
|
|
|
|
|
// HasFeature tests whether or not a feature is in the given feature set.
|
|
|
|
func (fs *FeatureSet) HasFeature(feature Feature) bool {
|
|
|
|
return fs.Set[feature]
|
|
|
|
}
|
|
|
|
|
2020-02-10 19:01:08 +00:00
|
|
|
// UseXsave returns true if 'fs' supports the "xsave" instruction.
|
|
|
|
//
|
|
|
|
// Irrelevant on arm64.
|
2019-10-25 03:09:59 +00:00
|
|
|
func (fs *FeatureSet) UseXsave() bool {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// FlagsString prints out supported CPU "flags" field in /proc/cpuinfo.
|
|
|
|
func (fs *FeatureSet) FlagsString() string {
|
|
|
|
var s []string
|
|
|
|
for f, _ := range arm64FeatureStrings {
|
|
|
|
if fs.Set[f] {
|
|
|
|
if fstr := f.flagString(); fstr != "" {
|
|
|
|
s = append(s, fstr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return strings.Join(s, " ")
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteCPUInfoTo is to generate a section of one cpu in /proc/cpuinfo. This is
|
|
|
|
// a minimal /proc/cpuinfo, and the bogomips field is simply made up.
|
|
|
|
func (fs FeatureSet) WriteCPUInfoTo(cpu uint, b *bytes.Buffer) {
|
|
|
|
fmt.Fprintf(b, "processor\t: %d\n", cpu)
|
|
|
|
fmt.Fprintf(b, "BogoMIPS\t: %.02f\n", cpuFreqMHz) // It's bogus anyway.
|
|
|
|
fmt.Fprintf(b, "Features\t\t: %s\n", fs.FlagsString())
|
|
|
|
fmt.Fprintf(b, "CPU implementer\t: 0x%x\n", cpuImplHex)
|
|
|
|
fmt.Fprintf(b, "CPU architecture\t: %d\n", cpuArchDec)
|
|
|
|
fmt.Fprintf(b, "CPU variant\t: 0x%x\n", cpuVarHex)
|
|
|
|
fmt.Fprintf(b, "CPU part\t: 0x%x\n", cpuPartHex)
|
|
|
|
fmt.Fprintf(b, "CPU revision\t: %d\n", cpuRevDec)
|
|
|
|
fmt.Fprintln(b, "") // The /proc/cpuinfo file ends with an extra newline.
|
|
|
|
}
|
|
|
|
|
|
|
|
// HostFeatureSet uses hwCap to get host values and construct a feature set
|
|
|
|
// that matches that of the host machine.
|
|
|
|
func HostFeatureSet() *FeatureSet {
|
|
|
|
s := make(map[Feature]bool)
|
|
|
|
|
|
|
|
for f, _ := range arm64FeatureStrings {
|
|
|
|
if hwCap&(1<<f) != 0 {
|
|
|
|
s[f] = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &FeatureSet{
|
|
|
|
Set: s,
|
|
|
|
CPUImplementer: uint8(cpuImplHex),
|
|
|
|
CPUArchitecture: uint8(cpuArchDec),
|
|
|
|
CPUVariant: uint8(cpuVarHex),
|
|
|
|
CPUPartnum: uint16(cpuPartHex),
|
|
|
|
CPURevision: uint8(cpuRevDec),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reads bogomips from host /proc/cpuinfo. Must run before whitelisting.
|
|
|
|
// This value is used to create the fake /proc/cpuinfo from a FeatureSet.
|
|
|
|
func initCPUInfo() {
|
|
|
|
cpuinfob, err := ioutil.ReadFile("/proc/cpuinfo")
|
|
|
|
if err != nil {
|
|
|
|
// Leave it as 0. The standalone VDSO bails out in the same way.
|
|
|
|
log.Warningf("Could not read /proc/cpuinfo: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
cpuinfo := string(cpuinfob)
|
|
|
|
|
|
|
|
// We get the value straight from host /proc/cpuinfo.
|
|
|
|
for _, line := range strings.Split(cpuinfo, "\n") {
|
|
|
|
switch {
|
|
|
|
case strings.Contains(line, "BogoMIPS"):
|
|
|
|
{
|
|
|
|
splitMHz := strings.Split(line, ":")
|
|
|
|
if len(splitMHz) < 2 {
|
|
|
|
log.Warningf("Could not read /proc/cpuinfo: malformed BogoMIPS")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there was a problem, leave cpuFreqMHz as 0.
|
|
|
|
var err error
|
|
|
|
cpuFreqMHz, err = strconv.ParseFloat(strings.TrimSpace(splitMHz[1]), 64)
|
|
|
|
if err != nil {
|
|
|
|
log.Warningf("Could not parse BogoMIPS value %v: %v", splitMHz[1], err)
|
|
|
|
cpuFreqMHz = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case strings.Contains(line, "CPU implementer"):
|
|
|
|
{
|
|
|
|
splitImpl := strings.Split(line, ":")
|
|
|
|
if len(splitImpl) < 2 {
|
|
|
|
log.Warningf("Could not read /proc/cpuinfo: malformed CPU implementer")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there was a problem, leave cpuImplHex as 0.
|
|
|
|
var err error
|
|
|
|
cpuImplHex, err = strconv.ParseUint(strings.TrimSpace(splitImpl[1]), 0, 64)
|
|
|
|
if err != nil {
|
|
|
|
log.Warningf("Could not parse CPU implementer value %v: %v", splitImpl[1], err)
|
|
|
|
cpuImplHex = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case strings.Contains(line, "CPU architecture"):
|
|
|
|
{
|
|
|
|
splitArch := strings.Split(line, ":")
|
|
|
|
if len(splitArch) < 2 {
|
|
|
|
log.Warningf("Could not read /proc/cpuinfo: malformed CPU architecture")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there was a problem, leave cpuArchDec as 0.
|
|
|
|
var err error
|
|
|
|
cpuArchDec, err = strconv.ParseUint(strings.TrimSpace(splitArch[1]), 0, 64)
|
|
|
|
if err != nil {
|
|
|
|
log.Warningf("Could not parse CPU architecture value %v: %v", splitArch[1], err)
|
|
|
|
cpuArchDec = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case strings.Contains(line, "CPU variant"):
|
|
|
|
{
|
|
|
|
splitVar := strings.Split(line, ":")
|
|
|
|
if len(splitVar) < 2 {
|
|
|
|
log.Warningf("Could not read /proc/cpuinfo: malformed CPU variant")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there was a problem, leave cpuVarHex as 0.
|
|
|
|
var err error
|
|
|
|
cpuVarHex, err = strconv.ParseUint(strings.TrimSpace(splitVar[1]), 0, 64)
|
|
|
|
if err != nil {
|
|
|
|
log.Warningf("Could not parse CPU variant value %v: %v", splitVar[1], err)
|
|
|
|
cpuVarHex = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case strings.Contains(line, "CPU part"):
|
|
|
|
{
|
|
|
|
splitPart := strings.Split(line, ":")
|
|
|
|
if len(splitPart) < 2 {
|
|
|
|
log.Warningf("Could not read /proc/cpuinfo: malformed CPU part")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there was a problem, leave cpuPartHex as 0.
|
|
|
|
var err error
|
|
|
|
cpuPartHex, err = strconv.ParseUint(strings.TrimSpace(splitPart[1]), 0, 64)
|
|
|
|
if err != nil {
|
|
|
|
log.Warningf("Could not parse CPU part value %v: %v", splitPart[1], err)
|
|
|
|
cpuPartHex = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case strings.Contains(line, "CPU revision"):
|
|
|
|
{
|
|
|
|
splitRev := strings.Split(line, ":")
|
|
|
|
if len(splitRev) < 2 {
|
|
|
|
log.Warningf("Could not read /proc/cpuinfo: malformed CPU revision")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there was a problem, leave cpuRevDec as 0.
|
|
|
|
var err error
|
|
|
|
cpuRevDec, err = strconv.ParseUint(strings.TrimSpace(splitRev[1]), 0, 64)
|
|
|
|
if err != nil {
|
|
|
|
log.Warningf("Could not parse CPU revision value %v: %v", splitRev[1], err)
|
|
|
|
cpuRevDec = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The auxiliary vector of a process on the Linux system can be read
|
|
|
|
// from /proc/self/auxv, and tags and values are stored as 8-bytes
|
|
|
|
// decimal key-value pairs on the 64-bit system.
|
|
|
|
//
|
|
|
|
// $ od -t d8 /proc/self/auxv
|
|
|
|
// 0000000 33 140734615224320
|
|
|
|
// 0000020 16 3219913727
|
|
|
|
// 0000040 6 4096
|
|
|
|
// 0000060 17 100
|
|
|
|
// 0000100 3 94665627353152
|
|
|
|
// 0000120 4 56
|
|
|
|
// 0000140 5 9
|
|
|
|
// 0000160 7 140425502162944
|
|
|
|
// 0000200 8 0
|
|
|
|
// 0000220 9 94665627365760
|
|
|
|
// 0000240 11 1000
|
|
|
|
// 0000260 12 1000
|
|
|
|
// 0000300 13 1000
|
|
|
|
// 0000320 14 1000
|
|
|
|
// 0000340 23 0
|
|
|
|
// 0000360 25 140734614619513
|
|
|
|
// 0000400 26 0
|
|
|
|
// 0000420 31 140734614626284
|
|
|
|
// 0000440 15 140734614619529
|
|
|
|
// 0000460 0 0
|
|
|
|
func initHwCap() {
|
|
|
|
auxv, err := ioutil.ReadFile("/proc/self/auxv")
|
|
|
|
if err != nil {
|
|
|
|
log.Warningf("Could not read /proc/self/auxv: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
l := len(auxv) / 16
|
|
|
|
for i := 0; i < l; i++ {
|
|
|
|
tag := binary.LittleEndian.Uint64(auxv[i*16:])
|
|
|
|
val := binary.LittleEndian.Uint64(auxv[(i*16 + 8):])
|
|
|
|
if tag == _AT_HWCAP {
|
|
|
|
hwCap = uint(val)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func initFeaturesFromString() {
|
|
|
|
for f, s := range arm64FeatureStrings {
|
|
|
|
arm64FeaturesFromString[s] = f
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
initCPUInfo()
|
|
|
|
initHwCap()
|
|
|
|
initFeaturesFromString()
|
|
|
|
}
|