diff options
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/compat_linux.c | 1 | ||||
-rw-r--r-- | arch/s390/kernel/kprobes.c | 70 | ||||
-rw-r--r-- | arch/s390/kernel/nmi.c | 10 | ||||
-rw-r--r-- | arch/s390/kernel/vtime.c | 19 |
4 files changed, 76 insertions, 24 deletions
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 1e6449c79ab6..53acaa86dd94 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/resource.h> | 25 | #include <linux/resource.h> |
26 | #include <linux/times.h> | 26 | #include <linux/times.h> |
27 | #include <linux/smp.h> | 27 | #include <linux/smp.h> |
28 | #include <linux/smp_lock.h> | ||
29 | #include <linux/sem.h> | 28 | #include <linux/sem.h> |
30 | #include <linux/msg.h> | 29 | #include <linux/msg.h> |
31 | #include <linux/shm.h> | 30 | #include <linux/shm.h> |
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index d60fc4398516..2564793ec2b6 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/sections.h> | 30 | #include <asm/sections.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/hardirq.h> | ||
33 | 34 | ||
34 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; | 35 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; |
35 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | 36 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); |
@@ -212,7 +213,7 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) | |||
212 | /* Set the PER control regs, turns on single step for this address */ | 213 | /* Set the PER control regs, turns on single step for this address */ |
213 | __ctl_load(kprobe_per_regs, 9, 11); | 214 | __ctl_load(kprobe_per_regs, 9, 11); |
214 | regs->psw.mask |= PSW_MASK_PER; | 215 | regs->psw.mask |= PSW_MASK_PER; |
215 | regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK); | 216 | regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT); |
216 | } | 217 | } |
217 | 218 | ||
218 | static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) | 219 | static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) |
@@ -239,7 +240,7 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, | |||
239 | __get_cpu_var(current_kprobe) = p; | 240 | __get_cpu_var(current_kprobe) = p; |
240 | /* Save the interrupt and per flags */ | 241 | /* Save the interrupt and per flags */ |
241 | kcb->kprobe_saved_imask = regs->psw.mask & | 242 | kcb->kprobe_saved_imask = regs->psw.mask & |
242 | (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK); | 243 | (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT); |
243 | /* Save the control regs that govern PER */ | 244 | /* Save the control regs that govern PER */ |
244 | __ctl_store(kcb->kprobe_saved_ctl, 9, 11); | 245 | __ctl_store(kcb->kprobe_saved_ctl, 9, 11); |
245 | } | 246 | } |
@@ -316,8 +317,6 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
316 | return 1; | 317 | return 1; |
317 | 318 | ||
318 | ss_probe: | 319 | ss_probe: |
319 | if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO)) | ||
320 | local_irq_disable(); | ||
321 | prepare_singlestep(p, regs); | 320 | prepare_singlestep(p, regs); |
322 | kcb->kprobe_status = KPROBE_HIT_SS; | 321 | kcb->kprobe_status = KPROBE_HIT_SS; |
323 | return 1; | 322 | return 1; |
@@ -350,6 +349,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, | |||
350 | struct hlist_node *node, *tmp; | 349 | struct hlist_node *node, *tmp; |
351 | unsigned long flags, orig_ret_address = 0; | 350 | unsigned long flags, orig_ret_address = 0; |
352 | unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; | 351 | unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; |
352 | kprobe_opcode_t *correct_ret_addr = NULL; | ||
353 | 353 | ||
354 | INIT_HLIST_HEAD(&empty_rp); | 354 | INIT_HLIST_HEAD(&empty_rp); |
355 | kretprobe_hash_lock(current, &head, &flags); | 355 | kretprobe_hash_lock(current, &head, &flags); |
@@ -372,10 +372,32 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, | |||
372 | /* another task is sharing our hash bucket */ | 372 | /* another task is sharing our hash bucket */ |
373 | continue; | 373 | continue; |
374 | 374 | ||
375 | if (ri->rp && ri->rp->handler) | 375 | orig_ret_address = (unsigned long)ri->ret_addr; |
376 | ri->rp->handler(ri, regs); | 376 | |
377 | if (orig_ret_address != trampoline_address) | ||
378 | /* | ||
379 | * This is the real return address. Any other | ||
380 | * instances associated with this task are for | ||
381 | * other calls deeper on the call stack | ||
382 | */ | ||
383 | break; | ||
384 | } | ||
385 | |||
386 | kretprobe_assert(ri, orig_ret_address, trampoline_address); | ||
387 | |||
388 | correct_ret_addr = ri->ret_addr; | ||
389 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | ||
390 | if (ri->task != current) | ||
391 | /* another task is sharing our hash bucket */ | ||
392 | continue; | ||
377 | 393 | ||
378 | orig_ret_address = (unsigned long)ri->ret_addr; | 394 | orig_ret_address = (unsigned long)ri->ret_addr; |
395 | |||
396 | if (ri->rp && ri->rp->handler) { | ||
397 | ri->ret_addr = correct_ret_addr; | ||
398 | ri->rp->handler(ri, regs); | ||
399 | } | ||
400 | |||
379 | recycle_rp_inst(ri, &empty_rp); | 401 | recycle_rp_inst(ri, &empty_rp); |
380 | 402 | ||
381 | if (orig_ret_address != trampoline_address) { | 403 | if (orig_ret_address != trampoline_address) { |
@@ -387,7 +409,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, | |||
387 | break; | 409 | break; |
388 | } | 410 | } |
389 | } | 411 | } |
390 | kretprobe_assert(ri, orig_ret_address, trampoline_address); | 412 | |
391 | regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE; | 413 | regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE; |
392 | 414 | ||
393 | reset_current_kprobe(); | 415 | reset_current_kprobe(); |
@@ -465,8 +487,6 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) | |||
465 | goto out; | 487 | goto out; |
466 | } | 488 | } |
467 | reset_current_kprobe(); | 489 | reset_current_kprobe(); |
468 | if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO)) | ||
469 | local_irq_enable(); | ||
470 | out: | 490 | out: |
471 | preempt_enable_no_resched(); | 491 | preempt_enable_no_resched(); |
472 | 492 | ||
@@ -482,7 +502,7 @@ out: | |||
482 | return 1; | 502 | return 1; |
483 | } | 503 | } |
484 | 504 | ||
485 | int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | 505 | static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr) |
486 | { | 506 | { |
487 | struct kprobe *cur = kprobe_running(); | 507 | struct kprobe *cur = kprobe_running(); |
488 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 508 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
@@ -508,8 +528,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | |||
508 | restore_previous_kprobe(kcb); | 528 | restore_previous_kprobe(kcb); |
509 | else { | 529 | else { |
510 | reset_current_kprobe(); | 530 | reset_current_kprobe(); |
511 | if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO)) | ||
512 | local_irq_enable(); | ||
513 | } | 531 | } |
514 | preempt_enable_no_resched(); | 532 | preempt_enable_no_resched(); |
515 | break; | 533 | break; |
@@ -553,6 +571,18 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | |||
553 | return 0; | 571 | return 0; |
554 | } | 572 | } |
555 | 573 | ||
574 | int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | ||
575 | { | ||
576 | int ret; | ||
577 | |||
578 | if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT)) | ||
579 | local_irq_disable(); | ||
580 | ret = kprobe_trap_handler(regs, trapnr); | ||
581 | if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT)) | ||
582 | local_irq_restore(regs->psw.mask & ~PSW_MASK_PER); | ||
583 | return ret; | ||
584 | } | ||
585 | |||
556 | /* | 586 | /* |
557 | * Wrapper routine to for handling exceptions. | 587 | * Wrapper routine to for handling exceptions. |
558 | */ | 588 | */ |
@@ -560,8 +590,12 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | |||
560 | unsigned long val, void *data) | 590 | unsigned long val, void *data) |
561 | { | 591 | { |
562 | struct die_args *args = (struct die_args *)data; | 592 | struct die_args *args = (struct die_args *)data; |
593 | struct pt_regs *regs = args->regs; | ||
563 | int ret = NOTIFY_DONE; | 594 | int ret = NOTIFY_DONE; |
564 | 595 | ||
596 | if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT)) | ||
597 | local_irq_disable(); | ||
598 | |||
565 | switch (val) { | 599 | switch (val) { |
566 | case DIE_BPT: | 600 | case DIE_BPT: |
567 | if (kprobe_handler(args->regs)) | 601 | if (kprobe_handler(args->regs)) |
@@ -572,16 +606,17 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | |||
572 | ret = NOTIFY_STOP; | 606 | ret = NOTIFY_STOP; |
573 | break; | 607 | break; |
574 | case DIE_TRAP: | 608 | case DIE_TRAP: |
575 | /* kprobe_running() needs smp_processor_id() */ | 609 | if (!preemptible() && kprobe_running() && |
576 | preempt_disable(); | 610 | kprobe_trap_handler(args->regs, args->trapnr)) |
577 | if (kprobe_running() && | ||
578 | kprobe_fault_handler(args->regs, args->trapnr)) | ||
579 | ret = NOTIFY_STOP; | 611 | ret = NOTIFY_STOP; |
580 | preempt_enable(); | ||
581 | break; | 612 | break; |
582 | default: | 613 | default: |
583 | break; | 614 | break; |
584 | } | 615 | } |
616 | |||
617 | if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT)) | ||
618 | local_irq_restore(regs->psw.mask & ~PSW_MASK_PER); | ||
619 | |||
585 | return ret; | 620 | return ret; |
586 | } | 621 | } |
587 | 622 | ||
@@ -595,6 +630,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
595 | 630 | ||
596 | /* setup return addr to the jprobe handler routine */ | 631 | /* setup return addr to the jprobe handler routine */ |
597 | regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE; | 632 | regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE; |
633 | regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT); | ||
598 | 634 | ||
599 | /* r14 is the function return address */ | 635 | /* r14 is the function return address */ |
600 | kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14]; | 636 | kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14]; |
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index ac151399ef34..1995c1712fc8 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c | |||
@@ -95,7 +95,6 @@ EXPORT_SYMBOL_GPL(s390_handle_mcck); | |||
95 | static int notrace s390_revalidate_registers(struct mci *mci) | 95 | static int notrace s390_revalidate_registers(struct mci *mci) |
96 | { | 96 | { |
97 | int kill_task; | 97 | int kill_task; |
98 | u64 tmpclock; | ||
99 | u64 zero; | 98 | u64 zero; |
100 | void *fpt_save_area, *fpt_creg_save_area; | 99 | void *fpt_save_area, *fpt_creg_save_area; |
101 | 100 | ||
@@ -214,11 +213,10 @@ static int notrace s390_revalidate_registers(struct mci *mci) | |||
214 | : "0", "cc"); | 213 | : "0", "cc"); |
215 | #endif | 214 | #endif |
216 | /* Revalidate clock comparator register */ | 215 | /* Revalidate clock comparator register */ |
217 | asm volatile( | 216 | if (S390_lowcore.clock_comparator == -1) |
218 | " stck 0(%1)\n" | 217 | set_clock_comparator(S390_lowcore.mcck_clock); |
219 | " sckc 0(%1)" | 218 | else |
220 | : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory"); | 219 | set_clock_comparator(S390_lowcore.clock_comparator); |
221 | |||
222 | /* Check if old PSW is valid */ | 220 | /* Check if old PSW is valid */ |
223 | if (!mci->wp) | 221 | if (!mci->wp) |
224 | /* | 222 | /* |
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 56c8687b29b3..7eff9b7347c0 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/kernel_stat.h> | 19 | #include <linux/kernel_stat.h> |
20 | #include <linux/rcupdate.h> | 20 | #include <linux/rcupdate.h> |
21 | #include <linux/posix-timers.h> | 21 | #include <linux/posix-timers.h> |
22 | #include <linux/cpu.h> | ||
22 | 23 | ||
23 | #include <asm/s390_ext.h> | 24 | #include <asm/s390_ext.h> |
24 | #include <asm/timer.h> | 25 | #include <asm/timer.h> |
@@ -566,6 +567,23 @@ void init_cpu_vtimer(void) | |||
566 | __ctl_set_bit(0,10); | 567 | __ctl_set_bit(0,10); |
567 | } | 568 | } |
568 | 569 | ||
570 | static int __cpuinit s390_nohz_notify(struct notifier_block *self, | ||
571 | unsigned long action, void *hcpu) | ||
572 | { | ||
573 | struct s390_idle_data *idle; | ||
574 | long cpu = (long) hcpu; | ||
575 | |||
576 | idle = &per_cpu(s390_idle, cpu); | ||
577 | switch (action) { | ||
578 | case CPU_DYING: | ||
579 | case CPU_DYING_FROZEN: | ||
580 | idle->nohz_delay = 0; | ||
581 | default: | ||
582 | break; | ||
583 | } | ||
584 | return NOTIFY_OK; | ||
585 | } | ||
586 | |||
569 | void __init vtime_init(void) | 587 | void __init vtime_init(void) |
570 | { | 588 | { |
571 | /* request the cpu timer external interrupt */ | 589 | /* request the cpu timer external interrupt */ |
@@ -574,5 +592,6 @@ void __init vtime_init(void) | |||
574 | 592 | ||
575 | /* Enable cpu timer interrupts on the boot cpu. */ | 593 | /* Enable cpu timer interrupts on the boot cpu. */ |
576 | init_cpu_vtimer(); | 594 | init_cpu_vtimer(); |
595 | cpu_notifier(s390_nohz_notify, 0); | ||
577 | } | 596 | } |
578 | 597 | ||