162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci#ifndef __ASM_ASM_EXTABLE_H
362306a36Sopenharmony_ci#define __ASM_ASM_EXTABLE_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/bits.h>
662306a36Sopenharmony_ci#include <asm/gpr-num.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define EX_TYPE_NONE			0
962306a36Sopenharmony_ci#define EX_TYPE_BPF			1
1062306a36Sopenharmony_ci#define EX_TYPE_UACCESS_ERR_ZERO	2
1162306a36Sopenharmony_ci#define EX_TYPE_KACCESS_ERR_ZERO	3
1262306a36Sopenharmony_ci#define EX_TYPE_LOAD_UNALIGNED_ZEROPAD	4
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/* Data fields for EX_TYPE_UACCESS_ERR_ZERO */
1562306a36Sopenharmony_ci#define EX_DATA_REG_ERR_SHIFT	0
1662306a36Sopenharmony_ci#define EX_DATA_REG_ERR		GENMASK(4, 0)
1762306a36Sopenharmony_ci#define EX_DATA_REG_ZERO_SHIFT	5
1862306a36Sopenharmony_ci#define EX_DATA_REG_ZERO	GENMASK(9, 5)
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* Data fields for EX_TYPE_LOAD_UNALIGNED_ZEROPAD */
2162306a36Sopenharmony_ci#define EX_DATA_REG_DATA_SHIFT	0
2262306a36Sopenharmony_ci#define EX_DATA_REG_DATA	GENMASK(4, 0)
2362306a36Sopenharmony_ci#define EX_DATA_REG_ADDR_SHIFT	5
2462306a36Sopenharmony_ci#define EX_DATA_REG_ADDR	GENMASK(9, 5)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#ifdef __ASSEMBLY__
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define __ASM_EXTABLE_RAW(insn, fixup, type, data)	\
2962306a36Sopenharmony_ci	.pushsection	__ex_table, "a";		\
3062306a36Sopenharmony_ci	.align		2;				\
3162306a36Sopenharmony_ci	.long		((insn) - .);			\
3262306a36Sopenharmony_ci	.long		((fixup) - .);			\
3362306a36Sopenharmony_ci	.short		(type);				\
3462306a36Sopenharmony_ci	.short		(data);				\
3562306a36Sopenharmony_ci	.popsection;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define EX_DATA_REG(reg, gpr)	\
3862306a36Sopenharmony_ci	(.L__gpr_num_##gpr << EX_DATA_REG_##reg##_SHIFT)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define _ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, zero)		\
4162306a36Sopenharmony_ci	__ASM_EXTABLE_RAW(insn, fixup, 					\
4262306a36Sopenharmony_ci			  EX_TYPE_UACCESS_ERR_ZERO,			\
4362306a36Sopenharmony_ci			  (						\
4462306a36Sopenharmony_ci			    EX_DATA_REG(ERR, err) |			\
4562306a36Sopenharmony_ci			    EX_DATA_REG(ZERO, zero)			\
4662306a36Sopenharmony_ci			  ))
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define _ASM_EXTABLE_UACCESS_ERR(insn, fixup, err)			\
4962306a36Sopenharmony_ci	_ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, wzr)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define _ASM_EXTABLE_UACCESS(insn, fixup)				\
5262306a36Sopenharmony_ci	_ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, wzr, wzr)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/*
5562306a36Sopenharmony_ci * Create an exception table entry for uaccess `insn`, which will branch to `fixup`
5662306a36Sopenharmony_ci * when an unhandled fault is taken.
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ci	.macro          _asm_extable_uaccess, insn, fixup
5962306a36Sopenharmony_ci	_ASM_EXTABLE_UACCESS(\insn, \fixup)
6062306a36Sopenharmony_ci	.endm
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/*
6362306a36Sopenharmony_ci * Create an exception table entry for `insn` if `fixup` is provided. Otherwise
6462306a36Sopenharmony_ci * do nothing.
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_ci	.macro		_cond_uaccess_extable, insn, fixup
6762306a36Sopenharmony_ci	.ifnc			\fixup,
6862306a36Sopenharmony_ci	_asm_extable_uaccess	\insn, \fixup
6962306a36Sopenharmony_ci	.endif
7062306a36Sopenharmony_ci	.endm
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#else /* __ASSEMBLY__ */
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#include <linux/stringify.h>
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define __ASM_EXTABLE_RAW(insn, fixup, type, data)	\
7762306a36Sopenharmony_ci	".pushsection	__ex_table, \"a\"\n"		\
7862306a36Sopenharmony_ci	".align		2\n"				\
7962306a36Sopenharmony_ci	".long		((" insn ") - .)\n"		\
8062306a36Sopenharmony_ci	".long		((" fixup ") - .)\n"		\
8162306a36Sopenharmony_ci	".short		(" type ")\n"			\
8262306a36Sopenharmony_ci	".short		(" data ")\n"			\
8362306a36Sopenharmony_ci	".popsection\n"
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define EX_DATA_REG(reg, gpr)						\
8662306a36Sopenharmony_ci	"((.L__gpr_num_" #gpr ") << " __stringify(EX_DATA_REG_##reg##_SHIFT) ")"
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define _ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, zero)		\
8962306a36Sopenharmony_ci	__DEFINE_ASM_GPR_NUMS						\
9062306a36Sopenharmony_ci	__ASM_EXTABLE_RAW(#insn, #fixup, 				\
9162306a36Sopenharmony_ci			  __stringify(EX_TYPE_UACCESS_ERR_ZERO),	\
9262306a36Sopenharmony_ci			  "("						\
9362306a36Sopenharmony_ci			    EX_DATA_REG(ERR, err) " | "			\
9462306a36Sopenharmony_ci			    EX_DATA_REG(ZERO, zero)			\
9562306a36Sopenharmony_ci			  ")")
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define _ASM_EXTABLE_KACCESS_ERR_ZERO(insn, fixup, err, zero)		\
9862306a36Sopenharmony_ci	__DEFINE_ASM_GPR_NUMS						\
9962306a36Sopenharmony_ci	__ASM_EXTABLE_RAW(#insn, #fixup, 				\
10062306a36Sopenharmony_ci			  __stringify(EX_TYPE_KACCESS_ERR_ZERO),	\
10162306a36Sopenharmony_ci			  "("						\
10262306a36Sopenharmony_ci			    EX_DATA_REG(ERR, err) " | "			\
10362306a36Sopenharmony_ci			    EX_DATA_REG(ZERO, zero)			\
10462306a36Sopenharmony_ci			  ")")
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#define _ASM_EXTABLE_UACCESS_ERR(insn, fixup, err)			\
10762306a36Sopenharmony_ci	_ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, wzr)
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define _ASM_EXTABLE_UACCESS(insn, fixup)				\
11062306a36Sopenharmony_ci	_ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, wzr, wzr)
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#define _ASM_EXTABLE_KACCESS_ERR(insn, fixup, err)			\
11362306a36Sopenharmony_ci	_ASM_EXTABLE_KACCESS_ERR_ZERO(insn, fixup, err, wzr)
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci#define _ASM_EXTABLE_LOAD_UNALIGNED_ZEROPAD(insn, fixup, data, addr)		\
11662306a36Sopenharmony_ci	__DEFINE_ASM_GPR_NUMS							\
11762306a36Sopenharmony_ci	__ASM_EXTABLE_RAW(#insn, #fixup,					\
11862306a36Sopenharmony_ci			  __stringify(EX_TYPE_LOAD_UNALIGNED_ZEROPAD),		\
11962306a36Sopenharmony_ci			  "("							\
12062306a36Sopenharmony_ci			    EX_DATA_REG(DATA, data) " | "			\
12162306a36Sopenharmony_ci			    EX_DATA_REG(ADDR, addr)				\
12262306a36Sopenharmony_ci			  ")")
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#endif /* __ASM_ASM_EXTABLE_H */
127