From 2a5efe88e9da9822cfdde4f6f68cf47b1202e86a Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Tue, 21 Jun 2022 02:10:55 -0700 Subject: [PATCH] Fix AMD cache hang on buggy Xen hypervisor (#104) Xen Hypervisor is buggy and returns the same entry no matter ECX value. Hack: When we encounter the same entry 100 times we break. Fixes #103 --- cpuid.go | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/cpuid.go b/cpuid.go index 781a9c9..bec4c24 100644 --- a/cpuid.go +++ b/cpuid.go @@ -14,6 +14,7 @@ import ( "flag" "fmt" "math" + "math/bits" "os" "runtime" "strings" @@ -389,8 +390,9 @@ func (c CPUInfo) IsVendor(v Vendor) bool { return c.VendorID == v } +// FeatureSet returns all available features as strings. func (c CPUInfo) FeatureSet() []string { - s := make([]string, 0) + s := make([]string, 0, c.featureSet.nEnabled()) s = append(s, c.featureSet.Strings()...) return s } @@ -563,6 +565,14 @@ func (s flagSet) hasSet(other flagSet) bool { return true } +// nEnabled will return the number of enabled flags. +func (s flagSet) nEnabled() (n int) { + for _, v := range s[:] { + n += bits.OnesCount64(uint64(v)) + } + return n +} + func flagSetWith(feat ...FeatureID) flagSet { var res flagSet for _, f := range feat { @@ -834,6 +844,11 @@ func (c *CPUInfo) cacheSize() { if maxExtendedFunction() < 0x8000001D { return } + + // Xen Hypervisor is buggy and returns the same entry no matter ECX value. + // Hack: When we encounter the same entry 100 times we break. + nSame := 0 + var last uint32 for i := uint32(0); i < math.MaxUint32; i++ { eax, ebx, ecx, _ := cpuidex(0x8000001D, i) @@ -849,6 +864,16 @@ func (c *CPUInfo) cacheSize() { return } + // Check for the same value repeated. + comb := eax ^ ebx ^ ecx + if comb == last { + nSame++ + if nSame == 100 { + return + } + } + last = comb + switch level { case 1: switch typ {