Files
kernel_linux_common_modules/pac/src/pointer_auth_context.c
T
2024-01-15 21:06:11 +08:00

134 lines
3.2 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#include <asm/asm-offsets.h>
#include <asm/ptrace.h>
#include <linux/irqflags.h>
/* 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);
}