diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-12-25 14:12:18 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-03-28 18:23:32 -0400 |
commit | 9a7513cfa26f5fcce15de6130ce3c27d77c0ce55 (patch) | |
tree | 1f7769fc94432e965b7e6d19bb0f28ed40254ae5 /arch/frv | |
parent | d597580d373774b1bdab84b3d26ff0b55162b916 (diff) |
frv: switch to use of fixup_exception()
Massage frv search_exception_table() to
a) taking pt_regs pointer as explicit argument
b) updating ->pc on success
Simplifies callers a bit and allows to convert to generic extable.h,
while we are at it.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/frv')
-rw-r--r-- | arch/frv/include/asm/Kbuild | 1 | ||||
-rw-r--r-- | arch/frv/include/asm/uaccess.h | 23 | ||||
-rw-r--r-- | arch/frv/kernel/traps.c | 7 | ||||
-rw-r--r-- | arch/frv/mm/extable.c | 27 | ||||
-rw-r--r-- | arch/frv/mm/fault.c | 6 |
5 files changed, 18 insertions, 46 deletions
diff --git a/arch/frv/include/asm/Kbuild b/arch/frv/include/asm/Kbuild index c33b46715f65..cce3bc3603ea 100644 --- a/arch/frv/include/asm/Kbuild +++ b/arch/frv/include/asm/Kbuild | |||
@@ -1,6 +1,7 @@ | |||
1 | 1 | ||
2 | generic-y += clkdev.h | 2 | generic-y += clkdev.h |
3 | generic-y += exec.h | 3 | generic-y += exec.h |
4 | generic-y += extable.h | ||
4 | generic-y += irq_work.h | 5 | generic-y += irq_work.h |
5 | generic-y += mcs_spinlock.h | 6 | generic-y += mcs_spinlock.h |
6 | generic-y += mm-arch-hooks.h | 7 | generic-y += mm-arch-hooks.h |
diff --git a/arch/frv/include/asm/uaccess.h b/arch/frv/include/asm/uaccess.h index 55b3a69c6c53..5bcc57de3c95 100644 --- a/arch/frv/include/asm/uaccess.h +++ b/arch/frv/include/asm/uaccess.h | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
19 | #include <asm/segment.h> | 19 | #include <asm/segment.h> |
20 | #include <asm/sections.h> | 20 | #include <asm/sections.h> |
21 | #include <asm/extable.h> | ||
21 | 22 | ||
22 | #define __ptr(x) ((unsigned long __force *)(x)) | 23 | #define __ptr(x) ((unsigned long __force *)(x)) |
23 | 24 | ||
@@ -59,26 +60,6 @@ static inline int ___range_ok(unsigned long addr, unsigned long size) | |||
59 | #define access_ok(type,addr,size) (__range_ok((void __user *)(addr), (size)) == 0) | 60 | #define access_ok(type,addr,size) (__range_ok((void __user *)(addr), (size)) == 0) |
60 | #define __access_ok(addr,size) (__range_ok((addr), (size)) == 0) | 61 | #define __access_ok(addr,size) (__range_ok((addr), (size)) == 0) |
61 | 62 | ||
62 | /* | ||
63 | * The exception table consists of pairs of addresses: the first is the | ||
64 | * address of an instruction that is allowed to fault, and the second is | ||
65 | * the address at which the program should continue. No registers are | ||
66 | * modified, so it is entirely up to the continuation code to figure out | ||
67 | * what to do. | ||
68 | * | ||
69 | * All the routines below use bits of fixup code that are out of line | ||
70 | * with the main instruction path. This means when everything is well, | ||
71 | * we don't even have to jump over them. Further, they do not intrude | ||
72 | * on our cache or tlb entries. | ||
73 | */ | ||
74 | struct exception_table_entry | ||
75 | { | ||
76 | unsigned long insn, fixup; | ||
77 | }; | ||
78 | |||
79 | /* Returns 0 if exception not found and fixup otherwise. */ | ||
80 | extern unsigned long search_exception_table(unsigned long); | ||
81 | |||
82 | 63 | ||
83 | /* | 64 | /* |
84 | * These are the main single-value transfer routines. They automatically | 65 | * These are the main single-value transfer routines. They automatically |
@@ -314,6 +295,4 @@ extern long strnlen_user(const char __user *src, long count); | |||
314 | 295 | ||
315 | #define strlen_user(str) strnlen_user(str, 32767) | 296 | #define strlen_user(str) strnlen_user(str, 32767) |
316 | 297 | ||
317 | extern unsigned long search_exception_table(unsigned long addr); | ||
318 | |||
319 | #endif /* _ASM_UACCESS_H */ | 298 | #endif /* _ASM_UACCESS_H */ |
diff --git a/arch/frv/kernel/traps.c b/arch/frv/kernel/traps.c index ce29991e4219..fb08ebe0dab4 100644 --- a/arch/frv/kernel/traps.c +++ b/arch/frv/kernel/traps.c | |||
@@ -360,13 +360,8 @@ asmlinkage void memory_access_exception(unsigned long esr0, | |||
360 | siginfo_t info; | 360 | siginfo_t info; |
361 | 361 | ||
362 | #ifdef CONFIG_MMU | 362 | #ifdef CONFIG_MMU |
363 | unsigned long fixup; | 363 | if (fixup_exception(__frame)) |
364 | |||
365 | fixup = search_exception_table(__frame->pc); | ||
366 | if (fixup) { | ||
367 | __frame->pc = fixup; | ||
368 | return; | 364 | return; |
369 | } | ||
370 | #endif | 365 | #endif |
371 | 366 | ||
372 | die_if_kernel("-- Memory Access Exception --\n" | 367 | die_if_kernel("-- Memory Access Exception --\n" |
diff --git a/arch/frv/mm/extable.c b/arch/frv/mm/extable.c index a0e8b3e03e4c..9198ddd16092 100644 --- a/arch/frv/mm/extable.c +++ b/arch/frv/mm/extable.c | |||
@@ -10,40 +10,39 @@ extern const void __memset_end, __memset_user_error_lr, __memset_user_error_hand | |||
10 | extern const void __memcpy_end, __memcpy_user_error_lr, __memcpy_user_error_handler; | 10 | extern const void __memcpy_end, __memcpy_user_error_lr, __memcpy_user_error_handler; |
11 | extern spinlock_t modlist_lock; | 11 | extern spinlock_t modlist_lock; |
12 | 12 | ||
13 | 13 | int fixup_exception(struct pt_regs *regs) | |
14 | /*****************************************************************************/ | ||
15 | /* | ||
16 | * see if there's a fixup handler available to deal with a kernel fault | ||
17 | */ | ||
18 | unsigned long search_exception_table(unsigned long pc) | ||
19 | { | 14 | { |
20 | const struct exception_table_entry *extab; | 15 | const struct exception_table_entry *extab; |
16 | unsigned long pc = regs->pc; | ||
21 | 17 | ||
22 | /* determine if the fault lay during a memcpy_user or a memset_user */ | 18 | /* determine if the fault lay during a memcpy_user or a memset_user */ |
23 | if (__frame->lr == (unsigned long) &__memset_user_error_lr && | 19 | if (regs->lr == (unsigned long) &__memset_user_error_lr && |
24 | (unsigned long) &memset <= pc && pc < (unsigned long) &__memset_end | 20 | (unsigned long) &memset <= pc && pc < (unsigned long) &__memset_end |
25 | ) { | 21 | ) { |
26 | /* the fault occurred in a protected memset | 22 | /* the fault occurred in a protected memset |
27 | * - we search for the return address (in LR) instead of the program counter | 23 | * - we search for the return address (in LR) instead of the program counter |
28 | * - it was probably during a clear_user() | 24 | * - it was probably during a clear_user() |
29 | */ | 25 | */ |
30 | return (unsigned long) &__memset_user_error_handler; | 26 | regs->pc = (unsigned long) &__memset_user_error_handler; |
27 | return 1; | ||
31 | } | 28 | } |
32 | 29 | ||
33 | if (__frame->lr == (unsigned long) &__memcpy_user_error_lr && | 30 | if (regs->lr == (unsigned long) &__memcpy_user_error_lr && |
34 | (unsigned long) &memcpy <= pc && pc < (unsigned long) &__memcpy_end | 31 | (unsigned long) &memcpy <= pc && pc < (unsigned long) &__memcpy_end |
35 | ) { | 32 | ) { |
36 | /* the fault occurred in a protected memset | 33 | /* the fault occurred in a protected memset |
37 | * - we search for the return address (in LR) instead of the program counter | 34 | * - we search for the return address (in LR) instead of the program counter |
38 | * - it was probably during a copy_to/from_user() | 35 | * - it was probably during a copy_to/from_user() |
39 | */ | 36 | */ |
40 | return (unsigned long) &__memcpy_user_error_handler; | 37 | regs->pc = (unsigned long) &__memcpy_user_error_handler; |
38 | return 1; | ||
41 | } | 39 | } |
42 | 40 | ||
43 | extab = search_exception_tables(pc); | 41 | extab = search_exception_tables(pc); |
44 | if (extab) | 42 | if (extab) { |
45 | return extab->fixup; | 43 | regs->pc = extab->fixup; |
44 | return 1; | ||
45 | } | ||
46 | 46 | ||
47 | return 0; | 47 | return 0; |
48 | 48 | } | |
49 | } /* end search_exception_table() */ | ||
diff --git a/arch/frv/mm/fault.c b/arch/frv/mm/fault.c index 614a46c413d2..179e79e220e5 100644 --- a/arch/frv/mm/fault.c +++ b/arch/frv/mm/fault.c | |||
@@ -33,7 +33,7 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear | |||
33 | { | 33 | { |
34 | struct vm_area_struct *vma; | 34 | struct vm_area_struct *vma; |
35 | struct mm_struct *mm; | 35 | struct mm_struct *mm; |
36 | unsigned long _pme, lrai, lrad, fixup; | 36 | unsigned long _pme, lrai, lrad; |
37 | unsigned long flags = 0; | 37 | unsigned long flags = 0; |
38 | siginfo_t info; | 38 | siginfo_t info; |
39 | pgd_t *pge; | 39 | pgd_t *pge; |
@@ -201,10 +201,8 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear | |||
201 | 201 | ||
202 | no_context: | 202 | no_context: |
203 | /* are we prepared to handle this kernel fault? */ | 203 | /* are we prepared to handle this kernel fault? */ |
204 | if ((fixup = search_exception_table(__frame->pc)) != 0) { | 204 | if (fixup_exception(__frame)) |
205 | __frame->pc = fixup; | ||
206 | return; | 205 | return; |
207 | } | ||
208 | 206 | ||
209 | /* | 207 | /* |
210 | * Oops. The kernel tried to access some bad page. We'll have to | 208 | * Oops. The kernel tried to access some bad page. We'll have to |