linux/arch/x86/mm/extable.c
<<
>>
Prefs
   1#include <linux/module.h>
   2#include <linux/spinlock.h>
   3#include <asm/uaccess.h>
   4
   5
   6int 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                /* If fixup is less than 16, it means uaccess error */
  27                if (fixup->fixup < 16) {
  28                        current_thread_info()->uaccess_err = -EFAULT;
  29                        regs->ip += fixup->fixup;
  30                        return 1;
  31                }
  32                regs->ip = fixup->fixup;
  33                return 1;
  34        }
  35
  36        return 0;
  37}
  38
  39#ifdef CONFIG_X86_64
  40/*
  41 * Need to defined our own search_extable on X86_64 to work around
  42 * a B stepping K8 bug.
  43 */
  44const struct exception_table_entry *
  45search_extable(const struct exception_table_entry *first,
  46               const struct exception_table_entry *last,
  47               unsigned long value)
  48{
  49        /* B stepping K8 bug */
  50        if ((value >> 32) == 0)
  51                value |= 0xffffffffUL << 32;
  52
  53        while (first <= last) {
  54                const struct exception_table_entry *mid;
  55                long diff;
  56
  57                mid = (last - first) / 2 + first;
  58                diff = mid->insn - value;
  59                if (diff == 0)
  60                        return mid;
  61                else if (diff < 0)
  62                        first = mid+1;
  63                else
  64                        last = mid-1;
  65        }
  66        return NULL;
  67}
  68#endif
  69
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.