Update dependencies
This commit is contained in:
264
vendor/gvisor.dev/gvisor/pkg/cpuid/cpuid.go
vendored
Normal file
264
vendor/gvisor.dev/gvisor/pkg/cpuid/cpuid.go
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
// Package cpuid provides basic functionality for creating and adjusting CPU
|
||||
// feature sets.
|
||||
//
|
||||
// Each architecture should define its own FeatureSet type, that must be
|
||||
// savable, along with an allFeatures map, appropriate arch hooks and a
|
||||
// HostFeatureSet function. This file contains common functionality to all
|
||||
// architectures, which is essentially string munging and some errors.
|
||||
//
|
||||
// Individual architectures may export methods on FeatureSet that are relevant,
|
||||
// e.g. FeatureSet.Vendor(). Common to all architectures, FeatureSets include
|
||||
// HasFeature, which provides a trivial mechanism to test for the presence of
|
||||
// specific hardware features. The hardware features are also defined on a
|
||||
// per-architecture basis.
|
||||
package cpuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
)
|
||||
|
||||
// contextID is the package for anyContext.Context.Value keys.
|
||||
type contextID int
|
||||
|
||||
const (
|
||||
// CtxFeatureSet is the FeatureSet for the context.
|
||||
CtxFeatureSet contextID = iota
|
||||
|
||||
// hardware capability bit vector.
|
||||
_AT_HWCAP = 16
|
||||
// hardware capability bit vector 2.
|
||||
_AT_HWCAP2 = 26
|
||||
)
|
||||
|
||||
// anyContext represents context.Context.
|
||||
type anyContext interface {
|
||||
Value(key any) any
|
||||
}
|
||||
|
||||
// FromContext returns the FeatureSet from the context, if available.
|
||||
func FromContext(ctx anyContext) FeatureSet {
|
||||
v := ctx.Value(CtxFeatureSet)
|
||||
if v == nil {
|
||||
return FeatureSet{} // Panics if used.
|
||||
}
|
||||
return v.(FeatureSet)
|
||||
}
|
||||
|
||||
// Feature is a unique identifier for a particular cpu feature. We just use an
|
||||
// int as a feature number on x86 and arm64.
|
||||
//
|
||||
// On x86, features are numbered according to "blocks". Each block is 32 bits, and
|
||||
// feature bits from the same source (cpuid leaf/level) are in the same block.
|
||||
//
|
||||
// On arm64, features are numbered according to the ELF HWCAP definition, from
|
||||
// arch/arm64/include/uapi/asm/hwcap.h.
|
||||
type Feature int
|
||||
|
||||
// allFeatureInfo is the value for allFeatures.
|
||||
type allFeatureInfo struct {
|
||||
// displayName is the short display name for the feature.
|
||||
displayName string
|
||||
|
||||
// shouldAppear indicates whether the feature normally appears in
|
||||
// cpuinfo. This affects FlagString only.
|
||||
shouldAppear bool
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.String.
|
||||
func (f Feature) String() string {
|
||||
info, ok := allFeatures[f]
|
||||
if ok {
|
||||
return info.displayName
|
||||
}
|
||||
return fmt.Sprintf("[0x%x?]", int(f)) // No given name.
|
||||
}
|
||||
|
||||
// reverseMap is a map from displayName to Feature.
|
||||
var reverseMap = func() map[string]Feature {
|
||||
m := make(map[string]Feature)
|
||||
for feature, info := range allFeatures {
|
||||
if info.displayName != "" {
|
||||
// Sanity check that the name is unique.
|
||||
if old, ok := m[info.displayName]; ok {
|
||||
panic(fmt.Sprintf("feature %v has conflicting values (0x%x vs 0x%x)", info.displayName, old, feature))
|
||||
}
|
||||
m[info.displayName] = feature
|
||||
}
|
||||
}
|
||||
return m
|
||||
}()
|
||||
|
||||
// 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) {
|
||||
feature, ok := reverseMap[s]
|
||||
return feature, ok
|
||||
}
|
||||
|
||||
// AllFeatures returns the full set of all possible features.
|
||||
func AllFeatures() (features []Feature) {
|
||||
archFlagOrder(func(f Feature) {
|
||||
features = append(features, f)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Subtract returns the features present in fs that are not present in other.
|
||||
// If all features in fs are present in other, Subtract returns nil.
|
||||
//
|
||||
// This does not check for any kinds of incompatibility.
|
||||
func (fs FeatureSet) Subtract(other FeatureSet) (left map[Feature]struct{}) {
|
||||
for feature := range allFeatures {
|
||||
thisHas := fs.HasFeature(feature)
|
||||
otherHas := other.HasFeature(feature)
|
||||
if thisHas && !otherHas {
|
||||
if left == nil {
|
||||
left = make(map[Feature]struct{})
|
||||
}
|
||||
left[feature] = struct{}{}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// FlagString prints out supported CPU flags.
|
||||
func (fs FeatureSet) FlagString() string {
|
||||
var s []string
|
||||
archFlagOrder(func(feature Feature) {
|
||||
if !fs.HasFeature(feature) {
|
||||
return
|
||||
}
|
||||
info := allFeatures[feature]
|
||||
if !info.shouldAppear {
|
||||
return
|
||||
}
|
||||
s = append(s, info.displayName)
|
||||
})
|
||||
return strings.Join(s, " ")
|
||||
}
|
||||
|
||||
// ErrIncompatible is returned for incompatible feature sets.
|
||||
type ErrIncompatible struct {
|
||||
reason string
|
||||
}
|
||||
|
||||
// Error implements error.Error.
|
||||
func (e *ErrIncompatible) Error() string {
|
||||
return fmt.Sprintf("incompatible FeatureSet: %v", e.reason)
|
||||
}
|
||||
|
||||
// CheckHostCompatible returns nil if fs is a subset of the host feature set.
|
||||
func (fs FeatureSet) CheckHostCompatible() error {
|
||||
hfs := HostFeatureSet()
|
||||
|
||||
// Check that hfs is a superset of fs.
|
||||
if diff := fs.Subtract(hfs); len(diff) > 0 {
|
||||
return &ErrIncompatible{
|
||||
reason: fmt.Sprintf("missing features: %v", diff),
|
||||
}
|
||||
}
|
||||
|
||||
// Make arch-specific checks.
|
||||
return fs.archCheckHostCompatible(hfs)
|
||||
}
|
||||
|
||||
// +stateify savable
|
||||
type hwCap struct {
|
||||
// hwCap1 stores HWCAP bits exposed through the elf auxiliary vector.
|
||||
hwCap1 uint64
|
||||
// hwCap2 stores HWCAP2 bits exposed through the elf auxiliary vector.
|
||||
hwCap2 uint64
|
||||
}
|
||||
|
||||
// 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 readHWCap(auxvFilepath string) (hwCap, error) {
|
||||
c := hwCap{}
|
||||
if runtime.GOOS != "linux" {
|
||||
// Don't try to read Linux-specific /proc files.
|
||||
return c, fmt.Errorf("readHwCap only supported on linux, not %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
auxv, err := os.ReadFile(auxvFilepath)
|
||||
if err != nil {
|
||||
return c, fmt.Errorf("failed to read file %s: %w", auxvFilepath, err)
|
||||
}
|
||||
|
||||
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 {
|
||||
c.hwCap1 = val
|
||||
} else if tag == _AT_HWCAP2 {
|
||||
c.hwCap2 = val
|
||||
}
|
||||
|
||||
if (c.hwCap1 != 0) && (c.hwCap2 != 0) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func initHWCap() {
|
||||
c, err := readHWCap("/proc/self/auxv")
|
||||
if err != nil {
|
||||
log.Warningf("cpuid HWCap not initialized: %w", err)
|
||||
} else {
|
||||
hostFeatureSet.hwCap = c
|
||||
}
|
||||
}
|
||||
|
||||
var initOnce sync.Once
|
||||
|
||||
// Initialize initializes the global data structures used by this package.
|
||||
// Must be called prior to using anything else in this package.
|
||||
func Initialize() {
|
||||
initOnce.Do(archInitialize)
|
||||
}
|
||||
Reference in New Issue
Block a user