aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@gmail.com>2011-03-20 08:14:30 -0400
committerUlrich Drepper <drepper@gmail.com>2011-03-20 08:14:30 -0400
commit2a1156010784332cbe4bf033ccedb19f52e56a75 (patch)
tree120bbcd9eb4077a6adcbd871dae448658c31d5d6
parent042c49c681ca671215849a3788595b7eba90ffd0 (diff)
downloadglibc-2a1156010784332cbe4bf033ccedb19f52e56a75.tar
glibc-2a1156010784332cbe4bf033ccedb19f52e56a75.tar.gz
glibc-2a1156010784332cbe4bf033ccedb19f52e56a75.tar.bz2
glibc-2a1156010784332cbe4bf033ccedb19f52e56a75.zip
Implement x86 cpuid handling of leaf4 for cache information.
-rw-r--r--ChangeLog7
-rw-r--r--NEWS4
-rw-r--r--sysdeps/unix/sysv/linux/i386/sysconf.c63
-rw-r--r--sysdeps/x86_64/cacheinfo.c49
4 files changed, 114 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index 738c209cf2..70b6faf20f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2011-03-20 Ulrich Drepper <drepper@gmail.com>
+
+ [BZ #12587]
+ * sysdeps/unix/sysv/linux/i386/sysconf.c (intel_check_word):
+ Handle cache information in CPU leaf 4.
+ * sysdeps/x86_64/cacheinfo.c (intel_check_word): Likewise.
+
2011-03-18 Ulrich Drepper <drepper@gmail.com>
[BZ #12583]
diff --git a/NEWS b/NEWS
index 7ca9123633..0bf33f528a 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU C Library NEWS -- history of user-visible changes. 2011-3-18
+GNU C Library NEWS -- history of user-visible changes. 2011-3-20
Copyright (C) 1992-2009, 2010, 2011 Free Software Foundation, Inc.
See the end for copying conditions.
@@ -9,7 +9,7 @@ Version 2.14
* The following bugs are resolved with this release:
- 11724, 12445, 12454, 12460, 12469, 12489, 12509, 12510, 12583
+ 11724, 12445, 12454, 12460, 12469, 12489, 12509, 12510, 12583, 12587
Version 2.13
diff --git a/sysdeps/unix/sysv/linux/i386/sysconf.c b/sysdeps/unix/sysv/linux/i386/sysconf.c
index ff3cf9f7c7..4ea1a2bf58 100644
--- a/sysdeps/unix/sysv/linux/i386/sysconf.c
+++ b/sysdeps/unix/sysv/linux/i386/sysconf.c
@@ -1,5 +1,5 @@
/* Get file-specific information about a file. Linux version.
- Copyright (C) 2003, 2004, 2006, 2007, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2006, 2007, 2009, 2011 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -186,6 +186,55 @@ intel_check_word (int name, unsigned int value, bool *has_level_2,
/* No need to look further. */
break;
}
+ else if (byte == 0xff)
+ {
+ /* CPUID leaf 0x4 contains all the information. We need to
+ iterate over it. */
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+
+ unsigned int round = 0;
+ while (1)
+ {
+ asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
+ : "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx)
+ : "0" (4), "2" (round));
+
+ enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f;
+ if (type == null)
+ /* That was the end. */
+ break;
+
+ unsigned int level = (eax >> 5) & 0x7;
+
+ if ((level == 1 && type == data
+ && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE))
+ || (level == 1 && type == inst
+ && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE))
+ || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE))
+ || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))
+ || (level == 4 && folded_rel_name == M(_SC_LEVEL4_CACHE_SIZE)))
+ {
+ unsigned int offset = M(name) - folded_rel_name;
+
+ if (offset == 0)
+ /* Cache size. */
+ return (((ebx >> 22) + 1)
+ * (((ebx >> 12) & 0x3ff) + 1)
+ * ((ebx & 0xfff) + 1)
+ * (ecx + 1));
+ if (offset == 1)
+ return (ebx >> 22) + 1;
+
+ assert (offset == 2);
+ return (ebx & 0xfff) + 1;
+ }
+ }
+ /* There is no other cache information anywhere else. */
+ break;
+ }
else
{
if (byte == 0x49 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))
@@ -358,11 +407,11 @@ handle_amd (int name)
case _SC_LEVEL2_CACHE_ASSOC:
ecx >>= 12;
switch (ecx & 0xf)
- {
- case 0:
- case 1:
- case 2:
- case 4:
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
return ecx & 0xf;
case 6:
return 8;
@@ -372,7 +421,7 @@ handle_amd (int name)
return (ecx << 6) & 0x3fffc00;
default:
return 0;
- }
+ }
case _SC_LEVEL2_CACHE_LINESIZE:
return (ecx & 0xf000) == 0 ? 0 : ecx & 0xff;
default:
diff --git a/sysdeps/x86_64/cacheinfo.c b/sysdeps/x86_64/cacheinfo.c
index 337444df07..fdd6427e12 100644
--- a/sysdeps/x86_64/cacheinfo.c
+++ b/sysdeps/x86_64/cacheinfo.c
@@ -181,6 +181,55 @@ intel_check_word (int name, unsigned int value, bool *has_level_2,
/* No need to look further. */
break;
}
+ else if (byte == 0xff)
+ {
+ /* CPUID leaf 0x4 contains all the information. We need to
+ iterate over it. */
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+
+ unsigned int round = 0;
+ while (1)
+ {
+ asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
+ : "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx)
+ : "0" (4), "2" (round));
+
+ enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f;
+ if (type == null)
+ /* That was the end. */
+ break;
+
+ unsigned int level = (eax >> 5) & 0x7;
+
+ if ((level == 1 && type == data
+ && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE))
+ || (level == 1 && type == inst
+ && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE))
+ || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE))
+ || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))
+ || (level == 4 && folded_rel_name == M(_SC_LEVEL4_CACHE_SIZE)))
+ {
+ unsigned int offset = M(name) - folded_rel_name;
+
+ if (offset == 0)
+ /* Cache size. */
+ return (((ebx >> 22) + 1)
+ * (((ebx >> 12) & 0x3ff) + 1)
+ * ((ebx & 0xfff) + 1)
+ * (ecx + 1));
+ if (offset == 1)
+ return (ebx >> 22) + 1;
+
+ assert (offset == 2);
+ return (ebx & 0xfff) + 1;
+ }
+ }
+ /* There is no other cache information anywhere else. */
+ break;
+ }
else
{
if (byte == 0x49 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))