[PATCH v2 1/1] x86: Fix for cache computation on Hygon under hypervisors

Jiamei Xie xiejiamei@hygon.cn
Wed Feb 4 02:03:44 GMT 2026


Hi

Just a gentle ping on this patch. It has already received a Reviewed-by,
but hasn’t been merged into master yet.

I’ve checked and it applies cleanly on current master.
Please let me know if anything else is needed from my side.

Best regards,
Jiamei

> -----Original Message-----
> From: H.J. Lu <hjl.tools@gmail.com>
> Sent: 2026年1月24日 7:59
> To: Jiamei Xie <xiejiamei@hygon.cn>
> Cc: libc-alpha@sourceware.org; Jing Li <lijing@hygon.cn>
> Subject: Re: [PATCH v2 1/1] x86: Fix for cache computation on Hygon under
> hypervisors
> 
> On Fri, Jan 16, 2026 at 3:46 PM Jiamei Xie <xiejiamei@hygon.cn> wrote:
> >
> > On Hygon CPUs, glibc currently relies on CPUID leaf 0x8000001D to
> > compute cache parameters. This works correctly on bare-metal systems.
> > However, under some hypervisors (e.g. QEMU with -cpu qemu64), the
> > maximum supported extended CPUID leaf is only 0x8000000A, and CPUID
> > 0x8000001D is not exposed. In this case, cache information computed
> > via 0x8000001D is zeroed out.
> >
> > This patch introduces legacy fallback of cache computation based on
> > CPUID 0x80000005 and 0x80000006, consistent with the AMD
> > implementation, to restore correct cache information under such
> > environments.
> >
> > Signed-off-by: Jiamei Xie <xiejiamei@hygon.cn>
> > ---
> >  sysdeps/x86/dl-cacheinfo.h | 201
> > +++++++++++++++++++++++++++++++++----
> >  1 file changed, 179 insertions(+), 22 deletions(-)
> >
> > diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h
> > index b6520bddaa..d2d4301bc7 100644
> > --- a/sysdeps/x86/dl-cacheinfo.h
> > +++ b/sysdeps/x86/dl-cacheinfo.h
> > @@ -585,35 +585,192 @@ handle_hygon (int name)
> >    unsigned int ebx;
> >    unsigned int ecx;
> >    unsigned int edx;
> > -  unsigned int count = 0x1;
> > +  unsigned int max_cpuid = 0;
> > +
> > +  /* No level 4 cache (yet).  */
> > +  if (name > _SC_LEVEL3_CACHE_LINESIZE)
> > +    return 0;
> > +
> > +  __cpuid (0x80000000, max_cpuid, ebx, ecx, edx);
> > +
> > +  if (max_cpuid >= 0x8000001D)
> > +    /* Use __cpuid__ '0x8000_001D' to compute cache details.  */
> > +    {
> > +      unsigned int count = 0x1;
> >
> > -  if (name >= _SC_LEVEL3_CACHE_SIZE)
> > -    count = 0x3;
> > -  else if (name >= _SC_LEVEL2_CACHE_SIZE)
> > -    count = 0x2;
> > -  else if (name >= _SC_LEVEL1_DCACHE_SIZE)
> > -    count = 0x0;
> > +      if (name >= _SC_LEVEL3_CACHE_SIZE)
> > +        count = 0x3;
> > +      else if (name >= _SC_LEVEL2_CACHE_SIZE)
> > +        count = 0x2;
> > +      else if (name >= _SC_LEVEL1_DCACHE_SIZE)
> > +        count = 0x0;
> > +
> > +      __cpuid_count (0x8000001D, count, eax, ebx, ecx, edx);
> >
> > -  /* Use __cpuid__ '0x8000_001D' to compute cache details.  */
> > -  __cpuid_count (0x8000001D, count, eax, ebx, ecx, edx);
> > +      if (ecx != 0)
> > +        {
> > +          switch (name)
> > +            {
> > +            case _SC_LEVEL1_ICACHE_ASSOC:
> > +            case _SC_LEVEL1_DCACHE_ASSOC:
> > +            case _SC_LEVEL2_CACHE_ASSOC:
> > +            case _SC_LEVEL3_CACHE_ASSOC:
> > +              return ((ebx >> 22) & 0x3ff) + 1;
> > +            case _SC_LEVEL1_ICACHE_LINESIZE:
> > +            case _SC_LEVEL1_DCACHE_LINESIZE:
> > +            case _SC_LEVEL2_CACHE_LINESIZE:
> > +            case _SC_LEVEL3_CACHE_LINESIZE:
> > +              return (ebx & 0xfff) + 1;
> > +            case _SC_LEVEL1_ICACHE_SIZE:
> > +            case _SC_LEVEL1_DCACHE_SIZE:
> > +            case _SC_LEVEL2_CACHE_SIZE:
> > +            case _SC_LEVEL3_CACHE_SIZE:
> > +              return (((ebx >> 22) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx
> + 1);
> > +            default:
> > +              __builtin_unreachable ();
> > +            }
> > +          return -1;
> > +       }
> > +    }
> > +
> > +  /* Legacy cache computation for some hypervisors that
> > +     accidentally configure __cpuid__ '0x8000_001D' to Zero.  */
> > +
> > +  unsigned int fn = 0x80000005 + (name >= _SC_LEVEL2_CACHE_SIZE);
> > +
> > +  if (max_cpuid < fn)
> > +    return 0;
> > +
> > +  __cpuid (fn, eax, ebx, ecx, edx);
> > +
> > +  if (name < _SC_LEVEL1_DCACHE_SIZE)
> > +    {
> > +      name += _SC_LEVEL1_DCACHE_SIZE - _SC_LEVEL1_ICACHE_SIZE;
> > +      ecx = edx;
> > +    }
> >
> >    switch (name)
> >      {
> > -    case _SC_LEVEL1_ICACHE_ASSOC:
> > -    case _SC_LEVEL1_DCACHE_ASSOC:
> > -    case _SC_LEVEL2_CACHE_ASSOC:
> > +      case _SC_LEVEL1_DCACHE_SIZE:
> > +        return (ecx >> 14) & 0x3fc00;
> > +
> > +      case _SC_LEVEL1_DCACHE_ASSOC:
> > +        ecx >>= 16;
> > +        if ((ecx & 0xff) == 0xff)
> > +        {
> > +          /* Fully associative.  */
> > +          return (ecx << 2) & 0x3fc00;
> > +        }
> > +        return ecx & 0xff;
> > +
> > +      case _SC_LEVEL1_DCACHE_LINESIZE:
> > +        return ecx & 0xff;
> > +
> > +      case _SC_LEVEL2_CACHE_SIZE:
> > +        return (ecx & 0xf000) == 0 ? 0 : (ecx >> 6) & 0x3fffc00;
> > +
> > +      case _SC_LEVEL2_CACHE_ASSOC:
> > +        switch ((ecx >> 12) & 0xf)
> > +          {
> > +            case 0:
> > +            case 1:
> > +            case 2:
> > +            case 4:
> > +              return (ecx >> 12) & 0xf;
> > +            case 6:
> > +              return 8;
> > +            case 8:
> > +              return 16;
> > +            case 10:
> > +              return 32;
> > +            case 11:
> > +              return 48;
> > +            case 12:
> > +              return 64;
> > +            case 13:
> > +              return 96;
> > +            case 14:
> > +              return 128;
> > +            case 15:
> > +              return ((ecx >> 6) & 0x3fffc00) / (ecx & 0xff);
> > +            default:
> > +              return 0;
> > +          }
> > +
> > +      case _SC_LEVEL2_CACHE_LINESIZE:
> > +        return (ecx & 0xf000) == 0 ? 0 : ecx & 0xff;
> > +
> > +      case _SC_LEVEL3_CACHE_SIZE:
> > +        {
> > +        long int total_l3_cache = 0, l3_cache_per_thread = 0;
> > +        unsigned int threads = 0;
> > +
> > +        if ((edx & 0xf000) == 0)
> > +          return 0;
> > +
> > +        total_l3_cache = (edx & 0x3ffc0000) << 1;
> > +
> > +        /* Figure out the number of logical threads that share L3.  */
> > +        if (max_cpuid >= 0x80000008)
> > +          {
> > +            /* Get width of APIC ID.  */
> > +            __cpuid (0x80000008, eax, ebx, ecx, edx);
> > +            threads = (ecx & 0xff) + 1;
> > +          }
> > +
> > +        if (threads == 0)
> > +          {
> > +            /* If APIC ID width is not available, use logical
> > +            processor count.  */
> > +            __cpuid (0x00000001, eax, ebx, ecx, edx);
> > +            if ((edx & (1 << 28)) != 0)
> > +              threads = (ebx >> 16) & 0xff;
> > +          }
> > +
> > +        /* Cap usage of highest cache level to the number of
> > +           supported threads.  */
> > +        if (threads > 0)
> > +          l3_cache_per_thread = total_l3_cache/threads;
> > +
> > +        /* Get shared cache per ccx.  */
> > +            /* Get number of threads share the L3 cache in CCX.  */
> > +            __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx);
> > +            unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1;
> > +            long int l3_cache_per_ccx = l3_cache_per_thread *
> threads_per_ccx;
> > +            return l3_cache_per_ccx;
> > +      }
> > +
> >      case _SC_LEVEL3_CACHE_ASSOC:
> > -      return ((ebx >> 22) & 0x3ff) + 1;
> > -    case _SC_LEVEL1_ICACHE_LINESIZE:
> > -    case _SC_LEVEL1_DCACHE_LINESIZE:
> > -    case _SC_LEVEL2_CACHE_LINESIZE:
> > +      switch ((edx >> 12) & 0xf)
> > +      {
> > +        case 0:
> > +        case 1:
> > +        case 2:
> > +        case 4:
> > +          return (edx >> 12) & 0xf;
> > +        case 6:
> > +          return 8;
> > +        case 8:
> > +          return 16;
> > +        case 10:
> > +          return 32;
> > +        case 11:
> > +          return 48;
> > +        case 12:
> > +          return 64;
> > +        case 13:
> > +          return 96;
> > +        case 14:
> > +          return 128;
> > +        case 15:
> > +          return ((edx & 0x3ffc0000) << 1) / (edx & 0xff);
> > +        default:
> > +          return 0;
> > +      }
> > +
> >      case _SC_LEVEL3_CACHE_LINESIZE:
> > -      return (ebx & 0xfff) + 1;
> > -    case _SC_LEVEL1_ICACHE_SIZE:
> > -    case _SC_LEVEL1_DCACHE_SIZE:
> > -    case _SC_LEVEL2_CACHE_SIZE:
> > -    case _SC_LEVEL3_CACHE_SIZE:
> > -      return (((ebx >> 22) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1);
> > +      return (edx & 0xf000) == 0 ? 0 : edx & 0xff;
> > +
> >      default:
> >        __builtin_unreachable ();
> >      }
> > --
> > 2.43.0
> >
> >
> 
> LGTM.
> 
> Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
> 
> Thanks.
> 
> --
> H.J.



More information about the Libc-alpha mailing list