From 61dbbaeb86c2181c79efae2d186193e0f8008af1 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 13 Oct 2013 21:11:30 +0200 Subject: [PATCH] parisc: provide macro to create exception table entries Provide a macro ASM_EXCEPTIONTABLE_ENTRY() to create exception table entries and convert all open-coded places to use that macro. This patch is a first step toward creating a exception table which only holds 32bit pointers even on a 64bit kernel. That way in my own kernel I was able to reduce the in-kernel exception table from 44kB to 22kB. Signed-off-by: Helge Deller --- arch/parisc/include/asm/assembly.h | 12 ++++++++++++ arch/parisc/include/asm/uaccess.h | 7 ++++--- arch/parisc/kernel/syscall.S | 6 ++---- arch/parisc/lib/lusercopy.S | 10 +++------- arch/parisc/mm/fault.c | 6 ++++++ 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/arch/parisc/include/asm/assembly.h b/arch/parisc/include/asm/assembly.h index 0da848232344fc..b3069fd83468c5 100644 --- a/arch/parisc/include/asm/assembly.h +++ b/arch/parisc/include/asm/assembly.h @@ -515,5 +515,17 @@ nop /* 7 */ .endm + /* + * ASM_EXCEPTIONTABLE_ENTRY + * + * Creates an exception table entry. + * Do not convert to a assembler macro. This won't work. + */ +#define ASM_EXCEPTIONTABLE_ENTRY(fault_addr, except_addr) \ + .section __ex_table,"aw" ! \ + ASM_ULONG_INSN fault_addr, except_addr ! \ + .previous + + #endif /* __ASSEMBLY__ */ #endif diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h index e0a82358517e03..4006964d8e1264 100644 --- a/arch/parisc/include/asm/uaccess.h +++ b/arch/parisc/include/asm/uaccess.h @@ -59,12 +59,13 @@ static inline long access_ok(int type, const void __user * addr, /* * The exception table contains two values: the first is an address * for an instruction that is allowed to fault, and the second is - * the address to the fixup routine. + * the address to the fixup routine. Even on a 64bit kernel we could + * use a 32bit (unsigned int) address here. */ struct exception_table_entry { - unsigned long insn; /* address of insn that is allowed to fault. */ - long fixup; /* fixup routine */ + unsigned long insn; /* address of insn that is allowed to fault. */ + unsigned long fixup; /* fixup routine */ }; #define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\ diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index e767ab733e321e..a63bb179f79a1f 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -649,10 +649,8 @@ cas_action: /* Two exception table entries, one for the load, the other for the store. Either return -EFAULT. Each of the entries must be relocated. */ - .section __ex_table,"aw" - ASM_ULONG_INSN (1b - linux_gateway_page), (3b - linux_gateway_page) - ASM_ULONG_INSN (2b - linux_gateway_page), (3b - linux_gateway_page) - .previous + ASM_EXCEPTIONTABLE_ENTRY(1b-linux_gateway_page, 3b-linux_gateway_page) + ASM_EXCEPTIONTABLE_ENTRY(2b-linux_gateway_page, 3b-linux_gateway_page) /* Make sure nothing else is placed on this page */ diff --git a/arch/parisc/lib/lusercopy.S b/arch/parisc/lib/lusercopy.S index 6f2d9355efe25a..a512f07d4feba9 100644 --- a/arch/parisc/lib/lusercopy.S +++ b/arch/parisc/lib/lusercopy.S @@ -88,9 +88,7 @@ ENDPROC(lclear_user) ldo 1(%r25),%r25 .previous - .section __ex_table,"aw" - ASM_ULONG_INSN 1b,2b - .previous + ASM_EXCEPTIONTABLE_ENTRY(1b,2b) .procend @@ -129,10 +127,8 @@ ENDPROC(lstrnlen_user) copy %r24,%r26 /* reset r26 so 0 is returned on fault */ .previous - .section __ex_table,"aw" - ASM_ULONG_INSN 1b,3b - ASM_ULONG_INSN 2b,3b - .previous + ASM_EXCEPTIONTABLE_ENTRY(1b,3b) + ASM_EXCEPTIONTABLE_ENTRY(2b,3b) .procend diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 0293588d5b8cb8..df0d32971cdf0e 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -142,6 +142,12 @@ int fixup_exception(struct pt_regs *regs) { const struct exception_table_entry *fix; + /* If we only stored 32bit addresses in the exception table we can drop + * out if we faulted on a 64bit address. */ + if ((sizeof(regs->iaoq[0]) > sizeof(fix->insn)) + && (regs->iaoq[0] >> 32)) + return 0; + fix = search_exception_tables(regs->iaoq[0]); if (fix) { struct exception_data *d;