1 #include <linux/module.h> 2 #include <asm/uaccess.h> 3 #include <asm/traps.h> 4 5 typedef bool (*ex_handler_t)(const struct exception_table_entry *, 6 struct pt_regs *, int); 7 8 static inline unsigned long 9 ex_fixup_addr(const struct exception_table_entry *x) 10 { 11 return (unsigned long)&x->fixup + x->fixup; 12 } 13 static inline ex_handler_t 14 ex_fixup_handler(const struct exception_table_entry *x) 15 { 16 return (ex_handler_t)((unsigned long)&x->handler + x->handler); 17 } 18 19 bool ex_handler_default(const struct exception_table_entry *fixup, 20 struct pt_regs *regs, int trapnr) 21 { 22 regs->ip = ex_fixup_addr(fixup); 23 return true; 24 } 25 EXPORT_SYMBOL(ex_handler_default); 26 27 bool ex_handler_fault(const struct exception_table_entry *fixup, 28 struct pt_regs *regs, int trapnr) 29 { 30 regs->ip = ex_fixup_addr(fixup); 31 regs->ax = trapnr; 32 return true; 33 } 34 EXPORT_SYMBOL_GPL(ex_handler_fault); 35 36 bool ex_handler_ext(const struct exception_table_entry *fixup, 37 struct pt_regs *regs, int trapnr) 38 { 39 /* Special hack for uaccess_err */ 40 current_thread_info()->uaccess_err = 1; 41 regs->ip = ex_fixup_addr(fixup); 42 return true; 43 } 44 EXPORT_SYMBOL(ex_handler_ext); 45 46 bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup, 47 struct pt_regs *regs, int trapnr) 48 { 49 WARN_ONCE(1, "unchecked MSR access error: RDMSR from 0x%x\n", 50 (unsigned int)regs->cx); 51 52 /* Pretend that the read succeeded and returned 0. */ 53 regs->ip = ex_fixup_addr(fixup); 54 regs->ax = 0; 55 regs->dx = 0; 56 return true; 57 } 58 EXPORT_SYMBOL(ex_handler_rdmsr_unsafe); 59 60 bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup, 61 struct pt_regs *regs, int trapnr) 62 { 63 WARN_ONCE(1, "unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x)\n", 64 (unsigned int)regs->cx, 65 (unsigned int)regs->dx, (unsigned int)regs->ax); 66 67 /* Pretend that the write succeeded. */ 68 regs->ip = ex_fixup_addr(fixup); 69 return true; 70 } 71 EXPORT_SYMBOL(ex_handler_wrmsr_unsafe); 72 73 bool ex_handler_clear_fs(const struct exception_table_entry *fixup, 74 struct pt_regs *regs, int trapnr) 75 { 76 if (static_cpu_has(X86_BUG_NULL_SEG)) 77 asm volatile ("mov %0, %%fs" : : "rm" (__USER_DS)); 78 asm volatile ("mov %0, %%fs" : : "rm" (0)); 79 return ex_handler_default(fixup, regs, trapnr); 80 } 81 EXPORT_SYMBOL(ex_handler_clear_fs); 82 83 bool ex_has_fault_handler(unsigned long ip) 84 { 85 const struct exception_table_entry *e; 86 ex_handler_t handler; 87 88 e = search_exception_tables(ip); 89 if (!e) 90 return false; 91 handler = ex_fixup_handler(e); 92 93 return handler == ex_handler_fault; 94 } 95 96 int fixup_exception(struct pt_regs *regs, int trapnr) 97 { 98 const struct exception_table_entry *e; 99 ex_handler_t handler; 100 101 #ifdef CONFIG_PNPBIOS 102 if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) { 103 extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp; 104 extern u32 pnp_bios_is_utter_crap; 105 pnp_bios_is_utter_crap = 1; 106 printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n"); 107 __asm__ volatile( 108 "movl %0, %%esp\n\t" 109 "jmp *%1\n\t" 110 : : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip)); 111 panic("do_trap: can't hit this"); 112 } 113 #endif 114 115 e = search_exception_tables(regs->ip); 116 if (!e) 117 return 0; 118 119 handler = ex_fixup_handler(e); 120 return handler(e, regs, trapnr); 121 } 122 123 extern unsigned int early_recursion_flag; 124 125 /* Restricted version used during very early boot */ 126 void __init early_fixup_exception(struct pt_regs *regs, int trapnr) 127 { 128 /* Ignore early NMIs. */ 129 if (trapnr == X86_TRAP_NMI) 130 return; 131 132 if (early_recursion_flag > 2) 133 goto halt_loop; 134 135 if (regs->cs != __KERNEL_CS) 136 goto fail; 137 138 /* 139 * The full exception fixup machinery is available as soon as 140 * the early IDT is loaded. This means that it is the 141 * responsibility of extable users to either function correctly 142 * when handlers are invoked early or to simply avoid causing 143 * exceptions before they're ready to handle them. 144 * 145 * This is better than filtering which handlers can be used, 146 * because refusing to call a handler here is guaranteed to 147 * result in a hard-to-debug panic. 148 * 149 * Keep in mind that not all vectors actually get here. Early 150 * fage faults, for example, are special. 151 */ 152 if (fixup_exception(regs, trapnr)) 153 return; 154 155 fail: 156 early_printk("PANIC: early exception 0x%02x IP %lx:%lx error %lx cr2 0x%lx\n", 157 (unsigned)trapnr, (unsigned long)regs->cs, regs->ip, 158 regs->orig_ax, read_cr2()); 159 160 show_regs(regs); 161 162 halt_loop: 163 while (true) 164 halt(); 165 } 166