1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _ASM_EXTABLE_H 3 #define _ASM_EXTABLE_H 4 5 /* 6 * About the exception table: 7 * 8 * - insn is a 32-bit pc-relative offset from the faulting insn. 9 * - nextinsn is a 16-bit offset off of the faulting instruction 10 * (not off of the *next* instruction as branches are). 11 * - errreg is the register in which to place -EFAULT. 12 * - valreg is the final target register for the load sequence 13 * and will be zeroed. 14 * 15 * Either errreg or valreg may be $31, in which case nothing happens. 16 * 17 * The exception fixup information "just so happens" to be arranged 18 * as in a MEM format instruction. This lets us emit our three 19 * values like so: 20 * 21 * lda valreg, nextinsn(errreg) 22 * 23 */ 24 25 struct exception_table_entry 26 { 27 signed int insn; 28 union exception_fixup { 29 unsigned unit; 30 struct { 31 signed int nextinsn : 16; 32 unsigned int errreg : 5; 33 unsigned int valreg : 5; 34 } bits; 35 } fixup; 36 }; 37 38 /* Returns the new pc */ 39 #define fixup_exception(map_reg, _fixup, pc) \ 40 ({ \ 41 if ((_fixup)->fixup.bits.valreg != 31) \ 42 map_reg((_fixup)->fixup.bits.valreg) = 0; \ 43 if ((_fixup)->fixup.bits.errreg != 31) \ 44 map_reg((_fixup)->fixup.bits.errreg) = -EFAULT; \ 45 (pc) + (_fixup)->fixup.bits.nextinsn; \ 46 }) 47 48 #define ARCH_HAS_RELATIVE_EXTABLE 49 50 #define swap_ex_entry_fixup(a, b, tmp, delta) \ 51 do { \ 52 (a)->fixup.unit = (b)->fixup.unit; \ 53 (b)->fixup.unit = (tmp).fixup.unit; \ 54 } while (0) 55 56 #endif 57