extable.c 1.3 KB

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