Implement x86 cpuid handling of leaf4 for cache information.
authorUlrich Drepper <drepper@gmail.com>
Sun, 20 Mar 2011 12:14:30 +0000 (08:14 -0400)
committerUlrich Drepper <drepper@gmail.com>
Sun, 20 Mar 2011 12:14:30 +0000 (08:14 -0400)
ChangeLog
NEWS
sysdeps/unix/sysv/linux/i386/sysconf.c
sysdeps/x86_64/cacheinfo.c

index 738c209..70b6faf 100644 (file)
--- 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 7ca9123..0bf33f5 100644 (file)
--- 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
 \f
 Version 2.13
 
index ff3cf9f..4ea1a2b 100644 (file)
@@ -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:
index 337444d..fdd6427 100644 (file)
@@ -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))