diff options
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/s390/kernel/entry.S | 29 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 21 | ||||
-rw-r--r-- | arch/s390/kernel/irq.c | 8 | ||||
-rw-r--r-- | arch/s390/kernel/process.c | 1 | ||||
-rw-r--r-- | arch/s390/kernel/stacktrace.c | 90 |
6 files changed, 141 insertions, 9 deletions
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 9269b5788fac..eabf00a6f770 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -21,6 +21,7 @@ obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \ | |||
21 | obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o | 21 | obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o |
22 | 22 | ||
23 | obj-$(CONFIG_VIRT_TIMER) += vtime.o | 23 | obj-$(CONFIG_VIRT_TIMER) += vtime.o |
24 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | ||
24 | 25 | ||
25 | # Kexec part | 26 | # Kexec part |
26 | S390_KEXEC_OBJS := machine_kexec.o crash.o | 27 | S390_KEXEC_OBJS := machine_kexec.o crash.o |
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index d8948c342caf..5b5799ac8f83 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -58,6 +58,21 @@ STACK_SIZE = 1 << STACK_SHIFT | |||
58 | 58 | ||
59 | #define BASED(name) name-system_call(%r13) | 59 | #define BASED(name) name-system_call(%r13) |
60 | 60 | ||
61 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
62 | .macro TRACE_IRQS_ON | ||
63 | l %r1,BASED(.Ltrace_irq_on) | ||
64 | basr %r14,%r1 | ||
65 | .endm | ||
66 | |||
67 | .macro TRACE_IRQS_OFF | ||
68 | l %r1,BASED(.Ltrace_irq_off) | ||
69 | basr %r14,%r1 | ||
70 | .endm | ||
71 | #else | ||
72 | #define TRACE_IRQS_ON | ||
73 | #define TRACE_IRQS_OFF | ||
74 | #endif | ||
75 | |||
61 | /* | 76 | /* |
62 | * Register usage in interrupt handlers: | 77 | * Register usage in interrupt handlers: |
63 | * R9 - pointer to current task structure | 78 | * R9 - pointer to current task structure |
@@ -361,6 +376,7 @@ ret_from_fork: | |||
361 | st %r15,SP_R15(%r15) # store stack pointer for new kthread | 376 | st %r15,SP_R15(%r15) # store stack pointer for new kthread |
362 | 0: l %r1,BASED(.Lschedtail) | 377 | 0: l %r1,BASED(.Lschedtail) |
363 | basr %r14,%r1 | 378 | basr %r14,%r1 |
379 | TRACE_IRQS_ON | ||
364 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 380 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
365 | b BASED(sysc_return) | 381 | b BASED(sysc_return) |
366 | 382 | ||
@@ -516,6 +532,7 @@ pgm_no_vtime3: | |||
516 | mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS | 532 | mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS |
517 | mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID | 533 | mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID |
518 | oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP | 534 | oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP |
535 | TRACE_IRQS_ON | ||
519 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 536 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
520 | b BASED(sysc_do_svc) | 537 | b BASED(sysc_do_svc) |
521 | 538 | ||
@@ -539,9 +556,11 @@ io_int_handler: | |||
539 | io_no_vtime: | 556 | io_no_vtime: |
540 | #endif | 557 | #endif |
541 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 558 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct |
559 | TRACE_IRQS_OFF | ||
542 | l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ | 560 | l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ |
543 | la %r2,SP_PTREGS(%r15) # address of register-save area | 561 | la %r2,SP_PTREGS(%r15) # address of register-save area |
544 | basr %r14,%r1 # branch to standard irq handler | 562 | basr %r14,%r1 # branch to standard irq handler |
563 | TRACE_IRQS_ON | ||
545 | 564 | ||
546 | io_return: | 565 | io_return: |
547 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 566 | tm SP_PSW+1(%r15),0x01 # returning to user ? |
@@ -651,10 +670,12 @@ ext_int_handler: | |||
651 | ext_no_vtime: | 670 | ext_no_vtime: |
652 | #endif | 671 | #endif |
653 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 672 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct |
673 | TRACE_IRQS_OFF | ||
654 | la %r2,SP_PTREGS(%r15) # address of register-save area | 674 | la %r2,SP_PTREGS(%r15) # address of register-save area |
655 | lh %r3,__LC_EXT_INT_CODE # get interruption code | 675 | lh %r3,__LC_EXT_INT_CODE # get interruption code |
656 | l %r1,BASED(.Ldo_extint) | 676 | l %r1,BASED(.Ldo_extint) |
657 | basr %r14,%r1 | 677 | basr %r14,%r1 |
678 | TRACE_IRQS_ON | ||
658 | b BASED(io_return) | 679 | b BASED(io_return) |
659 | 680 | ||
660 | __critical_end: | 681 | __critical_end: |
@@ -731,8 +752,10 @@ mcck_no_vtime: | |||
731 | stosm __SF_EMPTY(%r15),0x04 # turn dat on | 752 | stosm __SF_EMPTY(%r15),0x04 # turn dat on |
732 | tm __TI_flags+3(%r9),_TIF_MCCK_PENDING | 753 | tm __TI_flags+3(%r9),_TIF_MCCK_PENDING |
733 | bno BASED(mcck_return) | 754 | bno BASED(mcck_return) |
755 | TRACE_IRQS_OFF | ||
734 | l %r1,BASED(.Ls390_handle_mcck) | 756 | l %r1,BASED(.Ls390_handle_mcck) |
735 | basr %r14,%r1 # call machine check handler | 757 | basr %r14,%r1 # call machine check handler |
758 | TRACE_IRQS_ON | ||
736 | mcck_return: | 759 | mcck_return: |
737 | mvc __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW | 760 | mvc __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW |
738 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit | 761 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit |
@@ -1012,7 +1035,11 @@ cleanup_io_leave_insn: | |||
1012 | .Lvfork: .long sys_vfork | 1035 | .Lvfork: .long sys_vfork |
1013 | .Lschedtail: .long schedule_tail | 1036 | .Lschedtail: .long schedule_tail |
1014 | .Lsysc_table: .long sys_call_table | 1037 | .Lsysc_table: .long sys_call_table |
1015 | 1038 | #ifdef CONFIG_TRACE_IRQFLAGS | |
1039 | .Ltrace_irq_on:.long trace_hardirqs_on | ||
1040 | .Ltrace_irq_off: | ||
1041 | .long trace_hardirqs_off | ||
1042 | #endif | ||
1016 | .Lcritical_start: | 1043 | .Lcritical_start: |
1017 | .long __critical_start + 0x80000000 | 1044 | .long __critical_start + 0x80000000 |
1018 | .Lcritical_end: | 1045 | .Lcritical_end: |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 1ca499fa54b4..56f5f613b868 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -58,6 +58,19 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \ | |||
58 | 58 | ||
59 | #define BASED(name) name-system_call(%r13) | 59 | #define BASED(name) name-system_call(%r13) |
60 | 60 | ||
61 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
62 | .macro TRACE_IRQS_ON | ||
63 | brasl %r14,trace_hardirqs_on | ||
64 | .endm | ||
65 | |||
66 | .macro TRACE_IRQS_OFF | ||
67 | brasl %r14,trace_hardirqs_off | ||
68 | .endm | ||
69 | #else | ||
70 | #define TRACE_IRQS_ON | ||
71 | #define TRACE_IRQS_OFF | ||
72 | #endif | ||
73 | |||
61 | .macro STORE_TIMER lc_offset | 74 | .macro STORE_TIMER lc_offset |
62 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 75 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
63 | stpt \lc_offset | 76 | stpt \lc_offset |
@@ -354,6 +367,7 @@ ret_from_fork: | |||
354 | jo 0f | 367 | jo 0f |
355 | stg %r15,SP_R15(%r15) # store stack pointer for new kthread | 368 | stg %r15,SP_R15(%r15) # store stack pointer for new kthread |
356 | 0: brasl %r14,schedule_tail | 369 | 0: brasl %r14,schedule_tail |
370 | TRACE_IRQS_ON | ||
357 | stosm 24(%r15),0x03 # reenable interrupts | 371 | stosm 24(%r15),0x03 # reenable interrupts |
358 | j sysc_return | 372 | j sysc_return |
359 | 373 | ||
@@ -535,6 +549,7 @@ pgm_no_vtime3: | |||
535 | mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS | 549 | mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS |
536 | mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID | 550 | mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID |
537 | oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP | 551 | oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP |
552 | TRACE_IRQS_ON | ||
538 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 553 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
539 | j sysc_do_svc | 554 | j sysc_do_svc |
540 | 555 | ||
@@ -557,8 +572,10 @@ io_int_handler: | |||
557 | io_no_vtime: | 572 | io_no_vtime: |
558 | #endif | 573 | #endif |
559 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 574 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct |
575 | TRACE_IRQS_OFF | ||
560 | la %r2,SP_PTREGS(%r15) # address of register-save area | 576 | la %r2,SP_PTREGS(%r15) # address of register-save area |
561 | brasl %r14,do_IRQ # call standard irq handler | 577 | brasl %r14,do_IRQ # call standard irq handler |
578 | TRACE_IRQS_ON | ||
562 | 579 | ||
563 | io_return: | 580 | io_return: |
564 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 581 | tm SP_PSW+1(%r15),0x01 # returning to user ? |
@@ -665,9 +682,11 @@ ext_int_handler: | |||
665 | ext_no_vtime: | 682 | ext_no_vtime: |
666 | #endif | 683 | #endif |
667 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 684 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct |
685 | TRACE_IRQS_OFF | ||
668 | la %r2,SP_PTREGS(%r15) # address of register-save area | 686 | la %r2,SP_PTREGS(%r15) # address of register-save area |
669 | llgh %r3,__LC_EXT_INT_CODE # get interruption code | 687 | llgh %r3,__LC_EXT_INT_CODE # get interruption code |
670 | brasl %r14,do_extint | 688 | brasl %r14,do_extint |
689 | TRACE_IRQS_ON | ||
671 | j io_return | 690 | j io_return |
672 | 691 | ||
673 | __critical_end: | 692 | __critical_end: |
@@ -743,7 +762,9 @@ mcck_no_vtime: | |||
743 | stosm __SF_EMPTY(%r15),0x04 # turn dat on | 762 | stosm __SF_EMPTY(%r15),0x04 # turn dat on |
744 | tm __TI_flags+7(%r9),_TIF_MCCK_PENDING | 763 | tm __TI_flags+7(%r9),_TIF_MCCK_PENDING |
745 | jno mcck_return | 764 | jno mcck_return |
765 | TRACE_IRQS_OFF | ||
746 | brasl %r14,s390_handle_mcck | 766 | brasl %r14,s390_handle_mcck |
767 | TRACE_IRQS_ON | ||
747 | mcck_return: | 768 | mcck_return: |
748 | mvc __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW | 769 | mvc __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW |
749 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit | 770 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit |
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 480b6a5fef3a..1eef50918615 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
@@ -69,10 +69,6 @@ asmlinkage void do_softirq(void) | |||
69 | 69 | ||
70 | local_irq_save(flags); | 70 | local_irq_save(flags); |
71 | 71 | ||
72 | account_system_vtime(current); | ||
73 | |||
74 | local_bh_disable(); | ||
75 | |||
76 | if (local_softirq_pending()) { | 72 | if (local_softirq_pending()) { |
77 | /* Get current stack pointer. */ | 73 | /* Get current stack pointer. */ |
78 | asm volatile("la %0,0(15)" : "=a" (old)); | 74 | asm volatile("la %0,0(15)" : "=a" (old)); |
@@ -95,10 +91,6 @@ asmlinkage void do_softirq(void) | |||
95 | __do_softirq(); | 91 | __do_softirq(); |
96 | } | 92 | } |
97 | 93 | ||
98 | account_system_vtime(current); | ||
99 | |||
100 | __local_bh_enable(); | ||
101 | |||
102 | local_irq_restore(flags); | 94 | local_irq_restore(flags); |
103 | } | 95 | } |
104 | 96 | ||
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 1f9399191794..78c8e5548caf 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
@@ -142,6 +142,7 @@ static void default_idle(void) | |||
142 | return; | 142 | return; |
143 | } | 143 | } |
144 | 144 | ||
145 | trace_hardirqs_on(); | ||
145 | /* Wait for external, I/O or machine check interrupt. */ | 146 | /* Wait for external, I/O or machine check interrupt. */ |
146 | __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT | | 147 | __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT | |
147 | PSW_MASK_IO | PSW_MASK_EXT); | 148 | PSW_MASK_IO | PSW_MASK_EXT); |
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c new file mode 100644 index 000000000000..de83f38288d0 --- /dev/null +++ b/arch/s390/kernel/stacktrace.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * arch/s390/kernel/stacktrace.c | ||
3 | * | ||
4 | * Stack trace management functions | ||
5 | * | ||
6 | * Copyright (C) IBM Corp. 2006 | ||
7 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
8 | */ | ||
9 | |||
10 | #include <linux/sched.h> | ||
11 | #include <linux/stacktrace.h> | ||
12 | #include <linux/kallsyms.h> | ||
13 | |||
14 | static inline unsigned long save_context_stack(struct stack_trace *trace, | ||
15 | unsigned int *skip, | ||
16 | unsigned long sp, | ||
17 | unsigned long low, | ||
18 | unsigned long high) | ||
19 | { | ||
20 | struct stack_frame *sf; | ||
21 | struct pt_regs *regs; | ||
22 | unsigned long addr; | ||
23 | |||
24 | while(1) { | ||
25 | sp &= PSW_ADDR_INSN; | ||
26 | if (sp < low || sp > high) | ||
27 | return sp; | ||
28 | sf = (struct stack_frame *)sp; | ||
29 | while(1) { | ||
30 | addr = sf->gprs[8] & PSW_ADDR_INSN; | ||
31 | if (!(*skip)) | ||
32 | trace->entries[trace->nr_entries++] = addr; | ||
33 | else | ||
34 | (*skip)--; | ||
35 | if (trace->nr_entries >= trace->max_entries) | ||
36 | return sp; | ||
37 | low = sp; | ||
38 | sp = sf->back_chain & PSW_ADDR_INSN; | ||
39 | if (!sp) | ||
40 | break; | ||
41 | if (sp <= low || sp > high - sizeof(*sf)) | ||
42 | return sp; | ||
43 | sf = (struct stack_frame *)sp; | ||
44 | } | ||
45 | /* Zero backchain detected, check for interrupt frame. */ | ||
46 | sp = (unsigned long)(sf + 1); | ||
47 | if (sp <= low || sp > high - sizeof(*regs)) | ||
48 | return sp; | ||
49 | regs = (struct pt_regs *)sp; | ||
50 | addr = regs->psw.addr & PSW_ADDR_INSN; | ||
51 | if (!(*skip)) | ||
52 | trace->entries[trace->nr_entries++] = addr; | ||
53 | else | ||
54 | (*skip)--; | ||
55 | if (trace->nr_entries >= trace->max_entries) | ||
56 | return sp; | ||
57 | low = sp; | ||
58 | sp = regs->gprs[15]; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | void save_stack_trace(struct stack_trace *trace, | ||
63 | struct task_struct *task, int all_contexts, | ||
64 | unsigned int skip) | ||
65 | { | ||
66 | register unsigned long sp asm ("15"); | ||
67 | unsigned long orig_sp; | ||
68 | |||
69 | sp &= PSW_ADDR_INSN; | ||
70 | orig_sp = sp; | ||
71 | |||
72 | sp = save_context_stack(trace, &skip, sp, | ||
73 | S390_lowcore.panic_stack - PAGE_SIZE, | ||
74 | S390_lowcore.panic_stack); | ||
75 | if ((sp != orig_sp) && !all_contexts) | ||
76 | return; | ||
77 | sp = save_context_stack(trace, &skip, sp, | ||
78 | S390_lowcore.async_stack - ASYNC_SIZE, | ||
79 | S390_lowcore.async_stack); | ||
80 | if ((sp != orig_sp) && !all_contexts) | ||
81 | return; | ||
82 | if (task) | ||
83 | save_context_stack(trace, &skip, sp, | ||
84 | (unsigned long) task_stack_page(task), | ||
85 | (unsigned long) task_stack_page(task) + THREAD_SIZE); | ||
86 | else | ||
87 | save_context_stack(trace, &skip, sp, S390_lowcore.thread_info, | ||
88 | S390_lowcore.thread_info + THREAD_SIZE); | ||
89 | return; | ||
90 | } | ||