diff options
author | Michael Pratt <mpratt@google.com> | 2019-04-04 18:00:54 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2019-04-04 18:01:56 -0700 |
commit | 252f877f3d0ccc3f1aeb7de0e13d71fb3d4e7284 (patch) | |
tree | e01c2e8dd00c8cc260c69ecb6632875ce18d646c | |
parent | 88409e983c463b6d9c8085e7fdbe7ff45b3c5184 (diff) |
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
-rw-r--r-- | pkg/cpuid/cpuid.go | 26 |
1 files changed, 25 insertions, 1 deletions
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 } |