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