// 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. //go:build arm64 // +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 ( // ARM64FeatureFP indicates support for single and double precision // float point types. ARM64FeatureFP Feature = iota // ARM64FeatureASIMD indicates support for Advanced SIMD with single // and double precision float point arithmetic. ARM64FeatureASIMD // ARM64FeatureEVTSTRM indicates support for the generic timer // configured to generate events at a frequency of approximately // 100KHz. ARM64FeatureEVTSTRM // ARM64FeatureAES indicates support for AES instructions // (AESE/AESD/AESMC/AESIMC). ARM64FeatureAES // ARM64FeaturePMULL indicates support for AES instructions // (PMULL/PMULL2). ARM64FeaturePMULL // ARM64FeatureSHA1 indicates support for SHA1 instructions // (SHA1C/SHA1P/SHA1M etc). ARM64FeatureSHA1 // ARM64FeatureSHA2 indicates support for SHA2 instructions // (SHA256H/SHA256H2/SHA256SU0 etc). ARM64FeatureSHA2 // ARM64FeatureCRC32 indicates support for CRC32 instructions // (CRC32B/CRC32H/CRC32W etc). ARM64FeatureCRC32 // ARM64FeatureATOMICS indicates support for atomic instructions // (LDADD/LDCLR/LDEOR/LDSET etc). ARM64FeatureATOMICS // ARM64FeatureFPHP indicates support for half precision float point // arithmetic. ARM64FeatureFPHP // ARM64FeatureASIMDHP indicates support for ASIMD with half precision // float point arithmetic. ARM64FeatureASIMDHP // ARM64FeatureCPUID indicates support for EL0 access to certain ID // registers is available. ARM64FeatureCPUID // ARM64FeatureASIMDRDM indicates support for SQRDMLAH and SQRDMLSH // instructions. ARM64FeatureASIMDRDM // ARM64FeatureJSCVT indicates support for the FJCVTZS instruction. ARM64FeatureJSCVT // ARM64FeatureFCMA indicates support for the FCMLA and FCADD // instructions. ARM64FeatureFCMA // ARM64FeatureLRCPC indicates support for the LDAPRB/LDAPRH/LDAPR // instructions. ARM64FeatureLRCPC // ARM64FeatureDCPOP indicates support for DC instruction (DC CVAP). ARM64FeatureDCPOP // ARM64FeatureSHA3 indicates support for SHA3 instructions // (EOR3/RAX1/XAR/BCAX). ARM64FeatureSHA3 // ARM64FeatureSM3 indicates support for SM3 instructions // (SM3SS1/SM3TT1A/SM3TT1B). ARM64FeatureSM3 // ARM64FeatureSM4 indicates support for SM4 instructions // (SM4E/SM4EKEY). ARM64FeatureSM4 // ARM64FeatureASIMDDP indicates support for dot product instructions // (UDOT/SDOT). ARM64FeatureASIMDDP // ARM64FeatureSHA512 indicates support for SHA2 instructions // (SHA512H/SHA512H2/SHA512SU0). ARM64FeatureSHA512 // ARM64FeatureSVE indicates support for Scalable Vector Extension. ARM64FeatureSVE // ARM64FeatureASIMDFHM indicates support for FMLAL and FMLSL // instructions. 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("", 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] } // UseXsave returns true if 'fs' supports the "xsave" instruction. // // Irrelevant on arm64. 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<