mirror of
https://github.com/yuzu-emu/unicorn
synced 2024-11-25 17:45:29 +00:00
433bdcff34
Nobody has mentioned AIX host support on the mailing list for years, and we have no test systems for it so it is most likely broken. We've advertised in configure for two releases now that we plan to drop support for this host OS, and have had no complaints. Drop the AIX host support code. We can also drop the now-unused AIX version of sys_cache_info(). Note that the _CALL_AIX define used in the PPC tcg backend is also used for Linux PPC64, and so that code should not be removed. Backports commit 7872375219c03682bda3f6191fa5f6a58238ed36 from qemu
176 lines
4.5 KiB
C
176 lines
4.5 KiB
C
/*
|
|
* cacheinfo.c - helpers to query the host about its caches
|
|
*
|
|
* Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
|
|
* License: GNU GPL, version 2 or later.
|
|
* See the COPYING file in the top-level directory.
|
|
*/
|
|
|
|
#include "uc_priv.h"
|
|
#include "qemu/osdep.h"
|
|
|
|
/*
|
|
* Operating system specific detection mechanisms.
|
|
*/
|
|
|
|
#if defined(_WIN32)
|
|
|
|
static void sys_cache_info(int *isize, int *dsize)
|
|
{
|
|
SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buf;
|
|
DWORD size = 0;
|
|
BOOL success;
|
|
size_t i, n;
|
|
|
|
/* Check for the required buffer size first. Note that if the zero
|
|
size we use for the probe results in success, then there is no
|
|
data available; fail in that case. */
|
|
success = GetLogicalProcessorInformation(0, &size);
|
|
if (success || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
return;
|
|
}
|
|
|
|
n = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
|
|
size = n * sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
|
|
buf = g_new0(SYSTEM_LOGICAL_PROCESSOR_INFORMATION, n);
|
|
if (!GetLogicalProcessorInformation(buf, &size)) {
|
|
goto fail;
|
|
}
|
|
|
|
for (i = 0; i < n; i++) {
|
|
if (buf[i].Relationship == RelationCache
|
|
&& buf[i].Cache.Level == 1) {
|
|
switch (buf[i].Cache.Type) {
|
|
case CacheUnified:
|
|
*isize = *dsize = buf[i].Cache.LineSize;
|
|
break;
|
|
case CacheInstruction:
|
|
*isize = buf[i].Cache.LineSize;
|
|
break;
|
|
case CacheData:
|
|
*dsize = buf[i].Cache.LineSize;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
fail:
|
|
g_free(buf);
|
|
}
|
|
|
|
#elif defined(__APPLE__) \
|
|
|| defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
|
# include <sys/sysctl.h>
|
|
# if defined(__APPLE__)
|
|
# define SYSCTL_CACHELINE_NAME "hw.cachelinesize"
|
|
# else
|
|
# define SYSCTL_CACHELINE_NAME "machdep.cacheline_size"
|
|
# endif
|
|
|
|
static void sys_cache_info(int *isize, int *dsize)
|
|
{
|
|
/* There's only a single sysctl for both I/D cache line sizes. */
|
|
long size;
|
|
size_t len = sizeof(size);
|
|
if (!sysctlbyname(SYSCTL_CACHELINE_NAME, &size, &len, NULL, 0)) {
|
|
*isize = *dsize = size;
|
|
}
|
|
}
|
|
|
|
#else
|
|
/* POSIX */
|
|
|
|
static void sys_cache_info(int *isize, int *dsize)
|
|
{
|
|
# ifdef _SC_LEVEL1_ICACHE_LINESIZE
|
|
*isize = sysconf(_SC_LEVEL1_ICACHE_LINESIZE);
|
|
# endif
|
|
# ifdef _SC_LEVEL1_DCACHE_LINESIZE
|
|
*dsize = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
|
|
# endif
|
|
}
|
|
#endif /* sys_cache_info */
|
|
|
|
/*
|
|
* Architecture (+ OS) specific detection mechanisms.
|
|
*/
|
|
|
|
#if defined(__aarch64__)
|
|
|
|
static void arch_cache_info(int *isize, int *dsize)
|
|
{
|
|
if (*isize == 0 || *dsize == 0) {
|
|
unsigned long ctr;
|
|
|
|
/* The real cache geometry is in CCSIDR_EL1/CLIDR_EL1/CSSELR_EL1,
|
|
but (at least under Linux) these are marked protected by the
|
|
kernel. However, CTR_EL0 contains the minimum linesize in the
|
|
entire hierarchy, and is used by userspace cache flushing. */
|
|
asm volatile("mrs\t%0, ctr_el0" : "=r"(ctr));
|
|
if (*isize == 0) {
|
|
*isize = 4 << (ctr & 0xf);
|
|
}
|
|
if (*dsize == 0) {
|
|
*dsize = 4 << ((ctr >> 16) & 0xf);
|
|
}
|
|
}
|
|
}
|
|
|
|
#elif defined(_ARCH_PPC) && defined(__linux__)
|
|
# include "elf.h"
|
|
|
|
static void arch_cache_info(int *isize, int *dsize)
|
|
{
|
|
if (*isize == 0) {
|
|
*isize = qemu_getauxval(AT_ICACHEBSIZE);
|
|
}
|
|
if (*dsize == 0) {
|
|
*dsize = qemu_getauxval(AT_DCACHEBSIZE);
|
|
}
|
|
}
|
|
|
|
#else
|
|
static void arch_cache_info(int *isize, int *dsize) { }
|
|
#endif /* arch_cache_info */
|
|
|
|
/*
|
|
* ... and if all else fails ...
|
|
*/
|
|
|
|
static void fallback_cache_info(int *isize, int *dsize)
|
|
{
|
|
/* If we can only find one of the two, assume they're the same. */
|
|
if (*isize) {
|
|
if (*dsize) {
|
|
/* Success! */
|
|
} else {
|
|
*dsize = *isize;
|
|
}
|
|
} else if (*dsize) {
|
|
*isize = *dsize;
|
|
} else {
|
|
#if defined(_ARCH_PPC)
|
|
/* For PPC, we're going to use the icache size computed for
|
|
flush_icache_range. Which means that we must use the
|
|
architecture minimum. */
|
|
*isize = *dsize = 16;
|
|
#else
|
|
/* Otherwise, 64 bytes is not uncommon. */
|
|
*isize = *dsize = 64;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Unicorn: made externally linked so it can be called directly
|
|
void init_cache_info(struct uc_struct *uc)
|
|
{
|
|
int isize = 0, dsize = 0;
|
|
|
|
sys_cache_info(&isize, &dsize);
|
|
arch_cache_info(&isize, &dsize);
|
|
fallback_cache_info(&isize, &dsize);
|
|
|
|
uc->qemu_icache_linesize = isize;
|
|
uc->qemu_dcache_linesize = dsize;
|
|
}
|