Merge remote-tracking branch 'asoc/topic/tas5270' into asoc-next
[cascardo/linux.git] / arch / x86 / mm / extable.c
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 }