linux/arch/x86/mm/extable.c
<<
>>
Prefs
   1#include <linux/extable.h>
   2#include <asm/uaccess.h>
   3#include <asm/traps.h>
   4#include <asm/kdebug.h>
   5
   6typedef bool (*ex_handler_t)(const struct exception_table_entry *,
   7                            struct pt_regs *, int);
   8
   9static inline unsigned long
  10ex_fixup_addr(const struct exception_table_entry *x)
  11{
  12        return (unsigned long)&x->fixup + x->fixup;
  13}
  14static inline ex_handler_t
  15ex_fixup_handler(const struct exception_table_entry *x)
  16{
  17        return (ex_handler_t)((unsigned long)&x->handler + x->handler);
  18}
  19
  20bool ex_handler_default(const struct exception_table_entry *fixup,
  21                       struct pt_regs *regs, int trapnr)
  22{
  23        regs->ip = ex_fixup_addr(fixup);
  24        return true;
  25}
  26EXPORT_SYMBOL(ex_handler_default);
  27
  28bool ex_handler_fault(const struct exception_table_entry *fixup,
  29                     struct pt_regs *regs, int trapnr)
  30{
  31        regs->ip = ex_fixup_addr(fixup);
  32        regs->ax = trapnr;
  33        return true;
  34}
  35EXPORT_SYMBOL_GPL(ex_handler_fault);
  36
  37bool ex_handler_ext(const struct exception_table_entry *fixup,
  38                   struct pt_regs *regs, int trapnr)
  39{
  40        /* Special hack for uaccess_err */
  41        current->thread.uaccess_err = 1;
  42        regs->ip = ex_fixup_addr(fixup);
  43        return true;
  44}
  45EXPORT_SYMBOL(ex_handler_ext);
  46
  47bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup,
  48                             struct pt_regs *regs, int trapnr)
  49{
  50        if (pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pF)\n",
  51                         (unsigned int)regs->cx, regs->ip, (void *)regs->ip))
  52                show_stack_regs(regs);
  53
  54        /* Pretend that the read succeeded and returned 0. */
  55        regs->ip = ex_fixup_addr(fixup);
  56        regs->ax = 0;
  57        regs->dx = 0;
  58        return true;
  59}
  60EXPORT_SYMBOL(ex_handler_rdmsr_unsafe);
  61
  62bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup,
  63                             struct pt_regs *regs, int trapnr)
  64{
  65        if (pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pF)\n",
  66                         (unsigned int)regs->cx, (unsigned int)regs->dx,
  67                         (unsigned int)regs->ax,  regs->ip, (void *)regs->ip))
  68                show_stack_regs(regs);
  69
  70        /* Pretend that the write succeeded. */
  71        regs->ip = ex_fixup_addr(fixup);
  72        return true;
  73}
  74EXPORT_SYMBOL(ex_handler_wrmsr_unsafe);
  75
  76bool ex_handler_clear_fs(const struct exception_table_entry *fixup,
  77                         struct pt_regs *regs, int trapnr)
  78{
  79        if (static_cpu_has(X86_BUG_NULL_SEG))
  80                asm volatile ("mov %0, %%fs" : : "rm" (__USER_DS));
  81        asm volatile ("mov %0, %%fs" : : "rm" (0));
  82        return ex_handler_default(fixup, regs, trapnr);
  83}
  84EXPORT_SYMBOL(ex_handler_clear_fs);
  85
  86bool ex_has_fault_handler(unsigned long ip)
  87{
  88        const struct exception_table_entry *e;
  89        ex_handler_t handler;
  90
  91        e = search_exception_tables(ip);
  92        if (!e)
  93                return false;
  94        handler = ex_fixup_handler(e);
  95
  96        return handler == ex_handler_fault;
  97}
  98
  99int fixup_exception(struct pt_regs *regs, int trapnr)
 100{
 101        const struct exception_table_entry *e;
 102        ex_handler_t handler;
 103
 104#ifdef CONFIG_PNPBIOS
 105        if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
 106                extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
 107                extern u32 pnp_bios_is_utter_crap;
 108                pnp_bios_is_utter_crap = 1;
 109                printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n");
 110                __asm__ volatile(
 111                        "movl %0, %%esp\n\t"
 112                        "jmp *%1\n\t"
 113                        : : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip));
 114                panic("do_trap: can't hit this");
 115        }
 116#endif
 117
 118        e = search_exception_tables(regs->ip);
 119        if (!e)
 120                return 0;
 121
 122        handler = ex_fixup_handler(e);
 123        return handler(e, regs, trapnr);
 124}
 125
 126extern unsigned int early_recursion_flag;
 127
 128/* Restricted version used during very early boot */
 129void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
 130{
 131        /* Ignore early NMIs. */
 132        if (trapnr == X86_TRAP_NMI)
 133                return;
 134
 135        if (early_recursion_flag > 2)
 136                goto halt_loop;
 137
 138        /*
 139         * Old CPUs leave the high bits of CS on the stack
 140         * undefined.  I'm not sure which CPUs do this, but at least
 141         * the 486 DX works this way.
 142         */
 143        if ((regs->cs & 0xFFFF) != __KERNEL_CS)
 144                goto fail;
 145
 146        /*
 147         * The full exception fixup machinery is available as soon as
 148         * the early IDT is loaded.  This means that it is the
 149         * responsibility of extable users to either function correctly
 150         * when handlers are invoked early or to simply avoid causing
 151         * exceptions before they're ready to handle them.
 152         *
 153         * This is better than filtering which handlers can be used,
 154         * because refusing to call a handler here is guaranteed to
 155         * result in a hard-to-debug panic.
 156         *
 157         * Keep in mind that not all vectors actually get here.  Early
 158         * fage faults, for example, are special.
 159         */
 160        if (fixup_exception(regs, trapnr))
 161                return;
 162
 163fail:
 164        early_printk("PANIC: early exception 0x%02x IP %lx:%lx error %lx cr2 0x%lx\n",
 165                     (unsigned)trapnr, (unsigned long)regs->cs, regs->ip,
 166                     regs->orig_ax, read_cr2());
 167
 168        show_regs(regs);
 169
 170halt_loop:
 171        while (true)
 172                halt();
 173}
 174