extable.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:2k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/arch/sparc/mm/extable.c
  3.  */
  4. #include <linux/config.h>
  5. #include <linux/module.h>
  6. #include <asm/uaccess.h>
  7. extern const struct exception_table_entry __start___ex_table[];
  8. extern const struct exception_table_entry __stop___ex_table[];
  9. static unsigned long
  10. search_one_table(const struct exception_table_entry *start,
  11.  const struct exception_table_entry *end,
  12.  unsigned long value, unsigned long *g2)
  13. {
  14. const struct exception_table_entry *walk;
  15. /* Single insn entries are encoded as:
  16.  * word 1: insn address
  17.  * word 2: fixup code address
  18.  *
  19.  * Range entries are encoded as:
  20.  * word 1: first insn address
  21.  * word 2: 0
  22.  * word 3: last insn address + 4 bytes
  23.  * word 4: fixup code address
  24.  *
  25.  * See asm/uaccess.h for more details.
  26.  */
  27. /* 1. Try to find an exact match. */
  28. for (walk = start; walk <= end; walk++) {
  29. if (walk->fixup == 0) {
  30. /* A range entry, skip both parts. */
  31. walk++;
  32. continue;
  33. }
  34. if (walk->insn == value)
  35. return walk->fixup;
  36. }
  37. /* 2. Try to find a range match. */
  38. for (walk = start; walk <= (end - 1); walk++) {
  39. if (walk->fixup)
  40. continue;
  41. if (walk[0].insn <= value &&
  42.     walk[1].insn > value) {
  43. *g2 = (value - walk[0].insn) / 4;
  44. return walk[1].fixup;
  45. }
  46. walk++;
  47. }
  48.         return 0;
  49. }
  50. extern spinlock_t modlist_lock;
  51. unsigned long
  52. search_exception_table(unsigned long addr, unsigned long *g2)
  53. {
  54. unsigned long ret = 0, flags;
  55. #ifndef CONFIG_MODULES
  56. /* There is only the kernel to search.  */
  57. ret = search_one_table(__start___ex_table,
  58.        __stop___ex_table-1, addr, g2);
  59. return ret;
  60. #else
  61. /* The kernel is the last "module" -- no need to treat it special.  */
  62. struct module *mp;
  63. spin_lock_irqsave(&modlist_lock, flags);
  64. for (mp = module_list; mp != NULL; mp = mp->next) {
  65. if (mp->ex_table_start == NULL || !(mp->flags & (MOD_RUNNING | MOD_INITIALIZING)))
  66. continue;
  67. ret = search_one_table(mp->ex_table_start,
  68.        mp->ex_table_end-1, addr, g2);
  69. if (ret)
  70. break;
  71. }
  72. spin_unlock_irqrestore(&modlist_lock, flags);
  73. return ret;
  74. #endif
  75. }