diff options
author | Yoshinori Sato <ysato@users.sourceforge.jp> | 2015-05-10 13:36:51 -0400 |
---|---|---|
committer | Yoshinori Sato <ysato@users.sourceforge.jp> | 2015-06-23 00:35:50 -0400 |
commit | 883251dd163c551abcb1031803e20e3ccd1f988c (patch) | |
tree | af689584f4ee082cf973df93ca7b2ce216429c19 | |
parent | 88d1739f54200cecd7b25c9e53ede90309b59526 (diff) |
h8300: Interrupt and exceptions
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
-rw-r--r-- | arch/h8300/kernel/irq.c | 97 | ||||
-rw-r--r-- | arch/h8300/kernel/signal.c | 289 | ||||
-rw-r--r-- | arch/h8300/kernel/traps.c | 161 |
3 files changed, 547 insertions, 0 deletions
diff --git a/arch/h8300/kernel/irq.c b/arch/h8300/kernel/irq.c new file mode 100644 index 000000000000..da79f9521699 --- /dev/null +++ b/arch/h8300/kernel/irq.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * linux/arch/h8300/kernel/irq.c | ||
3 | * | ||
4 | * Copyright 2014-2015 Yoshinori Sato <ysato@users.sourceforge.jp> | ||
5 | */ | ||
6 | |||
7 | #include <linux/init.h> | ||
8 | #include <linux/interrupt.h> | ||
9 | #include <linux/irq.h> | ||
10 | #include <linux/irqdomain.h> | ||
11 | #include <linux/of_irq.h> | ||
12 | #include <asm/traps.h> | ||
13 | |||
14 | #ifdef CONFIG_RAMKERNEL | ||
15 | typedef void (*h8300_vector)(void); | ||
16 | |||
17 | static const h8300_vector __initconst trap_table[] = { | ||
18 | 0, 0, 0, 0, | ||
19 | _trace_break, | ||
20 | 0, 0, | ||
21 | _nmi, | ||
22 | _system_call, | ||
23 | 0, 0, | ||
24 | _trace_break, | ||
25 | }; | ||
26 | |||
27 | static unsigned long __init *get_vector_address(void) | ||
28 | { | ||
29 | unsigned long *rom_vector = CPU_VECTOR; | ||
30 | unsigned long base, tmp; | ||
31 | int vec_no; | ||
32 | |||
33 | base = rom_vector[EXT_IRQ0] & ADDR_MASK; | ||
34 | |||
35 | /* check romvector format */ | ||
36 | for (vec_no = EXT_IRQ0 + 1; vec_no <= EXT_IRQ0+EXT_IRQS; vec_no++) { | ||
37 | if ((base+(vec_no - EXT_IRQ0)*4) != | ||
38 | (rom_vector[vec_no] & ADDR_MASK)) | ||
39 | return NULL; | ||
40 | } | ||
41 | |||
42 | /* ramvector base address */ | ||
43 | base -= EXT_IRQ0*4; | ||
44 | |||
45 | /* writerble? */ | ||
46 | tmp = ~(*(volatile unsigned long *)base); | ||
47 | (*(volatile unsigned long *)base) = tmp; | ||
48 | if ((*(volatile unsigned long *)base) != tmp) | ||
49 | return NULL; | ||
50 | return (unsigned long *)base; | ||
51 | } | ||
52 | |||
53 | static void __init setup_vector(void) | ||
54 | { | ||
55 | int i; | ||
56 | unsigned long *ramvec, *ramvec_p; | ||
57 | const h8300_vector *trap_entry; | ||
58 | |||
59 | ramvec = get_vector_address(); | ||
60 | if (ramvec == NULL) | ||
61 | panic("interrupt vector serup failed."); | ||
62 | else | ||
63 | pr_debug("virtual vector at 0x%p\n", ramvec); | ||
64 | |||
65 | /* create redirect table */ | ||
66 | ramvec_p = ramvec; | ||
67 | trap_entry = trap_table; | ||
68 | for (i = 0; i < NR_IRQS; i++) { | ||
69 | if (i < 12) { | ||
70 | if (*trap_entry) | ||
71 | *ramvec_p = VECTOR(*trap_entry); | ||
72 | ramvec_p++; | ||
73 | trap_entry++; | ||
74 | } else | ||
75 | *ramvec_p++ = REDIRECT(_interrupt_entry); | ||
76 | } | ||
77 | _interrupt_redirect_table = ramvec; | ||
78 | } | ||
79 | #else | ||
80 | void setup_vector(void) | ||
81 | { | ||
82 | /* noting do */ | ||
83 | } | ||
84 | #endif | ||
85 | |||
86 | void __init init_IRQ(void) | ||
87 | { | ||
88 | setup_vector(); | ||
89 | irqchip_init(); | ||
90 | } | ||
91 | |||
92 | asmlinkage void do_IRQ(int irq) | ||
93 | { | ||
94 | irq_enter(); | ||
95 | generic_handle_irq(irq); | ||
96 | irq_exit(); | ||
97 | } | ||
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c new file mode 100644 index 000000000000..380fffd081b2 --- /dev/null +++ b/arch/h8300/kernel/signal.c | |||
@@ -0,0 +1,289 @@ | |||
1 | /* | ||
2 | * linux/arch/h8300/kernel/signal.c | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * uClinux H8/300 support by Yoshinori Sato <ysato@users.sourceforge.jp> | ||
13 | * and David McCullough <davidm@snapgear.com> | ||
14 | * | ||
15 | * Based on | ||
16 | * Linux/m68k by Hamish Macdonald | ||
17 | */ | ||
18 | |||
19 | /* | ||
20 | * ++roman (07/09/96): implemented signal stacks (specially for tosemu on | ||
21 | * Atari :-) Current limitation: Only one sigstack can be active at one time. | ||
22 | * If a second signal with SA_ONSTACK set arrives while working on a sigstack, | ||
23 | * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested | ||
24 | * signal handlers! | ||
25 | */ | ||
26 | |||
27 | #include <linux/sched.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/signal.h> | ||
31 | #include <linux/syscalls.h> | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/wait.h> | ||
34 | #include <linux/ptrace.h> | ||
35 | #include <linux/unistd.h> | ||
36 | #include <linux/stddef.h> | ||
37 | #include <linux/highuid.h> | ||
38 | #include <linux/personality.h> | ||
39 | #include <linux/tty.h> | ||
40 | #include <linux/binfmts.h> | ||
41 | #include <linux/tracehook.h> | ||
42 | |||
43 | #include <asm/setup.h> | ||
44 | #include <asm/uaccess.h> | ||
45 | #include <asm/pgtable.h> | ||
46 | #include <asm/traps.h> | ||
47 | #include <asm/ucontext.h> | ||
48 | |||
49 | /* | ||
50 | * Do a signal return; undo the signal stack. | ||
51 | * | ||
52 | * Keep the return code on the stack quadword aligned! | ||
53 | * That makes the cache flush below easier. | ||
54 | */ | ||
55 | |||
56 | struct rt_sigframe { | ||
57 | long dummy_er0; | ||
58 | long dummy_vector; | ||
59 | #if defined(CONFIG_CPU_H8S) | ||
60 | short dummy_exr; | ||
61 | #endif | ||
62 | long dummy_pc; | ||
63 | char *pretcode; | ||
64 | struct siginfo *pinfo; | ||
65 | void *puc; | ||
66 | unsigned char retcode[8]; | ||
67 | struct siginfo info; | ||
68 | struct ucontext uc; | ||
69 | int sig; | ||
70 | } __packed __aligned(2); | ||
71 | |||
72 | static inline int | ||
73 | restore_sigcontext(struct sigcontext *usc, int *pd0) | ||
74 | { | ||
75 | struct pt_regs *regs = current_pt_regs(); | ||
76 | int err = 0; | ||
77 | unsigned int ccr; | ||
78 | unsigned int usp; | ||
79 | unsigned int er0; | ||
80 | |||
81 | /* Always make any pending restarted system calls return -EINTR */ | ||
82 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
83 | |||
84 | /* restore passed registers */ | ||
85 | #define COPY(r) do { err |= get_user(regs->r, &usc->sc_##r); } while (0) | ||
86 | COPY(er1); | ||
87 | COPY(er2); | ||
88 | COPY(er3); | ||
89 | COPY(er5); | ||
90 | COPY(pc); | ||
91 | ccr = regs->ccr & 0x10; | ||
92 | COPY(ccr); | ||
93 | #undef COPY | ||
94 | regs->ccr &= 0xef; | ||
95 | regs->ccr |= ccr; | ||
96 | regs->orig_er0 = -1; /* disable syscall checks */ | ||
97 | err |= __get_user(usp, &usc->sc_usp); | ||
98 | wrusp(usp); | ||
99 | |||
100 | err |= __get_user(er0, &usc->sc_er0); | ||
101 | *pd0 = er0; | ||
102 | return err; | ||
103 | } | ||
104 | |||
105 | asmlinkage int sys_rt_sigreturn(void) | ||
106 | { | ||
107 | unsigned long usp = rdusp(); | ||
108 | struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4); | ||
109 | sigset_t set; | ||
110 | int er0; | ||
111 | |||
112 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
113 | goto badframe; | ||
114 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
115 | goto badframe; | ||
116 | |||
117 | set_current_blocked(&set); | ||
118 | |||
119 | if (restore_sigcontext(&frame->uc.uc_mcontext, &er0)) | ||
120 | goto badframe; | ||
121 | |||
122 | if (restore_altstack(&frame->uc.uc_stack)) | ||
123 | goto badframe; | ||
124 | |||
125 | return er0; | ||
126 | |||
127 | badframe: | ||
128 | force_sig(SIGSEGV, current); | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | ||
133 | unsigned long mask) | ||
134 | { | ||
135 | int err = 0; | ||
136 | |||
137 | err |= __put_user(regs->er0, &sc->sc_er0); | ||
138 | err |= __put_user(regs->er1, &sc->sc_er1); | ||
139 | err |= __put_user(regs->er2, &sc->sc_er2); | ||
140 | err |= __put_user(regs->er3, &sc->sc_er3); | ||
141 | err |= __put_user(regs->er4, &sc->sc_er4); | ||
142 | err |= __put_user(regs->er5, &sc->sc_er5); | ||
143 | err |= __put_user(regs->er6, &sc->sc_er6); | ||
144 | err |= __put_user(rdusp(), &sc->sc_usp); | ||
145 | err |= __put_user(regs->pc, &sc->sc_pc); | ||
146 | err |= __put_user(regs->ccr, &sc->sc_ccr); | ||
147 | err |= __put_user(mask, &sc->sc_mask); | ||
148 | |||
149 | return err; | ||
150 | } | ||
151 | |||
152 | static inline void __user * | ||
153 | get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size) | ||
154 | { | ||
155 | return (void __user *)((sigsp(rdusp(), ksig) - frame_size) & -8UL); | ||
156 | } | ||
157 | |||
158 | static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, | ||
159 | struct pt_regs *regs) | ||
160 | { | ||
161 | struct rt_sigframe *frame; | ||
162 | int err = 0; | ||
163 | unsigned char *ret; | ||
164 | |||
165 | frame = get_sigframe(ksig, regs, sizeof(*frame)); | ||
166 | |||
167 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
168 | return -EFAULT; | ||
169 | |||
170 | if (ksig->ka.sa.sa_flags & SA_SIGINFO) | ||
171 | err |= copy_siginfo_to_user(&frame->info, &ksig->info); | ||
172 | |||
173 | /* Create the ucontext. */ | ||
174 | err |= __put_user(0, &frame->uc.uc_flags); | ||
175 | err |= __put_user(0, &frame->uc.uc_link); | ||
176 | err |= __save_altstack(&frame->uc.uc_stack, rdusp()); | ||
177 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); | ||
178 | err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
179 | if (err) | ||
180 | return -EFAULT; | ||
181 | |||
182 | /* Set up to return from userspace. */ | ||
183 | ret = frame->retcode; | ||
184 | if (ksig->ka.sa.sa_flags & SA_RESTORER) | ||
185 | ret = (unsigned char *)(ksig->ka.sa.sa_restorer); | ||
186 | else { | ||
187 | /* sub.l er0,er0; mov.b #__NR_rt_sigreturn,r0l; trapa #0 */ | ||
188 | err |= __put_user(0x1a80f800 + (__NR_rt_sigreturn & 0xff), | ||
189 | (unsigned long *)(frame->retcode + 0)); | ||
190 | err |= __put_user(0x5700, | ||
191 | (unsigned short *)(frame->retcode + 4)); | ||
192 | } | ||
193 | err |= __put_user(ret, &frame->pretcode); | ||
194 | |||
195 | if (err) | ||
196 | return -EFAULT; | ||
197 | |||
198 | /* Set up registers for signal handler */ | ||
199 | wrusp((unsigned long) frame); | ||
200 | regs->pc = (unsigned long) ksig->ka.sa.sa_handler; | ||
201 | regs->er0 = ksig->sig; | ||
202 | regs->er1 = (unsigned long)&(frame->info); | ||
203 | regs->er2 = (unsigned long)&frame->uc; | ||
204 | regs->er5 = current->mm->start_data; /* GOT base */ | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static void | ||
210 | handle_restart(struct pt_regs *regs, struct k_sigaction *ka) | ||
211 | { | ||
212 | switch (regs->er0) { | ||
213 | case -ERESTARTNOHAND: | ||
214 | if (!ka) | ||
215 | goto do_restart; | ||
216 | regs->er0 = -EINTR; | ||
217 | break; | ||
218 | case -ERESTART_RESTARTBLOCK: | ||
219 | if (!ka) { | ||
220 | regs->er0 = __NR_restart_syscall; | ||
221 | regs->pc -= 2; | ||
222 | } else | ||
223 | regs->er0 = -EINTR; | ||
224 | break; | ||
225 | case -ERESTARTSYS: | ||
226 | if (!(ka->sa.sa_flags & SA_RESTART)) { | ||
227 | regs->er0 = -EINTR; | ||
228 | break; | ||
229 | } | ||
230 | /* fallthrough */ | ||
231 | case -ERESTARTNOINTR: | ||
232 | do_restart: | ||
233 | regs->er0 = regs->orig_er0; | ||
234 | regs->pc -= 2; | ||
235 | break; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * OK, we're invoking a handler | ||
241 | */ | ||
242 | static void | ||
243 | handle_signal(struct ksignal *ksig, struct pt_regs *regs) | ||
244 | { | ||
245 | sigset_t *oldset = sigmask_to_save(); | ||
246 | int ret; | ||
247 | /* are we from a system call? */ | ||
248 | if (regs->orig_er0 >= 0) | ||
249 | handle_restart(regs, &ksig->ka); | ||
250 | |||
251 | ret = setup_rt_frame(ksig, oldset, regs); | ||
252 | |||
253 | signal_setup_done(ret, ksig, 0); | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
258 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
259 | * mistake. | ||
260 | */ | ||
261 | static void do_signal(struct pt_regs *regs) | ||
262 | { | ||
263 | struct ksignal ksig; | ||
264 | |||
265 | current->thread.esp0 = (unsigned long) regs; | ||
266 | |||
267 | if (get_signal(&ksig)) { | ||
268 | /* Whee! Actually deliver the signal. */ | ||
269 | handle_signal(&ksig, regs); | ||
270 | return; | ||
271 | } | ||
272 | /* Did we come from a system call? */ | ||
273 | if (regs->orig_er0 >= 0) | ||
274 | handle_restart(regs, NULL); | ||
275 | |||
276 | /* If there's no signal to deliver, we just restore the saved mask. */ | ||
277 | restore_saved_sigmask(); | ||
278 | } | ||
279 | |||
280 | asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) | ||
281 | { | ||
282 | if (thread_info_flags & _TIF_SIGPENDING) | ||
283 | do_signal(regs); | ||
284 | |||
285 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | ||
286 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
287 | tracehook_notify_resume(regs); | ||
288 | } | ||
289 | } | ||
diff --git a/arch/h8300/kernel/traps.c b/arch/h8300/kernel/traps.c new file mode 100644 index 000000000000..1b2d7cdd6591 --- /dev/null +++ b/arch/h8300/kernel/traps.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * linux/arch/h8300/boot/traps.c -- general exception handling code | ||
3 | * H8/300 support Yoshinori Sato <ysato@users.sourceforge.jp> | ||
4 | * | ||
5 | * Cloned from Linux/m68k. | ||
6 | * | ||
7 | * No original Copyright holder listed, | ||
8 | * Probable original (C) Roman Zippel (assigned DJD, 1999) | ||
9 | * | ||
10 | * Copyright 1999-2000 D. Jeff Dionne, <jeff@rt-control.com> | ||
11 | * | ||
12 | * This file is subject to the terms and conditions of the GNU General Public | ||
13 | * License. See the file COPYING in the main directory of this archive | ||
14 | * for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/types.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/bug.h> | ||
24 | |||
25 | #include <asm/irq.h> | ||
26 | #include <asm/traps.h> | ||
27 | #include <asm/page.h> | ||
28 | |||
29 | static DEFINE_SPINLOCK(die_lock); | ||
30 | |||
31 | /* | ||
32 | * this must be called very early as the kernel might | ||
33 | * use some instruction that are emulated on the 060 | ||
34 | */ | ||
35 | |||
36 | void __init base_trap_init(void) | ||
37 | { | ||
38 | } | ||
39 | |||
40 | void __init trap_init(void) | ||
41 | { | ||
42 | } | ||
43 | |||
44 | asmlinkage void set_esp0(unsigned long ssp) | ||
45 | { | ||
46 | current->thread.esp0 = ssp; | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * Generic dumping code. Used for panic and debug. | ||
51 | */ | ||
52 | |||
53 | static void dump(struct pt_regs *fp) | ||
54 | { | ||
55 | unsigned long *sp; | ||
56 | unsigned char *tp; | ||
57 | int i; | ||
58 | |||
59 | pr_info("\nCURRENT PROCESS:\n\n"); | ||
60 | pr_info("COMM=%s PID=%d\n", current->comm, current->pid); | ||
61 | if (current->mm) { | ||
62 | pr_info("TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n", | ||
63 | (int) current->mm->start_code, | ||
64 | (int) current->mm->end_code, | ||
65 | (int) current->mm->start_data, | ||
66 | (int) current->mm->end_data, | ||
67 | (int) current->mm->end_data, | ||
68 | (int) current->mm->brk); | ||
69 | pr_info("USER-STACK=%08x KERNEL-STACK=%08lx\n\n", | ||
70 | (int) current->mm->start_stack, | ||
71 | (int) PAGE_SIZE+(unsigned long)current); | ||
72 | } | ||
73 | |||
74 | show_regs(fp); | ||
75 | pr_info("\nCODE:"); | ||
76 | tp = ((unsigned char *) fp->pc) - 0x20; | ||
77 | for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { | ||
78 | if ((i % 0x10) == 0) | ||
79 | pr_info("\n%08x: ", (int) (tp + i)); | ||
80 | pr_info("%08x ", (int) *sp++); | ||
81 | } | ||
82 | pr_info("\n"); | ||
83 | |||
84 | pr_info("\nKERNEL STACK:"); | ||
85 | tp = ((unsigned char *) fp) - 0x40; | ||
86 | for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { | ||
87 | if ((i % 0x10) == 0) | ||
88 | pr_info("\n%08x: ", (int) (tp + i)); | ||
89 | pr_info("%08x ", (int) *sp++); | ||
90 | } | ||
91 | pr_info("\n"); | ||
92 | if (STACK_MAGIC != *(unsigned long *)((unsigned long)current+PAGE_SIZE)) | ||
93 | pr_info("(Possibly corrupted stack page??)\n"); | ||
94 | |||
95 | pr_info("\n\n"); | ||
96 | } | ||
97 | |||
98 | void die(const char *str, struct pt_regs *fp, unsigned long err) | ||
99 | { | ||
100 | static int diecount; | ||
101 | |||
102 | oops_enter(); | ||
103 | |||
104 | console_verbose(); | ||
105 | spin_lock_irq(&die_lock); | ||
106 | report_bug(fp->pc, fp); | ||
107 | pr_crit("%s: %04lx [#%d] ", str, err & 0xffff, ++diecount); | ||
108 | dump(fp); | ||
109 | |||
110 | spin_unlock_irq(&die_lock); | ||
111 | do_exit(SIGSEGV); | ||
112 | } | ||
113 | |||
114 | static int kstack_depth_to_print = 24; | ||
115 | |||
116 | void show_stack(struct task_struct *task, unsigned long *esp) | ||
117 | { | ||
118 | unsigned long *stack, addr; | ||
119 | int i; | ||
120 | |||
121 | if (esp == NULL) | ||
122 | esp = (unsigned long *) &esp; | ||
123 | |||
124 | stack = esp; | ||
125 | |||
126 | pr_info("Stack from %08lx:", (unsigned long)stack); | ||
127 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
128 | if (((unsigned long)stack & (THREAD_SIZE - 1)) == 0) | ||
129 | break; | ||
130 | if (i % 8 == 0) | ||
131 | pr_info("\n "); | ||
132 | pr_info(" %08lx", *stack++); | ||
133 | } | ||
134 | |||
135 | pr_info("\nCall Trace:"); | ||
136 | i = 0; | ||
137 | stack = esp; | ||
138 | while (((unsigned long)stack & (THREAD_SIZE - 1)) != 0) { | ||
139 | addr = *stack++; | ||
140 | /* | ||
141 | * If the address is either in the text segment of the | ||
142 | * kernel, or in the region which contains vmalloc'ed | ||
143 | * memory, it *may* be the address of a calling | ||
144 | * routine; if so, print it so that someone tracing | ||
145 | * down the cause of the crash will be able to figure | ||
146 | * out the call path that was taken. | ||
147 | */ | ||
148 | if (check_kernel_text(addr)) { | ||
149 | if (i % 4 == 0) | ||
150 | pr_info("\n "); | ||
151 | pr_info(" [<%08lx>]", addr); | ||
152 | i++; | ||
153 | } | ||
154 | } | ||
155 | pr_info("\n"); | ||
156 | } | ||
157 | |||
158 | void show_trace_task(struct task_struct *tsk) | ||
159 | { | ||
160 | show_stack(tsk, (unsigned long *)tsk->thread.esp0); | ||
161 | } | ||