Commit 5f1888a0 authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman

powerpc/fault: Perform exception fixup in do_page_fault()

Exception fixup doesn't require the heady full regs saving,
do it from do_page_fault() directly.

For that, split bad_page_fault() in two parts.

As bad_page_fault() can also be called from other places than
handle_page_fault(), it will still perform exception fixup and
fallback on __bad_page_fault().

handle_page_fault() directly calls __bad_page_fault() as the
exception fixup will now be done by do_page_fault()
Signed-off-by: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/bd07d6fef9237614cd6d318d8f19faeeadaa816b.1607491748.git.christophe.leroy@csgroup.eu
parent cbd7e6ca
...@@ -113,6 +113,7 @@ ...@@ -113,6 +113,7 @@
struct pt_regs; struct pt_regs;
extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long); extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long);
extern void bad_page_fault(struct pt_regs *, unsigned long, int); extern void bad_page_fault(struct pt_regs *, unsigned long, int);
void __bad_page_fault(struct pt_regs *regs, unsigned long address, int sig);
extern void _exception(int, struct pt_regs *, int, unsigned long); extern void _exception(int, struct pt_regs *, int, unsigned long);
extern void _exception_pkey(struct pt_regs *, unsigned long, int); extern void _exception_pkey(struct pt_regs *, unsigned long, int);
extern void die(const char *, struct pt_regs *, long); extern void die(const char *, struct pt_regs *, long);
......
...@@ -684,7 +684,7 @@ handle_page_fault: ...@@ -684,7 +684,7 @@ handle_page_fault:
mr r5,r3 mr r5,r3
addi r3,r1,STACK_FRAME_OVERHEAD addi r3,r1,STACK_FRAME_OVERHEAD
lwz r4,_DAR(r1) lwz r4,_DAR(r1)
bl bad_page_fault bl __bad_page_fault
b ret_from_except_full b ret_from_except_full
#ifdef CONFIG_PPC_BOOK3S_32 #ifdef CONFIG_PPC_BOOK3S_32
......
...@@ -1023,7 +1023,7 @@ storage_fault_common: ...@@ -1023,7 +1023,7 @@ storage_fault_common:
mr r5,r3 mr r5,r3
addi r3,r1,STACK_FRAME_OVERHEAD addi r3,r1,STACK_FRAME_OVERHEAD
ld r4,_DAR(r1) ld r4,_DAR(r1)
bl bad_page_fault bl __bad_page_fault
b ret_from_except b ret_from_except
/* /*
......
...@@ -3259,7 +3259,7 @@ handle_page_fault: ...@@ -3259,7 +3259,7 @@ handle_page_fault:
mr r5,r3 mr r5,r3
addi r3,r1,STACK_FRAME_OVERHEAD addi r3,r1,STACK_FRAME_OVERHEAD
ld r4,_DAR(r1) ld r4,_DAR(r1)
bl bad_page_fault bl __bad_page_fault
b interrupt_return b interrupt_return
/* We have a data breakpoint exception - handle it */ /* We have a data breakpoint exception - handle it */
......
...@@ -545,10 +545,20 @@ NOKPROBE_SYMBOL(__do_page_fault); ...@@ -545,10 +545,20 @@ NOKPROBE_SYMBOL(__do_page_fault);
int do_page_fault(struct pt_regs *regs, unsigned long address, int do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned long error_code) unsigned long error_code)
{ {
const struct exception_table_entry *entry;
enum ctx_state prev_state = exception_enter(); enum ctx_state prev_state = exception_enter();
int rc = __do_page_fault(regs, address, error_code); int rc = __do_page_fault(regs, address, error_code);
exception_exit(prev_state); exception_exit(prev_state);
return rc; if (likely(!rc))
return 0;
entry = search_exception_tables(regs->nip);
if (unlikely(!entry))
return rc;
instruction_pointer_set(regs, extable_fixup(entry));
return 0;
} }
NOKPROBE_SYMBOL(do_page_fault); NOKPROBE_SYMBOL(do_page_fault);
...@@ -557,17 +567,10 @@ NOKPROBE_SYMBOL(do_page_fault); ...@@ -557,17 +567,10 @@ NOKPROBE_SYMBOL(do_page_fault);
* It is called from the DSI and ISI handlers in head.S and from some * It is called from the DSI and ISI handlers in head.S and from some
* of the procedures in traps.c. * of the procedures in traps.c.
*/ */
void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) void __bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
{ {
const struct exception_table_entry *entry;
int is_write = page_fault_is_write(regs->dsisr); int is_write = page_fault_is_write(regs->dsisr);
/* Are we prepared to handle this fault? */
if ((entry = search_exception_tables(regs->nip)) != NULL) {
regs->nip = extable_fixup(entry);
return;
}
/* kernel has accessed a bad area */ /* kernel has accessed a bad area */
switch (TRAP(regs)) { switch (TRAP(regs)) {
...@@ -601,3 +604,15 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) ...@@ -601,3 +604,15 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
die("Kernel access of bad area", regs, sig); die("Kernel access of bad area", regs, sig);
} }
void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
{
const struct exception_table_entry *entry;
/* Are we prepared to handle this fault? */
entry = search_exception_tables(instruction_pointer(regs));
if (entry)
instruction_pointer_set(regs, extable_fixup(entry));
else
__bad_page_fault(regs, address, sig);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment