extable.c 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  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. /* If fixup is less than 16, it means uaccess error */
  23. if (fixup->fixup < 16) {
  24. current_thread_info()->uaccess_err = -EFAULT;
  25. regs->ip += fixup->fixup;
  26. return 1;
  27. }
  28. regs->ip = fixup->fixup;
  29. return 1;
  30. }
  31. return 0;
  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. while (first <= last) {
  47. const struct exception_table_entry *mid;
  48. long diff;
  49. mid = (last - first) / 2 + first;
  50. diff = mid->insn - value;
  51. if (diff == 0)
  52. return mid;
  53. else if (diff < 0)
  54. first = mid+1;
  55. else
  56. last = mid-1;
  57. }
  58. return NULL;
  59. }
  60. #endif