diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-09 17:38:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-09 17:38:16 -0400 |
commit | c61c48dfe00907007df3b87e4ed271a5c143bdda (patch) | |
tree | 6d26bd3a8b4aa3cf35cad35fa27d1e0afe715db3 /arch/xtensa/kernel | |
parent | e30f4192456971623b40c97a027346b69457ef69 (diff) | |
parent | b341d84c8ac5ecbf7aa0b3ccd0745d87e881953c (diff) |
Merge tag 'xtensa-next-20130508' of git://github.com/czankel/xtensa-linux
Pull xtensa updates from Chris Zankel:
"Support for the latest MMU architecture that allows for a larger
accessible memory region, and various bug-fixes"
* tag 'xtensa-next-20130508' of git://github.com/czankel/xtensa-linux:
xtensa: Switch to asm-generic/linkage.h
xtensa: fix redboot load address
xtensa: ISS: fix timer_lock usage in rs_open
xtensa: disable IRQs while IRQ handler is running
xtensa: enable lockdep support
xtensa: fix arch_irqs_disabled_flags implementation
xtensa: add irq flags trace support
xtensa: provide custom CALLER_ADDR* implementations
xtensa: add stacktrace support
xtensa: clean up stpill_registers
xtensa: don't use a7 in simcalls
xtensa: don't attempt to use unconfigured timers
xtensa: provide default platform_pcibios_init implementation
xtensa: remove KCORE_ELF again
xtensa: document MMUv3 setup sequence
xtensa: add MMU v3 support
xtensa: fix ibreakenable register update
xtensa: fix oprofile building as module
Diffstat (limited to 'arch/xtensa/kernel')
-rw-r--r-- | arch/xtensa/kernel/Makefile | 8 | ||||
-rw-r--r-- | arch/xtensa/kernel/entry.S | 84 | ||||
-rw-r--r-- | arch/xtensa/kernel/head.S | 39 | ||||
-rw-r--r-- | arch/xtensa/kernel/platform.c | 1 | ||||
-rw-r--r-- | arch/xtensa/kernel/stacktrace.c | 120 | ||||
-rw-r--r-- | arch/xtensa/kernel/traps.c | 67 | ||||
-rw-r--r-- | arch/xtensa/kernel/vectors.S | 16 | ||||
-rw-r--r-- | arch/xtensa/kernel/vmlinux.lds.S | 48 | ||||
-rw-r--r-- | arch/xtensa/kernel/xtensa_ksyms.c | 5 |
9 files changed, 265 insertions, 123 deletions
diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile index c3a59d992ac0..1e7fc87a94bb 100644 --- a/arch/xtensa/kernel/Makefile +++ b/arch/xtensa/kernel/Makefile | |||
@@ -4,14 +4,16 @@ | |||
4 | 4 | ||
5 | extra-y := head.o vmlinux.lds | 5 | extra-y := head.o vmlinux.lds |
6 | 6 | ||
7 | obj-y := align.o entry.o irq.o coprocessor.o process.o ptrace.o \ | 7 | obj-y := align.o coprocessor.o entry.o irq.o pci-dma.o platform.o process.o \ |
8 | setup.o signal.o syscall.o time.o traps.o vectors.o platform.o \ | 8 | ptrace.o setup.o signal.o stacktrace.o syscall.o time.o traps.o \ |
9 | pci-dma.o | 9 | vectors.o |
10 | 10 | ||
11 | obj-$(CONFIG_KGDB) += xtensa-stub.o | 11 | obj-$(CONFIG_KGDB) += xtensa-stub.o |
12 | obj-$(CONFIG_PCI) += pci.o | 12 | obj-$(CONFIG_PCI) += pci.o |
13 | obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o | 13 | obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o |
14 | 14 | ||
15 | AFLAGS_head.o += -mtext-section-literals | ||
16 | |||
15 | # In the Xtensa architecture, assembly generates literals which must always | 17 | # In the Xtensa architecture, assembly generates literals which must always |
16 | # precede the L32R instruction with a relative offset less than 256 kB. | 18 | # precede the L32R instruction with a relative offset less than 256 kB. |
17 | # Therefore, the .text and .literal section must be combined in parenthesis | 19 | # Therefore, the .text and .literal section must be combined in parenthesis |
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 63845f950792..5082507d5631 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S | |||
@@ -354,16 +354,16 @@ common_exception: | |||
354 | * so we can allow exceptions and interrupts (*) again. | 354 | * so we can allow exceptions and interrupts (*) again. |
355 | * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X) | 355 | * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X) |
356 | * | 356 | * |
357 | * (*) We only allow interrupts of higher priority than current IRQ | 357 | * (*) We only allow interrupts if they were previously enabled and |
358 | * we're not handling an IRQ | ||
358 | */ | 359 | */ |
359 | 360 | ||
360 | rsr a3, ps | 361 | rsr a3, ps |
361 | addi a0, a0, -4 | 362 | addi a0, a0, -EXCCAUSE_LEVEL1_INTERRUPT |
362 | movi a2, 1 | 363 | movi a2, LOCKLEVEL |
363 | extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH | 364 | extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH |
364 | # a3 = PS.INTLEVEL | 365 | # a3 = PS.INTLEVEL |
365 | movnez a2, a3, a3 # a2 = 1: level-1, > 1: high priority | 366 | moveqz a3, a2, a0 # a3 = LOCKLEVEL iff interrupt |
366 | moveqz a3, a2, a0 # a3 = IRQ level iff interrupt | ||
367 | movi a2, 1 << PS_WOE_BIT | 367 | movi a2, 1 << PS_WOE_BIT |
368 | or a3, a3, a2 | 368 | or a3, a3, a2 |
369 | rsr a0, exccause | 369 | rsr a0, exccause |
@@ -389,6 +389,22 @@ common_exception: | |||
389 | 389 | ||
390 | save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT | 390 | save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT |
391 | 391 | ||
392 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
393 | l32i a4, a1, PT_DEPC | ||
394 | /* Double exception means we came here with an exception | ||
395 | * while PS.EXCM was set, i.e. interrupts disabled. | ||
396 | */ | ||
397 | bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f | ||
398 | l32i a4, a1, PT_EXCCAUSE | ||
399 | bnei a4, EXCCAUSE_LEVEL1_INTERRUPT, 1f | ||
400 | /* We came here with an interrupt means interrupts were enabled | ||
401 | * and we've just disabled them. | ||
402 | */ | ||
403 | movi a4, trace_hardirqs_off | ||
404 | callx4 a4 | ||
405 | 1: | ||
406 | #endif | ||
407 | |||
392 | /* Go to second-level dispatcher. Set up parameters to pass to the | 408 | /* Go to second-level dispatcher. Set up parameters to pass to the |
393 | * exception handler and call the exception handler. | 409 | * exception handler and call the exception handler. |
394 | */ | 410 | */ |
@@ -407,11 +423,29 @@ common_exception: | |||
407 | .global common_exception_return | 423 | .global common_exception_return |
408 | common_exception_return: | 424 | common_exception_return: |
409 | 425 | ||
426 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
427 | l32i a4, a1, PT_DEPC | ||
428 | /* Double exception means we came here with an exception | ||
429 | * while PS.EXCM was set, i.e. interrupts disabled. | ||
430 | */ | ||
431 | bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f | ||
432 | l32i a4, a1, PT_EXCCAUSE | ||
433 | bnei a4, EXCCAUSE_LEVEL1_INTERRUPT, 1f | ||
434 | /* We came here with an interrupt means interrupts were enabled | ||
435 | * and we'll reenable them on return. | ||
436 | */ | ||
437 | movi a4, trace_hardirqs_on | ||
438 | callx4 a4 | ||
439 | 1: | ||
440 | #endif | ||
441 | |||
410 | /* Jump if we are returning from kernel exceptions. */ | 442 | /* Jump if we are returning from kernel exceptions. */ |
411 | 443 | ||
412 | 1: l32i a3, a1, PT_PS | 444 | 1: l32i a3, a1, PT_PS |
413 | _bbci.l a3, PS_UM_BIT, 4f | 445 | _bbci.l a3, PS_UM_BIT, 4f |
414 | 446 | ||
447 | rsil a2, 0 | ||
448 | |||
415 | /* Specific to a user exception exit: | 449 | /* Specific to a user exception exit: |
416 | * We need to check some flags for signal handling and rescheduling, | 450 | * We need to check some flags for signal handling and rescheduling, |
417 | * and have to restore WB and WS, extra states, and all registers | 451 | * and have to restore WB and WS, extra states, and all registers |
@@ -652,51 +686,19 @@ common_exception_exit: | |||
652 | 686 | ||
653 | l32i a0, a1, PT_DEPC | 687 | l32i a0, a1, PT_DEPC |
654 | l32i a3, a1, PT_AREG3 | 688 | l32i a3, a1, PT_AREG3 |
655 | _bltui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f | ||
656 | |||
657 | wsr a0, depc | ||
658 | l32i a2, a1, PT_AREG2 | 689 | l32i a2, a1, PT_AREG2 |
659 | l32i a0, a1, PT_AREG0 | 690 | _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f |
660 | l32i a1, a1, PT_AREG1 | ||
661 | rfde | ||
662 | 691 | ||
663 | 1: | ||
664 | /* Restore a0...a3 and return */ | 692 | /* Restore a0...a3 and return */ |
665 | 693 | ||
666 | rsr a0, ps | ||
667 | extui a2, a0, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH | ||
668 | movi a0, 2f | ||
669 | slli a2, a2, 4 | ||
670 | add a0, a2, a0 | ||
671 | l32i a2, a1, PT_AREG2 | ||
672 | jx a0 | ||
673 | |||
674 | .macro irq_exit_level level | ||
675 | .align 16 | ||
676 | .if XCHAL_EXCM_LEVEL >= \level | ||
677 | l32i a0, a1, PT_PC | ||
678 | wsr a0, epc\level | ||
679 | l32i a0, a1, PT_AREG0 | 694 | l32i a0, a1, PT_AREG0 |
680 | l32i a1, a1, PT_AREG1 | 695 | l32i a1, a1, PT_AREG1 |
681 | rfi \level | 696 | rfe |
682 | .endif | ||
683 | .endm | ||
684 | 697 | ||
685 | .align 16 | 698 | 1: wsr a0, depc |
686 | 2: | ||
687 | l32i a0, a1, PT_AREG0 | 699 | l32i a0, a1, PT_AREG0 |
688 | l32i a1, a1, PT_AREG1 | 700 | l32i a1, a1, PT_AREG1 |
689 | rfe | 701 | rfde |
690 | |||
691 | .align 16 | ||
692 | /* no rfi for level-1 irq, handled by rfe above*/ | ||
693 | nop | ||
694 | |||
695 | irq_exit_level 2 | ||
696 | irq_exit_level 3 | ||
697 | irq_exit_level 4 | ||
698 | irq_exit_level 5 | ||
699 | irq_exit_level 6 | ||
700 | 702 | ||
701 | ENDPROC(kernel_exception) | 703 | ENDPROC(kernel_exception) |
702 | 704 | ||
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S index df88f98737f4..ef12c0e6fa25 100644 --- a/arch/xtensa/kernel/head.S +++ b/arch/xtensa/kernel/head.S | |||
@@ -48,17 +48,36 @@ | |||
48 | */ | 48 | */ |
49 | 49 | ||
50 | __HEAD | 50 | __HEAD |
51 | .begin no-absolute-literals | ||
52 | |||
51 | ENTRY(_start) | 53 | ENTRY(_start) |
52 | 54 | ||
53 | _j 2f | 55 | /* Preserve the pointer to the boot parameter list in EXCSAVE_1 */ |
56 | wsr a2, excsave1 | ||
57 | _j _SetupMMU | ||
58 | |||
59 | .align 4 | ||
60 | .literal_position | ||
61 | .Lstartup: | ||
62 | .word _startup | ||
63 | |||
54 | .align 4 | 64 | .align 4 |
55 | 1: .word _startup | 65 | .global _SetupMMU |
56 | 2: l32r a0, 1b | 66 | _SetupMMU: |
67 | Offset = _SetupMMU - _start | ||
68 | |||
69 | #ifdef CONFIG_INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX | ||
70 | initialize_mmu | ||
71 | #endif | ||
72 | .end no-absolute-literals | ||
73 | |||
74 | l32r a0, .Lstartup | ||
57 | jx a0 | 75 | jx a0 |
58 | 76 | ||
59 | ENDPROC(_start) | 77 | ENDPROC(_start) |
60 | 78 | ||
61 | .section .init.text, "ax" | 79 | __INIT |
80 | .literal_position | ||
62 | 81 | ||
63 | ENTRY(_startup) | 82 | ENTRY(_startup) |
64 | 83 | ||
@@ -67,10 +86,6 @@ ENTRY(_startup) | |||
67 | movi a0, LOCKLEVEL | 86 | movi a0, LOCKLEVEL |
68 | wsr a0, ps | 87 | wsr a0, ps |
69 | 88 | ||
70 | /* Preserve the pointer to the boot parameter list in EXCSAVE_1 */ | ||
71 | |||
72 | wsr a2, excsave1 | ||
73 | |||
74 | /* Start with a fresh windowbase and windowstart. */ | 89 | /* Start with a fresh windowbase and windowstart. */ |
75 | 90 | ||
76 | movi a1, 1 | 91 | movi a1, 1 |
@@ -86,7 +101,9 @@ ENTRY(_startup) | |||
86 | /* Clear debugging registers. */ | 101 | /* Clear debugging registers. */ |
87 | 102 | ||
88 | #if XCHAL_HAVE_DEBUG | 103 | #if XCHAL_HAVE_DEBUG |
104 | #if XCHAL_NUM_IBREAK > 0 | ||
89 | wsr a0, ibreakenable | 105 | wsr a0, ibreakenable |
106 | #endif | ||
90 | wsr a0, icount | 107 | wsr a0, icount |
91 | movi a1, 15 | 108 | movi a1, 15 |
92 | wsr a0, icountlevel | 109 | wsr a0, icountlevel |
@@ -156,8 +173,6 @@ ENTRY(_startup) | |||
156 | 173 | ||
157 | isync | 174 | isync |
158 | 175 | ||
159 | initialize_mmu | ||
160 | |||
161 | /* Unpack data sections | 176 | /* Unpack data sections |
162 | * | 177 | * |
163 | * The linker script used to build the Linux kernel image | 178 | * The linker script used to build the Linux kernel image |
@@ -205,6 +220,10 @@ ENTRY(_startup) | |||
205 | 220 | ||
206 | ___flush_dcache_all a2 a3 | 221 | ___flush_dcache_all a2 a3 |
207 | #endif | 222 | #endif |
223 | memw | ||
224 | isync | ||
225 | ___invalidate_icache_all a2 a3 | ||
226 | isync | ||
208 | 227 | ||
209 | /* Setup stack and enable window exceptions (keep irqs disabled) */ | 228 | /* Setup stack and enable window exceptions (keep irqs disabled) */ |
210 | 229 | ||
diff --git a/arch/xtensa/kernel/platform.c b/arch/xtensa/kernel/platform.c index 44bf21c3769a..2bd6c351f37c 100644 --- a/arch/xtensa/kernel/platform.c +++ b/arch/xtensa/kernel/platform.c | |||
@@ -36,6 +36,7 @@ _F(void, power_off, (void), { while(1); }); | |||
36 | _F(void, idle, (void), { __asm__ __volatile__ ("waiti 0" ::: "memory"); }); | 36 | _F(void, idle, (void), { __asm__ __volatile__ ("waiti 0" ::: "memory"); }); |
37 | _F(void, heartbeat, (void), { }); | 37 | _F(void, heartbeat, (void), { }); |
38 | _F(int, pcibios_fixup, (void), { return 0; }); | 38 | _F(int, pcibios_fixup, (void), { return 0; }); |
39 | _F(void, pcibios_init, (void), { }); | ||
39 | 40 | ||
40 | #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT | 41 | #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT |
41 | _F(void, calibrate_ccount, (void), | 42 | _F(void, calibrate_ccount, (void), |
diff --git a/arch/xtensa/kernel/stacktrace.c b/arch/xtensa/kernel/stacktrace.c new file mode 100644 index 000000000000..7d2c317bd98b --- /dev/null +++ b/arch/xtensa/kernel/stacktrace.c | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * arch/xtensa/kernel/stacktrace.c | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * Copyright (C) 2001 - 2013 Tensilica Inc. | ||
9 | */ | ||
10 | #include <linux/export.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/stacktrace.h> | ||
13 | |||
14 | #include <asm/stacktrace.h> | ||
15 | #include <asm/traps.h> | ||
16 | |||
17 | void walk_stackframe(unsigned long *sp, | ||
18 | int (*fn)(struct stackframe *frame, void *data), | ||
19 | void *data) | ||
20 | { | ||
21 | unsigned long a0, a1; | ||
22 | unsigned long sp_end; | ||
23 | |||
24 | a1 = (unsigned long)sp; | ||
25 | sp_end = ALIGN(a1, THREAD_SIZE); | ||
26 | |||
27 | spill_registers(); | ||
28 | |||
29 | while (a1 < sp_end) { | ||
30 | struct stackframe frame; | ||
31 | |||
32 | sp = (unsigned long *)a1; | ||
33 | |||
34 | a0 = *(sp - 4); | ||
35 | a1 = *(sp - 3); | ||
36 | |||
37 | if (a1 <= (unsigned long)sp) | ||
38 | break; | ||
39 | |||
40 | frame.pc = MAKE_PC_FROM_RA(a0, a1); | ||
41 | frame.sp = a1; | ||
42 | |||
43 | if (fn(&frame, data)) | ||
44 | return; | ||
45 | } | ||
46 | } | ||
47 | |||
48 | #ifdef CONFIG_STACKTRACE | ||
49 | |||
50 | struct stack_trace_data { | ||
51 | struct stack_trace *trace; | ||
52 | unsigned skip; | ||
53 | }; | ||
54 | |||
55 | static int stack_trace_cb(struct stackframe *frame, void *data) | ||
56 | { | ||
57 | struct stack_trace_data *trace_data = data; | ||
58 | struct stack_trace *trace = trace_data->trace; | ||
59 | |||
60 | if (trace_data->skip) { | ||
61 | --trace_data->skip; | ||
62 | return 0; | ||
63 | } | ||
64 | if (!kernel_text_address(frame->pc)) | ||
65 | return 0; | ||
66 | |||
67 | trace->entries[trace->nr_entries++] = frame->pc; | ||
68 | return trace->nr_entries >= trace->max_entries; | ||
69 | } | ||
70 | |||
71 | void save_stack_trace_tsk(struct task_struct *task, struct stack_trace *trace) | ||
72 | { | ||
73 | struct stack_trace_data trace_data = { | ||
74 | .trace = trace, | ||
75 | .skip = trace->skip, | ||
76 | }; | ||
77 | walk_stackframe(stack_pointer(task), stack_trace_cb, &trace_data); | ||
78 | } | ||
79 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | ||
80 | |||
81 | void save_stack_trace(struct stack_trace *trace) | ||
82 | { | ||
83 | save_stack_trace_tsk(current, trace); | ||
84 | } | ||
85 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
86 | |||
87 | #endif | ||
88 | |||
89 | #ifdef CONFIG_FRAME_POINTER | ||
90 | |||
91 | struct return_addr_data { | ||
92 | unsigned long addr; | ||
93 | unsigned skip; | ||
94 | }; | ||
95 | |||
96 | static int return_address_cb(struct stackframe *frame, void *data) | ||
97 | { | ||
98 | struct return_addr_data *r = data; | ||
99 | |||
100 | if (r->skip) { | ||
101 | --r->skip; | ||
102 | return 0; | ||
103 | } | ||
104 | if (!kernel_text_address(frame->pc)) | ||
105 | return 0; | ||
106 | r->addr = frame->pc; | ||
107 | return 1; | ||
108 | } | ||
109 | |||
110 | unsigned long return_address(unsigned level) | ||
111 | { | ||
112 | struct return_addr_data r = { | ||
113 | .skip = level + 1, | ||
114 | }; | ||
115 | walk_stackframe(stack_pointer(NULL), return_address_cb, &r); | ||
116 | return r.addr; | ||
117 | } | ||
118 | EXPORT_SYMBOL(return_address); | ||
119 | |||
120 | #endif | ||
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c index 458186dab5dc..3e8a05c874cd 100644 --- a/arch/xtensa/kernel/traps.c +++ b/arch/xtensa/kernel/traps.c | |||
@@ -11,7 +11,7 @@ | |||
11 | * | 11 | * |
12 | * Essentially rewritten for the Xtensa architecture port. | 12 | * Essentially rewritten for the Xtensa architecture port. |
13 | * | 13 | * |
14 | * Copyright (C) 2001 - 2005 Tensilica Inc. | 14 | * Copyright (C) 2001 - 2013 Tensilica Inc. |
15 | * | 15 | * |
16 | * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> | 16 | * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> |
17 | * Chris Zankel <chris@zankel.net> | 17 | * Chris Zankel <chris@zankel.net> |
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/hardirq.h> | 33 | #include <linux/hardirq.h> |
34 | 34 | ||
35 | #include <asm/stacktrace.h> | ||
35 | #include <asm/ptrace.h> | 36 | #include <asm/ptrace.h> |
36 | #include <asm/timex.h> | 37 | #include <asm/timex.h> |
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
@@ -195,7 +196,6 @@ void do_multihit(struct pt_regs *regs, unsigned long exccause) | |||
195 | 196 | ||
196 | /* | 197 | /* |
197 | * IRQ handler. | 198 | * IRQ handler. |
198 | * PS.INTLEVEL is the current IRQ priority level. | ||
199 | */ | 199 | */ |
200 | 200 | ||
201 | extern void do_IRQ(int, struct pt_regs *); | 201 | extern void do_IRQ(int, struct pt_regs *); |
@@ -212,18 +212,21 @@ void do_interrupt(struct pt_regs *regs) | |||
212 | XCHAL_INTLEVEL6_MASK, | 212 | XCHAL_INTLEVEL6_MASK, |
213 | XCHAL_INTLEVEL7_MASK, | 213 | XCHAL_INTLEVEL7_MASK, |
214 | }; | 214 | }; |
215 | unsigned level = get_sr(ps) & PS_INTLEVEL_MASK; | ||
216 | |||
217 | if (WARN_ON_ONCE(level >= ARRAY_SIZE(int_level_mask))) | ||
218 | return; | ||
219 | 215 | ||
220 | for (;;) { | 216 | for (;;) { |
221 | unsigned intread = get_sr(interrupt); | 217 | unsigned intread = get_sr(interrupt); |
222 | unsigned intenable = get_sr(intenable); | 218 | unsigned intenable = get_sr(intenable); |
223 | unsigned int_at_level = intread & intenable & | 219 | unsigned int_at_level = intread & intenable; |
224 | int_level_mask[level]; | 220 | unsigned level; |
221 | |||
222 | for (level = LOCKLEVEL; level > 0; --level) { | ||
223 | if (int_at_level & int_level_mask[level]) { | ||
224 | int_at_level &= int_level_mask[level]; | ||
225 | break; | ||
226 | } | ||
227 | } | ||
225 | 228 | ||
226 | if (!int_at_level) | 229 | if (level == 0) |
227 | return; | 230 | return; |
228 | 231 | ||
229 | /* | 232 | /* |
@@ -404,53 +407,25 @@ void show_regs(struct pt_regs * regs) | |||
404 | regs->syscall); | 407 | regs->syscall); |
405 | } | 408 | } |
406 | 409 | ||
407 | static __always_inline unsigned long *stack_pointer(struct task_struct *task) | 410 | static int show_trace_cb(struct stackframe *frame, void *data) |
408 | { | 411 | { |
409 | unsigned long *sp; | 412 | if (kernel_text_address(frame->pc)) { |
410 | 413 | printk(" [<%08lx>] ", frame->pc); | |
411 | if (!task || task == current) | 414 | print_symbol("%s\n", frame->pc); |
412 | __asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp)); | 415 | } |
413 | else | 416 | return 0; |
414 | sp = (unsigned long *)task->thread.sp; | ||
415 | |||
416 | return sp; | ||
417 | } | 417 | } |
418 | 418 | ||
419 | void show_trace(struct task_struct *task, unsigned long *sp) | 419 | void show_trace(struct task_struct *task, unsigned long *sp) |
420 | { | 420 | { |
421 | unsigned long a0, a1, pc; | 421 | if (!sp) |
422 | unsigned long sp_start, sp_end; | 422 | sp = stack_pointer(task); |
423 | |||
424 | if (sp) | ||
425 | a1 = (unsigned long)sp; | ||
426 | else | ||
427 | a1 = (unsigned long)stack_pointer(task); | ||
428 | |||
429 | sp_start = a1 & ~(THREAD_SIZE-1); | ||
430 | sp_end = sp_start + THREAD_SIZE; | ||
431 | 423 | ||
432 | printk("Call Trace:"); | 424 | printk("Call Trace:"); |
433 | #ifdef CONFIG_KALLSYMS | 425 | #ifdef CONFIG_KALLSYMS |
434 | printk("\n"); | 426 | printk("\n"); |
435 | #endif | 427 | #endif |
436 | spill_registers(); | 428 | walk_stackframe(sp, show_trace_cb, NULL); |
437 | |||
438 | while (a1 > sp_start && a1 < sp_end) { | ||
439 | sp = (unsigned long*)a1; | ||
440 | |||
441 | a0 = *(sp - 4); | ||
442 | a1 = *(sp - 3); | ||
443 | |||
444 | if (a1 <= (unsigned long) sp) | ||
445 | break; | ||
446 | |||
447 | pc = MAKE_PC_FROM_RA(a0, a1); | ||
448 | |||
449 | if (kernel_text_address(pc)) { | ||
450 | printk(" [<%08lx>] ", pc); | ||
451 | print_symbol("%s\n", pc); | ||
452 | } | ||
453 | } | ||
454 | printk("\n"); | 429 | printk("\n"); |
455 | } | 430 | } |
456 | 431 | ||
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S index 82109b42e240..f9e175382aa9 100644 --- a/arch/xtensa/kernel/vectors.S +++ b/arch/xtensa/kernel/vectors.S | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <asm/processor.h> | 50 | #include <asm/processor.h> |
51 | #include <asm/page.h> | 51 | #include <asm/page.h> |
52 | #include <asm/thread_info.h> | 52 | #include <asm/thread_info.h> |
53 | #include <asm/vectors.h> | ||
53 | 54 | ||
54 | #define WINDOW_VECTORS_SIZE 0x180 | 55 | #define WINDOW_VECTORS_SIZE 0x180 |
55 | 56 | ||
@@ -220,7 +221,7 @@ ENTRY(_DoubleExceptionVector) | |||
220 | 221 | ||
221 | xsr a0, depc # get DEPC, save a0 | 222 | xsr a0, depc # get DEPC, save a0 |
222 | 223 | ||
223 | movi a3, XCHAL_WINDOW_VECTORS_VADDR | 224 | movi a3, WINDOW_VECTORS_VADDR |
224 | _bltu a0, a3, .Lfixup | 225 | _bltu a0, a3, .Lfixup |
225 | addi a3, a3, WINDOW_VECTORS_SIZE | 226 | addi a3, a3, WINDOW_VECTORS_SIZE |
226 | _bgeu a0, a3, .Lfixup | 227 | _bgeu a0, a3, .Lfixup |
@@ -385,9 +386,12 @@ ENDPROC(_DebugInterruptVector) | |||
385 | .if XCHAL_EXCM_LEVEL >= \level | 386 | .if XCHAL_EXCM_LEVEL >= \level |
386 | .section .Level\level\()InterruptVector.text, "ax" | 387 | .section .Level\level\()InterruptVector.text, "ax" |
387 | ENTRY(_Level\level\()InterruptVector) | 388 | ENTRY(_Level\level\()InterruptVector) |
388 | wsr a0, epc1 | 389 | wsr a0, excsave2 |
389 | rsr a0, epc\level | 390 | rsr a0, epc\level |
390 | xsr a0, epc1 | 391 | wsr a0, epc1 |
392 | movi a0, EXCCAUSE_LEVEL1_INTERRUPT | ||
393 | wsr a0, exccause | ||
394 | rsr a0, eps\level | ||
391 | # branch to user or kernel vector | 395 | # branch to user or kernel vector |
392 | j _SimulateUserKernelVectorException | 396 | j _SimulateUserKernelVectorException |
393 | .endif | 397 | .endif |
@@ -439,10 +443,8 @@ ENDPROC(_WindowOverflow4) | |||
439 | */ | 443 | */ |
440 | .align 4 | 444 | .align 4 |
441 | _SimulateUserKernelVectorException: | 445 | _SimulateUserKernelVectorException: |
442 | wsr a0, excsave2 | 446 | addi a0, a0, (1 << PS_EXCM_BIT) |
443 | movi a0, 4 # LEVEL1_INTERRUPT cause | 447 | wsr a0, ps |
444 | wsr a0, exccause | ||
445 | rsr a0, ps | ||
446 | bbsi.l a0, PS_UM_BIT, 1f # branch if user mode | 448 | bbsi.l a0, PS_UM_BIT, 1f # branch if user mode |
447 | rsr a0, excsave2 # restore a0 | 449 | rsr a0, excsave2 # restore a0 |
448 | j _KernelExceptionVector # simulate kernel vector exception | 450 | j _KernelExceptionVector # simulate kernel vector exception |
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S index 14695240536d..21acd11b5df2 100644 --- a/arch/xtensa/kernel/vmlinux.lds.S +++ b/arch/xtensa/kernel/vmlinux.lds.S | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/page.h> | 18 | #include <asm/page.h> |
19 | #include <asm/thread_info.h> | 19 | #include <asm/thread_info.h> |
20 | 20 | ||
21 | #include <asm/vectors.h> | ||
21 | #include <variant/core.h> | 22 | #include <variant/core.h> |
22 | #include <platform/hardware.h> | 23 | #include <platform/hardware.h> |
23 | OUTPUT_ARCH(xtensa) | 24 | OUTPUT_ARCH(xtensa) |
@@ -30,7 +31,7 @@ jiffies = jiffies_64; | |||
30 | #endif | 31 | #endif |
31 | 32 | ||
32 | #ifndef KERNELOFFSET | 33 | #ifndef KERNELOFFSET |
33 | #define KERNELOFFSET 0xd0001000 | 34 | #define KERNELOFFSET 0xd0003000 |
34 | #endif | 35 | #endif |
35 | 36 | ||
36 | /* Note: In the following macros, it would be nice to specify only the | 37 | /* Note: In the following macros, it would be nice to specify only the |
@@ -185,16 +186,16 @@ SECTIONS | |||
185 | 186 | ||
186 | SECTION_VECTOR (_WindowVectors_text, | 187 | SECTION_VECTOR (_WindowVectors_text, |
187 | .WindowVectors.text, | 188 | .WindowVectors.text, |
188 | XCHAL_WINDOW_VECTORS_VADDR, 4, | 189 | WINDOW_VECTORS_VADDR, 4, |
189 | .dummy) | 190 | .dummy) |
190 | SECTION_VECTOR (_DebugInterruptVector_literal, | 191 | SECTION_VECTOR (_DebugInterruptVector_literal, |
191 | .DebugInterruptVector.literal, | 192 | .DebugInterruptVector.literal, |
192 | XCHAL_DEBUG_VECTOR_VADDR - 4, | 193 | DEBUG_VECTOR_VADDR - 4, |
193 | SIZEOF(.WindowVectors.text), | 194 | SIZEOF(.WindowVectors.text), |
194 | .WindowVectors.text) | 195 | .WindowVectors.text) |
195 | SECTION_VECTOR (_DebugInterruptVector_text, | 196 | SECTION_VECTOR (_DebugInterruptVector_text, |
196 | .DebugInterruptVector.text, | 197 | .DebugInterruptVector.text, |
197 | XCHAL_DEBUG_VECTOR_VADDR, | 198 | DEBUG_VECTOR_VADDR, |
198 | 4, | 199 | 4, |
199 | .DebugInterruptVector.literal) | 200 | .DebugInterruptVector.literal) |
200 | #undef LAST | 201 | #undef LAST |
@@ -202,7 +203,7 @@ SECTIONS | |||
202 | #if XCHAL_EXCM_LEVEL >= 2 | 203 | #if XCHAL_EXCM_LEVEL >= 2 |
203 | SECTION_VECTOR (_Level2InterruptVector_text, | 204 | SECTION_VECTOR (_Level2InterruptVector_text, |
204 | .Level2InterruptVector.text, | 205 | .Level2InterruptVector.text, |
205 | XCHAL_INTLEVEL2_VECTOR_VADDR, | 206 | INTLEVEL2_VECTOR_VADDR, |
206 | SIZEOF(LAST), LAST) | 207 | SIZEOF(LAST), LAST) |
207 | # undef LAST | 208 | # undef LAST |
208 | # define LAST .Level2InterruptVector.text | 209 | # define LAST .Level2InterruptVector.text |
@@ -210,7 +211,7 @@ SECTIONS | |||
210 | #if XCHAL_EXCM_LEVEL >= 3 | 211 | #if XCHAL_EXCM_LEVEL >= 3 |
211 | SECTION_VECTOR (_Level3InterruptVector_text, | 212 | SECTION_VECTOR (_Level3InterruptVector_text, |
212 | .Level3InterruptVector.text, | 213 | .Level3InterruptVector.text, |
213 | XCHAL_INTLEVEL3_VECTOR_VADDR, | 214 | INTLEVEL3_VECTOR_VADDR, |
214 | SIZEOF(LAST), LAST) | 215 | SIZEOF(LAST), LAST) |
215 | # undef LAST | 216 | # undef LAST |
216 | # define LAST .Level3InterruptVector.text | 217 | # define LAST .Level3InterruptVector.text |
@@ -218,7 +219,7 @@ SECTIONS | |||
218 | #if XCHAL_EXCM_LEVEL >= 4 | 219 | #if XCHAL_EXCM_LEVEL >= 4 |
219 | SECTION_VECTOR (_Level4InterruptVector_text, | 220 | SECTION_VECTOR (_Level4InterruptVector_text, |
220 | .Level4InterruptVector.text, | 221 | .Level4InterruptVector.text, |
221 | XCHAL_INTLEVEL4_VECTOR_VADDR, | 222 | INTLEVEL4_VECTOR_VADDR, |
222 | SIZEOF(LAST), LAST) | 223 | SIZEOF(LAST), LAST) |
223 | # undef LAST | 224 | # undef LAST |
224 | # define LAST .Level4InterruptVector.text | 225 | # define LAST .Level4InterruptVector.text |
@@ -226,7 +227,7 @@ SECTIONS | |||
226 | #if XCHAL_EXCM_LEVEL >= 5 | 227 | #if XCHAL_EXCM_LEVEL >= 5 |
227 | SECTION_VECTOR (_Level5InterruptVector_text, | 228 | SECTION_VECTOR (_Level5InterruptVector_text, |
228 | .Level5InterruptVector.text, | 229 | .Level5InterruptVector.text, |
229 | XCHAL_INTLEVEL5_VECTOR_VADDR, | 230 | INTLEVEL5_VECTOR_VADDR, |
230 | SIZEOF(LAST), LAST) | 231 | SIZEOF(LAST), LAST) |
231 | # undef LAST | 232 | # undef LAST |
232 | # define LAST .Level5InterruptVector.text | 233 | # define LAST .Level5InterruptVector.text |
@@ -234,39 +235,39 @@ SECTIONS | |||
234 | #if XCHAL_EXCM_LEVEL >= 6 | 235 | #if XCHAL_EXCM_LEVEL >= 6 |
235 | SECTION_VECTOR (_Level6InterruptVector_text, | 236 | SECTION_VECTOR (_Level6InterruptVector_text, |
236 | .Level6InterruptVector.text, | 237 | .Level6InterruptVector.text, |
237 | XCHAL_INTLEVEL6_VECTOR_VADDR, | 238 | INTLEVEL6_VECTOR_VADDR, |
238 | SIZEOF(LAST), LAST) | 239 | SIZEOF(LAST), LAST) |
239 | # undef LAST | 240 | # undef LAST |
240 | # define LAST .Level6InterruptVector.text | 241 | # define LAST .Level6InterruptVector.text |
241 | #endif | 242 | #endif |
242 | SECTION_VECTOR (_KernelExceptionVector_literal, | 243 | SECTION_VECTOR (_KernelExceptionVector_literal, |
243 | .KernelExceptionVector.literal, | 244 | .KernelExceptionVector.literal, |
244 | XCHAL_KERNEL_VECTOR_VADDR - 4, | 245 | KERNEL_VECTOR_VADDR - 4, |
245 | SIZEOF(LAST), LAST) | 246 | SIZEOF(LAST), LAST) |
246 | #undef LAST | 247 | #undef LAST |
247 | SECTION_VECTOR (_KernelExceptionVector_text, | 248 | SECTION_VECTOR (_KernelExceptionVector_text, |
248 | .KernelExceptionVector.text, | 249 | .KernelExceptionVector.text, |
249 | XCHAL_KERNEL_VECTOR_VADDR, | 250 | KERNEL_VECTOR_VADDR, |
250 | 4, | 251 | 4, |
251 | .KernelExceptionVector.literal) | 252 | .KernelExceptionVector.literal) |
252 | SECTION_VECTOR (_UserExceptionVector_literal, | 253 | SECTION_VECTOR (_UserExceptionVector_literal, |
253 | .UserExceptionVector.literal, | 254 | .UserExceptionVector.literal, |
254 | XCHAL_USER_VECTOR_VADDR - 4, | 255 | USER_VECTOR_VADDR - 4, |
255 | SIZEOF(.KernelExceptionVector.text), | 256 | SIZEOF(.KernelExceptionVector.text), |
256 | .KernelExceptionVector.text) | 257 | .KernelExceptionVector.text) |
257 | SECTION_VECTOR (_UserExceptionVector_text, | 258 | SECTION_VECTOR (_UserExceptionVector_text, |
258 | .UserExceptionVector.text, | 259 | .UserExceptionVector.text, |
259 | XCHAL_USER_VECTOR_VADDR, | 260 | USER_VECTOR_VADDR, |
260 | 4, | 261 | 4, |
261 | .UserExceptionVector.literal) | 262 | .UserExceptionVector.literal) |
262 | SECTION_VECTOR (_DoubleExceptionVector_literal, | 263 | SECTION_VECTOR (_DoubleExceptionVector_literal, |
263 | .DoubleExceptionVector.literal, | 264 | .DoubleExceptionVector.literal, |
264 | XCHAL_DOUBLEEXC_VECTOR_VADDR - 16, | 265 | DOUBLEEXC_VECTOR_VADDR - 16, |
265 | SIZEOF(.UserExceptionVector.text), | 266 | SIZEOF(.UserExceptionVector.text), |
266 | .UserExceptionVector.text) | 267 | .UserExceptionVector.text) |
267 | SECTION_VECTOR (_DoubleExceptionVector_text, | 268 | SECTION_VECTOR (_DoubleExceptionVector_text, |
268 | .DoubleExceptionVector.text, | 269 | .DoubleExceptionVector.text, |
269 | XCHAL_DOUBLEEXC_VECTOR_VADDR, | 270 | DOUBLEEXC_VECTOR_VADDR, |
270 | 32, | 271 | 32, |
271 | .DoubleExceptionVector.literal) | 272 | .DoubleExceptionVector.literal) |
272 | 273 | ||
@@ -284,11 +285,26 @@ SECTIONS | |||
284 | . = ALIGN(0x10); | 285 | . = ALIGN(0x10); |
285 | .bootstrap : { *(.bootstrap.literal .bootstrap.text .bootstrap.data) } | 286 | .bootstrap : { *(.bootstrap.literal .bootstrap.text .bootstrap.data) } |
286 | 287 | ||
287 | .ResetVector.text XCHAL_RESET_VECTOR_VADDR : | 288 | .ResetVector.text RESET_VECTOR_VADDR : |
288 | { | 289 | { |
289 | *(.ResetVector.text) | 290 | *(.ResetVector.text) |
290 | } | 291 | } |
291 | 292 | ||
293 | |||
294 | /* | ||
295 | * This is a remapped copy of the Secondary Reset Vector Code. | ||
296 | * It keeps gdb in sync with the PC after switching | ||
297 | * to the temporary mapping used while setting up | ||
298 | * the V2 MMU mappings for Linux. | ||
299 | * | ||
300 | * Only debug information about this section is put in the kernel image. | ||
301 | */ | ||
302 | .SecondaryResetVector.remapped_text 0x46000000 (INFO): | ||
303 | { | ||
304 | *(.SecondaryResetVector.remapped_text) | ||
305 | } | ||
306 | |||
307 | |||
292 | .xt.lit : { *(.xt.lit) } | 308 | .xt.lit : { *(.xt.lit) } |
293 | .xt.prop : { *(.xt.prop) } | 309 | .xt.prop : { *(.xt.prop) } |
294 | 310 | ||
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index afe058b24e6e..42c53c87c204 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c | |||
@@ -119,3 +119,8 @@ EXPORT_SYMBOL(outsl); | |||
119 | EXPORT_SYMBOL(insb); | 119 | EXPORT_SYMBOL(insb); |
120 | EXPORT_SYMBOL(insw); | 120 | EXPORT_SYMBOL(insw); |
121 | EXPORT_SYMBOL(insl); | 121 | EXPORT_SYMBOL(insl); |
122 | |||
123 | extern long common_exception_return; | ||
124 | extern long _spill_registers; | ||
125 | EXPORT_SYMBOL(common_exception_return); | ||
126 | EXPORT_SYMBOL(_spill_registers); | ||