summaryrefslogtreecommitdiff
path: root/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
diff options
context:
space:
mode:
authorFelix Geyer <fgeyer@debian.org>2014-04-05 22:17:15 +0200
committerFelix Geyer <fgeyer@debian.org>2014-04-05 22:17:15 +0200
commit1700c7d32f7d9d101cbba9f1fcb8bb57ed16a727 (patch)
tree727251ad65172262944f82bb0f28601c3fb6f6b3 /src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
parent1e85aed889b772c2f2daa7a6d9e8bd967aa213d8 (diff)
downloadvirtualbox-upstream.tar.gz
Imported Upstream version 4.3.10-dfsgupstream/4.3.10-dfsgupstream
Diffstat (limited to 'src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp')
-rw-r--r--src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp65
1 files changed, 54 insertions, 11 deletions
diff --git a/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp b/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
index e3d6f9a45..2e094bf7b 100644
--- a/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
+++ b/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
@@ -770,6 +770,7 @@ static bool cpumR3IsEcxRelevantForCpuIdLeaf(uint32_t uLeaf, uint32_t *pcSubLeave
{
*pfFinalEcxUnchanged = false;
+ uint32_t auCur[4];
uint32_t auPrev[4];
ASMCpuIdExSlow(uLeaf, 0, 0, 0, &auPrev[0], &auPrev[1], &auPrev[2], &auPrev[3]);
@@ -777,7 +778,6 @@ static bool cpumR3IsEcxRelevantForCpuIdLeaf(uint32_t uLeaf, uint32_t *pcSubLeave
uint32_t uSubLeaf = 1;
for (;;)
{
- uint32_t auCur[4];
ASMCpuIdExSlow(uLeaf, 0, uSubLeaf, 0, &auCur[0], &auCur[1], &auCur[2], &auCur[3]);
if (memcmp(auCur, auPrev, sizeof(auCur)))
break;
@@ -792,33 +792,76 @@ static bool cpumR3IsEcxRelevantForCpuIdLeaf(uint32_t uLeaf, uint32_t *pcSubLeave
}
/* Count sub-leaves. */
+ uint32_t cRepeats = 0;
uSubLeaf = 0;
for (;;)
{
- uint32_t auCur[4];
ASMCpuIdExSlow(uLeaf, 0, uSubLeaf, 0, &auCur[0], &auCur[1], &auCur[2], &auCur[3]);
- /* Exactly when this terminates isn't quite consistent. When working
- 0xb, we should probably only check if ebx == 0... */
+ /* Figuring out when to stop isn't entirely straight forward as we need
+ to cover undocumented behavior up to a point and implementation shortcuts. */
+
+ /* 1. Look for zero values. */
if ( auCur[0] == 0
&& auCur[1] == 0
&& (auCur[2] == 0 || auCur[2] == uSubLeaf)
- && (auCur[3] == 0 || uLeaf == 0xb) )
+ && (auCur[3] == 0 || uLeaf == 0xb /* edx is fixed */) )
+ break;
+
+ /* 2. Look for more than 4 repeating value sets. */
+ if ( auCur[0] == auPrev[0]
+ && auCur[1] == auPrev[1]
+ && ( auCur[2] == auPrev[2]
+ || ( auCur[2] == uSubLeaf
+ && auPrev[2] == uSubLeaf - 1) )
+ && auCur[3] == auPrev[3])
{
- if (auCur[2] == uSubLeaf)
- *pfFinalEcxUnchanged = true;
- *pcSubLeaves = uSubLeaf + 1;
- return true;
+ cRepeats++;
+ if (cRepeats > 4)
+ break;
}
+ else
+ cRepeats = 0;
- /* Advance / give up. */
- uSubLeaf++;
+ /* 3. Leaf 0xb level type 0 check. */
+ if ( uLeaf == 0xb
+ && (auCur[3] & 0xff00) == 0
+ && (auPrev[3] & 0xff00) == 0)
+ break;
+
+ /* 99. Give up. */
if (uSubLeaf >= 128)
{
+#ifndef IN_VBOX_CPU_REPORT
+ /* Ok, limit it according to the documentation if possible just to
+ avoid annoying users with these detection issues. */
+ uint32_t cDocLimit = UINT32_MAX;
+ if (uLeaf == 0x4)
+ cDocLimit = 4;
+ else if (uLeaf == 0x7)
+ cDocLimit = 1;
+ else if (uLeaf == 0xf)
+ cDocLimit = 2;
+ if (cDocLimit != UINT32_MAX)
+ {
+ *pfFinalEcxUnchanged = auCur[2] == uSubLeaf;
+ *pcSubLeaves = cDocLimit + 3;
+ return true;
+ }
+#endif
*pcSubLeaves = UINT32_MAX;
return true;
}
+
+ /* Advance. */
+ uSubLeaf++;
+ memcpy(auPrev, auCur, sizeof(auCur));
}
+
+ /* Standard exit. */
+ *pfFinalEcxUnchanged = auCur[2] == uSubLeaf;
+ *pcSubLeaves = uSubLeaf + 1 - cRepeats;
+ return true;
}