github.com/sagernet/gvisor@v0.0.0-20240428053021-e691de28565f/pkg/cpuid/native_amd64.go (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  //go:build amd64
    16  // +build amd64
    17  
    18  package cpuid
    19  
    20  import (
    21  	"io/ioutil"
    22  	"strconv"
    23  	"strings"
    24  
    25  	"github.com/sagernet/gvisor/pkg/log"
    26  )
    27  
    28  // cpuididFunction is a useful type wrapper. The format is eax | (ecx << 32).
    29  type cpuidFunction uint64
    30  
    31  func (f cpuidFunction) eax() uint32 {
    32  	return uint32(f)
    33  }
    34  
    35  func (f cpuidFunction) ecx() uint32 {
    36  	return uint32(f >> 32)
    37  }
    38  
    39  // The constants below are the lower or "standard" cpuid functions, ordered as
    40  // defined by the hardware. Note that these may not be included in the standard
    41  // set of functions that we are allowed to execute, which are filtered in the
    42  // Native.Query function defined below.
    43  const (
    44  	vendorID                      cpuidFunction = 0x0               // Returns vendor ID and largest standard function.
    45  	featureInfo                   cpuidFunction = 0x1               // Returns basic feature bits and processor signature.
    46  	intelCacheDescriptors         cpuidFunction = 0x2               // Returns list of cache descriptors. Intel only.
    47  	intelSerialNumber             cpuidFunction = 0x3               // Returns processor serial number (obsolete on new hardware). Intel only.
    48  	intelDeterministicCacheParams cpuidFunction = 0x4               // Returns deterministic cache information. Intel only.
    49  	monitorMwaitParams            cpuidFunction = 0x5               // Returns information about monitor/mwait instructions.
    50  	powerParams                   cpuidFunction = 0x6               // Returns information about power management and thermal sensors.
    51  	extendedFeatureInfo           cpuidFunction = 0x7               // Returns extended feature bits.
    52  	_                                                               // Function 0x8 is reserved.
    53  	intelDCAParams                cpuidFunction = 0x9               // Returns direct cache access information. Intel only.
    54  	intelPMCInfo                  cpuidFunction = 0xa               // Returns information about performance monitoring features. Intel only.
    55  	intelX2APICInfo               cpuidFunction = 0xb               // Returns core/logical processor topology. Intel only.
    56  	_                                                               // Function 0xc is reserved.
    57  	xSaveInfo                     cpuidFunction = 0xd               // Returns information about extended state management.
    58  	xSaveInfoSub                  cpuidFunction = 0xd | (0x1 << 32) // Returns information about extended state management (Sub-leaf).
    59  )
    60  
    61  const xSaveInfoNumLeaves = 64 // Maximum number of xSaveInfo leaves.
    62  
    63  // The "extended" functions.
    64  const (
    65  	extendedStart         cpuidFunction = 0x80000000
    66  	extendedFunctionInfo  cpuidFunction = extendedStart + 0 // Returns highest available extended function in eax.
    67  	extendedFeatures                    = extendedStart + 1 // Returns some extended feature bits in edx and ecx.
    68  	processorBrandString2               = extendedStart + 2 // Processor Name String Identifier.
    69  	processorBrandString3               = extendedStart + 3 // Processor Name String Identifier.
    70  	processorBrandString4               = extendedStart + 4 // Processor Name String Identifier.
    71  	l1CacheAndTLBInfo                   = extendedStart + 5 // Returns L2 cache information.
    72  	l2CacheInfo                         = extendedStart + 6 // Returns L2 cache information.
    73  	addressSizes                        = extendedStart + 8 // Physical and virtual address sizes.
    74  )
    75  
    76  var allowedBasicFunctions = [...]bool{
    77  	vendorID:                      true,
    78  	featureInfo:                   true,
    79  	extendedFeatureInfo:           true,
    80  	intelCacheDescriptors:         true,
    81  	intelDeterministicCacheParams: true,
    82  	xSaveInfo:                     true,
    83  }
    84  
    85  var allowedExtendedFunctions = [...]bool{
    86  	extendedFunctionInfo - extendedStart:  true,
    87  	extendedFeatures - extendedStart:      true,
    88  	addressSizes - extendedStart:          true,
    89  	processorBrandString2 - extendedStart: true,
    90  	processorBrandString3 - extendedStart: true,
    91  	processorBrandString4 - extendedStart: true,
    92  	l1CacheAndTLBInfo - extendedStart:     true,
    93  	l2CacheInfo - extendedStart:           true,
    94  }
    95  
    96  // Function executes a CPUID function.
    97  //
    98  // This is typically the native function or a Static definition.
    99  type Function interface {
   100  	Query(In) Out
   101  }
   102  
   103  // Native is a native Function.
   104  //
   105  // This implements Function.
   106  type Native struct{}
   107  
   108  // In is input to the Query function.
   109  //
   110  // +stateify savable
   111  type In struct {
   112  	Eax uint32
   113  	Ecx uint32
   114  }
   115  
   116  // normalize drops irrelevant Ecx values.
   117  func (i *In) normalize() {
   118  	switch cpuidFunction(i.Eax) {
   119  	case vendorID, featureInfo, intelCacheDescriptors, extendedFunctionInfo, extendedFeatures:
   120  		i.Ecx = 0 // Ignore.
   121  	case processorBrandString2, processorBrandString3, processorBrandString4, l1CacheAndTLBInfo, l2CacheInfo:
   122  		i.Ecx = 0 // Ignore.
   123  	case intelDeterministicCacheParams, extendedFeatureInfo:
   124  		// Preserve i.Ecx.
   125  	}
   126  }
   127  
   128  // Out is output from the Query function.
   129  //
   130  // +stateify savable
   131  type Out struct {
   132  	Eax uint32
   133  	Ebx uint32
   134  	Ecx uint32
   135  	Edx uint32
   136  }
   137  
   138  // native is the native Query function.
   139  func native(In) Out
   140  
   141  // Query executes CPUID natively.
   142  //
   143  // This implements Function.
   144  //
   145  //go:nosplit
   146  func (*Native) Query(in In) Out {
   147  	if int(in.Eax) < len(allowedBasicFunctions) && allowedBasicFunctions[in.Eax] {
   148  		return native(in)
   149  	} else if in.Eax >= uint32(extendedStart) {
   150  		if l := int(in.Eax - uint32(extendedStart)); l < len(allowedExtendedFunctions) && allowedExtendedFunctions[l] {
   151  			return native(in)
   152  		}
   153  	}
   154  	return Out{} // All zeros.
   155  }
   156  
   157  // query is a internal wrapper.
   158  //
   159  //go:nosplit
   160  func (fs FeatureSet) query(fn cpuidFunction) (uint32, uint32, uint32, uint32) {
   161  	out := fs.Query(In{Eax: fn.eax(), Ecx: fn.ecx()})
   162  	return out.Eax, out.Ebx, out.Ecx, out.Edx
   163  }
   164  
   165  var hostFeatureSet FeatureSet
   166  
   167  // HostFeatureSet returns a host CPUID.
   168  //
   169  //go:nosplit
   170  func HostFeatureSet() FeatureSet {
   171  	return hostFeatureSet
   172  }
   173  
   174  var (
   175  	// cpuFreqMHz is the native CPU frequency.
   176  	cpuFreqMHz float64
   177  )
   178  
   179  // Reads max cpu frequency from host /proc/cpuinfo. Must run before syscall
   180  // filter installation. This value is used to create the fake /proc/cpuinfo
   181  // from a FeatureSet.
   182  func readMaxCPUFreq() {
   183  	cpuinfob, err := ioutil.ReadFile("/proc/cpuinfo")
   184  	if err != nil {
   185  		// Leave it as 0... the VDSO bails out in the same way.
   186  		log.Warningf("Could not read /proc/cpuinfo: %v", err)
   187  		return
   188  	}
   189  	cpuinfo := string(cpuinfob)
   190  
   191  	// We get the value straight from host /proc/cpuinfo. On machines with
   192  	// frequency scaling enabled, this will only get the current value
   193  	// which will likely be inaccurate. This is fine on machines with
   194  	// frequency scaling disabled.
   195  	for _, line := range strings.Split(cpuinfo, "\n") {
   196  		if strings.Contains(line, "cpu MHz") {
   197  			splitMHz := strings.Split(line, ":")
   198  			if len(splitMHz) < 2 {
   199  				log.Warningf("Could not read /proc/cpuinfo: malformed cpu MHz line")
   200  				return
   201  			}
   202  
   203  			// If there was a problem, leave cpuFreqMHz as 0.
   204  			var err error
   205  			cpuFreqMHz, err = strconv.ParseFloat(strings.TrimSpace(splitMHz[1]), 64)
   206  			if err != nil {
   207  				log.Warningf("Could not parse cpu MHz value %v: %v", splitMHz[1], err)
   208  				cpuFreqMHz = 0
   209  				return
   210  			}
   211  			return
   212  		}
   213  	}
   214  	log.Warningf("Could not parse /proc/cpuinfo, it is empty or does not contain cpu MHz")
   215  
   216  }
   217  
   218  // xgetbv reads an extended control register.
   219  func xgetbv(reg uintptr) uint64
   220  
   221  // archInitialize initializes hostFeatureSet.
   222  func archInitialize() {
   223  	hostFeatureSet = FeatureSet{
   224  		Function: &Native{},
   225  	}.Fixed()
   226  
   227  	readMaxCPUFreq()
   228  	initHWCap()
   229  }