Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  2) /* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  3) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  4) #include <linux/perf_event.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  5) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  6) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  7) /* Kernel callchain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  8) struct stackframe {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  9) 	unsigned long fp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) 	unsigned long ra;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)  * Get the return address for a single stackframe and return a pointer to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)  * next frame tail.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) 				    unsigned long fp, unsigned long reg_ra)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) 	struct stackframe buftail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) 	unsigned long ra = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) 	unsigned long __user *user_frame_tail =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) 		(unsigned long __user *)(fp - sizeof(struct stackframe));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) 	/* Check accessibility of one struct frame_tail beyond */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) 	if (!access_ok(user_frame_tail, sizeof(buftail)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) 	if (__copy_from_user_inatomic(&buftail, user_frame_tail,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) 				      sizeof(buftail)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) 	if (reg_ra != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) 		ra = reg_ra;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) 		ra = buftail.ra;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) 	fp = buftail.fp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) 	if (ra != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) 		perf_callchain_store(entry, ra);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) 	return fp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)  * This will be called when the target is in user mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)  * This function will only be called when we use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)  * "PERF_SAMPLE_CALLCHAIN" in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)  * kernel/events/core.c:perf_prepare_sample()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)  * How to trigger perf_callchain_[user/kernel] :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)  * $ perf record -e cpu-clock --call-graph fp ./program
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)  * $ perf report --call-graph
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)  * On RISC-V platform, the program being sampled and the C library
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)  * need to be compiled with -fno-omit-frame-pointer, otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)  * the user stack will not contain function frame.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) 			 struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) 	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) 	unsigned long fp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) 	/* RISC-V does not support perf in guest mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) 	if (guest_cbs && guest_cbs->is_in_guest())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) 	fp = regs->s0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) 	perf_callchain_store(entry, regs->epc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) 	fp = user_backtrace(entry, fp, regs->ra);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) 	while (fp && !(fp & 0x3) && entry->nr < entry->max_stack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) 		fp = user_backtrace(entry, fp, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) bool fill_callchain(unsigned long pc, void *entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) 	return perf_callchain_store(entry, pc) == 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) void notrace walk_stackframe(struct task_struct *task,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) 	struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) 			   struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) 	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) 	/* RISC-V does not support perf in guest mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) 	if (guest_cbs && guest_cbs->is_in_guest()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) 		pr_warn("RISC-V does not support perf in guest mode!");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) 	walk_stackframe(NULL, regs, fill_callchain, entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }