Blame sysdeps/x86/dl-cacheinfo.h

Packit Service 4f62bc
/* Initialize x86 cache info.
Packit Service 4f62bc
   Copyright (C) 2020 Free Software Foundation, Inc.
Packit Service 4f62bc
   This file is part of the GNU C Library.
Packit Service 4f62bc
Packit Service 4f62bc
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 4f62bc
   modify it under the terms of the GNU Lesser General Public
Packit Service 4f62bc
   License as published by the Free Software Foundation; either
Packit Service 4f62bc
   version 2.1 of the License, or (at your option) any later version.
Packit Service 4f62bc
Packit Service 4f62bc
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 4f62bc
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 4f62bc
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 4f62bc
   Lesser General Public License for more details.
Packit Service 4f62bc
Packit Service 4f62bc
   You should have received a copy of the GNU Lesser General Public
Packit Service 4f62bc
   License along with the GNU C Library; if not, see
Packit Service 4f62bc
   <https://www.gnu.org/licenses/>.  */
Packit Service 4f62bc
Packit Service 4f62bc
static const struct intel_02_cache_info
Packit Service 4f62bc
{
Packit Service 4f62bc
  unsigned char idx;
Packit Service 4f62bc
  unsigned char assoc;
Packit Service 4f62bc
  unsigned char linesize;
Packit Service 4f62bc
  unsigned char rel_name;
Packit Service 4f62bc
  unsigned int size;
Packit Service 4f62bc
} intel_02_known [] =
Packit Service 4f62bc
  {
Packit Service 4f62bc
#define M(sc) ((sc) - _SC_LEVEL1_ICACHE_SIZE)
Packit Service 4f62bc
    { 0x06,  4, 32, M(_SC_LEVEL1_ICACHE_SIZE),    8192 },
Packit Service 4f62bc
    { 0x08,  4, 32, M(_SC_LEVEL1_ICACHE_SIZE),   16384 },
Packit Service 4f62bc
    { 0x09,  4, 32, M(_SC_LEVEL1_ICACHE_SIZE),   32768 },
Packit Service 4f62bc
    { 0x0a,  2, 32, M(_SC_LEVEL1_DCACHE_SIZE),    8192 },
Packit Service 4f62bc
    { 0x0c,  4, 32, M(_SC_LEVEL1_DCACHE_SIZE),   16384 },
Packit Service 4f62bc
    { 0x0d,  4, 64, M(_SC_LEVEL1_DCACHE_SIZE),   16384 },
Packit Service 4f62bc
    { 0x0e,  6, 64, M(_SC_LEVEL1_DCACHE_SIZE),   24576 },
Packit Service 4f62bc
    { 0x21,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),   262144 },
Packit Service 4f62bc
    { 0x22,  4, 64, M(_SC_LEVEL3_CACHE_SIZE),   524288 },
Packit Service 4f62bc
    { 0x23,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  1048576 },
Packit Service 4f62bc
    { 0x25,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  2097152 },
Packit Service 4f62bc
    { 0x29,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  4194304 },
Packit Service 4f62bc
    { 0x2c,  8, 64, M(_SC_LEVEL1_DCACHE_SIZE),   32768 },
Packit Service 4f62bc
    { 0x30,  8, 64, M(_SC_LEVEL1_ICACHE_SIZE),   32768 },
Packit Service 4f62bc
    { 0x39,  4, 64, M(_SC_LEVEL2_CACHE_SIZE),   131072 },
Packit Service 4f62bc
    { 0x3a,  6, 64, M(_SC_LEVEL2_CACHE_SIZE),   196608 },
Packit Service 4f62bc
    { 0x3b,  2, 64, M(_SC_LEVEL2_CACHE_SIZE),   131072 },
Packit Service 4f62bc
    { 0x3c,  4, 64, M(_SC_LEVEL2_CACHE_SIZE),   262144 },
Packit Service 4f62bc
    { 0x3d,  6, 64, M(_SC_LEVEL2_CACHE_SIZE),   393216 },
Packit Service 4f62bc
    { 0x3e,  4, 64, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 4f62bc
    { 0x3f,  2, 64, M(_SC_LEVEL2_CACHE_SIZE),   262144 },
Packit Service 4f62bc
    { 0x41,  4, 32, M(_SC_LEVEL2_CACHE_SIZE),   131072 },
Packit Service 4f62bc
    { 0x42,  4, 32, M(_SC_LEVEL2_CACHE_SIZE),   262144 },
Packit Service 4f62bc
    { 0x43,  4, 32, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 4f62bc
    { 0x44,  4, 32, M(_SC_LEVEL2_CACHE_SIZE),  1048576 },
Packit Service 4f62bc
    { 0x45,  4, 32, M(_SC_LEVEL2_CACHE_SIZE),  2097152 },
Packit Service 4f62bc
    { 0x46,  4, 64, M(_SC_LEVEL3_CACHE_SIZE),  4194304 },
Packit Service 4f62bc
    { 0x47,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  8388608 },
Packit Service 4f62bc
    { 0x48, 12, 64, M(_SC_LEVEL2_CACHE_SIZE),  3145728 },
Packit Service 4f62bc
    { 0x49, 16, 64, M(_SC_LEVEL2_CACHE_SIZE),  4194304 },
Packit Service 4f62bc
    { 0x4a, 12, 64, M(_SC_LEVEL3_CACHE_SIZE),  6291456 },
Packit Service 4f62bc
    { 0x4b, 16, 64, M(_SC_LEVEL3_CACHE_SIZE),  8388608 },
Packit Service 4f62bc
    { 0x4c, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 12582912 },
Packit Service 4f62bc
    { 0x4d, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 16777216 },
Packit Service 4f62bc
    { 0x4e, 24, 64, M(_SC_LEVEL2_CACHE_SIZE),  6291456 },
Packit Service 4f62bc
    { 0x60,  8, 64, M(_SC_LEVEL1_DCACHE_SIZE),   16384 },
Packit Service 4f62bc
    { 0x66,  4, 64, M(_SC_LEVEL1_DCACHE_SIZE),    8192 },
Packit Service 4f62bc
    { 0x67,  4, 64, M(_SC_LEVEL1_DCACHE_SIZE),   16384 },
Packit Service 4f62bc
    { 0x68,  4, 64, M(_SC_LEVEL1_DCACHE_SIZE),   32768 },
Packit Service 4f62bc
    { 0x78,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),  1048576 },
Packit Service 4f62bc
    { 0x79,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),   131072 },
Packit Service 4f62bc
    { 0x7a,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),   262144 },
Packit Service 4f62bc
    { 0x7b,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 4f62bc
    { 0x7c,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),  1048576 },
Packit Service 4f62bc
    { 0x7d,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),  2097152 },
Packit Service 4f62bc
    { 0x7f,  2, 64, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 4f62bc
    { 0x80,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 4f62bc
    { 0x82,  8, 32, M(_SC_LEVEL2_CACHE_SIZE),   262144 },
Packit Service 4f62bc
    { 0x83,  8, 32, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 4f62bc
    { 0x84,  8, 32, M(_SC_LEVEL2_CACHE_SIZE),  1048576 },
Packit Service 4f62bc
    { 0x85,  8, 32, M(_SC_LEVEL2_CACHE_SIZE),  2097152 },
Packit Service 4f62bc
    { 0x86,  4, 64, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 4f62bc
    { 0x87,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),  1048576 },
Packit Service 4f62bc
    { 0xd0,  4, 64, M(_SC_LEVEL3_CACHE_SIZE),   524288 },
Packit Service 4f62bc
    { 0xd1,  4, 64, M(_SC_LEVEL3_CACHE_SIZE),  1048576 },
Packit Service 4f62bc
    { 0xd2,  4, 64, M(_SC_LEVEL3_CACHE_SIZE),  2097152 },
Packit Service 4f62bc
    { 0xd6,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  1048576 },
Packit Service 4f62bc
    { 0xd7,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  2097152 },
Packit Service 4f62bc
    { 0xd8,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  4194304 },
Packit Service 4f62bc
    { 0xdc, 12, 64, M(_SC_LEVEL3_CACHE_SIZE),  2097152 },
Packit Service 4f62bc
    { 0xdd, 12, 64, M(_SC_LEVEL3_CACHE_SIZE),  4194304 },
Packit Service 4f62bc
    { 0xde, 12, 64, M(_SC_LEVEL3_CACHE_SIZE),  8388608 },
Packit Service 4f62bc
    { 0xe2, 16, 64, M(_SC_LEVEL3_CACHE_SIZE),  2097152 },
Packit Service 4f62bc
    { 0xe3, 16, 64, M(_SC_LEVEL3_CACHE_SIZE),  4194304 },
Packit Service 4f62bc
    { 0xe4, 16, 64, M(_SC_LEVEL3_CACHE_SIZE),  8388608 },
Packit Service 4f62bc
    { 0xea, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 12582912 },
Packit Service 4f62bc
    { 0xeb, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 18874368 },
Packit Service 4f62bc
    { 0xec, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 25165824 },
Packit Service 4f62bc
  };
Packit Service 4f62bc
Packit Service 4f62bc
#define nintel_02_known (sizeof (intel_02_known) / sizeof (intel_02_known [0]))
Packit Service 4f62bc
Packit Service 4f62bc
static int
Packit Service 4f62bc
intel_02_known_compare (const void *p1, const void *p2)
Packit Service 4f62bc
{
Packit Service 4f62bc
  const struct intel_02_cache_info *i1;
Packit Service 4f62bc
  const struct intel_02_cache_info *i2;
Packit Service 4f62bc
Packit Service 4f62bc
  i1 = (const struct intel_02_cache_info *) p1;
Packit Service 4f62bc
  i2 = (const struct intel_02_cache_info *) p2;
Packit Service 4f62bc
Packit Service 4f62bc
  if (i1->idx == i2->idx)
Packit Service 4f62bc
    return 0;
Packit Service 4f62bc
Packit Service 4f62bc
  return i1->idx < i2->idx ? -1 : 1;
Packit Service 4f62bc
}
Packit Service 4f62bc
Packit Service 4f62bc
Packit Service 4f62bc
static long int
Packit Service 4f62bc
__attribute__ ((noinline))
Packit Service 4f62bc
intel_check_word (int name, unsigned int value, bool *has_level_2,
Packit Service 4f62bc
		  bool *no_level_2_or_3,
Packit Service 4f62bc
		  const struct cpu_features *cpu_features)
Packit Service 4f62bc
{
Packit Service 4f62bc
  if ((value & 0x80000000) != 0)
Packit Service 4f62bc
    /* The register value is reserved.  */
Packit Service 4f62bc
    return 0;
Packit Service 4f62bc
Packit Service 4f62bc
  /* Fold the name.  The _SC_ constants are always in the order SIZE,
Packit Service 4f62bc
     ASSOC, LINESIZE.  */
Packit Service 4f62bc
  int folded_rel_name = (M(name) / 3) * 3;
Packit Service 4f62bc
Packit Service 4f62bc
  while (value != 0)
Packit Service 4f62bc
    {
Packit Service 4f62bc
      unsigned int byte = value & 0xff;
Packit Service 4f62bc
Packit Service 4f62bc
      if (byte == 0x40)
Packit Service 4f62bc
	{
Packit Service 4f62bc
	  *no_level_2_or_3 = true;
Packit Service 4f62bc
Packit Service 4f62bc
	  if (folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))
Packit Service 4f62bc
	    /* No need to look further.  */
Packit Service 4f62bc
	    break;
Packit Service 4f62bc
	}
Packit Service 4f62bc
      else if (byte == 0xff)
Packit Service 4f62bc
	{
Packit Service 4f62bc
	  /* CPUID leaf 0x4 contains all the information.  We need to
Packit Service 4f62bc
	     iterate over it.  */
Packit Service 4f62bc
	  unsigned int eax;
Packit Service 4f62bc
	  unsigned int ebx;
Packit Service 4f62bc
	  unsigned int ecx;
Packit Service 4f62bc
	  unsigned int edx;
Packit Service 4f62bc
Packit Service 4f62bc
	  unsigned int round = 0;
Packit Service 4f62bc
	  while (1)
Packit Service 4f62bc
	    {
Packit Service 4f62bc
	      __cpuid_count (4, round, eax, ebx, ecx, edx);
Packit Service 4f62bc
Packit Service 4f62bc
	      enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f;
Packit Service 4f62bc
	      if (type == null)
Packit Service 4f62bc
		/* That was the end.  */
Packit Service 4f62bc
		break;
Packit Service 4f62bc
Packit Service 4f62bc
	      unsigned int level = (eax >> 5) & 0x7;
Packit Service 4f62bc
Packit Service 4f62bc
	      if ((level == 1 && type == data
Packit Service 4f62bc
		   && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE))
Packit Service 4f62bc
		  || (level == 1 && type == inst
Packit Service 4f62bc
		      && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE))
Packit Service 4f62bc
		  || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE))
Packit Service 4f62bc
		  || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))
Packit Service 4f62bc
		  || (level == 4 && folded_rel_name == M(_SC_LEVEL4_CACHE_SIZE)))
Packit Service 4f62bc
		{
Packit Service 4f62bc
		  unsigned int offset = M(name) - folded_rel_name;
Packit Service 4f62bc
Packit Service 4f62bc
		  if (offset == 0)
Packit Service 4f62bc
		    /* Cache size.  */
Packit Service 4f62bc
		    return (((ebx >> 22) + 1)
Packit Service 4f62bc
			    * (((ebx >> 12) & 0x3ff) + 1)
Packit Service 4f62bc
			    * ((ebx & 0xfff) + 1)
Packit Service 4f62bc
			    * (ecx + 1));
Packit Service 4f62bc
		  if (offset == 1)
Packit Service 4f62bc
		    return (ebx >> 22) + 1;
Packit Service 4f62bc
Packit Service 4f62bc
		  assert (offset == 2);
Packit Service 4f62bc
		  return (ebx & 0xfff) + 1;
Packit Service 4f62bc
		}
Packit Service 4f62bc
Packit Service 4f62bc
	      ++round;
Packit Service 4f62bc
	    }
Packit Service 4f62bc
	  /* There is no other cache information anywhere else.  */
Packit Service 4f62bc
	  break;
Packit Service 4f62bc
	}
Packit Service 4f62bc
      else
Packit Service 4f62bc
	{
Packit Service 4f62bc
	  if (byte == 0x49 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))
Packit Service 4f62bc
	    {
Packit Service 4f62bc
	      /* Intel reused this value.  For family 15, model 6 it
Packit Service 4f62bc
		 specifies the 3rd level cache.  Otherwise the 2nd
Packit Service 4f62bc
		 level cache.  */
Packit Service 4f62bc
	      unsigned int family = cpu_features->basic.family;
Packit Service 4f62bc
	      unsigned int model = cpu_features->basic.model;
Packit Service 4f62bc
Packit Service 4f62bc
	      if (family == 15 && model == 6)
Packit Service 4f62bc
		{
Packit Service 4f62bc
		  /* The level 3 cache is encoded for this model like
Packit Service 4f62bc
		     the level 2 cache is for other models.  Pretend
Packit Service 4f62bc
		     the caller asked for the level 2 cache.  */
Packit Service 4f62bc
		  name = (_SC_LEVEL2_CACHE_SIZE
Packit Service 4f62bc
			  + (name - _SC_LEVEL3_CACHE_SIZE));
Packit Service 4f62bc
		  folded_rel_name = M(_SC_LEVEL2_CACHE_SIZE);
Packit Service 4f62bc
		}
Packit Service 4f62bc
	    }
Packit Service 4f62bc
Packit Service 4f62bc
	  struct intel_02_cache_info *found;
Packit Service 4f62bc
	  struct intel_02_cache_info search;
Packit Service 4f62bc
Packit Service 4f62bc
	  search.idx = byte;
Packit Service 4f62bc
	  found = bsearch (&search, intel_02_known, nintel_02_known,
Packit Service 4f62bc
			   sizeof (intel_02_known[0]), intel_02_known_compare);
Packit Service 4f62bc
	  if (found != NULL)
Packit Service 4f62bc
	    {
Packit Service 4f62bc
	      if (found->rel_name == folded_rel_name)
Packit Service 4f62bc
		{
Packit Service 4f62bc
		  unsigned int offset = M(name) - folded_rel_name;
Packit Service 4f62bc
Packit Service 4f62bc
		  if (offset == 0)
Packit Service 4f62bc
		    /* Cache size.  */
Packit Service 4f62bc
		    return found->size;
Packit Service 4f62bc
		  if (offset == 1)
Packit Service 4f62bc
		    return found->assoc;
Packit Service 4f62bc
Packit Service 4f62bc
		  assert (offset == 2);
Packit Service 4f62bc
		  return found->linesize;
Packit Service 4f62bc
		}
Packit Service 4f62bc
Packit Service 4f62bc
	      if (found->rel_name == M(_SC_LEVEL2_CACHE_SIZE))
Packit Service 4f62bc
		*has_level_2 = true;
Packit Service 4f62bc
	    }
Packit Service 4f62bc
	}
Packit Service 4f62bc
Packit Service 4f62bc
      /* Next byte for the next round.  */
Packit Service 4f62bc
      value >>= 8;
Packit Service 4f62bc
    }
Packit Service 4f62bc
Packit Service 4f62bc
  /* Nothing found.  */
Packit Service 4f62bc
  return 0;
Packit Service 4f62bc
}
Packit Service 4f62bc
Packit Service 4f62bc
Packit Service 4f62bc
static long int __attribute__ ((noinline))
Packit Service 4f62bc
handle_intel (int name, const struct cpu_features *cpu_features)
Packit Service 4f62bc
{
Packit Service 4f62bc
  unsigned int maxidx = cpu_features->basic.max_cpuid;
Packit Service 4f62bc
Packit Service 4f62bc
  /* Return -1 for older CPUs.  */
Packit Service 4f62bc
  if (maxidx < 2)
Packit Service 4f62bc
    return -1;
Packit Service 4f62bc
Packit Service 4f62bc
  /* OK, we can use the CPUID instruction to get all info about the
Packit Service 4f62bc
     caches.  */
Packit Service 4f62bc
  unsigned int cnt = 0;
Packit Service 4f62bc
  unsigned int max = 1;
Packit Service 4f62bc
  long int result = 0;
Packit Service 4f62bc
  bool no_level_2_or_3 = false;
Packit Service 4f62bc
  bool has_level_2 = false;
Packit Service 4f62bc
Packit Service 4f62bc
  while (cnt++ < max)
Packit Service 4f62bc
    {
Packit Service 4f62bc
      unsigned int eax;
Packit Service 4f62bc
      unsigned int ebx;
Packit Service 4f62bc
      unsigned int ecx;
Packit Service 4f62bc
      unsigned int edx;
Packit Service 4f62bc
      __cpuid (2, eax, ebx, ecx, edx);
Packit Service 4f62bc
Packit Service 4f62bc
      /* The low byte of EAX in the first round contain the number of
Packit Service 4f62bc
	 rounds we have to make.  At least one, the one we are already
Packit Service 4f62bc
	 doing.  */
Packit Service 4f62bc
      if (cnt == 1)
Packit Service 4f62bc
	{
Packit Service 4f62bc
	  max = eax & 0xff;
Packit Service 4f62bc
	  eax &= 0xffffff00;
Packit Service 4f62bc
	}
Packit Service 4f62bc
Packit Service 4f62bc
      /* Process the individual registers' value.  */
Packit Service 4f62bc
      result = intel_check_word (name, eax, &has_level_2,
Packit Service 4f62bc
				 &no_level_2_or_3, cpu_features);
Packit Service 4f62bc
      if (result != 0)
Packit Service 4f62bc
	return result;
Packit Service 4f62bc
Packit Service 4f62bc
      result = intel_check_word (name, ebx, &has_level_2,
Packit Service 4f62bc
				 &no_level_2_or_3, cpu_features);
Packit Service 4f62bc
      if (result != 0)
Packit Service 4f62bc
	return result;
Packit Service 4f62bc
Packit Service 4f62bc
      result = intel_check_word (name, ecx, &has_level_2,
Packit Service 4f62bc
				 &no_level_2_or_3, cpu_features);
Packit Service 4f62bc
      if (result != 0)
Packit Service 4f62bc
	return result;
Packit Service 4f62bc
Packit Service 4f62bc
      result = intel_check_word (name, edx, &has_level_2,
Packit Service 4f62bc
				 &no_level_2_or_3, cpu_features);
Packit Service 4f62bc
      if (result != 0)
Packit Service 4f62bc
	return result;
Packit Service 4f62bc
    }
Packit Service 4f62bc
Packit Service 4f62bc
  if (name >= _SC_LEVEL2_CACHE_SIZE && name <= _SC_LEVEL3_CACHE_LINESIZE
Packit Service 4f62bc
      && no_level_2_or_3)
Packit Service 4f62bc
    return -1;
Packit Service 4f62bc
Packit Service 4f62bc
  return 0;
Packit Service 4f62bc
}
Packit Service 4f62bc
Packit Service 4f62bc
Packit Service 4f62bc
static long int __attribute__ ((noinline))
Packit Service 4f62bc
handle_amd (int name)
Packit Service 4f62bc
{
Packit Service 4f62bc
  unsigned int eax;
Packit Service 4f62bc
  unsigned int ebx;
Packit Service 4f62bc
  unsigned int ecx;
Packit Service 4f62bc
  unsigned int edx;
Packit Service 4f62bc
  __cpuid (0x80000000, eax, ebx, ecx, edx);
Packit Service 4f62bc
Packit Service 4f62bc
  /* No level 4 cache (yet).  */
Packit Service 4f62bc
  if (name > _SC_LEVEL3_CACHE_LINESIZE)
Packit Service 4f62bc
    return 0;
Packit Service 4f62bc
Packit Service 4f62bc
  unsigned int fn = 0x80000005 + (name >= _SC_LEVEL2_CACHE_SIZE);
Packit Service 4f62bc
  if (eax < fn)
Packit Service 4f62bc
    return 0;
Packit Service 4f62bc
Packit Service 4f62bc
  __cpuid (fn, eax, ebx, ecx, edx);
Packit Service 4f62bc
Packit Service 4f62bc
  if (name < _SC_LEVEL1_DCACHE_SIZE)
Packit Service 4f62bc
    {
Packit Service 4f62bc
      name += _SC_LEVEL1_DCACHE_SIZE - _SC_LEVEL1_ICACHE_SIZE;
Packit Service 4f62bc
      ecx = edx;
Packit Service 4f62bc
    }
Packit Service 4f62bc
Packit Service 4f62bc
  switch (name)
Packit Service 4f62bc
    {
Packit Service 4f62bc
    case _SC_LEVEL1_DCACHE_SIZE:
Packit Service 4f62bc
      return (ecx >> 14) & 0x3fc00;
Packit Service 4f62bc
Packit Service 4f62bc
    case _SC_LEVEL1_DCACHE_ASSOC:
Packit Service 4f62bc
      ecx >>= 16;
Packit Service 4f62bc
      if ((ecx & 0xff) == 0xff)
Packit Service 4f62bc
	/* Fully associative.  */
Packit Service 4f62bc
	return (ecx << 2) & 0x3fc00;
Packit Service 4f62bc
      return ecx & 0xff;
Packit Service 4f62bc
Packit Service 4f62bc
    case _SC_LEVEL1_DCACHE_LINESIZE:
Packit Service 4f62bc
      return ecx & 0xff;
Packit Service 4f62bc
Packit Service 4f62bc
    case _SC_LEVEL2_CACHE_SIZE:
Packit Service 4f62bc
      return (ecx & 0xf000) == 0 ? 0 : (ecx >> 6) & 0x3fffc00;
Packit Service 4f62bc
Packit Service 4f62bc
    case _SC_LEVEL2_CACHE_ASSOC:
Packit Service 4f62bc
      switch ((ecx >> 12) & 0xf)
Packit Service 4f62bc
	{
Packit Service 4f62bc
	case 0:
Packit Service 4f62bc
	case 1:
Packit Service 4f62bc
	case 2:
Packit Service 4f62bc
	case 4:
Packit Service 4f62bc
	  return (ecx >> 12) & 0xf;
Packit Service 4f62bc
	case 6:
Packit Service 4f62bc
	  return 8;
Packit Service 4f62bc
	case 8:
Packit Service 4f62bc
	  return 16;
Packit Service 4f62bc
	case 10:
Packit Service 4f62bc
	  return 32;
Packit Service 4f62bc
	case 11:
Packit Service 4f62bc
	  return 48;
Packit Service 4f62bc
	case 12:
Packit Service 4f62bc
	  return 64;
Packit Service 4f62bc
	case 13:
Packit Service 4f62bc
	  return 96;
Packit Service 4f62bc
	case 14:
Packit Service 4f62bc
	  return 128;
Packit Service 4f62bc
	case 15:
Packit Service 4f62bc
	  return ((ecx >> 6) & 0x3fffc00) / (ecx & 0xff);
Packit Service 4f62bc
	default:
Packit Service 4f62bc
	  return 0;
Packit Service 4f62bc
	}
Packit Service 4f62bc
      /* NOTREACHED */
Packit Service 4f62bc
Packit Service 4f62bc
    case _SC_LEVEL2_CACHE_LINESIZE:
Packit Service 4f62bc
      return (ecx & 0xf000) == 0 ? 0 : ecx & 0xff;
Packit Service 4f62bc
Packit Service 4f62bc
    case _SC_LEVEL3_CACHE_SIZE:
Packit Service 4f62bc
      return (edx & 0xf000) == 0 ? 0 : (edx & 0x3ffc0000) << 1;
Packit Service 4f62bc
Packit Service 4f62bc
    case _SC_LEVEL3_CACHE_ASSOC:
Packit Service 4f62bc
      switch ((edx >> 12) & 0xf)
Packit Service 4f62bc
	{
Packit Service 4f62bc
	case 0:
Packit Service 4f62bc
	case 1:
Packit Service 4f62bc
	case 2:
Packit Service 4f62bc
	case 4:
Packit Service 4f62bc
	  return (edx >> 12) & 0xf;
Packit Service 4f62bc
	case 6:
Packit Service 4f62bc
	  return 8;
Packit Service 4f62bc
	case 8:
Packit Service 4f62bc
	  return 16;
Packit Service 4f62bc
	case 10:
Packit Service 4f62bc
	  return 32;
Packit Service 4f62bc
	case 11:
Packit Service 4f62bc
	  return 48;
Packit Service 4f62bc
	case 12:
Packit Service 4f62bc
	  return 64;
Packit Service 4f62bc
	case 13:
Packit Service 4f62bc
	  return 96;
Packit Service 4f62bc
	case 14:
Packit Service 4f62bc
	  return 128;
Packit Service 4f62bc
	case 15:
Packit Service 4f62bc
	  return ((edx & 0x3ffc0000) << 1) / (edx & 0xff);
Packit Service 4f62bc
	default:
Packit Service 4f62bc
	  return 0;
Packit Service 4f62bc
	}
Packit Service 4f62bc
      /* NOTREACHED */
Packit Service 4f62bc
Packit Service 4f62bc
    case _SC_LEVEL3_CACHE_LINESIZE:
Packit Service 4f62bc
      return (edx & 0xf000) == 0 ? 0 : edx & 0xff;
Packit Service 4f62bc
Packit Service 4f62bc
    default:
Packit Service 4f62bc
      assert (! "cannot happen");
Packit Service 4f62bc
    }
Packit Service 4f62bc
  return -1;
Packit Service 4f62bc
}
Packit Service 4f62bc
Packit Service 4f62bc
Packit Service 4f62bc
static long int __attribute__ ((noinline))
Packit Service 4f62bc
handle_zhaoxin (int name)
Packit Service 4f62bc
{
Packit Service 4f62bc
  unsigned int eax;
Packit Service 4f62bc
  unsigned int ebx;
Packit Service 4f62bc
  unsigned int ecx;
Packit Service 4f62bc
  unsigned int edx;
Packit Service 4f62bc
Packit Service 4f62bc
  int folded_rel_name = (M(name) / 3) * 3;
Packit Service 4f62bc
Packit Service 4f62bc
  unsigned int round = 0;
Packit Service 4f62bc
  while (1)
Packit Service 4f62bc
    {
Packit Service 4f62bc
      __cpuid_count (4, round, eax, ebx, ecx, edx);
Packit Service 4f62bc
Packit Service 4f62bc
      enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f;
Packit Service 4f62bc
      if (type == null)
Packit Service 4f62bc
        break;
Packit Service 4f62bc
Packit Service 4f62bc
      unsigned int level = (eax >> 5) & 0x7;
Packit Service 4f62bc
Packit Service 4f62bc
      if ((level == 1 && type == data
Packit Service 4f62bc
        && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE))
Packit Service 4f62bc
        || (level == 1 && type == inst
Packit Service 4f62bc
            && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE))
Packit Service 4f62bc
        || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE))
Packit Service 4f62bc
        || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)))
Packit Service 4f62bc
        {
Packit Service 4f62bc
          unsigned int offset = M(name) - folded_rel_name;
Packit Service 4f62bc
Packit Service 4f62bc
          if (offset == 0)
Packit Service 4f62bc
            /* Cache size.  */
Packit Service 4f62bc
            return (((ebx >> 22) + 1)
Packit Service 4f62bc
                * (((ebx >> 12) & 0x3ff) + 1)
Packit Service 4f62bc
                * ((ebx & 0xfff) + 1)
Packit Service 4f62bc
                * (ecx + 1));
Packit Service 4f62bc
          if (offset == 1)
Packit Service 4f62bc
            return (ebx >> 22) + 1;
Packit Service 4f62bc
Packit Service 4f62bc
          assert (offset == 2);
Packit Service 4f62bc
          return (ebx & 0xfff) + 1;
Packit Service 4f62bc
        }
Packit Service 4f62bc
Packit Service 4f62bc
      ++round;
Packit Service 4f62bc
    }
Packit Service 4f62bc
Packit Service 4f62bc
  /* Nothing found.  */
Packit Service 4f62bc
  return 0;
Packit Service 4f62bc
}