1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se> 4 * 5 * (C) Copyright 2000 6 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 7 */ 8 #include <common.h> 9 10 /* 11 * The exception table consists of pairs of addresses: the first is the 12 * address of an instruction that is allowed to fault, and the second is 13 * the address at which the program should continue. No registers are 14 * modified, so it is entirely up to the continuation code to figure out 15 * what to do. 16 * 17 * All the routines below use bits of fixup code that are out of line 18 * with the main instruction path. This means when everything is well, 19 * we don't even have to jump over them. Further, they do not intrude 20 * on our cache or tlb entries. 21 */ 22 23 struct exception_table_entry 24 { 25 unsigned long insn, fixup; 26 }; 27 28 extern const struct exception_table_entry __start___ex_table[]; 29 extern const struct exception_table_entry __stop___ex_table[]; 30 31 static inline unsigned long 32 search_one_table(const struct exception_table_entry *first, 33 const struct exception_table_entry *last, 34 unsigned long value) 35 { 36 long diff; 37 while (first <= last) { 38 diff = first->insn - value; 39 if (diff == 0) 40 return first->fixup; 41 first++; 42 } 43 44 return 0; 45 } 46 47 unsigned long 48 search_exception_table(unsigned long addr) 49 { 50 unsigned long ret; 51 52 /* There is only the kernel to search. */ 53 ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); 54 /* if the serial port does not hang in exception, printf can be used */ 55 #if !defined(CONFIG_SYS_SERIAL_HANG_IN_EXCEPTION) 56 debug("Bus Fault @ 0x%08lx, fixup 0x%08lx\n", addr, ret); 57 #endif 58 if (ret) return ret; 59 60 return 0; 61 } 62