Linux Audio

Check our new training course

Loading...
v3.1
 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}
v3.5.6
  1#include <linux/module.h>
  2#include <linux/spinlock.h>
  3#include <linux/sort.h>
  4#include <asm/uaccess.h>
  5
  6static inline unsigned long
  7ex_insn_addr(const struct exception_table_entry *x)
  8{
  9	return (unsigned long)&x->insn + x->insn;
 10}
 11static inline unsigned long
 12ex_fixup_addr(const struct exception_table_entry *x)
 13{
 14	return (unsigned long)&x->fixup + x->fixup;
 15}
 16
 17int fixup_exception(struct pt_regs *regs)
 18{
 19	const struct exception_table_entry *fixup;
 20	unsigned long new_ip;
 21
 22#ifdef CONFIG_PNPBIOS
 23	if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
 24		extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
 25		extern u32 pnp_bios_is_utter_crap;
 26		pnp_bios_is_utter_crap = 1;
 27		printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n");
 28		__asm__ volatile(
 29			"movl %0, %%esp\n\t"
 30			"jmp *%1\n\t"
 31			: : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip));
 32		panic("do_trap: can't hit this");
 33	}
 34#endif
 35
 36	fixup = search_exception_tables(regs->ip);
 37	if (fixup) {
 38		new_ip = ex_fixup_addr(fixup);
 39
 40		if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
 41			/* Special hack for uaccess_err */
 42			current_thread_info()->uaccess_err = 1;
 43			new_ip -= 0x7ffffff0;
 44		}
 45		regs->ip = new_ip;
 46		return 1;
 47	}
 48
 49	return 0;
 50}
 51
 52/* Restricted version used during very early boot */
 53int __init early_fixup_exception(unsigned long *ip)
 54{
 55	const struct exception_table_entry *fixup;
 56	unsigned long new_ip;
 57
 58	fixup = search_exception_tables(*ip);
 59	if (fixup) {
 60		new_ip = ex_fixup_addr(fixup);
 61
 62		if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
 63			/* uaccess handling not supported during early boot */
 64			return 0;
 65		}
 66
 67		*ip = new_ip;
 68		return 1;
 69	}
 70
 71	return 0;
 72}
 73
 74/*
 75 * Search one exception table for an entry corresponding to the
 76 * given instruction address, and return the address of the entry,
 77 * or NULL if none is found.
 78 * We use a binary search, and thus we assume that the table is
 79 * already sorted.
 80 */
 81const struct exception_table_entry *
 82search_extable(const struct exception_table_entry *first,
 83	       const struct exception_table_entry *last,
 84	       unsigned long value)
 85{
 86	while (first <= last) {
 87		const struct exception_table_entry *mid;
 88		unsigned long addr;
 89
 90		mid = ((last - first) >> 1) + first;
 91		addr = ex_insn_addr(mid);
 92		if (addr < value)
 93			first = mid + 1;
 94		else if (addr > value)
 95			last = mid - 1;
 96		else
 97			return mid;
 98        }
 99        return NULL;
100}
101
102/*
103 * The exception table needs to be sorted so that the binary
104 * search that we use to find entries in it works properly.
105 * This is used both for the kernel exception table and for
106 * the exception tables of modules that get loaded.
107 *
108 */
109static int cmp_ex(const void *a, const void *b)
110{
111	const struct exception_table_entry *x = a, *y = b;
112
113	/*
114	 * This value will always end up fittin in an int, because on
115	 * both i386 and x86-64 the kernel symbol-reachable address
116	 * space is < 2 GiB.
117	 *
118	 * This compare is only valid after normalization.
119	 */
120	return x->insn - y->insn;
121}
122
123void sort_extable(struct exception_table_entry *start,
124		  struct exception_table_entry *finish)
125{
126	struct exception_table_entry *p;
127	int i;
128
129	/* Convert all entries to being relative to the start of the section */
130	i = 0;
131	for (p = start; p < finish; p++) {
132		p->insn += i;
133		i += 4;
134		p->fixup += i;
135		i += 4;
136	}
137
138	sort(start, finish - start, sizeof(struct exception_table_entry),
139	     cmp_ex, NULL);
140
141	/* Denormalize all entries */
142	i = 0;
143	for (p = start; p < finish; p++) {
144		p->insn -= i;
145		i += 4;
146		p->fixup -= i;
147		i += 4;
148	}
149}
150
151#ifdef CONFIG_MODULES
152/*
153 * If the exception table is sorted, any referring to the module init
154 * will be at the beginning or the end.
155 */
156void trim_init_extable(struct module *m)
157{
158	/*trim the beginning*/
159	while (m->num_exentries &&
160	       within_module_init(ex_insn_addr(&m->extable[0]), m)) {
161		m->extable++;
162		m->num_exentries--;
163	}
164	/*trim the end*/
165	while (m->num_exentries &&
166	       within_module_init(ex_insn_addr(&m->extable[m->num_exentries-1]), m))
167		m->num_exentries--;
168}
169#endif /* CONFIG_MODULES */