1419b0af8Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2419b0af8Sopenharmony_ci/*
3419b0af8Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
4419b0af8Sopenharmony_ci */
5419b0af8Sopenharmony_ci
6419b0af8Sopenharmony_ci#include <asm/asm-offsets.h>
7419b0af8Sopenharmony_ci#include <asm/ptrace.h>
8419b0af8Sopenharmony_ci#include <linux/irqflags.h>
9419b0af8Sopenharmony_ci
10419b0af8Sopenharmony_ci/* The members of arrays below are corresponding to the enum defined in pointer_auth_context.h:
11419b0af8Sopenharmony_ci * enum pac_pt_regs {
12419b0af8Sopenharmony_ci *   REGS_X16 = 0,
13419b0af8Sopenharmony_ci *   REGS_X17,
14419b0af8Sopenharmony_ci *   REGS_LR,
15419b0af8Sopenharmony_ci *   REGS_SP,
16419b0af8Sopenharmony_ci *   REGS_PC,
17419b0af8Sopenharmony_ci *   REGS_PSTATE,
18419b0af8Sopenharmony_ci * };
19419b0af8Sopenharmony_ci *
20419b0af8Sopenharmony_ci * compat_regs_offset_array[]:
21419b0af8Sopenharmony_ci *   S_X14: the offset of compat_lr
22419b0af8Sopenharmony_ci *   S_X13: the offset of compat_sp
23419b0af8Sopenharmony_ci */
24419b0af8Sopenharmony_cistatic off_t compat_regs_offset_array[] = {0, 0, S_X14, S_X13, S_PC, S_PSTATE};
25419b0af8Sopenharmony_cistatic off_t regs_offset_array[] = {S_X16, S_X17, S_LR, S_SP, S_PC, S_PSTATE};
26419b0af8Sopenharmony_ci
27419b0af8Sopenharmony_ciint set_compat_exception_context_register(void *regs, enum pac_pt_regs regs_enum, u64 val)
28419b0af8Sopenharmony_ci{
29419b0af8Sopenharmony_ci	switch (regs_enum) {
30419b0af8Sopenharmony_ci	case REGS_LR:
31419b0af8Sopenharmony_ci	case REGS_SP:
32419b0af8Sopenharmony_ci	case REGS_PC:
33419b0af8Sopenharmony_ci	case REGS_PSTATE:
34419b0af8Sopenharmony_ci		return set_compat_exception_context_register_asm(regs, compat_regs_offset_array[regs_enum], val);
35419b0af8Sopenharmony_ci	default:
36419b0af8Sopenharmony_ci		return -EINVAL;
37419b0af8Sopenharmony_ci	}
38419b0af8Sopenharmony_ci}
39419b0af8Sopenharmony_ci
40419b0af8Sopenharmony_ciint set_exception_context_register(void *regs, enum pac_pt_regs regs_enum, u64 val)
41419b0af8Sopenharmony_ci{
42419b0af8Sopenharmony_ci	if (compat_user_mode((struct pt_regs *)regs)) {
43419b0af8Sopenharmony_ci		return set_compat_exception_context_register(regs, regs_enum, val);
44419b0af8Sopenharmony_ci	} else {
45419b0af8Sopenharmony_ci		switch (regs_enum) {
46419b0af8Sopenharmony_ci		case REGS_X16:
47419b0af8Sopenharmony_ci		case REGS_X17:
48419b0af8Sopenharmony_ci		case REGS_LR:
49419b0af8Sopenharmony_ci		case REGS_SP:
50419b0af8Sopenharmony_ci		case REGS_PC:
51419b0af8Sopenharmony_ci		case REGS_PSTATE:
52419b0af8Sopenharmony_ci			return set_exception_context_register_asm(regs, regs_offset_array[regs_enum], val);
53419b0af8Sopenharmony_ci		default:
54419b0af8Sopenharmony_ci			return -EINVAL;
55419b0af8Sopenharmony_ci		}
56419b0af8Sopenharmony_ci	}
57419b0af8Sopenharmony_ci}
58419b0af8Sopenharmony_ci
59419b0af8Sopenharmony_civoid set_compat_exception_context_register_index(struct pt_regs *regs, int index, uint64_t val)
60419b0af8Sopenharmony_ci{
61419b0af8Sopenharmony_ci	/* 14 means the index of compat_lr */
62419b0af8Sopenharmony_ci	if (index == 14) {
63419b0af8Sopenharmony_ci		set_compat_exception_context_register_asm(regs, S_X14, val);
64419b0af8Sopenharmony_ci	/* 13 means the index of compat_sp */
65419b0af8Sopenharmony_ci	} else if (index == 13) {
66419b0af8Sopenharmony_ci		set_compat_exception_context_register_asm(regs, S_X13, val);
67419b0af8Sopenharmony_ci	} else {
68419b0af8Sopenharmony_ci		regs->regs[index] = val;
69419b0af8Sopenharmony_ci	}
70419b0af8Sopenharmony_ci}
71419b0af8Sopenharmony_ci
72419b0af8Sopenharmony_civoid set_exception_context_register_index(struct pt_regs *regs, int index, uint64_t val)
73419b0af8Sopenharmony_ci{
74419b0af8Sopenharmony_ci	off_t offset;
75419b0af8Sopenharmony_ci
76419b0af8Sopenharmony_ci	if (compat_user_mode(regs)) {
77419b0af8Sopenharmony_ci		set_compat_exception_context_register_index(regs, index, val);
78419b0af8Sopenharmony_ci	} else {
79419b0af8Sopenharmony_ci		switch (index) {
80419b0af8Sopenharmony_ci		/* 16 means the index of regs[16] */
81419b0af8Sopenharmony_ci		case 16:
82419b0af8Sopenharmony_ci		/* 17 means the index of regs[17] */
83419b0af8Sopenharmony_ci		case 17:
84419b0af8Sopenharmony_ci		/* 30 means the index of regs[30] */
85419b0af8Sopenharmony_ci		case 30:
86419b0af8Sopenharmony_ci			offset = offsetof(struct pt_regs, regs[index]);
87419b0af8Sopenharmony_ci			set_exception_context_register_asm(regs, offset, val);
88419b0af8Sopenharmony_ci			break;
89419b0af8Sopenharmony_ci		default:
90419b0af8Sopenharmony_ci			regs->regs[index] = val;
91419b0af8Sopenharmony_ci		}
92419b0af8Sopenharmony_ci	}
93419b0af8Sopenharmony_ci}
94419b0af8Sopenharmony_ci
95419b0af8Sopenharmony_civoid sign_compat_exception_context(void *regs)
96419b0af8Sopenharmony_ci{
97419b0af8Sopenharmony_ci	unsigned long irq_flags;
98419b0af8Sopenharmony_ci	local_irq_save(irq_flags);
99419b0af8Sopenharmony_ci	sign_compat_exception_context_asm(regs);
100419b0af8Sopenharmony_ci	local_irq_restore(irq_flags);
101419b0af8Sopenharmony_ci}
102419b0af8Sopenharmony_ci
103419b0af8Sopenharmony_civoid auth_compat_exception_context(void *regs)
104419b0af8Sopenharmony_ci{
105419b0af8Sopenharmony_ci	unsigned long irq_flags;
106419b0af8Sopenharmony_ci	local_irq_save(irq_flags);
107419b0af8Sopenharmony_ci	auth_compat_exception_context_asm(regs);
108419b0af8Sopenharmony_ci	local_irq_restore(irq_flags);
109419b0af8Sopenharmony_ci}
110419b0af8Sopenharmony_ci
111419b0af8Sopenharmony_civoid sign_exception_context(void *regs)
112419b0af8Sopenharmony_ci{
113419b0af8Sopenharmony_ci	unsigned long irq_flags;
114419b0af8Sopenharmony_ci	local_irq_save(irq_flags);
115419b0af8Sopenharmony_ci	if (compat_user_mode((struct pt_regs *)regs)) {
116419b0af8Sopenharmony_ci		sign_compat_exception_context_asm(regs);
117419b0af8Sopenharmony_ci	} else {
118419b0af8Sopenharmony_ci		sign_exception_context_asm(regs);
119419b0af8Sopenharmony_ci	}
120419b0af8Sopenharmony_ci	local_irq_restore(irq_flags);
121419b0af8Sopenharmony_ci}
122419b0af8Sopenharmony_ci
123419b0af8Sopenharmony_civoid auth_exception_context(void *regs)
124419b0af8Sopenharmony_ci{
125419b0af8Sopenharmony_ci	unsigned long irq_flags;
126419b0af8Sopenharmony_ci	local_irq_save(irq_flags);
127419b0af8Sopenharmony_ci	if (compat_user_mode((struct pt_regs *)regs)) {
128419b0af8Sopenharmony_ci		auth_compat_exception_context_asm(regs);
129419b0af8Sopenharmony_ci	} else {
130419b0af8Sopenharmony_ci		auth_exception_context_asm(regs);
131419b0af8Sopenharmony_ci	}
132419b0af8Sopenharmony_ci	local_irq_restore(irq_flags);
133419b0af8Sopenharmony_ci}
134