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  }