summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2019-04-04 18:00:54 -0700
committerShentubot <shentubot@google.com>2019-04-04 18:01:56 -0700
commit252f877f3d0ccc3f1aeb7de0e13d71fb3d4e7284 (patch)
treee01c2e8dd00c8cc260c69ecb6632875ce18d646c
parent88409e983c463b6d9c8085e7fdbe7ff45b3c5184 (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.go26
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
}