cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

perf_regs.c (5773B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/errno.h>
      3#include <linux/kernel.h>
      4#include <linux/sched.h>
      5#include <linux/sched/task_stack.h>
      6#include <linux/perf_event.h>
      7#include <linux/bug.h>
      8#include <linux/stddef.h>
      9#include <asm/perf_regs.h>
     10#include <asm/ptrace.h>
     11
     12#ifdef CONFIG_X86_32
     13#define PERF_REG_X86_MAX PERF_REG_X86_32_MAX
     14#else
     15#define PERF_REG_X86_MAX PERF_REG_X86_64_MAX
     16#endif
     17
     18#define PT_REGS_OFFSET(id, r) [id] = offsetof(struct pt_regs, r)
     19
     20static unsigned int pt_regs_offset[PERF_REG_X86_MAX] = {
     21	PT_REGS_OFFSET(PERF_REG_X86_AX, ax),
     22	PT_REGS_OFFSET(PERF_REG_X86_BX, bx),
     23	PT_REGS_OFFSET(PERF_REG_X86_CX, cx),
     24	PT_REGS_OFFSET(PERF_REG_X86_DX, dx),
     25	PT_REGS_OFFSET(PERF_REG_X86_SI, si),
     26	PT_REGS_OFFSET(PERF_REG_X86_DI, di),
     27	PT_REGS_OFFSET(PERF_REG_X86_BP, bp),
     28	PT_REGS_OFFSET(PERF_REG_X86_SP, sp),
     29	PT_REGS_OFFSET(PERF_REG_X86_IP, ip),
     30	PT_REGS_OFFSET(PERF_REG_X86_FLAGS, flags),
     31	PT_REGS_OFFSET(PERF_REG_X86_CS, cs),
     32	PT_REGS_OFFSET(PERF_REG_X86_SS, ss),
     33#ifdef CONFIG_X86_32
     34	PT_REGS_OFFSET(PERF_REG_X86_DS, ds),
     35	PT_REGS_OFFSET(PERF_REG_X86_ES, es),
     36	PT_REGS_OFFSET(PERF_REG_X86_FS, fs),
     37	PT_REGS_OFFSET(PERF_REG_X86_GS, gs),
     38#else
     39	/*
     40	 * The pt_regs struct does not store
     41	 * ds, es, fs, gs in 64 bit mode.
     42	 */
     43	(unsigned int) -1,
     44	(unsigned int) -1,
     45	(unsigned int) -1,
     46	(unsigned int) -1,
     47#endif
     48#ifdef CONFIG_X86_64
     49	PT_REGS_OFFSET(PERF_REG_X86_R8, r8),
     50	PT_REGS_OFFSET(PERF_REG_X86_R9, r9),
     51	PT_REGS_OFFSET(PERF_REG_X86_R10, r10),
     52	PT_REGS_OFFSET(PERF_REG_X86_R11, r11),
     53	PT_REGS_OFFSET(PERF_REG_X86_R12, r12),
     54	PT_REGS_OFFSET(PERF_REG_X86_R13, r13),
     55	PT_REGS_OFFSET(PERF_REG_X86_R14, r14),
     56	PT_REGS_OFFSET(PERF_REG_X86_R15, r15),
     57#endif
     58};
     59
     60u64 perf_reg_value(struct pt_regs *regs, int idx)
     61{
     62	struct x86_perf_regs *perf_regs;
     63
     64	if (idx >= PERF_REG_X86_XMM0 && idx < PERF_REG_X86_XMM_MAX) {
     65		perf_regs = container_of(regs, struct x86_perf_regs, regs);
     66		if (!perf_regs->xmm_regs)
     67			return 0;
     68		return perf_regs->xmm_regs[idx - PERF_REG_X86_XMM0];
     69	}
     70
     71	if (WARN_ON_ONCE(idx >= ARRAY_SIZE(pt_regs_offset)))
     72		return 0;
     73
     74	return regs_get_register(regs, pt_regs_offset[idx]);
     75}
     76
     77#define PERF_REG_X86_RESERVED	(((1ULL << PERF_REG_X86_XMM0) - 1) & \
     78				 ~((1ULL << PERF_REG_X86_MAX) - 1))
     79
     80#ifdef CONFIG_X86_32
     81#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_R8) | \
     82		       (1ULL << PERF_REG_X86_R9) | \
     83		       (1ULL << PERF_REG_X86_R10) | \
     84		       (1ULL << PERF_REG_X86_R11) | \
     85		       (1ULL << PERF_REG_X86_R12) | \
     86		       (1ULL << PERF_REG_X86_R13) | \
     87		       (1ULL << PERF_REG_X86_R14) | \
     88		       (1ULL << PERF_REG_X86_R15))
     89
     90int perf_reg_validate(u64 mask)
     91{
     92	if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
     93		return -EINVAL;
     94
     95	return 0;
     96}
     97
     98u64 perf_reg_abi(struct task_struct *task)
     99{
    100	return PERF_SAMPLE_REGS_ABI_32;
    101}
    102
    103void perf_get_regs_user(struct perf_regs *regs_user,
    104			struct pt_regs *regs)
    105{
    106	regs_user->regs = task_pt_regs(current);
    107	regs_user->abi = perf_reg_abi(current);
    108}
    109#else /* CONFIG_X86_64 */
    110#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
    111		       (1ULL << PERF_REG_X86_ES) | \
    112		       (1ULL << PERF_REG_X86_FS) | \
    113		       (1ULL << PERF_REG_X86_GS))
    114
    115int perf_reg_validate(u64 mask)
    116{
    117	if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
    118		return -EINVAL;
    119
    120	return 0;
    121}
    122
    123u64 perf_reg_abi(struct task_struct *task)
    124{
    125	if (!user_64bit_mode(task_pt_regs(task)))
    126		return PERF_SAMPLE_REGS_ABI_32;
    127	else
    128		return PERF_SAMPLE_REGS_ABI_64;
    129}
    130
    131static DEFINE_PER_CPU(struct pt_regs, nmi_user_regs);
    132
    133void perf_get_regs_user(struct perf_regs *regs_user,
    134			struct pt_regs *regs)
    135{
    136	struct pt_regs *regs_user_copy = this_cpu_ptr(&nmi_user_regs);
    137	struct pt_regs *user_regs = task_pt_regs(current);
    138
    139	if (!in_nmi()) {
    140		regs_user->regs = user_regs;
    141		regs_user->abi = perf_reg_abi(current);
    142		return;
    143	}
    144
    145	/*
    146	 * If we're in an NMI that interrupted task_pt_regs setup, then
    147	 * we can't sample user regs at all.  This check isn't really
    148	 * sufficient, though, as we could be in an NMI inside an interrupt
    149	 * that happened during task_pt_regs setup.
    150	 */
    151	if (regs->sp > (unsigned long)&user_regs->r11 &&
    152	    regs->sp <= (unsigned long)(user_regs + 1)) {
    153		regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
    154		regs_user->regs = NULL;
    155		return;
    156	}
    157
    158	/*
    159	 * These registers are always saved on 64-bit syscall entry.
    160	 * On 32-bit entry points, they are saved too except r8..r11.
    161	 */
    162	regs_user_copy->ip = user_regs->ip;
    163	regs_user_copy->ax = user_regs->ax;
    164	regs_user_copy->cx = user_regs->cx;
    165	regs_user_copy->dx = user_regs->dx;
    166	regs_user_copy->si = user_regs->si;
    167	regs_user_copy->di = user_regs->di;
    168	regs_user_copy->r8 = user_regs->r8;
    169	regs_user_copy->r9 = user_regs->r9;
    170	regs_user_copy->r10 = user_regs->r10;
    171	regs_user_copy->r11 = user_regs->r11;
    172	regs_user_copy->orig_ax = user_regs->orig_ax;
    173	regs_user_copy->flags = user_regs->flags;
    174	regs_user_copy->sp = user_regs->sp;
    175	regs_user_copy->cs = user_regs->cs;
    176	regs_user_copy->ss = user_regs->ss;
    177	/*
    178	 * Store user space frame-pointer value on sample
    179	 * to facilitate stack unwinding for cases when
    180	 * user space executable code has such support
    181	 * enabled at compile time:
    182	 */
    183	regs_user_copy->bp = user_regs->bp;
    184
    185	regs_user_copy->bx = -1;
    186	regs_user_copy->r12 = -1;
    187	regs_user_copy->r13 = -1;
    188	regs_user_copy->r14 = -1;
    189	regs_user_copy->r15 = -1;
    190	/*
    191	 * For this to be at all useful, we need a reasonable guess for
    192	 * the ABI.  Be careful: we're in NMI context, and we're
    193	 * considering current to be the current task, so we should
    194	 * be careful not to look at any other percpu variables that might
    195	 * change during context switches.
    196	 */
    197	regs_user->abi = user_64bit_mode(user_regs) ?
    198		PERF_SAMPLE_REGS_ABI_64 : PERF_SAMPLE_REGS_ABI_32;
    199
    200	regs_user->regs = regs_user_copy;
    201}
    202#endif /* CONFIG_X86_32 */