Blame view
arch/sh/mm/extable_64.c
2.13 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
a23ba4357 sh: comment tidyi... |
2 |
* arch/sh/mm/extable_64.c |
1da177e4c Linux-2.6.12-rc2 |
3 4 5 6 7 |
* * Copyright (C) 2003 Richard Curnow * Copyright (C) 2003, 2004 Paul Mundt * * Cloned from the 2.5 SH version.. |
a23ba4357 sh: comment tidyi... |
8 9 10 11 |
* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. |
1da177e4c Linux-2.6.12-rc2 |
12 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
13 14 15 16 17 18 19 20 21 22 |
#include <linux/rwsem.h> #include <linux/module.h> #include <asm/uaccess.h> extern unsigned long copy_user_memcpy, copy_user_memcpy_end; extern void __copy_user_fixup(void); static const struct exception_table_entry __copy_user_fixup_ex = { .fixup = (unsigned long)&__copy_user_fixup, }; |
a23ba4357 sh: comment tidyi... |
23 24 25 26 27 28 29 30 31 32 |
/* * Some functions that may trap due to a bad user-mode address have too * many loads and stores in them to make it at all practical to label * each one and put them all in the main exception table. * * In particular, the fast memcpy routine is like this. It's fix-up is * just to fall back to a slow byte-at-a-time copy, which is handled the * conventional way. So it's functionally OK to just handle any trap * occurring in the fast memcpy with that fixup. */ |
1da177e4c Linux-2.6.12-rc2 |
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 69 70 71 72 73 74 75 76 77 78 79 80 81 |
static const struct exception_table_entry *check_exception_ranges(unsigned long addr) { if ((addr >= (unsigned long)©_user_memcpy) && (addr <= (unsigned long)©_user_memcpy_end)) return &__copy_user_fixup_ex; return NULL; } /* Simple binary search */ const struct exception_table_entry * search_extable(const struct exception_table_entry *first, const struct exception_table_entry *last, unsigned long value) { const struct exception_table_entry *mid; mid = check_exception_ranges(value); if (mid) return mid; while (first <= last) { 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; } int fixup_exception(struct pt_regs *regs) { const struct exception_table_entry *fixup; fixup = search_exception_tables(regs->pc); if (fixup) { regs->pc = fixup->fixup; return 1; } return 0; } |