18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/** 38c2ecf20Sopenharmony_ci * Copyright (C) 2005 Brian Rogan <bcr6@cornell.edu>, IBM 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci**/ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/time.h> 88c2ecf20Sopenharmony_ci#include <linux/oprofile.h> 98c2ecf20Sopenharmony_ci#include <linux/sched.h> 108c2ecf20Sopenharmony_ci#include <asm/processor.h> 118c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 128c2ecf20Sopenharmony_ci#include <linux/compat.h> 138c2ecf20Sopenharmony_ci#include <asm/oprofile_impl.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define STACK_SP(STACK) *(STACK) 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define STACK_LR64(STACK) *((unsigned long *)(STACK) + 2) 188c2ecf20Sopenharmony_ci#define STACK_LR32(STACK) *((unsigned int *)(STACK) + 1) 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 218c2ecf20Sopenharmony_ci#define STACK_LR(STACK) STACK_LR64(STACK) 228c2ecf20Sopenharmony_ci#else 238c2ecf20Sopenharmony_ci#define STACK_LR(STACK) STACK_LR32(STACK) 248c2ecf20Sopenharmony_ci#endif 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic unsigned int user_getsp32(unsigned int sp, int is_first) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci unsigned int stack_frame[2]; 298c2ecf20Sopenharmony_ci void __user *p = compat_ptr(sp); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci /* 328c2ecf20Sopenharmony_ci * The most likely reason for this is that we returned -EFAULT, 338c2ecf20Sopenharmony_ci * which means that we've done all that we can do from 348c2ecf20Sopenharmony_ci * interrupt context. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci if (copy_from_user_nofault(stack_frame, (void __user *)p, 378c2ecf20Sopenharmony_ci sizeof(stack_frame))) 388c2ecf20Sopenharmony_ci return 0; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (!is_first) 418c2ecf20Sopenharmony_ci oprofile_add_trace(STACK_LR32(stack_frame)); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* 448c2ecf20Sopenharmony_ci * We do not enforce increasing stack addresses here because 458c2ecf20Sopenharmony_ci * we may transition to a different stack, eg a signal handler. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci return STACK_SP(stack_frame); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 518c2ecf20Sopenharmony_cistatic unsigned long user_getsp64(unsigned long sp, int is_first) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci unsigned long stack_frame[3]; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (copy_from_user_nofault(stack_frame, (void __user *)sp, 568c2ecf20Sopenharmony_ci sizeof(stack_frame))) 578c2ecf20Sopenharmony_ci return 0; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (!is_first) 608c2ecf20Sopenharmony_ci oprofile_add_trace(STACK_LR64(stack_frame)); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return STACK_SP(stack_frame); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci#endif 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic unsigned long kernel_getsp(unsigned long sp, int is_first) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci unsigned long *stack_frame = (unsigned long *)sp; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD)) 718c2ecf20Sopenharmony_ci return 0; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (!is_first) 748c2ecf20Sopenharmony_ci oprofile_add_trace(STACK_LR(stack_frame)); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* 778c2ecf20Sopenharmony_ci * We do not enforce increasing stack addresses here because 788c2ecf20Sopenharmony_ci * we might be transitioning from an interrupt stack to a kernel 798c2ecf20Sopenharmony_ci * stack. validate_sp() is designed to understand this, so just 808c2ecf20Sopenharmony_ci * use it. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci return STACK_SP(stack_frame); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_civoid op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci unsigned long sp = regs->gpr[1]; 888c2ecf20Sopenharmony_ci int first_frame = 1; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* We ditch the top stackframe so need to loop through an extra time */ 918c2ecf20Sopenharmony_ci depth += 1; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (!user_mode(regs)) { 948c2ecf20Sopenharmony_ci while (depth--) { 958c2ecf20Sopenharmony_ci sp = kernel_getsp(sp, first_frame); 968c2ecf20Sopenharmony_ci if (!sp) 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci first_frame = 0; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci } else { 1018c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 1028c2ecf20Sopenharmony_ci if (!is_32bit_task()) { 1038c2ecf20Sopenharmony_ci while (depth--) { 1048c2ecf20Sopenharmony_ci sp = user_getsp64(sp, first_frame); 1058c2ecf20Sopenharmony_ci if (!sp) 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci first_frame = 0; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci return; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci#endif 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci while (depth--) { 1148c2ecf20Sopenharmony_ci sp = user_getsp32(sp, first_frame); 1158c2ecf20Sopenharmony_ci if (!sp) 1168c2ecf20Sopenharmony_ci break; 1178c2ecf20Sopenharmony_ci first_frame = 0; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci} 121