Commit | Line | Data |
---|---|---|
6d48583b HH |
1 | #include <linux/module.h> |
2 | #include <linux/spinlock.h> | |
3 | #include <asm/uaccess.h> | |
4 | ||
5 | ||
6 | int fixup_exception(struct pt_regs *regs) | |
7 | { | |
8 | const struct exception_table_entry *fixup; | |
9 | ||
10 | #ifdef CONFIG_PNPBIOS | |
11 | if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) { | |
12 | extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp; | |
13 | extern u32 pnp_bios_is_utter_crap; | |
14 | pnp_bios_is_utter_crap = 1; | |
15 | printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n"); | |
16 | __asm__ volatile( | |
17 | "movl %0, %%esp\n\t" | |
18 | "jmp *%1\n\t" | |
19 | : : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip)); | |
20 | panic("do_trap: can't hit this"); | |
21 | } | |
22 | #endif | |
23 | ||
24 | fixup = search_exception_tables(regs->ip); | |
25 | if (fixup) { | |
26 | regs->ip = fixup->fixup; | |
27 | return 1; | |
28 | } | |
29 | ||
30 | return 0; | |
31 | } | |
32 | ||
33 | #ifdef CONFIG_X86_64 | |
34 | /* | |
35 | * Need to defined our own search_extable on X86_64 to work around | |
36 | * a B stepping K8 bug. | |
37 | */ | |
38 | const struct exception_table_entry * | |
39 | search_extable(const struct exception_table_entry *first, | |
40 | const struct exception_table_entry *last, | |
41 | unsigned long value) | |
42 | { | |
43 | /* B stepping K8 bug */ | |
44 | if ((value >> 32) == 0) | |
45 | value |= 0xffffffffUL << 32; | |
46 | ||
47 | while (first <= last) { | |
48 | const struct exception_table_entry *mid; | |
49 | long diff; | |
50 | ||
51 | mid = (last - first) / 2 + first; | |
52 | diff = mid->insn - value; | |
53 | if (diff == 0) | |
54 | return mid; | |
55 | else if (diff < 0) | |
56 | first = mid+1; | |
57 | else | |
58 | last = mid-1; | |
59 | } | |
60 | return NULL; | |
61 | } | |
62 | #endif |