// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2023 Huawei Device Co., Ltd. */ #include #include #include /* The members of arrays below are corresponding to the enum defined in pointer_auth_context.h: * enum pac_pt_regs { * REGS_X16 = 0, * REGS_X17, * REGS_LR, * REGS_SP, * REGS_PC, * REGS_PSTATE, * }; * * compat_regs_offset_array[]: * S_X14: the offset of compat_lr * S_X13: the offset of compat_sp */ static off_t compat_regs_offset_array[] = {0, 0, S_X14, S_X13, S_PC, S_PSTATE}; static off_t regs_offset_array[] = {S_X16, S_X17, S_LR, S_SP, S_PC, S_PSTATE}; int set_compat_exception_context_register(void *regs, enum pac_pt_regs regs_enum, u64 val) { switch (regs_enum) { case REGS_LR: case REGS_SP: case REGS_PC: case REGS_PSTATE: return set_compat_exception_context_register_asm(regs, compat_regs_offset_array[regs_enum], val); default: return -EINVAL; } } int set_exception_context_register(void *regs, enum pac_pt_regs regs_enum, u64 val) { if (compat_user_mode((struct pt_regs *)regs)) { return set_compat_exception_context_register(regs, regs_enum, val); } else { switch (regs_enum) { case REGS_X16: case REGS_X17: case REGS_LR: case REGS_SP: case REGS_PC: case REGS_PSTATE: return set_exception_context_register_asm(regs, regs_offset_array[regs_enum], val); default: return -EINVAL; } } } void set_compat_exception_context_register_index(struct pt_regs *regs, int index, uint64_t val) { /* 14 means the index of compat_lr */ if (index == 14) { set_compat_exception_context_register_asm(regs, S_X14, val); /* 13 means the index of compat_sp */ } else if (index == 13) { set_compat_exception_context_register_asm(regs, S_X13, val); } else { regs->regs[index] = val; } } void set_exception_context_register_index(struct pt_regs *regs, int index, uint64_t val) { off_t offset; if (compat_user_mode(regs)) { set_compat_exception_context_register_index(regs, index, val); } else { switch (index) { /* 16 means the index of regs[16] */ case 16: /* 17 means the index of regs[17] */ case 17: /* 30 means the index of regs[30] */ case 30: offset = offsetof(struct pt_regs, regs[index]); set_exception_context_register_asm(regs, offset, val); break; default: regs->regs[index] = val; } } } void sign_compat_exception_context(void *regs) { unsigned long irq_flags; local_irq_save(irq_flags); sign_compat_exception_context_asm(regs); local_irq_restore(irq_flags); } void auth_compat_exception_context(void *regs) { unsigned long irq_flags; local_irq_save(irq_flags); auth_compat_exception_context_asm(regs); local_irq_restore(irq_flags); } void sign_exception_context(void *regs) { unsigned long irq_flags; local_irq_save(irq_flags); if (compat_user_mode((struct pt_regs *)regs)) { sign_compat_exception_context_asm(regs); } else { sign_exception_context_asm(regs); } local_irq_restore(irq_flags); } void auth_exception_context(void *regs) { unsigned long irq_flags; local_irq_save(irq_flags); if (compat_user_mode((struct pt_regs *)regs)) { auth_compat_exception_context_asm(regs); } else { auth_exception_context_asm(regs); } local_irq_restore(irq_flags); }