1// SPDX-License-Identifier: GPL-2.0 2/* 3 * linux/arch/sparc/mm/extable.c 4 */ 5 6#include <linux/module.h> 7#include <linux/extable.h> 8#include <linux/uaccess.h> 9 10void sort_extable(struct exception_table_entry *start, 11 struct exception_table_entry *finish) 12{ 13} 14 15/* Caller knows they are in a range if ret->fixup == 0 */ 16const struct exception_table_entry * 17search_extable(const struct exception_table_entry *base, 18 const size_t num, 19 unsigned long value) 20{ 21 int i; 22 23 /* Single insn entries are encoded as: 24 * word 1: insn address 25 * word 2: fixup code address 26 * 27 * Range entries are encoded as: 28 * word 1: first insn address 29 * word 2: 0 30 * word 3: last insn address + 4 bytes 31 * word 4: fixup code address 32 * 33 * Deleted entries are encoded as: 34 * word 1: unused 35 * word 2: -1 36 * 37 * See asm/uaccess.h for more details. 38 */ 39 40 /* 1. Try to find an exact match. */ 41 for (i = 0; i < num; i++) { 42 if (base[i].fixup == 0) { 43 /* A range entry, skip both parts. */ 44 i++; 45 continue; 46 } 47 48 /* A deleted entry; see trim_init_extable */ 49 if (base[i].fixup == -1) 50 continue; 51 52 if (base[i].insn == value) 53 return &base[i]; 54 } 55 56 /* 2. Try to find a range match. */ 57 for (i = 0; i < (num - 1); i++) { 58 if (base[i].fixup) 59 continue; 60 61 if (base[i].insn <= value && base[i + 1].insn > value) 62 return &base[i]; 63 64 i++; 65 } 66 67 return NULL; 68} 69 70#ifdef CONFIG_MODULES 71/* We could memmove them around; easier to mark the trimmed ones. */ 72void trim_init_extable(struct module *m) 73{ 74 unsigned int i; 75 bool range; 76 77 for (i = 0; i < m->num_exentries; i += range ? 2 : 1) { 78 range = m->extable[i].fixup == 0; 79 80 if (within_module_init(m->extable[i].insn, m)) { 81 m->extable[i].fixup = -1; 82 if (range) 83 m->extable[i+1].fixup = -1; 84 } 85 if (range) 86 i++; 87 } 88} 89#endif /* CONFIG_MODULES */ 90 91/* Special extable search, which handles ranges. Returns fixup */ 92unsigned long search_extables_range(unsigned long addr, unsigned long *g2) 93{ 94 const struct exception_table_entry *entry; 95 96 entry = search_exception_tables(addr); 97 if (!entry) 98 return 0; 99 100 /* Inside range? Fix g2 and return correct fixup */ 101 if (!entry->fixup) { 102 *g2 = (addr - entry->insn) / 4; 103 return (entry + 1)->fixup; 104 } 105 106 return entry->fixup; 107} 108