native_amd64.go raw

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