1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2023 Huawei Device Co., Ltd. 4 */ 5 6#include <asm/asm-offsets.h> 7#include <asm/ptrace.h> 8#include <linux/irqflags.h> 9 10/* The members of arrays below are corresponding to the enum defined in pointer_auth_context.h: 11 * enum pac_pt_regs { 12 * REGS_X16 = 0, 13 * REGS_X17, 14 * REGS_LR, 15 * REGS_SP, 16 * REGS_PC, 17 * REGS_PSTATE, 18 * }; 19 * 20 * compat_regs_offset_array[]: 21 * S_X14: the offset of compat_lr 22 * S_X13: the offset of compat_sp 23 */ 24static off_t compat_regs_offset_array[] = {0, 0, S_X14, S_X13, S_PC, S_PSTATE}; 25static off_t regs_offset_array[] = {S_X16, S_X17, S_LR, S_SP, S_PC, S_PSTATE}; 26 27int set_compat_exception_context_register(void *regs, enum pac_pt_regs regs_enum, u64 val) 28{ 29 switch (regs_enum) { 30 case REGS_LR: 31 case REGS_SP: 32 case REGS_PC: 33 case REGS_PSTATE: 34 return set_compat_exception_context_register_asm(regs, compat_regs_offset_array[regs_enum], val); 35 default: 36 return -EINVAL; 37 } 38} 39 40int set_exception_context_register(void *regs, enum pac_pt_regs regs_enum, u64 val) 41{ 42 if (compat_user_mode((struct pt_regs *)regs)) { 43 return set_compat_exception_context_register(regs, regs_enum, val); 44 } else { 45 switch (regs_enum) { 46 case REGS_X16: 47 case REGS_X17: 48 case REGS_LR: 49 case REGS_SP: 50 case REGS_PC: 51 case REGS_PSTATE: 52 return set_exception_context_register_asm(regs, regs_offset_array[regs_enum], val); 53 default: 54 return -EINVAL; 55 } 56 } 57} 58 59void set_compat_exception_context_register_index(struct pt_regs *regs, int index, uint64_t val) 60{ 61 /* 14 means the index of compat_lr */ 62 if (index == 14) { 63 set_compat_exception_context_register_asm(regs, S_X14, val); 64 /* 13 means the index of compat_sp */ 65 } else if (index == 13) { 66 set_compat_exception_context_register_asm(regs, S_X13, val); 67 } else { 68 regs->regs[index] = val; 69 } 70} 71 72void set_exception_context_register_index(struct pt_regs *regs, int index, uint64_t val) 73{ 74 off_t offset; 75 76 if (compat_user_mode(regs)) { 77 set_compat_exception_context_register_index(regs, index, val); 78 } else { 79 switch (index) { 80 /* 16 means the index of regs[16] */ 81 case 16: 82 /* 17 means the index of regs[17] */ 83 case 17: 84 /* 30 means the index of regs[30] */ 85 case 30: 86 offset = offsetof(struct pt_regs, regs[index]); 87 set_exception_context_register_asm(regs, offset, val); 88 break; 89 default: 90 regs->regs[index] = val; 91 } 92 } 93} 94 95void sign_compat_exception_context(void *regs) 96{ 97 unsigned long irq_flags; 98 local_irq_save(irq_flags); 99 sign_compat_exception_context_asm(regs); 100 local_irq_restore(irq_flags); 101} 102 103void auth_compat_exception_context(void *regs) 104{ 105 unsigned long irq_flags; 106 local_irq_save(irq_flags); 107 auth_compat_exception_context_asm(regs); 108 local_irq_restore(irq_flags); 109} 110 111void sign_exception_context(void *regs) 112{ 113 unsigned long irq_flags; 114 local_irq_save(irq_flags); 115 if (compat_user_mode((struct pt_regs *)regs)) { 116 sign_compat_exception_context_asm(regs); 117 } else { 118 sign_exception_context_asm(regs); 119 } 120 local_irq_restore(irq_flags); 121} 122 123void auth_exception_context(void *regs) 124{ 125 unsigned long irq_flags; 126 local_irq_save(irq_flags); 127 if (compat_user_mode((struct pt_regs *)regs)) { 128 auth_compat_exception_context_asm(regs); 129 } else { 130 auth_exception_context_asm(regs); 131 } 132 local_irq_restore(irq_flags); 133} 134