github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/cpuid/cpuid_x86_test.go (about) 1 // Copyright 2018 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 // +build 386 amd64 16 17 package cpuid 18 19 import ( 20 "testing" 21 ) 22 23 // These are the default values of various FeatureSet fields. 24 const ( 25 defaultVendorID = "GenuineIntel" 26 27 // These processor signature defaults are derived from the values 28 // listed in Intel Application Note 485 for i7/Xeon processors. 29 defaultExtFamily uint8 = 0 30 defaultExtModel uint8 = 1 31 defaultType uint8 = 0 32 defaultFamily uint8 = 0x06 33 defaultModel uint8 = 0x0a 34 defaultSteppingID uint8 = 0 35 ) 36 37 // newEmptyFeatureSet creates a new FeatureSet with a sensible default model and no features. 38 func newEmptyFeatureSet() *FeatureSet { 39 return &FeatureSet{ 40 Set: make(map[Feature]bool), 41 VendorID: defaultVendorID, 42 ExtendedFamily: defaultExtFamily, 43 ExtendedModel: defaultExtModel, 44 ProcessorType: defaultType, 45 Family: defaultFamily, 46 Model: defaultModel, 47 SteppingID: defaultSteppingID, 48 } 49 } 50 51 var justFPU = &FeatureSet{ 52 Set: map[Feature]bool{ 53 X86FeatureFPU: true, 54 }} 55 56 var justFPUandPAE = &FeatureSet{ 57 Set: map[Feature]bool{ 58 X86FeatureFPU: true, 59 X86FeaturePAE: true, 60 }} 61 62 func TestSubtract(t *testing.T) { 63 if diff := justFPU.Subtract(justFPUandPAE); diff != nil { 64 t.Errorf("Got %v is not subset of %v, want diff (%v) to be nil", justFPU, justFPUandPAE, diff) 65 } 66 67 if justFPUandPAE.Subtract(justFPU) == nil { 68 t.Errorf("Got %v is a subset of %v, want diff to be nil", justFPU, justFPUandPAE) 69 } 70 } 71 72 // TODO(b/73346484): Run this test on a very old platform, and make sure more 73 // bits are enabled than just FPU and PAE. This test currently may not detect 74 // if HostFeatureSet gives back junk bits. 75 func TestHostFeatureSet(t *testing.T) { 76 hostFeatures := HostFeatureSet() 77 if justFPUandPAE.Subtract(hostFeatures) != nil { 78 t.Errorf("Got invalid feature set %v from HostFeatureSet()", hostFeatures) 79 } 80 } 81 82 func TestHasFeature(t *testing.T) { 83 if !justFPU.HasFeature(X86FeatureFPU) { 84 t.Errorf("HasFeature failed, %v should contain %v", justFPU, X86FeatureFPU) 85 } 86 87 if justFPU.HasFeature(X86FeatureAVX) { 88 t.Errorf("HasFeature failed, %v should not contain %v", justFPU, X86FeatureAVX) 89 } 90 } 91 92 // Note: these tests are aware of and abuse internal details of FeatureSets. 93 // Users of FeatureSets should not depend on this. 94 func TestAdd(t *testing.T) { 95 // Test a basic insertion into the FeatureSet. 96 testFeatures := newEmptyFeatureSet() 97 testFeatures.Add(X86FeatureCLFSH) 98 if len(testFeatures.Set) != 1 { 99 t.Errorf("Got length %v want 1", len(testFeatures.Set)) 100 } 101 102 if !testFeatures.HasFeature(X86FeatureCLFSH) { 103 t.Errorf("Add failed, got %v want set with %v", testFeatures, X86FeatureCLFSH) 104 } 105 106 // Test that duplicates are ignored. 107 testFeatures.Add(X86FeatureCLFSH) 108 if len(testFeatures.Set) != 1 { 109 t.Errorf("Got length %v, want 1", len(testFeatures.Set)) 110 } 111 } 112 113 func TestRemove(t *testing.T) { 114 // Try removing the last feature. 115 testFeatures := newEmptyFeatureSet() 116 testFeatures.Add(X86FeatureFPU) 117 testFeatures.Add(X86FeaturePAE) 118 testFeatures.Remove(X86FeaturePAE) 119 if !testFeatures.HasFeature(X86FeatureFPU) || len(testFeatures.Set) != 1 || testFeatures.HasFeature(X86FeaturePAE) { 120 t.Errorf("Remove failed, got %v want %v", testFeatures, justFPU) 121 } 122 123 // Try removing a feature not in the set. 124 testFeatures.Remove(X86FeatureRDRAND) 125 if !testFeatures.HasFeature(X86FeatureFPU) || len(testFeatures.Set) != 1 { 126 t.Errorf("Remove failed, got %v want %v", testFeatures, justFPU) 127 } 128 } 129 130 func TestFeatureFromString(t *testing.T) { 131 f, ok := FeatureFromString("avx") 132 if f != X86FeatureAVX || !ok { 133 t.Errorf("got %v want avx", f) 134 } 135 136 f, ok = FeatureFromString("bad") 137 if ok { 138 t.Errorf("got %v want nothing", f) 139 } 140 } 141 142 // This tests function 0 (eax=0), which returns the vendor ID and highest cpuid 143 // function reported to be available. 144 func TestEmulateIDVendorAndLength(t *testing.T) { 145 testFeatures := newEmptyFeatureSet() 146 147 ax, bx, cx, dx := testFeatures.EmulateID(0, 0) 148 wantEax := uint32(0xd) // Highest supported cpuid function. 149 150 // These magical constants are the characters of "GenuineIntel". 151 // See Intel AN485 for a reference on why they are laid out like this. 152 wantEbx := uint32(0x756e6547) 153 wantEcx := uint32(0x6c65746e) 154 wantEdx := uint32(0x49656e69) 155 if wantEax != ax { 156 t.Errorf("highest function failed, got %x want %x", ax, wantEax) 157 } 158 159 if wantEbx != bx || wantEcx != cx || wantEdx != dx { 160 t.Errorf("vendor string emulation failed, bx:cx:dx, got %x:%x:%x want %x:%x:%x", bx, cx, dx, wantEbx, wantEcx, wantEdx) 161 } 162 } 163 164 func TestEmulateIDBasicFeatures(t *testing.T) { 165 // Make a minimal test feature set. 166 testFeatures := newEmptyFeatureSet() 167 testFeatures.Add(X86FeatureCLFSH) 168 testFeatures.Add(X86FeatureAVX) 169 testFeatures.CacheLine = 64 170 171 ax, bx, cx, dx := testFeatures.EmulateID(1, 0) 172 ECXAVXBit := uint32(1 << uint(X86FeatureAVX)) 173 EDXCLFlushBit := uint32(1 << uint(X86FeatureCLFSH-32)) // We adjust by 32 since it's in block 1. 174 175 if EDXCLFlushBit&dx == 0 || dx&^EDXCLFlushBit != 0 { 176 t.Errorf("EmulateID failed, got feature bits %x want %x", dx, testFeatures.blockMask(1)) 177 } 178 179 if ECXAVXBit&cx == 0 || cx&^ECXAVXBit != 0 { 180 t.Errorf("EmulateID failed, got feature bits %x want %x", cx, testFeatures.blockMask(0)) 181 } 182 183 // Default signature bits, based on values for i7/Xeon. 184 // See Intel AN485 for information on stepping/model bits. 185 defaultSignature := uint32(0x000106a0) 186 if defaultSignature != ax { 187 t.Errorf("EmulateID stepping emulation failed, got %x want %x", ax, defaultSignature) 188 } 189 190 clflushSizeInfo := uint32(8 << 8) 191 if clflushSizeInfo != bx { 192 t.Errorf("EmulateID bx emulation failed, got %x want %x", bx, clflushSizeInfo) 193 } 194 } 195 196 func TestEmulateIDExtendedFeatures(t *testing.T) { 197 // Make a minimal test feature set, one bit in each extended feature word. 198 testFeatures := newEmptyFeatureSet() 199 testFeatures.Add(X86FeatureSMEP) 200 testFeatures.Add(X86FeatureAVX512VBMI) 201 202 ax, bx, cx, dx := testFeatures.EmulateID(7, 0) 203 EBXSMEPBit := uint32(1 << uint(X86FeatureSMEP-2*32)) // Adjust by 2*32 since SMEP is a block 2 feature. 204 ECXAVXBit := uint32(1 << uint(X86FeatureAVX512VBMI-3*32)) // We adjust by 3*32 since it's a block 3 feature. 205 206 // Test that the desired bit is set and no other bits are set. 207 if EBXSMEPBit&bx == 0 || bx&^EBXSMEPBit != 0 { 208 t.Errorf("extended feature emulation failed, got feature bits %x want %x", bx, testFeatures.blockMask(2)) 209 } 210 211 if ECXAVXBit&cx == 0 || cx&^ECXAVXBit != 0 { 212 t.Errorf("extended feature emulation failed, got feature bits %x want %x", cx, testFeatures.blockMask(3)) 213 } 214 215 if ax != 0 || dx != 0 { 216 t.Errorf("extended feature emulation failed, ax:dx, got %x:%x want 0:0", ax, dx) 217 } 218 219 // Check that no subleaves other than 0 do anything. 220 ax, bx, cx, dx = testFeatures.EmulateID(7, 1) 221 if ax != 0 || bx != 0 || cx != 0 || dx != 0 { 222 t.Errorf("extended feature emulation failed, got %x:%x:%x:%x want 0:0", ax, bx, cx, dx) 223 } 224 225 } 226 227 // Checks that the expected extended features are available via cpuid functions 228 // 0x80000000 and up. 229 func TestEmulateIDExtended(t *testing.T) { 230 testFeatures := newEmptyFeatureSet() 231 testFeatures.Add(X86FeatureSYSCALL) 232 EDXSYSCALLBit := uint32(1 << uint(X86FeatureSYSCALL-6*32)) // Adjust by 6*32 since SYSCALL is a block 6 feature. 233 234 ax, bx, cx, dx := testFeatures.EmulateID(0x80000000, 0) 235 if ax != 0x80000001 || bx != 0 || cx != 0 || dx != 0 { 236 t.Errorf("EmulateID extended emulation failed, ax:bx:cx:dx, got %x:%x:%x:%x want 0x80000001:0:0:0", ax, bx, cx, dx) 237 } 238 239 _, _, _, dx = testFeatures.EmulateID(0x80000001, 0) 240 if EDXSYSCALLBit&dx == 0 || dx&^EDXSYSCALLBit != 0 { 241 t.Errorf("extended feature emulation failed, got feature bits %x want %x", dx, testFeatures.blockMask(6)) 242 } 243 }