github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/cpuid/cpuid_parse_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 "fmt" 21 "io/ioutil" 22 "regexp" 23 "strconv" 24 "strings" 25 "testing" 26 27 "golang.org/x/sys/unix" 28 ) 29 30 func kernelVersion() (int, int, error) { 31 var u unix.Utsname 32 if err := unix.Uname(&u); err != nil { 33 return 0, 0, err 34 } 35 36 var sb strings.Builder 37 for _, b := range u.Release { 38 if b == 0 { 39 break 40 } 41 sb.WriteByte(byte(b)) 42 } 43 44 s := strings.Split(sb.String(), ".") 45 if len(s) < 2 { 46 return 0, 0, fmt.Errorf("kernel release missing major and minor component: %s", sb.String()) 47 } 48 49 major, err := strconv.Atoi(s[0]) 50 if err != nil { 51 return 0, 0, fmt.Errorf("error parsing major version %q in %q: %w", s[0], sb.String(), err) 52 } 53 54 minor, err := strconv.Atoi(s[1]) 55 if err != nil { 56 return 0, 0, fmt.Errorf("error parsing minor version %q in %q: %w", s[1], sb.String(), err) 57 } 58 59 return major, minor, nil 60 } 61 62 // TestHostFeatureFlags tests that all features detected by HostFeatureSet are 63 // on the host. 64 // 65 // It does *not* verify that all features reported by the host are detected by 66 // HostFeatureSet. 67 // 68 // i.e., test that HostFeatureSet is a subset of the host features. 69 func TestHostFeatureFlags(t *testing.T) { 70 cpuinfoBytes, _ := ioutil.ReadFile("/proc/cpuinfo") 71 cpuinfo := string(cpuinfoBytes) 72 t.Logf("Host cpu info:\n%s", cpuinfo) 73 74 major, minor, err := kernelVersion() 75 if err != nil { 76 t.Fatalf("Unable to parse kernel version: %v", err) 77 } 78 79 re := regexp.MustCompile(`(?m)^flags\s+: (.*)$`) 80 m := re.FindStringSubmatch(cpuinfo) 81 if len(m) != 2 { 82 t.Fatalf("Unable to extract flags from %q", cpuinfo) 83 } 84 85 cpuinfoFlags := make(map[string]struct{}) 86 for _, f := range strings.Split(m[1], " ") { 87 cpuinfoFlags[f] = struct{}{} 88 } 89 90 fs := HostFeatureSet() 91 92 // All features have a string and appear in host cpuinfo. 93 for f := range fs.Set { 94 name := f.flagString(false) 95 if name == "" { 96 t.Errorf("Non-parsable feature: %v", f) 97 } 98 99 // Special cases not consistently visible. We don't mind if 100 // they are exposed in earlier versions. 101 switch { 102 // Block 0. 103 case f == X86FeatureSDBG && (major < 4 || major == 4 && minor < 3): 104 // SDBG only exposed in 105 // b1c599b8ff80ea79b9f8277a3f9f36a7b0cfedce (4.3). 106 continue 107 // Block 2. 108 case f == X86FeatureRDT && (major < 4 || major == 4 && minor < 10): 109 // RDT only exposed in 110 // 4ab1586488cb56ed8728e54c4157cc38646874d9 (4.10). 111 continue 112 // Block 3. 113 case f == X86FeatureAVX512VBMI && (major < 4 || major == 4 && minor < 10): 114 // AVX512VBMI only exposed in 115 // a8d9df5a509a232a959e4ef2e281f7ecd77810d6 (4.10). 116 continue 117 case f == X86FeatureUMIP && (major < 4 || major == 4 && minor < 15): 118 // UMIP only exposed in 119 // 3522c2a6a4f341058b8291326a945e2a2d2aaf55 (4.15). 120 continue 121 case f == X86FeaturePKU && (major < 4 || major == 4 && minor < 9): 122 // PKU only exposed in 123 // dfb4a70f20c5b3880da56ee4c9484bdb4e8f1e65 (4.9). 124 continue 125 // Block 4. 126 case f == X86FeatureXSAVES && (major < 4 || major == 4 && minor < 8): 127 // XSAVES only exposed in 128 // b8be15d588060a03569ac85dc4a0247460988f5b (4.8). 129 continue 130 // Block 5. 131 case f == X86FeaturePERFCTR_LLC && (major < 4 || major == 4 && minor < 14): 132 // PERFCTR_LLC renamed in 133 // 910448bbed066ab1082b510eef1ae61bb792d854 (4.14). 134 continue 135 } 136 137 hidden := f.flagString(true) == "" 138 _, ok := cpuinfoFlags[name] 139 if hidden && ok { 140 t.Errorf("Unexpectedly hidden flag: %v", f) 141 } else if !hidden && !ok { 142 t.Errorf("Non-native flag: %v", f) 143 } 144 } 145 }