162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_EXTABLE_H
362306a36Sopenharmony_ci#define _ASM_EXTABLE_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * About the exception table:
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * - insn is a 32-bit pc-relative offset from the faulting insn.
962306a36Sopenharmony_ci * - nextinsn is a 16-bit offset off of the faulting instruction
1062306a36Sopenharmony_ci *   (not off of the *next* instruction as branches are).
1162306a36Sopenharmony_ci * - errreg is the register in which to place -EFAULT.
1262306a36Sopenharmony_ci * - valreg is the final target register for the load sequence
1362306a36Sopenharmony_ci *   and will be zeroed.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * Either errreg or valreg may be $31, in which case nothing happens.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * The exception fixup information "just so happens" to be arranged
1862306a36Sopenharmony_ci * as in a MEM format instruction.  This lets us emit our three
1962306a36Sopenharmony_ci * values like so:
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci *      lda valreg, nextinsn(errreg)
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct exception_table_entry
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	signed int insn;
2862306a36Sopenharmony_ci	union exception_fixup {
2962306a36Sopenharmony_ci		unsigned unit;
3062306a36Sopenharmony_ci		struct {
3162306a36Sopenharmony_ci			signed int nextinsn : 16;
3262306a36Sopenharmony_ci			unsigned int errreg : 5;
3362306a36Sopenharmony_ci			unsigned int valreg : 5;
3462306a36Sopenharmony_ci		} bits;
3562306a36Sopenharmony_ci	} fixup;
3662306a36Sopenharmony_ci};
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* Returns the new pc */
3962306a36Sopenharmony_ci#define fixup_exception(map_reg, _fixup, pc)			\
4062306a36Sopenharmony_ci({								\
4162306a36Sopenharmony_ci	if ((_fixup)->fixup.bits.valreg != 31)			\
4262306a36Sopenharmony_ci		map_reg((_fixup)->fixup.bits.valreg) = 0;	\
4362306a36Sopenharmony_ci	if ((_fixup)->fixup.bits.errreg != 31)			\
4462306a36Sopenharmony_ci		map_reg((_fixup)->fixup.bits.errreg) = -EFAULT;	\
4562306a36Sopenharmony_ci	(pc) + (_fixup)->fixup.bits.nextinsn;			\
4662306a36Sopenharmony_ci})
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define ARCH_HAS_RELATIVE_EXTABLE
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define swap_ex_entry_fixup(a, b, tmp, delta)			\
5162306a36Sopenharmony_ci	do {							\
5262306a36Sopenharmony_ci		(a)->fixup.unit = (b)->fixup.unit;		\
5362306a36Sopenharmony_ci		(b)->fixup.unit = (tmp).fixup.unit;		\
5462306a36Sopenharmony_ci	} while (0)
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#endif
57