b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 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 |