From 252f877f3d0ccc3f1aeb7de0e13d71fb3d4e7284 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Thu, 4 Apr 2019 18:00:54 -0700 Subject: Set fixed field in CPUID function 2 From the SDM: "The least-significant byte in register EAX (register AL) will always return 01H. Software should ignore this value and not interpret it as an informational descriptor." Unfortunately, online docs [1] [2] (likely based on an old version of the SDM) say: "The least-significant byte in register EAX (register AL) indicates the number of times the CPUID instruction must be executed with an input value of 2 to get a complete description of the processor's caches and TLBs." dlang uses this second interpretation [3] and will loop 2^32 times if we return zero. Fix this by specifying the fixed value of one. We still don't support exposing the actual cache information, leaving all other bytes empty. A zero byte means: "Null descriptor, this byte contains no information." [1] http://www.sandpile.org/x86/cpuid.htm#level_0000_0002h [2] https://c9x.me/x86/html/file_module_x86_id_45.html [3] https://github.com/dlang/druntime/blob/424640864c2aa001731467e96f637bd3e704e481/src/core/cpuid.d#L533-L534 PiperOrigin-RevId: 242046629 Change-Id: Ic0f0a5f974b20f71391cb85645bdcd4003e5fe88 --- pkg/cpuid/cpuid.go | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'pkg/cpuid') diff --git a/pkg/cpuid/cpuid.go b/pkg/cpuid/cpuid.go index 0571b7cde..64e2e68f1 100644 --- a/pkg/cpuid/cpuid.go +++ b/pkg/cpuid/cpuid.go @@ -551,6 +551,16 @@ func (fs FeatureSet) CPUInfo(cpu uint) string { return b.String() } +// AMD returns true if fs describes an AMD CPU. +func (fs *FeatureSet) AMD() bool { + return fs.VendorID == "AuthenticAMD" +} + +// Intel returns true if fs describes an Intel CPU. +func (fs *FeatureSet) Intel() bool { + return fs.VendorID == "GenuineIntel" +} + // Helper to convert 3 regs into 12-byte vendor ID. func vendorIDFromRegs(bx, cx, dx uint32) string { bytes := make([]byte, 0, 12) @@ -735,6 +745,20 @@ func (fs *FeatureSet) EmulateID(origAx, origCx uint32) (ax, bx, cx, dx uint32) { cx = fs.blockMask(block(0)) dx = fs.blockMask(block(1)) ax = fs.signature() + case intelCacheDescriptors: + if !fs.Intel() { + // Reserved on non-Intel. + return 0, 0, 0, 0 + } + + // "The least-significant byte in register EAX (register AL) + // will always return 01H. Software should ignore this value + // and not interpret it as an informational descriptor." - SDM + // + // We do not support exposing cache information, but we do set + // this fixed field because some language runtimes (dlang) get + // confused by ax = 0 and will loop infinitely. + ax = 1 case xSaveInfo: if !fs.UseXsave() { return 0, 0, 0, 0 @@ -753,7 +777,7 @@ func (fs *FeatureSet) EmulateID(origAx, origCx uint32) (ax, bx, cx, dx uint32) { case extendedFeatures: cx = fs.blockMask(block(5)) dx = fs.blockMask(block(6)) - if fs.VendorID == "AuthenticAMD" { + if fs.AMD() { // AMD duplicates some block 1 features in block 6. dx |= fs.blockMask(block(1)) & block6DuplicateMask } -- cgit v1.2.3