about summary refs log tree commit diff
path: root/sysdeps/x86_64
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 /sysdeps/x86_64
parent042c49c681ca671215849a3788595b7eba90ffd0 (diff)
downloadglibc-2a1156010784332cbe4bf033ccedb19f52e56a75.tar.gz
glibc-2a1156010784332cbe4bf033ccedb19f52e56a75.tar.xz
glibc-2a1156010784332cbe4bf033ccedb19f52e56a75.zip
Implement x86 cpuid handling of leaf4 for cache information.
Diffstat (limited to 'sysdeps/x86_64')
-rw-r--r--sysdeps/x86_64/cacheinfo.c49
1 files changed, 49 insertions, 0 deletions
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))