18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/sparc/mm/extable.c 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/extable.h> 88c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_civoid sort_extable(struct exception_table_entry *start, 118c2ecf20Sopenharmony_ci struct exception_table_entry *finish) 128c2ecf20Sopenharmony_ci{ 138c2ecf20Sopenharmony_ci} 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* Caller knows they are in a range if ret->fixup == 0 */ 168c2ecf20Sopenharmony_ciconst struct exception_table_entry * 178c2ecf20Sopenharmony_cisearch_extable(const struct exception_table_entry *base, 188c2ecf20Sopenharmony_ci const size_t num, 198c2ecf20Sopenharmony_ci unsigned long value) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci int i; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci /* Single insn entries are encoded as: 248c2ecf20Sopenharmony_ci * word 1: insn address 258c2ecf20Sopenharmony_ci * word 2: fixup code address 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * Range entries are encoded as: 288c2ecf20Sopenharmony_ci * word 1: first insn address 298c2ecf20Sopenharmony_ci * word 2: 0 308c2ecf20Sopenharmony_ci * word 3: last insn address + 4 bytes 318c2ecf20Sopenharmony_ci * word 4: fixup code address 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Deleted entries are encoded as: 348c2ecf20Sopenharmony_ci * word 1: unused 358c2ecf20Sopenharmony_ci * word 2: -1 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * See asm/uaccess.h for more details. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci /* 1. Try to find an exact match. */ 418c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 428c2ecf20Sopenharmony_ci if (base[i].fixup == 0) { 438c2ecf20Sopenharmony_ci /* A range entry, skip both parts. */ 448c2ecf20Sopenharmony_ci i++; 458c2ecf20Sopenharmony_ci continue; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* A deleted entry; see trim_init_extable */ 498c2ecf20Sopenharmony_ci if (base[i].fixup == -1) 508c2ecf20Sopenharmony_ci continue; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (base[i].insn == value) 538c2ecf20Sopenharmony_ci return &base[i]; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* 2. Try to find a range match. */ 578c2ecf20Sopenharmony_ci for (i = 0; i < (num - 1); i++) { 588c2ecf20Sopenharmony_ci if (base[i].fixup) 598c2ecf20Sopenharmony_ci continue; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (base[i].insn <= value && base[i + 1].insn > value) 628c2ecf20Sopenharmony_ci return &base[i]; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci i++; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return NULL; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#ifdef CONFIG_MODULES 718c2ecf20Sopenharmony_ci/* We could memmove them around; easier to mark the trimmed ones. */ 728c2ecf20Sopenharmony_civoid trim_init_extable(struct module *m) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci unsigned int i; 758c2ecf20Sopenharmony_ci bool range; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci for (i = 0; i < m->num_exentries; i += range ? 2 : 1) { 788c2ecf20Sopenharmony_ci range = m->extable[i].fixup == 0; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (within_module_init(m->extable[i].insn, m)) { 818c2ecf20Sopenharmony_ci m->extable[i].fixup = -1; 828c2ecf20Sopenharmony_ci if (range) 838c2ecf20Sopenharmony_ci m->extable[i+1].fixup = -1; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci if (range) 868c2ecf20Sopenharmony_ci i++; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci#endif /* CONFIG_MODULES */ 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/* Special extable search, which handles ranges. Returns fixup */ 928c2ecf20Sopenharmony_ciunsigned long search_extables_range(unsigned long addr, unsigned long *g2) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci const struct exception_table_entry *entry; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci entry = search_exception_tables(addr); 978c2ecf20Sopenharmony_ci if (!entry) 988c2ecf20Sopenharmony_ci return 0; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* Inside range? Fix g2 and return correct fixup */ 1018c2ecf20Sopenharmony_ci if (!entry->fixup) { 1028c2ecf20Sopenharmony_ci *g2 = (addr - entry->insn) / 4; 1038c2ecf20Sopenharmony_ci return (entry + 1)->fixup; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return entry->fixup; 1078c2ecf20Sopenharmony_ci} 108