qemu/util/cacheinfo.c
<<
>>
Prefs
   1/*
   2 * cacheinfo.c - helpers to query the host about its caches
   3 *
   4 * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
   5 * License: GNU GPL, version 2 or later.
   6 *   See the COPYING file in the top-level directory.
   7 */
   8
   9#include "qemu/osdep.h"
  10
  11int qemu_icache_linesize = 0;
  12int qemu_dcache_linesize = 0;
  13
  14/*
  15 * Operating system specific detection mechanisms.
  16 */
  17
  18#if defined(_AIX)
  19# include <sys/systemcfg.h>
  20
  21static void sys_cache_info(int *isize, int *dsize)
  22{
  23    *isize = _system_configuration.icache_line;
  24    *dsize = _system_configuration.dcache_line;
  25}
  26
  27#elif defined(_WIN32)
  28
  29static void sys_cache_info(int *isize, int *dsize)
  30{
  31    SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buf;
  32    DWORD size = 0;
  33    BOOL success;
  34    size_t i, n;
  35
  36    /* Check for the required buffer size first.  Note that if the zero
  37       size we use for the probe results in success, then there is no
  38       data available; fail in that case.  */
  39    success = GetLogicalProcessorInformation(0, &size);
  40    if (success || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  41        return;
  42    }
  43
  44    n = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  45    size = n * sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  46    buf = g_new0(SYSTEM_LOGICAL_PROCESSOR_INFORMATION, n);
  47    if (!GetLogicalProcessorInformation(buf, &size)) {
  48        goto fail;
  49    }
  50
  51    for (i = 0; i < n; i++) {
  52        if (buf[i].Relationship == RelationCache
  53            && buf[i].Cache.Level == 1) {
  54            switch (buf[i].Cache.Type) {
  55            case CacheUnified:
  56                *isize = *dsize = buf[i].Cache.LineSize;
  57                break;
  58            case CacheInstruction:
  59                *isize = buf[i].Cache.LineSize;
  60                break;
  61            case CacheData:
  62                *dsize = buf[i].Cache.LineSize;
  63                break;
  64            default:
  65                break;
  66            }
  67        }
  68    }
  69 fail:
  70    g_free(buf);
  71}
  72
  73#elif defined(__APPLE__) \
  74      || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  75# include <sys/sysctl.h>
  76# if defined(__APPLE__)
  77#  define SYSCTL_CACHELINE_NAME "hw.cachelinesize"
  78# else
  79#  define SYSCTL_CACHELINE_NAME "machdep.cacheline_size"
  80# endif
  81
  82static void sys_cache_info(int *isize, int *dsize)
  83{
  84    /* There's only a single sysctl for both I/D cache line sizes.  */
  85    long size;
  86    size_t len = sizeof(size);
  87    if (!sysctlbyname(SYSCTL_CACHELINE_NAME, &size, &len, NULL, 0)) {
  88        *isize = *dsize = size;
  89    }
  90}
  91
  92#else
  93/* POSIX */
  94
  95static void sys_cache_info(int *isize, int *dsize)
  96{
  97# ifdef _SC_LEVEL1_ICACHE_LINESIZE
  98    *isize = sysconf(_SC_LEVEL1_ICACHE_LINESIZE);
  99# endif
 100# ifdef _SC_LEVEL1_DCACHE_LINESIZE
 101    *dsize = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
 102# endif
 103}
 104#endif /* sys_cache_info */
 105
 106/*
 107 * Architecture (+ OS) specific detection mechanisms.
 108 */
 109
 110#if defined(__aarch64__)
 111
 112static void arch_cache_info(int *isize, int *dsize)
 113{
 114    if (*isize == 0 || *dsize == 0) {
 115        unsigned long ctr;
 116
 117        /* The real cache geometry is in CCSIDR_EL1/CLIDR_EL1/CSSELR_EL1,
 118           but (at least under Linux) these are marked protected by the
 119           kernel.  However, CTR_EL0 contains the minimum linesize in the
 120           entire hierarchy, and is used by userspace cache flushing.  */
 121        asm volatile("mrs\t%0, ctr_el0" : "=r"(ctr));
 122        if (*isize == 0) {
 123            *isize = 4 << (ctr & 0xf);
 124        }
 125        if (*dsize == 0) {
 126            *dsize = 4 << ((ctr >> 16) & 0xf);
 127        }
 128    }
 129}
 130
 131#elif defined(_ARCH_PPC) && defined(__linux__)
 132# include "elf.h"
 133
 134static void arch_cache_info(int *isize, int *dsize)
 135{
 136    if (*isize == 0) {
 137        *isize = qemu_getauxval(AT_ICACHEBSIZE);
 138    }
 139    if (*dsize == 0) {
 140        *dsize = qemu_getauxval(AT_DCACHEBSIZE);
 141    }
 142}
 143
 144#else
 145static void arch_cache_info(int *isize, int *dsize) { }
 146#endif /* arch_cache_info */
 147
 148/*
 149 * ... and if all else fails ...
 150 */
 151
 152static void fallback_cache_info(int *isize, int *dsize)
 153{
 154    /* If we can only find one of the two, assume they're the same.  */
 155    if (*isize) {
 156        if (*dsize) {
 157            /* Success! */
 158        } else {
 159            *dsize = *isize;
 160        }
 161    } else if (*dsize) {
 162        *isize = *dsize;
 163    } else {
 164#if defined(_ARCH_PPC)
 165        /* For PPC, we're going to use the icache size computed for
 166           flush_icache_range.  Which means that we must use the
 167           architecture minimum.  */
 168        *isize = *dsize = 16;
 169#else
 170        /* Otherwise, 64 bytes is not uncommon.  */
 171        *isize = *dsize = 64;
 172#endif
 173    }
 174}
 175
 176static void __attribute__((constructor)) init_cache_info(void)
 177{
 178    int isize = 0, dsize = 0;
 179
 180    sys_cache_info(&isize, &dsize);
 181    arch_cache_info(&isize, &dsize);
 182    fallback_cache_info(&isize, &dsize);
 183
 184    qemu_icache_linesize = isize;
 185    qemu_dcache_linesize = dsize;
 186}
 187