2019-05-28 09:57:18 -07:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
2013-08-06 17:42:36 +10:00
|
|
|
/*
|
|
|
|
* Copyright 2013, Michael Ellerman, IBM Corp.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _SELFTESTS_POWERPC_UTILS_H
|
|
|
|
#define _SELFTESTS_POWERPC_UTILS_H
|
|
|
|
|
2016-05-02 13:51:38 +10:00
|
|
|
#define __cacheline_aligned __attribute__((aligned(128)))
|
|
|
|
|
2013-08-06 17:42:36 +10:00
|
|
|
#include <stdint.h>
|
2023-06-19 17:36:27 +10:00
|
|
|
#include <stdio.h>
|
2013-08-06 17:42:36 +10:00
|
|
|
#include <stdbool.h>
|
2023-06-19 17:36:27 +10:00
|
|
|
#include <sys/signal.h>
|
2015-11-24 13:05:39 +11:00
|
|
|
#include <linux/auxvec.h>
|
2018-05-21 20:43:57 +05:30
|
|
|
#include <linux/perf_event.h>
|
2020-08-19 11:57:22 +10:00
|
|
|
#include <asm/cputable.h>
|
2015-12-23 16:49:50 +11:00
|
|
|
#include "reg.h"
|
2023-06-19 17:36:27 +10:00
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#ifndef ARRAY_SIZE
|
|
|
|
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
|
|
|
#endif
|
2013-08-06 17:42:36 +10:00
|
|
|
|
|
|
|
/* Avoid headaches with PRI?64 - just use %ll? always */
|
|
|
|
typedef unsigned long long u64;
|
|
|
|
typedef signed long long s64;
|
|
|
|
|
|
|
|
/* Just for familiarity */
|
|
|
|
typedef uint32_t u32;
|
2015-02-23 16:14:44 +01:00
|
|
|
typedef uint16_t u16;
|
2013-08-06 17:42:36 +10:00
|
|
|
typedef uint8_t u8;
|
|
|
|
|
2016-09-23 16:18:17 +10:00
|
|
|
void test_harness_set_timeout(uint64_t time);
|
2023-08-17 11:21:53 -05:00
|
|
|
int test_harness(int (test_function)(void), const char *name);
|
2017-02-06 21:13:27 +11:00
|
|
|
|
|
|
|
int read_auxv(char *buf, ssize_t buf_size);
|
|
|
|
void *find_auxv_entry(int type, char *auxv);
|
|
|
|
void *get_auxv_entry(int type);
|
|
|
|
|
2023-04-06 14:33:16 +10:00
|
|
|
#define BIND_CPU_ANY (-1)
|
|
|
|
|
2015-12-16 18:59:31 +11:00
|
|
|
int pick_online_cpu(void);
|
2023-04-06 14:33:15 +10:00
|
|
|
int bind_to_cpu(int cpu);
|
2013-08-06 17:42:36 +10:00
|
|
|
|
2023-02-03 11:39:45 +11:00
|
|
|
int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base);
|
|
|
|
int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base);
|
|
|
|
int parse_int(const char *buffer, size_t count, int *result, int base);
|
|
|
|
int parse_uint(const char *buffer, size_t count, unsigned int *result, int base);
|
|
|
|
int parse_long(const char *buffer, size_t count, long *result, int base);
|
|
|
|
int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base);
|
|
|
|
|
2023-02-03 11:39:43 +11:00
|
|
|
int read_file(const char *path, char *buf, size_t count, size_t *len);
|
|
|
|
int write_file(const char *path, const char *buf, size_t count);
|
2023-02-03 11:39:47 +11:00
|
|
|
int read_file_alloc(const char *path, char **buf, size_t *len);
|
2023-02-03 11:39:46 +11:00
|
|
|
int read_long(const char *path, long *result, int base);
|
|
|
|
int write_long(const char *path, long result, int base);
|
|
|
|
int read_ulong(const char *path, unsigned long *result, int base);
|
|
|
|
int write_ulong(const char *path, unsigned long result, int base);
|
2023-02-03 11:39:44 +11:00
|
|
|
int read_debugfs_file(const char *debugfs_file, char *buf, size_t count);
|
|
|
|
int write_debugfs_file(const char *debugfs_file, const char *buf, size_t count);
|
|
|
|
int read_debugfs_int(const char *debugfs_file, int *result);
|
|
|
|
int write_debugfs_int(const char *debugfs_file, int result);
|
2019-05-20 20:55:20 +10:00
|
|
|
int read_sysfs_file(char *debugfs_file, char *result, size_t result_size);
|
2018-05-21 20:43:57 +05:30
|
|
|
int perf_event_open_counter(unsigned int type,
|
|
|
|
unsigned long config, int group_fd);
|
|
|
|
int perf_event_enable(int fd);
|
|
|
|
int perf_event_disable(int fd);
|
|
|
|
int perf_event_reset(int fd);
|
|
|
|
|
2020-11-17 16:59:15 +11:00
|
|
|
struct perf_event_read {
|
|
|
|
__u64 nr;
|
|
|
|
__u64 l1d_misses;
|
|
|
|
};
|
|
|
|
|
2020-07-27 09:30:39 +05:30
|
|
|
#if !defined(__GLIBC_PREREQ) || !__GLIBC_PREREQ(2, 30)
|
|
|
|
#include <sys/syscall.h>
|
|
|
|
|
|
|
|
static inline pid_t gettid(void)
|
|
|
|
{
|
|
|
|
return syscall(SYS_gettid);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-07-11 15:25:18 +10:00
|
|
|
static inline bool have_hwcap(unsigned long ftr)
|
|
|
|
{
|
|
|
|
return ((unsigned long)get_auxv_entry(AT_HWCAP) & ftr) == ftr;
|
|
|
|
}
|
|
|
|
|
2016-09-23 16:18:07 +10:00
|
|
|
#ifdef AT_HWCAP2
|
2015-11-24 13:05:39 +11:00
|
|
|
static inline bool have_hwcap2(unsigned long ftr2)
|
|
|
|
{
|
|
|
|
return ((unsigned long)get_auxv_entry(AT_HWCAP2) & ftr2) == ftr2;
|
|
|
|
}
|
2016-09-23 16:18:07 +10:00
|
|
|
#else
|
|
|
|
static inline bool have_hwcap2(unsigned long ftr2)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
2015-11-24 13:05:39 +11:00
|
|
|
|
selftests/powerpc: Add support to fetch "platform" and "base platform" from auxv to detect platform.
The /proc/self/auxv contains information about "platform" on any system.
Also "base platform" which is an indication about platform string
corresponding to the real PVR. When systems are booted in compat mode,
say, power10 booted in power9 mode, "platform" will point to power9
whereas base platform will point to power10. Incase, if the distro
doesn't support platform indicated by real PVR, base platform will have
a default value.
The mismatch of platform/base platform is an indication of system booted
in compat mode. In such cases, distro will have a Generic Compat
registered which supports basic features for performance monitoring.
Some of the selftest needs to be handled differently ( ex: generic
events, alternative events, bhrb filter map) in Generic Compat PMU.
Hence selftest framework needs utility functions to identify such cases.
One way is make sure of auxv information. Below condition can be used to
detect if Generic Compat PMU is registered. ie:
if ((AT_PLATFORM != AT_BASE_PLATFORM) && (AT_BASE_PLATFORM != PVR))
this indicates Generic Compat PMU.
Add utility function in "include/utils.h" to return:
AT_PLATFORM and AT_BASE_PLATFORM from auxv. Also update misc.c in
"sampling_tests" folder to add function to use above check to determine
presence of generic compat pmu.
In other architecture ( like x86 ), pmu_name is exposed via
"/sys/bus/event_source/devices/cpu/caps". The same could be used in
powerpc in future. Since currently we don't have the "caps" support in
powerpc, patch uses auxv information to detect platform type and compat
mode. But as placeholder utility function is added considering
possiblity of getting "caps" information via sysfs. If that doesn't
exist, fallback to using auxv information.
Signed-off-by: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20220610134113.62991-3-atrajeev@linux.vnet.ibm.com
2022-06-10 19:10:40 +05:30
|
|
|
static inline char *auxv_base_platform(void)
|
|
|
|
{
|
|
|
|
return ((char *)get_auxv_entry(AT_BASE_PLATFORM));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline char *auxv_platform(void)
|
|
|
|
{
|
|
|
|
return ((char *)get_auxv_entry(AT_PLATFORM));
|
|
|
|
}
|
|
|
|
|
2018-07-26 22:24:57 +10:00
|
|
|
bool is_ppc64le(void);
|
2020-06-04 18:26:09 +05:30
|
|
|
int using_hash_mmu(bool *using_hash);
|
2018-07-26 22:24:57 +10:00
|
|
|
|
2023-06-19 17:36:27 +10:00
|
|
|
struct sigaction push_signal_handler(int sig, void (*fn)(int, siginfo_t *, void *));
|
|
|
|
struct sigaction pop_signal_handler(int sig, struct sigaction old_handler);
|
|
|
|
|
2013-08-06 17:42:36 +10:00
|
|
|
/* Yes, this is evil */
|
|
|
|
#define FAIL_IF(x) \
|
|
|
|
do { \
|
|
|
|
if ((x)) { \
|
|
|
|
fprintf(stderr, \
|
|
|
|
"[FAIL] Test FAILED on line %d\n", __LINE__); \
|
|
|
|
return 1; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2023-06-19 17:36:27 +10:00
|
|
|
#define FAIL_IF_MSG(x, msg) \
|
|
|
|
do { \
|
|
|
|
if ((x)) { \
|
|
|
|
fprintf(stderr, \
|
|
|
|
"[FAIL] Test FAILED on line %d: %s\n", \
|
|
|
|
__LINE__, msg); \
|
|
|
|
return 1; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2020-07-27 09:30:38 +05:30
|
|
|
#define FAIL_IF_EXIT(x) \
|
|
|
|
do { \
|
|
|
|
if ((x)) { \
|
|
|
|
fprintf(stderr, \
|
|
|
|
"[FAIL] Test FAILED on line %d\n", __LINE__); \
|
|
|
|
_exit(1); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2023-06-19 17:36:27 +10:00
|
|
|
#define FAIL_IF_EXIT_MSG(x, msg) \
|
|
|
|
do { \
|
|
|
|
if ((x)) { \
|
|
|
|
fprintf(stderr, \
|
|
|
|
"[FAIL] Test FAILED on line %d: %s\n", \
|
|
|
|
__LINE__, msg); \
|
|
|
|
_exit(1); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2014-06-10 22:23:09 +10:00
|
|
|
/* The test harness uses this, yes it's gross */
|
|
|
|
#define MAGIC_SKIP_RETURN_VALUE 99
|
|
|
|
|
|
|
|
#define SKIP_IF(x) \
|
|
|
|
do { \
|
|
|
|
if ((x)) { \
|
|
|
|
fprintf(stderr, \
|
|
|
|
"[SKIP] Test skipped on line %d\n", __LINE__); \
|
|
|
|
return MAGIC_SKIP_RETURN_VALUE; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2018-10-31 11:38:21 -03:00
|
|
|
#define SKIP_IF_MSG(x, msg) \
|
|
|
|
do { \
|
|
|
|
if ((x)) { \
|
|
|
|
fprintf(stderr, \
|
|
|
|
"[SKIP] Test skipped on line %d: %s\n", \
|
|
|
|
__LINE__, msg); \
|
|
|
|
return MAGIC_SKIP_RETURN_VALUE; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2014-01-21 15:22:17 +11:00
|
|
|
#define _str(s) #s
|
|
|
|
#define str(s) _str(s)
|
|
|
|
|
2020-07-27 09:30:35 +05:30
|
|
|
#define sigsafe_err(msg) ({ \
|
|
|
|
ssize_t nbytes __attribute__((unused)); \
|
|
|
|
nbytes = write(STDERR_FILENO, msg, strlen(msg)); })
|
|
|
|
|
2016-05-02 13:51:38 +10:00
|
|
|
/* POWER9 feature */
|
|
|
|
#ifndef PPC_FEATURE2_ARCH_3_00
|
|
|
|
#define PPC_FEATURE2_ARCH_3_00 0x00800000
|
|
|
|
#endif
|
|
|
|
|
2020-05-20 12:11:03 +10:00
|
|
|
/* POWER10 feature */
|
|
|
|
#ifndef PPC_FEATURE2_ARCH_3_1
|
|
|
|
#define PPC_FEATURE2_ARCH_3_1 0x00040000
|
|
|
|
#endif
|
|
|
|
|
2020-06-22 12:18:32 +10:00
|
|
|
/* POWER10 features */
|
|
|
|
#ifndef PPC_FEATURE2_MMA
|
|
|
|
#define PPC_FEATURE2_MMA 0x00020000
|
|
|
|
#endif
|
|
|
|
|
2018-05-21 20:43:56 +05:30
|
|
|
#if defined(__powerpc64__)
|
|
|
|
#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP]
|
selftests/powerpc: New TM signal self test
A new self test that forces MSR[TS] to be set without calling any TM
instruction. This test also tries to cause a page fault at a signal
handler, exactly between MSR[TS] set and tm_recheckpoint(), forcing
thread->texasr to be rewritten with TEXASR[FS] = 0, which will cause a BUG
when tm_recheckpoint() is called.
This test is not deterministic, since it is hard to guarantee that the page
access will cause a page fault. In order to force more page faults at
signal context, the signal handler and the ucontext are being mapped into a
MADV_DONTNEED memory chunks.
Tests have shown that the bug could be exposed with few interactions in a
buggy kernel. This test is configured to loop 5000x, having a good chance
to hit the kernel issue in just one run. This self test takes less than
two seconds to run.
This test uses set/getcontext because the kernel will recheckpoint
zeroed structures, causing the test to segfault, which is undesired because
the test needs to rerun, so, there is a signal handler for SIGSEGV which
will restart the test.
v2: Uses the MADV_DONTNEED memory advice
v3: Fix memcpy and 32-bits compilation
v4: Does not define unused macros
Signed-off-by: Breno Leitao <leitao@debian.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2019-01-08 09:31:21 -02:00
|
|
|
#define UCONTEXT_MSR(UC) (UC)->uc_mcontext.gp_regs[PT_MSR]
|
2018-05-21 20:43:56 +05:30
|
|
|
#elif defined(__powerpc__)
|
|
|
|
#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP]
|
selftests/powerpc: New TM signal self test
A new self test that forces MSR[TS] to be set without calling any TM
instruction. This test also tries to cause a page fault at a signal
handler, exactly between MSR[TS] set and tm_recheckpoint(), forcing
thread->texasr to be rewritten with TEXASR[FS] = 0, which will cause a BUG
when tm_recheckpoint() is called.
This test is not deterministic, since it is hard to guarantee that the page
access will cause a page fault. In order to force more page faults at
signal context, the signal handler and the ucontext are being mapped into a
MADV_DONTNEED memory chunks.
Tests have shown that the bug could be exposed with few interactions in a
buggy kernel. This test is configured to loop 5000x, having a good chance
to hit the kernel issue in just one run. This self test takes less than
two seconds to run.
This test uses set/getcontext because the kernel will recheckpoint
zeroed structures, causing the test to segfault, which is undesired because
the test needs to rerun, so, there is a signal handler for SIGSEGV which
will restart the test.
v2: Uses the MADV_DONTNEED memory advice
v3: Fix memcpy and 32-bits compilation
v4: Does not define unused macros
Signed-off-by: Breno Leitao <leitao@debian.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2019-01-08 09:31:21 -02:00
|
|
|
#define UCONTEXT_MSR(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_MSR]
|
2018-05-21 20:43:56 +05:30
|
|
|
#else
|
|
|
|
#error implement UCONTEXT_NIA
|
|
|
|
#endif
|
|
|
|
|
2013-08-06 17:42:36 +10:00
|
|
|
#endif /* _SELFTESTS_POWERPC_UTILS_H */
|