extable.c 1.5 KB
Newer Older
H
Harvey Harrison 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#include <linux/module.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>


int fixup_exception(struct pt_regs *regs)
{
	const struct exception_table_entry *fixup;

#ifdef CONFIG_PNPBIOS
	if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
		extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
		extern u32 pnp_bios_is_utter_crap;
		pnp_bios_is_utter_crap = 1;
		printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n");
		__asm__ volatile(
			"movl %0, %%esp\n\t"
			"jmp *%1\n\t"
			: : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip));
		panic("do_trap: can't hit this");
	}
#endif

	fixup = search_exception_tables(regs->ip);
	if (fixup) {
26 27 28 29 30 31
		/* If fixup is less than 16, it means uaccess error */
		if (fixup->fixup < 16) {
			current_thread_info()->uaccess_err = -EFAULT;
			regs->ip += fixup->fixup;
			return 1;
		}
H
Harvey Harrison 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
		regs->ip = fixup->fixup;
		return 1;
	}

	return 0;
}

#ifdef CONFIG_X86_64
/*
 * Need to defined our own search_extable on X86_64 to work around
 * a B stepping K8 bug.
 */
const struct exception_table_entry *
search_extable(const struct exception_table_entry *first,
	       const struct exception_table_entry *last,
	       unsigned long value)
{
	/* B stepping K8 bug */
	if ((value >> 32) == 0)
		value |= 0xffffffffUL << 32;

	while (first <= last) {
		const struct exception_table_entry *mid;
		long diff;

		mid = (last - first) / 2 + first;
		diff = mid->insn - value;
		if (diff == 0)
			return mid;
		else if (diff < 0)
			first = mid+1;
		else
			last = mid-1;
	}
	return NULL;
}
#endif