File: native_amd64.go

package info (click to toggle)
golang-gvisor-gvisor 0.0~20240729.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 21,276 kB
  • sloc: asm: 3,361; ansic: 1,197; cpp: 348; makefile: 92; python: 89; sh: 83
file content (229 lines) | stat: -rw-r--r-- 8,043 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// 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.

//go:build amd64
// +build amd64

package cpuid

import (
	"io/ioutil"
	"strconv"
	"strings"

	"gvisor.dev/gvisor/pkg/log"
)

// cpuididFunction is a useful type wrapper. The format is eax | (ecx << 32).
type cpuidFunction uint64

func (f cpuidFunction) eax() uint32 {
	return uint32(f)
}

func (f cpuidFunction) ecx() uint32 {
	return uint32(f >> 32)
}

// The constants below are the lower or "standard" cpuid functions, ordered as
// defined by the hardware. Note that these may not be included in the standard
// set of functions that we are allowed to execute, which are filtered in the
// Native.Query function defined below.
const (
	vendorID                      cpuidFunction = 0x0               // Returns vendor ID and largest standard function.
	featureInfo                   cpuidFunction = 0x1               // Returns basic feature bits and processor signature.
	intelCacheDescriptors         cpuidFunction = 0x2               // Returns list of cache descriptors. Intel only.
	intelSerialNumber             cpuidFunction = 0x3               // Returns processor serial number (obsolete on new hardware). Intel only.
	intelDeterministicCacheParams cpuidFunction = 0x4               // Returns deterministic cache information. Intel only.
	monitorMwaitParams            cpuidFunction = 0x5               // Returns information about monitor/mwait instructions.
	powerParams                   cpuidFunction = 0x6               // Returns information about power management and thermal sensors.
	extendedFeatureInfo           cpuidFunction = 0x7               // Returns extended feature bits.
	_                                                               // Function 0x8 is reserved.
	intelDCAParams                cpuidFunction = 0x9               // Returns direct cache access information. Intel only.
	intelPMCInfo                  cpuidFunction = 0xa               // Returns information about performance monitoring features. Intel only.
	intelX2APICInfo               cpuidFunction = 0xb               // Returns core/logical processor topology. Intel only.
	_                                                               // Function 0xc is reserved.
	xSaveInfo                     cpuidFunction = 0xd               // Returns information about extended state management.
	xSaveInfoSub                  cpuidFunction = 0xd | (0x1 << 32) // Returns information about extended state management (Sub-leaf).
)

const xSaveInfoNumLeaves = 64 // Maximum number of xSaveInfo leaves.

// The "extended" functions.
const (
	extendedStart         cpuidFunction = 0x80000000
	extendedFunctionInfo  cpuidFunction = extendedStart + 0 // Returns highest available extended function in eax.
	extendedFeatures                    = extendedStart + 1 // Returns some extended feature bits in edx and ecx.
	processorBrandString2               = extendedStart + 2 // Processor Name String Identifier.
	processorBrandString3               = extendedStart + 3 // Processor Name String Identifier.
	processorBrandString4               = extendedStart + 4 // Processor Name String Identifier.
	l1CacheAndTLBInfo                   = extendedStart + 5 // Returns L2 cache information.
	l2CacheInfo                         = extendedStart + 6 // Returns L2 cache information.
	addressSizes                        = extendedStart + 8 // Physical and virtual address sizes.
)

var allowedBasicFunctions = [...]bool{
	vendorID:                      true,
	featureInfo:                   true,
	extendedFeatureInfo:           true,
	intelCacheDescriptors:         true,
	intelDeterministicCacheParams: true,
	xSaveInfo:                     true,
}

var allowedExtendedFunctions = [...]bool{
	extendedFunctionInfo - extendedStart:  true,
	extendedFeatures - extendedStart:      true,
	addressSizes - extendedStart:          true,
	processorBrandString2 - extendedStart: true,
	processorBrandString3 - extendedStart: true,
	processorBrandString4 - extendedStart: true,
	l1CacheAndTLBInfo - extendedStart:     true,
	l2CacheInfo - extendedStart:           true,
}

// Function executes a CPUID function.
//
// This is typically the native function or a Static definition.
type Function interface {
	Query(In) Out
}

// Native is a native Function.
//
// This implements Function.
type Native struct{}

// In is input to the Query function.
//
// +stateify savable
type In struct {
	Eax uint32
	Ecx uint32
}

// normalize drops irrelevant Ecx values.
func (i *In) normalize() {
	switch cpuidFunction(i.Eax) {
	case vendorID, featureInfo, intelCacheDescriptors, extendedFunctionInfo, extendedFeatures:
		i.Ecx = 0 // Ignore.
	case processorBrandString2, processorBrandString3, processorBrandString4, l1CacheAndTLBInfo, l2CacheInfo:
		i.Ecx = 0 // Ignore.
	case intelDeterministicCacheParams, extendedFeatureInfo:
		// Preserve i.Ecx.
	}
}

// Out is output from the Query function.
//
// +stateify savable
type Out struct {
	Eax uint32
	Ebx uint32
	Ecx uint32
	Edx uint32
}

// native is the native Query function.
func native(In) Out

// Query executes CPUID natively.
//
// This implements Function.
//
//go:nosplit
func (*Native) Query(in In) Out {
	if int(in.Eax) < len(allowedBasicFunctions) && allowedBasicFunctions[in.Eax] {
		return native(in)
	} else if in.Eax >= uint32(extendedStart) {
		if l := int(in.Eax - uint32(extendedStart)); l < len(allowedExtendedFunctions) && allowedExtendedFunctions[l] {
			return native(in)
		}
	}
	return Out{} // All zeros.
}

// query is a internal wrapper.
//
//go:nosplit
func (fs FeatureSet) query(fn cpuidFunction) (uint32, uint32, uint32, uint32) {
	out := fs.Query(In{Eax: fn.eax(), Ecx: fn.ecx()})
	return out.Eax, out.Ebx, out.Ecx, out.Edx
}

var hostFeatureSet FeatureSet

// HostFeatureSet returns a host CPUID.
//
//go:nosplit
func HostFeatureSet() FeatureSet {
	return hostFeatureSet
}

var (
	// cpuFreqMHz is the native CPU frequency.
	cpuFreqMHz float64
)

// Reads max cpu frequency from host /proc/cpuinfo. Must run before syscall
// filter installation. This value is used to create the fake /proc/cpuinfo
// from a FeatureSet.
func readMaxCPUFreq() {
	cpuinfob, err := ioutil.ReadFile("/proc/cpuinfo")
	if err != nil {
		// Leave it as 0... the 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. On machines with
	// frequency scaling enabled, this will only get the current value
	// which will likely be inaccurate. This is fine on machines with
	// frequency scaling disabled.
	for _, line := range strings.Split(cpuinfo, "\n") {
		if strings.Contains(line, "cpu MHz") {
			splitMHz := strings.Split(line, ":")
			if len(splitMHz) < 2 {
				log.Warningf("Could not read /proc/cpuinfo: malformed cpu MHz line")
				return
			}

			// 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 cpu MHz value %v: %v", splitMHz[1], err)
				cpuFreqMHz = 0
				return
			}
			return
		}
	}
	log.Warningf("Could not parse /proc/cpuinfo, it is empty or does not contain cpu MHz")

}

// xgetbv reads an extended control register.
func xgetbv(reg uintptr) uint64

// archInitialize initializes hostFeatureSet.
func archInitialize() {
	hostFeatureSet = FeatureSet{
		Function: &Native{},
	}.Fixed()

	readMaxCPUFreq()
	initHWCap()
}