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 sort_extable(struct exception_table_entry * start,struct exception_table_entry * finish)10 void 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 */ 16 const struct exception_table_entry * search_extable(const struct exception_table_entry * base,const size_t num,unsigned long value)17 search_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. */ trim_init_extable(struct module * m)72 void 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 */ search_extables_range(unsigned long addr,unsigned long * g2)92 unsigned 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