extable.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #include <linux/module.h>
  2. #include <asm/uaccess.h>
  3. typedef bool (*ex_handler_t)(const struct exception_table_entry *,
  4. struct pt_regs *, int);
  5. static inline unsigned long
  6. ex_fixup_addr(const struct exception_table_entry *x)
  7. {
  8. return (unsigned long)&x->fixup + x->fixup;
  9. }
  10. static inline ex_handler_t
  11. ex_fixup_handler(const struct exception_table_entry *x)
  12. {
  13. return (ex_handler_t)((unsigned long)&x->handler + x->handler);
  14. }
  15. bool ex_handler_default(const struct exception_table_entry *fixup,
  16. struct pt_regs *regs, int trapnr)
  17. {
  18. regs->ip = ex_fixup_addr(fixup);
  19. return true;
  20. }
  21. EXPORT_SYMBOL(ex_handler_default);
  22. bool ex_handler_fault(const struct exception_table_entry *fixup,
  23. struct pt_regs *regs, int trapnr)
  24. {
  25. regs->ip = ex_fixup_addr(fixup);
  26. regs->ax = trapnr;
  27. return true;
  28. }
  29. EXPORT_SYMBOL_GPL(ex_handler_fault);
  30. bool ex_handler_ext(const struct exception_table_entry *fixup,
  31. struct pt_regs *regs, int trapnr)
  32. {
  33. /* Special hack for uaccess_err */
  34. current_thread_info()->uaccess_err = 1;
  35. regs->ip = ex_fixup_addr(fixup);
  36. return true;
  37. }
  38. EXPORT_SYMBOL(ex_handler_ext);
  39. bool ex_has_fault_handler(unsigned long ip)
  40. {
  41. const struct exception_table_entry *e;
  42. ex_handler_t handler;
  43. e = search_exception_tables(ip);
  44. if (!e)
  45. return false;
  46. handler = ex_fixup_handler(e);
  47. return handler == ex_handler_fault;
  48. }
  49. int fixup_exception(struct pt_regs *regs, int trapnr)
  50. {
  51. const struct exception_table_entry *e;
  52. ex_handler_t handler;
  53. #ifdef CONFIG_PNPBIOS
  54. if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
  55. extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
  56. extern u32 pnp_bios_is_utter_crap;
  57. pnp_bios_is_utter_crap = 1;
  58. printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n");
  59. __asm__ volatile(
  60. "movl %0, %%esp\n\t"
  61. "jmp *%1\n\t"
  62. : : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip));
  63. panic("do_trap: can't hit this");
  64. }
  65. #endif
  66. e = search_exception_tables(regs->ip);
  67. if (!e)
  68. return 0;
  69. handler = ex_fixup_handler(e);
  70. return handler(e, regs, trapnr);
  71. }
  72. /* Restricted version used during very early boot */
  73. int __init early_fixup_exception(unsigned long *ip)
  74. {
  75. const struct exception_table_entry *e;
  76. unsigned long new_ip;
  77. ex_handler_t handler;
  78. e = search_exception_tables(*ip);
  79. if (!e)
  80. return 0;
  81. new_ip = ex_fixup_addr(e);
  82. handler = ex_fixup_handler(e);
  83. /* special handling not supported during early boot */
  84. if (handler != ex_handler_default)
  85. return 0;
  86. *ip = new_ip;
  87. return 1;
  88. }