1 #include <linux/module.h> 2 #include <asm/uaccess.h> 3 4 typedef bool (*ex_handler_t)(const struct exception_table_entry *, 5 struct pt_regs *, int); 6 7 static inline unsigned long 8 ex_fixup_addr(const struct exception_table_entry *x) 9 { 10 return (unsigned long)&x->fixup + x->fixup; 11 } 12 static inline ex_handler_t 13 ex_fixup_handler(const struct exception_table_entry *x) 14 { 15 return (ex_handler_t)((unsigned long)&x->handler + x->handler); 16 } 17 18 bool ex_handler_default(const struct exception_table_entry *fixup, 19 struct pt_regs *regs, int trapnr) 20 { 21 regs->ip = ex_fixup_addr(fixup); 22 return true; 23 } 24 EXPORT_SYMBOL(ex_handler_default); 25 26 bool ex_handler_fault(const struct exception_table_entry *fixup, 27 struct pt_regs *regs, int trapnr) 28 { 29 regs->ip = ex_fixup_addr(fixup); 30 regs->ax = trapnr; 31 return true; 32 } 33 EXPORT_SYMBOL_GPL(ex_handler_fault); 34 35 bool ex_handler_ext(const struct exception_table_entry *fixup, 36 struct pt_regs *regs, int trapnr) 37 { 38 /* Special hack for uaccess_err */ 39 current_thread_info()->uaccess_err = 1; 40 regs->ip = ex_fixup_addr(fixup); 41 return true; 42 } 43 EXPORT_SYMBOL(ex_handler_ext); 44 45 bool ex_has_fault_handler(unsigned long ip) 46 { 47 const struct exception_table_entry *e; 48 ex_handler_t handler; 49 50 e = search_exception_tables(ip); 51 if (!e) 52 return false; 53 handler = ex_fixup_handler(e); 54 55 return handler == ex_handler_fault; 56 } 57 58 int fixup_exception(struct pt_regs *regs, int trapnr) 59 { 60 const struct exception_table_entry *e; 61 ex_handler_t handler; 62 63 #ifdef CONFIG_PNPBIOS 64 if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) { 65 extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp; 66 extern u32 pnp_bios_is_utter_crap; 67 pnp_bios_is_utter_crap = 1; 68 printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n"); 69 __asm__ volatile( 70 "movl %0, %%esp\n\t" 71 "jmp *%1\n\t" 72 : : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip)); 73 panic("do_trap: can't hit this"); 74 } 75 #endif 76 77 e = search_exception_tables(regs->ip); 78 if (!e) 79 return 0; 80 81 handler = ex_fixup_handler(e); 82 return handler(e, regs, trapnr); 83 } 84 85 /* Restricted version used during very early boot */ 86 int __init early_fixup_exception(unsigned long *ip) 87 { 88 const struct exception_table_entry *e; 89 unsigned long new_ip; 90 ex_handler_t handler; 91 92 e = search_exception_tables(*ip); 93 if (!e) 94 return 0; 95 96 new_ip = ex_fixup_addr(e); 97 handler = ex_fixup_handler(e); 98 99 /* special handling not supported during early boot */ 100 if (handler != ex_handler_default) 101 return 0; 102 103 *ip = new_ip; 104 return 1; 105 } 106