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_event.c (1737B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Linux performance counter support for MIPS.
      4 *
      5 * Copyright (C) 2010 MIPS Technologies, Inc.
      6 * Author: Deng-Cheng Zhu
      7 *
      8 * This code is based on the implementation for ARM, which is in turn
      9 * based on the sparc64 perf event code and the x86 code. Performance
     10 * counter access is based on the MIPS Oprofile code. And the callchain
     11 * support references the code of MIPS stacktrace.c.
     12 */
     13
     14#include <linux/perf_event.h>
     15#include <linux/sched/task_stack.h>
     16
     17#include <asm/stacktrace.h>
     18
     19/* Callchain handling code. */
     20
     21/*
     22 * Leave userspace callchain empty for now. When we find a way to trace
     23 * the user stack callchains, we will add it here.
     24 */
     25
     26static void save_raw_perf_callchain(struct perf_callchain_entry_ctx *entry,
     27				    unsigned long reg29)
     28{
     29	unsigned long *sp = (unsigned long *)reg29;
     30	unsigned long addr;
     31
     32	while (!kstack_end(sp)) {
     33		addr = *sp++;
     34		if (__kernel_text_address(addr)) {
     35			perf_callchain_store(entry, addr);
     36			if (entry->nr >= entry->max_stack)
     37				break;
     38		}
     39	}
     40}
     41
     42void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
     43			   struct pt_regs *regs)
     44{
     45	unsigned long sp = regs->regs[29];
     46#ifdef CONFIG_KALLSYMS
     47	unsigned long ra = regs->regs[31];
     48	unsigned long pc = regs->cp0_epc;
     49
     50	if (raw_show_trace || !__kernel_text_address(pc)) {
     51		unsigned long stack_page =
     52			(unsigned long)task_stack_page(current);
     53		if (stack_page && sp >= stack_page &&
     54		    sp <= stack_page + THREAD_SIZE - 32)
     55			save_raw_perf_callchain(entry, sp);
     56		return;
     57	}
     58	do {
     59		perf_callchain_store(entry, pc);
     60		if (entry->nr >= entry->max_stack)
     61			break;
     62		pc = unwind_stack(current, &sp, pc, &ra);
     63	} while (pc);
     64#else
     65	save_raw_perf_callchain(entry, sp);
     66#endif
     67}