Commit 5b5b7fd1 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'parisc-4.6-3' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux

Pull parisc fixes from Helge Deller:
 "Since commit 0de79858 ("parisc: Use generic extable search and
  sort routines") module loading is boken on parisc, because the parisc
  module loader wasn't prepared for the new R_PARISC_PCREL32 relocations.

  In addition, due to that breakage, Mikulas Patocka noticed that
  handling exceptions from modules probably never worked on parisc.  It
  was just masked by the fact that exceptions from modules don't happen
  during normal use.

  This patch series fixes those issues and survives the tests of the
  lib/test_user_copy kernel module test.  Some patches are tagged for
  stable"

* 'parisc-4.6-3' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
  parisc: Update comment regarding relative extable support
  parisc: Unbreak handling exceptions from kernel modules
  parisc: Fix kernel crash with reversed copy_from_user()
  parisc: Avoid function pointers for kernel exception routines
  parisc: Handle R_PARISC_PCREL32 relocations in kernel modules
parents 239467e8 cb910c17
...@@ -44,20 +44,18 @@ static inline long access_ok(int type, const void __user * addr, ...@@ -44,20 +44,18 @@ static inline long access_ok(int type, const void __user * addr,
#define LDD_USER(ptr) BUILD_BUG() #define LDD_USER(ptr) BUILD_BUG()
#define STD_KERNEL(x, ptr) __put_kernel_asm64(x, ptr) #define STD_KERNEL(x, ptr) __put_kernel_asm64(x, ptr)
#define STD_USER(x, ptr) __put_user_asm64(x, ptr) #define STD_USER(x, ptr) __put_user_asm64(x, ptr)
#define ASM_WORD_INSN ".word\t"
#else #else
#define LDD_KERNEL(ptr) __get_kernel_asm("ldd", ptr) #define LDD_KERNEL(ptr) __get_kernel_asm("ldd", ptr)
#define LDD_USER(ptr) __get_user_asm("ldd", ptr) #define LDD_USER(ptr) __get_user_asm("ldd", ptr)
#define STD_KERNEL(x, ptr) __put_kernel_asm("std", x, ptr) #define STD_KERNEL(x, ptr) __put_kernel_asm("std", x, ptr)
#define STD_USER(x, ptr) __put_user_asm("std", x, ptr) #define STD_USER(x, ptr) __put_user_asm("std", x, ptr)
#define ASM_WORD_INSN ".dword\t"
#endif #endif
/* /*
* The exception table contains two values: the first is an address * The exception table contains two values: the first is the relative offset to
* for an instruction that is allowed to fault, and the second is * the address of the instruction that is allowed to fault, and the second is
* the address to the fixup routine. Even on a 64bit kernel we could * the relative offset to the address of the fixup routine. Since relative
* use a 32bit (unsigned int) address here. * addresses are used, 32bit values are sufficient even on 64bit kernel.
*/ */
#define ARCH_HAS_RELATIVE_EXTABLE #define ARCH_HAS_RELATIVE_EXTABLE
...@@ -77,6 +75,7 @@ struct exception_table_entry { ...@@ -77,6 +75,7 @@ struct exception_table_entry {
*/ */
struct exception_data { struct exception_data {
unsigned long fault_ip; unsigned long fault_ip;
unsigned long fault_gp;
unsigned long fault_space; unsigned long fault_space;
unsigned long fault_addr; unsigned long fault_addr;
}; };
......
...@@ -299,6 +299,7 @@ int main(void) ...@@ -299,6 +299,7 @@ int main(void)
#endif #endif
BLANK(); BLANK();
DEFINE(EXCDATA_IP, offsetof(struct exception_data, fault_ip)); DEFINE(EXCDATA_IP, offsetof(struct exception_data, fault_ip));
DEFINE(EXCDATA_GP, offsetof(struct exception_data, fault_gp));
DEFINE(EXCDATA_SPACE, offsetof(struct exception_data, fault_space)); DEFINE(EXCDATA_SPACE, offsetof(struct exception_data, fault_space));
DEFINE(EXCDATA_ADDR, offsetof(struct exception_data, fault_addr)); DEFINE(EXCDATA_ADDR, offsetof(struct exception_data, fault_addr));
BLANK(); BLANK();
......
...@@ -660,6 +660,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs, ...@@ -660,6 +660,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
} }
*loc = (*loc & ~0x3ff1ffd) | reassemble_22(val); *loc = (*loc & ~0x3ff1ffd) | reassemble_22(val);
break; break;
case R_PARISC_PCREL32:
/* 32-bit PC relative address */
*loc = val - dot - 8 + addend;
break;
default: default:
printk(KERN_ERR "module %s: Unknown relocation: %u\n", printk(KERN_ERR "module %s: Unknown relocation: %u\n",
...@@ -788,6 +792,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs, ...@@ -788,6 +792,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
CHECK_RELOC(val, 22); CHECK_RELOC(val, 22);
*loc = (*loc & ~0x3ff1ffd) | reassemble_22(val); *loc = (*loc & ~0x3ff1ffd) | reassemble_22(val);
break; break;
case R_PARISC_PCREL32:
/* 32-bit PC relative address */
*loc = val - dot - 8 + addend;
break;
case R_PARISC_DIR64: case R_PARISC_DIR64:
/* 64-bit effective address */ /* 64-bit effective address */
*loc64 = val + addend; *loc64 = val + addend;
......
...@@ -47,11 +47,11 @@ EXPORT_SYMBOL(__cmpxchg_u64); ...@@ -47,11 +47,11 @@ EXPORT_SYMBOL(__cmpxchg_u64);
EXPORT_SYMBOL(lclear_user); EXPORT_SYMBOL(lclear_user);
EXPORT_SYMBOL(lstrnlen_user); EXPORT_SYMBOL(lstrnlen_user);
/* Global fixups */ /* Global fixups - defined as int to avoid creation of function pointers */
extern void fixup_get_user_skip_1(void); extern int fixup_get_user_skip_1;
extern void fixup_get_user_skip_2(void); extern int fixup_get_user_skip_2;
extern void fixup_put_user_skip_1(void); extern int fixup_put_user_skip_1;
extern void fixup_put_user_skip_2(void); extern int fixup_put_user_skip_2;
EXPORT_SYMBOL(fixup_get_user_skip_1); EXPORT_SYMBOL(fixup_get_user_skip_1);
EXPORT_SYMBOL(fixup_get_user_skip_2); EXPORT_SYMBOL(fixup_get_user_skip_2);
EXPORT_SYMBOL(fixup_put_user_skip_1); EXPORT_SYMBOL(fixup_put_user_skip_1);
......
...@@ -795,6 +795,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs) ...@@ -795,6 +795,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
if (fault_space == 0 && !faulthandler_disabled()) if (fault_space == 0 && !faulthandler_disabled())
{ {
/* Clean up and return if in exception table. */
if (fixup_exception(regs))
return;
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC); pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
parisc_terminate("Kernel Fault", regs, code, fault_address); parisc_terminate("Kernel Fault", regs, code, fault_address);
} }
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
.macro get_fault_ip t1 t2 .macro get_fault_ip t1 t2
loadgp
addil LT%__per_cpu_offset,%r27 addil LT%__per_cpu_offset,%r27
LDREG RT%__per_cpu_offset(%r1),\t1 LDREG RT%__per_cpu_offset(%r1),\t1
/* t2 = smp_processor_id() */ /* t2 = smp_processor_id() */
...@@ -40,14 +41,19 @@ ...@@ -40,14 +41,19 @@
LDREG RT%exception_data(%r1),\t1 LDREG RT%exception_data(%r1),\t1
/* t1 = this_cpu_ptr(&exception_data) */ /* t1 = this_cpu_ptr(&exception_data) */
add,l \t1,\t2,\t1 add,l \t1,\t2,\t1
/* %r27 = t1->fault_gp - restore gp */
LDREG EXCDATA_GP(\t1), %r27
/* t1 = t1->fault_ip */ /* t1 = t1->fault_ip */
LDREG EXCDATA_IP(\t1), \t1 LDREG EXCDATA_IP(\t1), \t1
.endm .endm
#else #else
.macro get_fault_ip t1 t2 .macro get_fault_ip t1 t2
loadgp
/* t1 = this_cpu_ptr(&exception_data) */ /* t1 = this_cpu_ptr(&exception_data) */
addil LT%exception_data,%r27 addil LT%exception_data,%r27
LDREG RT%exception_data(%r1),\t2 LDREG RT%exception_data(%r1),\t2
/* %r27 = t2->fault_gp - restore gp */
LDREG EXCDATA_GP(\t2), %r27
/* t1 = t2->fault_ip */ /* t1 = t2->fault_ip */
LDREG EXCDATA_IP(\t2), \t1 LDREG EXCDATA_IP(\t2), \t1
.endm .endm
......
...@@ -145,6 +145,7 @@ int fixup_exception(struct pt_regs *regs) ...@@ -145,6 +145,7 @@ int fixup_exception(struct pt_regs *regs)
struct exception_data *d; struct exception_data *d;
d = this_cpu_ptr(&exception_data); d = this_cpu_ptr(&exception_data);
d->fault_ip = regs->iaoq[0]; d->fault_ip = regs->iaoq[0];
d->fault_gp = regs->gr[27];
d->fault_space = regs->isr; d->fault_space = regs->isr;
d->fault_addr = regs->ior; d->fault_addr = regs->ior;
......
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