diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-06-05 14:15:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-06-05 14:15:33 -0400 |
commit | 5975b2c0c10adbc7894a54ab7b30db4fbcdd8c41 (patch) | |
tree | f62bb70c952848e00caead9ac08acbee7e75a5d0 | |
parent | d834502e2fca9380a1579fecd134ef94c063b662 (diff) | |
parent | 58f1c654d13a42575d507ea61f6de0332a761e75 (diff) |
Merge branch 'parisc-4.7-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux
Pull parisc fixes from Helge Deller:
- Fix printk time stamps on SMP systems which got wrong due to a patch
which was added during the merge window
- Fix two bugs in the stack backtrace code: Races in module unloading
and possible invalid accesses to memory due to wrong instruction
decoding (Mikulas Patocka)
- Fix userspace crash when syscalls access invalid unaligned userspace
addresses. Those syscalls will now return EFAULT as expected.
(tagged for stable kernel series)
* 'parisc-4.7-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
parisc: Move die_if_kernel() prototype into traps.h header
parisc: Fix pagefault crash in unaligned __get_user() call
parisc: Fix printk time during boot
parisc: Fix backtrace on PA-RISC
-rw-r--r-- | arch/parisc/include/asm/traps.h | 2 | ||||
-rw-r--r-- | arch/parisc/kernel/processor.c | 5 | ||||
-rw-r--r-- | arch/parisc/kernel/time.c | 5 | ||||
-rw-r--r-- | arch/parisc/kernel/unaligned.c | 13 | ||||
-rw-r--r-- | arch/parisc/kernel/unwind.c | 22 |
5 files changed, 29 insertions, 18 deletions
diff --git a/arch/parisc/include/asm/traps.h b/arch/parisc/include/asm/traps.h index 4736020ba5ea..5e953ab4530d 100644 --- a/arch/parisc/include/asm/traps.h +++ b/arch/parisc/include/asm/traps.h | |||
@@ -8,6 +8,8 @@ struct pt_regs; | |||
8 | void parisc_terminate(char *msg, struct pt_regs *regs, | 8 | void parisc_terminate(char *msg, struct pt_regs *regs, |
9 | int code, unsigned long offset) __noreturn __cold; | 9 | int code, unsigned long offset) __noreturn __cold; |
10 | 10 | ||
11 | void die_if_kernel(char *str, struct pt_regs *regs, long err); | ||
12 | |||
11 | /* mm/fault.c */ | 13 | /* mm/fault.c */ |
12 | void do_page_fault(struct pt_regs *regs, unsigned long code, | 14 | void do_page_fault(struct pt_regs *regs, unsigned long code, |
13 | unsigned long address); | 15 | unsigned long address); |
diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index e81ccf1716e9..5adc339eb7c8 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c | |||
@@ -324,8 +324,9 @@ int init_per_cpu(int cpunum) | |||
324 | per_cpu(cpu_data, cpunum).fp_rev = coproc_cfg.revision; | 324 | per_cpu(cpu_data, cpunum).fp_rev = coproc_cfg.revision; |
325 | per_cpu(cpu_data, cpunum).fp_model = coproc_cfg.model; | 325 | per_cpu(cpu_data, cpunum).fp_model = coproc_cfg.model; |
326 | 326 | ||
327 | printk(KERN_INFO "FP[%d] enabled: Rev %ld Model %ld\n", | 327 | if (cpunum == 0) |
328 | cpunum, coproc_cfg.revision, coproc_cfg.model); | 328 | printk(KERN_INFO "FP[%d] enabled: Rev %ld Model %ld\n", |
329 | cpunum, coproc_cfg.revision, coproc_cfg.model); | ||
329 | 330 | ||
330 | /* | 331 | /* |
331 | ** store status register to stack (hopefully aligned) | 332 | ** store status register to stack (hopefully aligned) |
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 58dd6801f5be..31ec99a5f119 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c | |||
@@ -309,11 +309,6 @@ void __init time_init(void) | |||
309 | clocks_calc_mult_shift(&cyc2ns_mul, &cyc2ns_shift, current_cr16_khz, | 309 | clocks_calc_mult_shift(&cyc2ns_mul, &cyc2ns_shift, current_cr16_khz, |
310 | NSEC_PER_MSEC, 0); | 310 | NSEC_PER_MSEC, 0); |
311 | 311 | ||
312 | #if defined(CONFIG_HAVE_UNSTABLE_SCHED_CLOCK) && defined(CONFIG_64BIT) | ||
313 | /* At bootup only one 64bit CPU is online and cr16 is "stable" */ | ||
314 | set_sched_clock_stable(); | ||
315 | #endif | ||
316 | |||
317 | start_cpu_itimer(); /* get CPU 0 started */ | 312 | start_cpu_itimer(); /* get CPU 0 started */ |
318 | 313 | ||
319 | /* register at clocksource framework */ | 314 | /* register at clocksource framework */ |
diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index d7c0acb35ec2..2b65c0177778 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/ratelimit.h> | 28 | #include <linux/ratelimit.h> |
29 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
30 | #include <asm/hardirq.h> | 30 | #include <asm/hardirq.h> |
31 | #include <asm/traps.h> | ||
31 | 32 | ||
32 | /* #define DEBUG_UNALIGNED 1 */ | 33 | /* #define DEBUG_UNALIGNED 1 */ |
33 | 34 | ||
@@ -130,8 +131,6 @@ | |||
130 | 131 | ||
131 | int unaligned_enabled __read_mostly = 1; | 132 | int unaligned_enabled __read_mostly = 1; |
132 | 133 | ||
133 | void die_if_kernel (char *str, struct pt_regs *regs, long err); | ||
134 | |||
135 | static int emulate_ldh(struct pt_regs *regs, int toreg) | 134 | static int emulate_ldh(struct pt_regs *regs, int toreg) |
136 | { | 135 | { |
137 | unsigned long saddr = regs->ior; | 136 | unsigned long saddr = regs->ior; |
@@ -666,7 +665,7 @@ void handle_unaligned(struct pt_regs *regs) | |||
666 | break; | 665 | break; |
667 | } | 666 | } |
668 | 667 | ||
669 | if (modify && R1(regs->iir)) | 668 | if (ret == 0 && modify && R1(regs->iir)) |
670 | regs->gr[R1(regs->iir)] = newbase; | 669 | regs->gr[R1(regs->iir)] = newbase; |
671 | 670 | ||
672 | 671 | ||
@@ -677,6 +676,14 @@ void handle_unaligned(struct pt_regs *regs) | |||
677 | 676 | ||
678 | if (ret) | 677 | if (ret) |
679 | { | 678 | { |
679 | /* | ||
680 | * The unaligned handler failed. | ||
681 | * If we were called by __get_user() or __put_user() jump | ||
682 | * to it's exception fixup handler instead of crashing. | ||
683 | */ | ||
684 | if (!user_mode(regs) && fixup_exception(regs)) | ||
685 | return; | ||
686 | |||
680 | printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret); | 687 | printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret); |
681 | die_if_kernel("Unaligned data reference", regs, 28); | 688 | die_if_kernel("Unaligned data reference", regs, 28); |
682 | 689 | ||
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c index ddd988b267a9..e278a87f43cc 100644 --- a/arch/parisc/kernel/unwind.c +++ b/arch/parisc/kernel/unwind.c | |||
@@ -75,7 +75,10 @@ find_unwind_entry(unsigned long addr) | |||
75 | if (addr >= kernel_unwind_table.start && | 75 | if (addr >= kernel_unwind_table.start && |
76 | addr <= kernel_unwind_table.end) | 76 | addr <= kernel_unwind_table.end) |
77 | e = find_unwind_entry_in_table(&kernel_unwind_table, addr); | 77 | e = find_unwind_entry_in_table(&kernel_unwind_table, addr); |
78 | else | 78 | else { |
79 | unsigned long flags; | ||
80 | |||
81 | spin_lock_irqsave(&unwind_lock, flags); | ||
79 | list_for_each_entry(table, &unwind_tables, list) { | 82 | list_for_each_entry(table, &unwind_tables, list) { |
80 | if (addr >= table->start && | 83 | if (addr >= table->start && |
81 | addr <= table->end) | 84 | addr <= table->end) |
@@ -86,6 +89,8 @@ find_unwind_entry(unsigned long addr) | |||
86 | break; | 89 | break; |
87 | } | 90 | } |
88 | } | 91 | } |
92 | spin_unlock_irqrestore(&unwind_lock, flags); | ||
93 | } | ||
89 | 94 | ||
90 | return e; | 95 | return e; |
91 | } | 96 | } |
@@ -303,18 +308,16 @@ static void unwind_frame_regs(struct unwind_frame_info *info) | |||
303 | 308 | ||
304 | insn = *(unsigned int *)npc; | 309 | insn = *(unsigned int *)npc; |
305 | 310 | ||
306 | if ((insn & 0xffffc000) == 0x37de0000 || | 311 | if ((insn & 0xffffc001) == 0x37de0000 || |
307 | (insn & 0xffe00000) == 0x6fc00000) { | 312 | (insn & 0xffe00001) == 0x6fc00000) { |
308 | /* ldo X(sp), sp, or stwm X,D(sp) */ | 313 | /* ldo X(sp), sp, or stwm X,D(sp) */ |
309 | frame_size += (insn & 0x1 ? -1 << 13 : 0) | | 314 | frame_size += (insn & 0x3fff) >> 1; |
310 | ((insn & 0x3fff) >> 1); | ||
311 | dbg("analyzing func @ %lx, insn=%08x @ " | 315 | dbg("analyzing func @ %lx, insn=%08x @ " |
312 | "%lx, frame_size = %ld\n", info->ip, | 316 | "%lx, frame_size = %ld\n", info->ip, |
313 | insn, npc, frame_size); | 317 | insn, npc, frame_size); |
314 | } else if ((insn & 0xffe00008) == 0x73c00008) { | 318 | } else if ((insn & 0xffe00009) == 0x73c00008) { |
315 | /* std,ma X,D(sp) */ | 319 | /* std,ma X,D(sp) */ |
316 | frame_size += (insn & 0x1 ? -1 << 13 : 0) | | 320 | frame_size += ((insn >> 4) & 0x3ff) << 3; |
317 | (((insn >> 4) & 0x3ff) << 3); | ||
318 | dbg("analyzing func @ %lx, insn=%08x @ " | 321 | dbg("analyzing func @ %lx, insn=%08x @ " |
319 | "%lx, frame_size = %ld\n", info->ip, | 322 | "%lx, frame_size = %ld\n", info->ip, |
320 | insn, npc, frame_size); | 323 | insn, npc, frame_size); |
@@ -333,6 +336,9 @@ static void unwind_frame_regs(struct unwind_frame_info *info) | |||
333 | } | 336 | } |
334 | } | 337 | } |
335 | 338 | ||
339 | if (frame_size > e->Total_frame_size << 3) | ||
340 | frame_size = e->Total_frame_size << 3; | ||
341 | |||
336 | if (!unwind_special(info, e->region_start, frame_size)) { | 342 | if (!unwind_special(info, e->region_start, frame_size)) { |
337 | info->prev_sp = info->sp - frame_size; | 343 | info->prev_sp = info->sp - frame_size; |
338 | if (e->Millicode) | 344 | if (e->Millicode) |