1/* 2 * linux/arch/x86_64/mm/extable.c 3 */ 4 5#include <linux/config.h> 6#include <linux/module.h> 7#include <linux/spinlock.h> 8#include <linux/init.h> 9#include <asm/uaccess.h> 10 11extern const struct exception_table_entry __start___ex_table[]; 12extern const struct exception_table_entry __stop___ex_table[]; 13 14static inline unsigned long 15search_one_table(const struct exception_table_entry *first, 16 const struct exception_table_entry *last, 17 unsigned long value) 18{ 19 while (first <= last) { 20 const struct exception_table_entry *mid; 21 long diff; 22 23 mid = (last - first) / 2 + first; 24 diff = mid->insn - value; 25 if (diff == 0) 26 return mid->fixup; 27 else if (diff < 0) 28 first = mid+1; 29 else 30 last = mid-1; 31 } 32 return 0; 33} 34 35extern spinlock_t modlist_lock; 36 37unsigned long 38search_exception_table(unsigned long addr) 39{ 40 unsigned long ret = 0; 41 unsigned long flags; 42 43 /* Workaround for an Opteron issue */ 44 if ((addr >> 32) == 0) 45 addr |= 0xffffffffUL << 32; 46 47#ifndef CONFIG_MODULES 48 /* There is only the kernel to search. */ 49 ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); 50 return ret; 51#else 52 /* The kernel is the last "module" -- no need to treat it special. */ 53 struct module *mp; 54 55 spin_lock_irqsave(&modlist_lock, flags); 56 for (mp = module_list; mp != NULL; mp = mp->next) { 57 if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING))) 58 continue; 59 ret = search_one_table(mp->ex_table_start, 60 mp->ex_table_end - 1, addr); 61 if (ret) 62 break; 63 } 64 spin_unlock_irqrestore(&modlist_lock, flags); 65 return ret; 66#endif 67} 68

