18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/arm/include/asm/ptrace.h 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1996-2003 Russell King 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#ifndef __ASM_ARM_PTRACE_H 88c2ecf20Sopenharmony_ci#define __ASM_ARM_PTRACE_H 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <uapi/asm/ptrace.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__ 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct pt_regs { 168c2ecf20Sopenharmony_ci unsigned long uregs[18]; 178c2ecf20Sopenharmony_ci}; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistruct svc_pt_regs { 208c2ecf20Sopenharmony_ci struct pt_regs regs; 218c2ecf20Sopenharmony_ci u32 dacr; 228c2ecf20Sopenharmony_ci u32 addr_limit; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define to_svc_pt_regs(r) container_of(r, struct svc_pt_regs, regs) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define user_mode(regs) \ 288c2ecf20Sopenharmony_ci (((regs)->ARM_cpsr & 0xf) == 0) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM_THUMB 318c2ecf20Sopenharmony_ci#define thumb_mode(regs) \ 328c2ecf20Sopenharmony_ci (((regs)->ARM_cpsr & PSR_T_BIT)) 338c2ecf20Sopenharmony_ci#else 348c2ecf20Sopenharmony_ci#define thumb_mode(regs) (0) 358c2ecf20Sopenharmony_ci#endif 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#ifndef CONFIG_CPU_V7M 388c2ecf20Sopenharmony_ci#define isa_mode(regs) \ 398c2ecf20Sopenharmony_ci ((((regs)->ARM_cpsr & PSR_J_BIT) >> (__ffs(PSR_J_BIT) - 1)) | \ 408c2ecf20Sopenharmony_ci (((regs)->ARM_cpsr & PSR_T_BIT) >> (__ffs(PSR_T_BIT)))) 418c2ecf20Sopenharmony_ci#else 428c2ecf20Sopenharmony_ci#define isa_mode(regs) 1 /* Thumb */ 438c2ecf20Sopenharmony_ci#endif 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define processor_mode(regs) \ 468c2ecf20Sopenharmony_ci ((regs)->ARM_cpsr & MODE_MASK) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define interrupts_enabled(regs) \ 498c2ecf20Sopenharmony_ci (!((regs)->ARM_cpsr & PSR_I_BIT)) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define fast_interrupts_enabled(regs) \ 528c2ecf20Sopenharmony_ci (!((regs)->ARM_cpsr & PSR_F_BIT)) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* Are the current registers suitable for user mode? 558c2ecf20Sopenharmony_ci * (used to maintain security in signal handlers) 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cistatic inline int valid_user_regs(struct pt_regs *regs) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci#ifndef CONFIG_CPU_V7M 608c2ecf20Sopenharmony_ci unsigned long mode = regs->ARM_cpsr & MODE_MASK; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* 638c2ecf20Sopenharmony_ci * Always clear the F (FIQ) and A (delayed abort) bits 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci regs->ARM_cpsr &= ~(PSR_F_BIT | PSR_A_BIT); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if ((regs->ARM_cpsr & PSR_I_BIT) == 0) { 688c2ecf20Sopenharmony_ci if (mode == USR_MODE) 698c2ecf20Sopenharmony_ci return 1; 708c2ecf20Sopenharmony_ci if (elf_hwcap & HWCAP_26BIT && mode == USR26_MODE) 718c2ecf20Sopenharmony_ci return 1; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* 758c2ecf20Sopenharmony_ci * Force CPSR to something logical... 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci regs->ARM_cpsr &= PSR_f | PSR_s | PSR_x | PSR_T_BIT | MODE32_BIT; 788c2ecf20Sopenharmony_ci if (!(elf_hwcap & HWCAP_26BIT)) 798c2ecf20Sopenharmony_ci regs->ARM_cpsr |= USR_MODE; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci#else /* ifndef CONFIG_CPU_V7M */ 838c2ecf20Sopenharmony_ci return 1; 848c2ecf20Sopenharmony_ci#endif 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic inline long regs_return_value(struct pt_regs *regs) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci return regs->ARM_r0; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define instruction_pointer(regs) (regs)->ARM_pc 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#ifdef CONFIG_THUMB2_KERNEL 958c2ecf20Sopenharmony_ci#define frame_pointer(regs) (regs)->ARM_r7 968c2ecf20Sopenharmony_ci#else 978c2ecf20Sopenharmony_ci#define frame_pointer(regs) (regs)->ARM_fp 988c2ecf20Sopenharmony_ci#endif 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic inline void instruction_pointer_set(struct pt_regs *regs, 1018c2ecf20Sopenharmony_ci unsigned long val) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci instruction_pointer(regs) = val; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 1078c2ecf20Sopenharmony_ciextern unsigned long profile_pc(struct pt_regs *regs); 1088c2ecf20Sopenharmony_ci#else 1098c2ecf20Sopenharmony_ci#define profile_pc(regs) instruction_pointer(regs) 1108c2ecf20Sopenharmony_ci#endif 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define predicate(x) ((x) & 0xf0000000) 1138c2ecf20Sopenharmony_ci#define PREDICATE_ALWAYS 0xe0000000 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* 1168c2ecf20Sopenharmony_ci * True if instr is a 32-bit thumb instruction. This works if instr 1178c2ecf20Sopenharmony_ci * is the first or only half-word of a thumb instruction. It also works 1188c2ecf20Sopenharmony_ci * when instr holds all 32-bits of a wide thumb instruction if stored 1198c2ecf20Sopenharmony_ci * in the form (first_half<<16)|(second_half) 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci#define is_wide_instruction(instr) ((unsigned)(instr) >= 0xe800) 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * kprobe-based event tracer support 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci#include <linux/compiler.h> 1278c2ecf20Sopenharmony_ci#define MAX_REG_OFFSET (offsetof(struct pt_regs, ARM_ORIG_r0)) 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ciextern int regs_query_register_offset(const char *name); 1308c2ecf20Sopenharmony_ciextern const char *regs_query_register_name(unsigned int offset); 1318c2ecf20Sopenharmony_ciextern bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr); 1328c2ecf20Sopenharmony_ciextern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, 1338c2ecf20Sopenharmony_ci unsigned int n); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/** 1368c2ecf20Sopenharmony_ci * regs_get_register() - get register value from its offset 1378c2ecf20Sopenharmony_ci * @regs: pt_regs from which register value is gotten 1388c2ecf20Sopenharmony_ci * @offset: offset number of the register. 1398c2ecf20Sopenharmony_ci * 1408c2ecf20Sopenharmony_ci * regs_get_register returns the value of a register whose offset from @regs. 1418c2ecf20Sopenharmony_ci * The @offset is the offset of the register in struct pt_regs. 1428c2ecf20Sopenharmony_ci * If @offset is bigger than MAX_REG_OFFSET, this returns 0. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_cistatic inline unsigned long regs_get_register(struct pt_regs *regs, 1458c2ecf20Sopenharmony_ci unsigned int offset) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci if (unlikely(offset > MAX_REG_OFFSET)) 1488c2ecf20Sopenharmony_ci return 0; 1498c2ecf20Sopenharmony_ci return *(unsigned long *)((unsigned long)regs + offset); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* Valid only for Kernel mode traps. */ 1538c2ecf20Sopenharmony_cistatic inline unsigned long kernel_stack_pointer(struct pt_regs *regs) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci return regs->ARM_sp; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic inline unsigned long user_stack_pointer(struct pt_regs *regs) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci return regs->ARM_sp; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci#define current_pt_regs(void) ({ (struct pt_regs *) \ 1648c2ecf20Sopenharmony_ci ((current_stack_pointer | (THREAD_SIZE - 1)) - 7) - 1; \ 1658c2ecf20Sopenharmony_ci}) 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* 1698c2ecf20Sopenharmony_ci * Update ITSTATE after normal execution of an IT block instruction. 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * The 8 IT state bits are split into two parts in CPSR: 1728c2ecf20Sopenharmony_ci * ITSTATE<1:0> are in CPSR<26:25> 1738c2ecf20Sopenharmony_ci * ITSTATE<7:2> are in CPSR<15:10> 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_cistatic inline unsigned long it_advance(unsigned long cpsr) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci if ((cpsr & 0x06000400) == 0) { 1788c2ecf20Sopenharmony_ci /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */ 1798c2ecf20Sopenharmony_ci cpsr &= ~PSR_IT_MASK; 1808c2ecf20Sopenharmony_ci } else { 1818c2ecf20Sopenharmony_ci /* We need to shift left ITSTATE<4:0> */ 1828c2ecf20Sopenharmony_ci const unsigned long mask = 0x06001c00; /* Mask ITSTATE<4:0> */ 1838c2ecf20Sopenharmony_ci unsigned long it = cpsr & mask; 1848c2ecf20Sopenharmony_ci it <<= 1; 1858c2ecf20Sopenharmony_ci it |= it >> (27 - 10); /* Carry ITSTATE<2> to correct place */ 1868c2ecf20Sopenharmony_ci it &= mask; 1878c2ecf20Sopenharmony_ci cpsr &= ~mask; 1888c2ecf20Sopenharmony_ci cpsr |= it; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci return cpsr; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci#endif /* __ASSEMBLY__ */ 1948c2ecf20Sopenharmony_ci#endif 195