diff options
author | Aurelien Jacquiot <a-jacquiot@ti.com> | 2011-10-04 11:10:02 -0400 |
---|---|---|
committer | Mark Salter <msalter@redhat.com> | 2011-10-06 19:48:02 -0400 |
commit | e94e668251ab31b17ef6dcd16ba7fe05ffc1917a (patch) | |
tree | b0024e31bb2a321ccea190d66be4d91f4bc39d29 | |
parent | 8a0c9e0348479f1b85c640da4795bdd775970bf3 (diff) |
C6X: build infrastructure
Original port to early 2.6 kernel using TI COFF toolchain.
Brought up to date by Mark Salter <msalter@redhat.com>
Signed-off-by: Aurelien Jacquiot <a-jacquiot@ti.com>
Signed-off-by: Mark Salter <msalter@redhat.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r-- | arch/c6x/include/asm/traps.h | 36 | ||||
-rw-r--r-- | arch/c6x/kernel/asm-offsets.c | 123 | ||||
-rw-r--r-- | arch/c6x/kernel/entry.S | 803 | ||||
-rw-r--r-- | arch/c6x/kernel/traps.c | 423 |
4 files changed, 1385 insertions, 0 deletions
diff --git a/arch/c6x/include/asm/traps.h b/arch/c6x/include/asm/traps.h new file mode 100644 index 000000000000..62124d7b1b5f --- /dev/null +++ b/arch/c6x/include/asm/traps.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Port on Texas Instruments TMS320C6x architecture | ||
3 | * | ||
4 | * Copyright (C) 2004, 2009, 2011 Texas Instruments Incorporated | ||
5 | * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #ifndef _ASM_C6X_TRAPS_H | ||
12 | #define _ASM_C6X_TRAPS_H | ||
13 | |||
14 | #define EXCEPT_TYPE_NXF 31 /* NMI */ | ||
15 | #define EXCEPT_TYPE_EXC 30 /* external exception */ | ||
16 | #define EXCEPT_TYPE_IXF 1 /* internal exception */ | ||
17 | #define EXCEPT_TYPE_SXF 0 /* software exception */ | ||
18 | |||
19 | #define EXCEPT_CAUSE_LBX (1 << 7) /* loop buffer exception */ | ||
20 | #define EXCEPT_CAUSE_PRX (1 << 6) /* privilege exception */ | ||
21 | #define EXCEPT_CAUSE_RAX (1 << 5) /* resource access exception */ | ||
22 | #define EXCEPT_CAUSE_RCX (1 << 4) /* resource conflict exception */ | ||
23 | #define EXCEPT_CAUSE_OPX (1 << 3) /* opcode exception */ | ||
24 | #define EXCEPT_CAUSE_EPX (1 << 2) /* execute packet exception */ | ||
25 | #define EXCEPT_CAUSE_FPX (1 << 1) /* fetch packet exception */ | ||
26 | #define EXCEPT_CAUSE_IFX (1 << 0) /* instruction fetch exception */ | ||
27 | |||
28 | struct exception_info { | ||
29 | char *kernel_str; | ||
30 | int signo; | ||
31 | int code; | ||
32 | }; | ||
33 | |||
34 | extern int (*c6x_nmi_handler)(struct pt_regs *regs); | ||
35 | |||
36 | #endif /* _ASM_C6X_TRAPS_H */ | ||
diff --git a/arch/c6x/kernel/asm-offsets.c b/arch/c6x/kernel/asm-offsets.c new file mode 100644 index 000000000000..759ad6d207b6 --- /dev/null +++ b/arch/c6x/kernel/asm-offsets.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * Generate definitions needed by assembly language modules. | ||
3 | * This code generates raw asm output which is post-processed | ||
4 | * to extract and format the required data. | ||
5 | */ | ||
6 | |||
7 | #include <linux/sched.h> | ||
8 | #include <linux/thread_info.h> | ||
9 | #include <asm/procinfo.h> | ||
10 | #include <linux/kbuild.h> | ||
11 | #include <linux/unistd.h> | ||
12 | |||
13 | void foo(void) | ||
14 | { | ||
15 | OFFSET(REGS_A16, pt_regs, a16); | ||
16 | OFFSET(REGS_A17, pt_regs, a17); | ||
17 | OFFSET(REGS_A18, pt_regs, a18); | ||
18 | OFFSET(REGS_A19, pt_regs, a19); | ||
19 | OFFSET(REGS_A20, pt_regs, a20); | ||
20 | OFFSET(REGS_A21, pt_regs, a21); | ||
21 | OFFSET(REGS_A22, pt_regs, a22); | ||
22 | OFFSET(REGS_A23, pt_regs, a23); | ||
23 | OFFSET(REGS_A24, pt_regs, a24); | ||
24 | OFFSET(REGS_A25, pt_regs, a25); | ||
25 | OFFSET(REGS_A26, pt_regs, a26); | ||
26 | OFFSET(REGS_A27, pt_regs, a27); | ||
27 | OFFSET(REGS_A28, pt_regs, a28); | ||
28 | OFFSET(REGS_A29, pt_regs, a29); | ||
29 | OFFSET(REGS_A30, pt_regs, a30); | ||
30 | OFFSET(REGS_A31, pt_regs, a31); | ||
31 | |||
32 | OFFSET(REGS_B16, pt_regs, b16); | ||
33 | OFFSET(REGS_B17, pt_regs, b17); | ||
34 | OFFSET(REGS_B18, pt_regs, b18); | ||
35 | OFFSET(REGS_B19, pt_regs, b19); | ||
36 | OFFSET(REGS_B20, pt_regs, b20); | ||
37 | OFFSET(REGS_B21, pt_regs, b21); | ||
38 | OFFSET(REGS_B22, pt_regs, b22); | ||
39 | OFFSET(REGS_B23, pt_regs, b23); | ||
40 | OFFSET(REGS_B24, pt_regs, b24); | ||
41 | OFFSET(REGS_B25, pt_regs, b25); | ||
42 | OFFSET(REGS_B26, pt_regs, b26); | ||
43 | OFFSET(REGS_B27, pt_regs, b27); | ||
44 | OFFSET(REGS_B28, pt_regs, b28); | ||
45 | OFFSET(REGS_B29, pt_regs, b29); | ||
46 | OFFSET(REGS_B30, pt_regs, b30); | ||
47 | OFFSET(REGS_B31, pt_regs, b31); | ||
48 | |||
49 | OFFSET(REGS_A0, pt_regs, a0); | ||
50 | OFFSET(REGS_A1, pt_regs, a1); | ||
51 | OFFSET(REGS_A2, pt_regs, a2); | ||
52 | OFFSET(REGS_A3, pt_regs, a3); | ||
53 | OFFSET(REGS_A4, pt_regs, a4); | ||
54 | OFFSET(REGS_A5, pt_regs, a5); | ||
55 | OFFSET(REGS_A6, pt_regs, a6); | ||
56 | OFFSET(REGS_A7, pt_regs, a7); | ||
57 | OFFSET(REGS_A8, pt_regs, a8); | ||
58 | OFFSET(REGS_A9, pt_regs, a9); | ||
59 | OFFSET(REGS_A10, pt_regs, a10); | ||
60 | OFFSET(REGS_A11, pt_regs, a11); | ||
61 | OFFSET(REGS_A12, pt_regs, a12); | ||
62 | OFFSET(REGS_A13, pt_regs, a13); | ||
63 | OFFSET(REGS_A14, pt_regs, a14); | ||
64 | OFFSET(REGS_A15, pt_regs, a15); | ||
65 | |||
66 | OFFSET(REGS_B0, pt_regs, b0); | ||
67 | OFFSET(REGS_B1, pt_regs, b1); | ||
68 | OFFSET(REGS_B2, pt_regs, b2); | ||
69 | OFFSET(REGS_B3, pt_regs, b3); | ||
70 | OFFSET(REGS_B4, pt_regs, b4); | ||
71 | OFFSET(REGS_B5, pt_regs, b5); | ||
72 | OFFSET(REGS_B6, pt_regs, b6); | ||
73 | OFFSET(REGS_B7, pt_regs, b7); | ||
74 | OFFSET(REGS_B8, pt_regs, b8); | ||
75 | OFFSET(REGS_B9, pt_regs, b9); | ||
76 | OFFSET(REGS_B10, pt_regs, b10); | ||
77 | OFFSET(REGS_B11, pt_regs, b11); | ||
78 | OFFSET(REGS_B12, pt_regs, b12); | ||
79 | OFFSET(REGS_B13, pt_regs, b13); | ||
80 | OFFSET(REGS_DP, pt_regs, dp); | ||
81 | OFFSET(REGS_SP, pt_regs, sp); | ||
82 | |||
83 | OFFSET(REGS_TSR, pt_regs, tsr); | ||
84 | OFFSET(REGS_ORIG_A4, pt_regs, orig_a4); | ||
85 | |||
86 | DEFINE(REGS__END, sizeof(struct pt_regs)); | ||
87 | BLANK(); | ||
88 | |||
89 | OFFSET(THREAD_PC, thread_struct, pc); | ||
90 | OFFSET(THREAD_B15_14, thread_struct, b15_14); | ||
91 | OFFSET(THREAD_A15_14, thread_struct, a15_14); | ||
92 | OFFSET(THREAD_B13_12, thread_struct, b13_12); | ||
93 | OFFSET(THREAD_A13_12, thread_struct, a13_12); | ||
94 | OFFSET(THREAD_B11_10, thread_struct, b11_10); | ||
95 | OFFSET(THREAD_A11_10, thread_struct, a11_10); | ||
96 | OFFSET(THREAD_RICL_ICL, thread_struct, ricl_icl); | ||
97 | BLANK(); | ||
98 | |||
99 | OFFSET(TASK_STATE, task_struct, state); | ||
100 | BLANK(); | ||
101 | |||
102 | OFFSET(THREAD_INFO_FLAGS, thread_info, flags); | ||
103 | OFFSET(THREAD_INFO_PREEMPT_COUNT, thread_info, preempt_count); | ||
104 | BLANK(); | ||
105 | |||
106 | /* These would be unneccessary if we ran asm files | ||
107 | * through the preprocessor. | ||
108 | */ | ||
109 | DEFINE(KTHREAD_SIZE, THREAD_SIZE); | ||
110 | DEFINE(KTHREAD_SHIFT, THREAD_SHIFT); | ||
111 | DEFINE(KTHREAD_START_SP, THREAD_START_SP); | ||
112 | DEFINE(ENOSYS_, ENOSYS); | ||
113 | DEFINE(NR_SYSCALLS_, __NR_syscalls); | ||
114 | |||
115 | DEFINE(_TIF_SYSCALL_TRACE, (1<<TIF_SYSCALL_TRACE)); | ||
116 | DEFINE(_TIF_NOTIFY_RESUME, (1<<TIF_NOTIFY_RESUME)); | ||
117 | DEFINE(_TIF_SIGPENDING, (1<<TIF_SIGPENDING)); | ||
118 | DEFINE(_TIF_NEED_RESCHED, (1<<TIF_NEED_RESCHED)); | ||
119 | DEFINE(_TIF_POLLING_NRFLAG, (1<<TIF_POLLING_NRFLAG)); | ||
120 | |||
121 | DEFINE(_TIF_ALLWORK_MASK, TIF_ALLWORK_MASK); | ||
122 | DEFINE(_TIF_WORK_MASK, TIF_WORK_MASK); | ||
123 | } | ||
diff --git a/arch/c6x/kernel/entry.S b/arch/c6x/kernel/entry.S new file mode 100644 index 000000000000..3e977ccda827 --- /dev/null +++ b/arch/c6x/kernel/entry.S | |||
@@ -0,0 +1,803 @@ | |||
1 | ; | ||
2 | ; Port on Texas Instruments TMS320C6x architecture | ||
3 | ; | ||
4 | ; Copyright (C) 2004-2011 Texas Instruments Incorporated | ||
5 | ; Author: Aurelien Jacquiot (aurelien.jacquiot@virtuallogix.com) | ||
6 | ; Updated for 2.6.34: Mark Salter <msalter@redhat.com> | ||
7 | ; | ||
8 | ; This program is free software; you can redistribute it and/or modify | ||
9 | ; it under the terms of the GNU General Public License version 2 as | ||
10 | ; published by the Free Software Foundation. | ||
11 | ; | ||
12 | |||
13 | #include <linux/sys.h> | ||
14 | #include <linux/linkage.h> | ||
15 | #include <asm/thread_info.h> | ||
16 | #include <asm/asm-offsets.h> | ||
17 | #include <asm/unistd.h> | ||
18 | #include <asm/errno.h> | ||
19 | |||
20 | ; Registers naming | ||
21 | #define DP B14 | ||
22 | #define SP B15 | ||
23 | |||
24 | #ifndef CONFIG_PREEMPT | ||
25 | #define resume_kernel restore_all | ||
26 | #endif | ||
27 | |||
28 | .altmacro | ||
29 | |||
30 | .macro MASK_INT reg | ||
31 | MVC .S2 CSR,reg | ||
32 | CLR .S2 reg,0,0,reg | ||
33 | MVC .S2 reg,CSR | ||
34 | .endm | ||
35 | |||
36 | .macro UNMASK_INT reg | ||
37 | MVC .S2 CSR,reg | ||
38 | SET .S2 reg,0,0,reg | ||
39 | MVC .S2 reg,CSR | ||
40 | .endm | ||
41 | |||
42 | .macro GET_THREAD_INFO reg | ||
43 | SHR .S1X SP,THREAD_SHIFT,reg | ||
44 | SHL .S1 reg,THREAD_SHIFT,reg | ||
45 | .endm | ||
46 | |||
47 | ;; | ||
48 | ;; This defines the normal kernel pt_regs layout. | ||
49 | ;; | ||
50 | .macro SAVE_ALL __rp __tsr | ||
51 | STW .D2T2 B0,*SP--[2] ; save original B0 | ||
52 | MVKL .S2 current_ksp,B0 | ||
53 | MVKH .S2 current_ksp,B0 | ||
54 | LDW .D2T2 *B0,B1 ; KSP | ||
55 | |||
56 | NOP 3 | ||
57 | STW .D2T2 B1,*+SP[1] ; save original B1 | ||
58 | XOR .D2 SP,B1,B0 ; (SP ^ KSP) | ||
59 | LDW .D2T2 *+SP[1],B1 ; restore B0/B1 | ||
60 | LDW .D2T2 *++SP[2],B0 | ||
61 | SHR .S2 B0,THREAD_SHIFT,B0 ; 0 if already using kstack | ||
62 | [B0] STDW .D2T2 SP:DP,*--B1[1] ; user: save user sp/dp kstack | ||
63 | [B0] MV .S2 B1,SP ; and switch to kstack | ||
64 | ||[!B0] STDW .D2T2 SP:DP,*--SP[1] ; kernel: save on current stack | ||
65 | |||
66 | SUBAW .D2 SP,2,SP | ||
67 | |||
68 | ADD .D1X SP,-8,A15 | ||
69 | || STDW .D2T1 A15:A14,*SP--[16] ; save A15:A14 | ||
70 | |||
71 | STDW .D2T2 B13:B12,*SP--[1] | ||
72 | || STDW .D1T1 A13:A12,*A15--[1] | ||
73 | || MVC .S2 __rp,B13 | ||
74 | |||
75 | STDW .D2T2 B11:B10,*SP--[1] | ||
76 | || STDW .D1T1 A11:A10,*A15--[1] | ||
77 | || MVC .S2 CSR,B12 | ||
78 | |||
79 | STDW .D2T2 B9:B8,*SP--[1] | ||
80 | || STDW .D1T1 A9:A8,*A15--[1] | ||
81 | || MVC .S2 RILC,B11 | ||
82 | STDW .D2T2 B7:B6,*SP--[1] | ||
83 | || STDW .D1T1 A7:A6,*A15--[1] | ||
84 | || MVC .S2 ILC,B10 | ||
85 | |||
86 | STDW .D2T2 B5:B4,*SP--[1] | ||
87 | || STDW .D1T1 A5:A4,*A15--[1] | ||
88 | |||
89 | STDW .D2T2 B3:B2,*SP--[1] | ||
90 | || STDW .D1T1 A3:A2,*A15--[1] | ||
91 | || MVC .S2 __tsr,B5 | ||
92 | |||
93 | STDW .D2T2 B1:B0,*SP--[1] | ||
94 | || STDW .D1T1 A1:A0,*A15--[1] | ||
95 | || MV .S1X B5,A5 | ||
96 | |||
97 | STDW .D2T2 B31:B30,*SP--[1] | ||
98 | || STDW .D1T1 A31:A30,*A15--[1] | ||
99 | STDW .D2T2 B29:B28,*SP--[1] | ||
100 | || STDW .D1T1 A29:A28,*A15--[1] | ||
101 | STDW .D2T2 B27:B26,*SP--[1] | ||
102 | || STDW .D1T1 A27:A26,*A15--[1] | ||
103 | STDW .D2T2 B25:B24,*SP--[1] | ||
104 | || STDW .D1T1 A25:A24,*A15--[1] | ||
105 | STDW .D2T2 B23:B22,*SP--[1] | ||
106 | || STDW .D1T1 A23:A22,*A15--[1] | ||
107 | STDW .D2T2 B21:B20,*SP--[1] | ||
108 | || STDW .D1T1 A21:A20,*A15--[1] | ||
109 | STDW .D2T2 B19:B18,*SP--[1] | ||
110 | || STDW .D1T1 A19:A18,*A15--[1] | ||
111 | STDW .D2T2 B17:B16,*SP--[1] | ||
112 | || STDW .D1T1 A17:A16,*A15--[1] | ||
113 | |||
114 | STDW .D2T2 B13:B12,*SP--[1] ; save PC and CSR | ||
115 | |||
116 | STDW .D2T2 B11:B10,*SP--[1] ; save RILC and ILC | ||
117 | STDW .D2T1 A5:A4,*SP--[1] ; save TSR and orig A4 | ||
118 | |||
119 | ;; We left an unused word on the stack just above pt_regs. | ||
120 | ;; It is used to save whether or not this frame is due to | ||
121 | ;; a syscall. It is cleared here, but the syscall handler | ||
122 | ;; sets it to a non-zero value. | ||
123 | MVK .L2 0,B1 | ||
124 | STW .D2T2 B1,*+SP(REGS__END+8) ; clear syscall flag | ||
125 | .endm | ||
126 | |||
127 | .macro RESTORE_ALL __rp __tsr | ||
128 | LDDW .D2T2 *++SP[1],B9:B8 ; get TSR (B9) | ||
129 | LDDW .D2T2 *++SP[1],B11:B10 ; get RILC (B11) and ILC (B10) | ||
130 | LDDW .D2T2 *++SP[1],B13:B12 ; get PC (B13) and CSR (B12) | ||
131 | |||
132 | ADDAW .D1X SP,30,A15 | ||
133 | |||
134 | LDDW .D1T1 *++A15[1],A17:A16 | ||
135 | || LDDW .D2T2 *++SP[1],B17:B16 | ||
136 | LDDW .D1T1 *++A15[1],A19:A18 | ||
137 | || LDDW .D2T2 *++SP[1],B19:B18 | ||
138 | LDDW .D1T1 *++A15[1],A21:A20 | ||
139 | || LDDW .D2T2 *++SP[1],B21:B20 | ||
140 | LDDW .D1T1 *++A15[1],A23:A22 | ||
141 | || LDDW .D2T2 *++SP[1],B23:B22 | ||
142 | LDDW .D1T1 *++A15[1],A25:A24 | ||
143 | || LDDW .D2T2 *++SP[1],B25:B24 | ||
144 | LDDW .D1T1 *++A15[1],A27:A26 | ||
145 | || LDDW .D2T2 *++SP[1],B27:B26 | ||
146 | LDDW .D1T1 *++A15[1],A29:A28 | ||
147 | || LDDW .D2T2 *++SP[1],B29:B28 | ||
148 | LDDW .D1T1 *++A15[1],A31:A30 | ||
149 | || LDDW .D2T2 *++SP[1],B31:B30 | ||
150 | |||
151 | LDDW .D1T1 *++A15[1],A1:A0 | ||
152 | || LDDW .D2T2 *++SP[1],B1:B0 | ||
153 | |||
154 | LDDW .D1T1 *++A15[1],A3:A2 | ||
155 | || LDDW .D2T2 *++SP[1],B3:B2 | ||
156 | || MVC .S2 B9,__tsr | ||
157 | LDDW .D1T1 *++A15[1],A5:A4 | ||
158 | || LDDW .D2T2 *++SP[1],B5:B4 | ||
159 | || MVC .S2 B11,RILC | ||
160 | LDDW .D1T1 *++A15[1],A7:A6 | ||
161 | || LDDW .D2T2 *++SP[1],B7:B6 | ||
162 | || MVC .S2 B10,ILC | ||
163 | |||
164 | LDDW .D1T1 *++A15[1],A9:A8 | ||
165 | || LDDW .D2T2 *++SP[1],B9:B8 | ||
166 | || MVC .S2 B13,__rp | ||
167 | |||
168 | LDDW .D1T1 *++A15[1],A11:A10 | ||
169 | || LDDW .D2T2 *++SP[1],B11:B10 | ||
170 | || MVC .S2 B12,CSR | ||
171 | |||
172 | LDDW .D1T1 *++A15[1],A13:A12 | ||
173 | || LDDW .D2T2 *++SP[1],B13:B12 | ||
174 | |||
175 | MV .D2X A15,SP | ||
176 | || MVKL .S1 current_ksp,A15 | ||
177 | MVKH .S1 current_ksp,A15 | ||
178 | || ADDAW .D1X SP,6,A14 | ||
179 | STW .D1T1 A14,*A15 ; save kernel stack pointer | ||
180 | |||
181 | LDDW .D2T1 *++SP[1],A15:A14 | ||
182 | |||
183 | B .S2 __rp ; return from interruption | ||
184 | LDDW .D2T2 *+SP[1],SP:DP | ||
185 | NOP 4 | ||
186 | .endm | ||
187 | |||
188 | .section .text | ||
189 | |||
190 | ;; | ||
191 | ;; Jump to schedule() then return to ret_from_exception | ||
192 | ;; | ||
193 | _reschedule: | ||
194 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
195 | MVKL .S1 schedule,A0 | ||
196 | MVKH .S1 schedule,A0 | ||
197 | B .S2X A0 | ||
198 | #else | ||
199 | B .S1 schedule | ||
200 | #endif | ||
201 | ADDKPC .S2 ret_from_exception,B3,4 | ||
202 | |||
203 | ;; | ||
204 | ;; Called before syscall handler when process is being debugged | ||
205 | ;; | ||
206 | tracesys_on: | ||
207 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
208 | MVKL .S1 syscall_trace_entry,A0 | ||
209 | MVKH .S1 syscall_trace_entry,A0 | ||
210 | B .S2X A0 | ||
211 | #else | ||
212 | B .S1 syscall_trace_entry | ||
213 | #endif | ||
214 | ADDKPC .S2 ret_from_syscall_trace,B3,3 | ||
215 | ADD .S1X 8,SP,A4 | ||
216 | |||
217 | ret_from_syscall_trace: | ||
218 | ;; tracing returns (possibly new) syscall number | ||
219 | MV .D2X A4,B0 | ||
220 | || MVK .S2 __NR_syscalls,B1 | ||
221 | CMPLTU .L2 B0,B1,B1 | ||
222 | |||
223 | [!B1] BNOP .S2 ret_from_syscall_function,5 | ||
224 | || MVK .S1 -ENOSYS,A4 | ||
225 | |||
226 | ;; reload syscall args from (possibly modified) stack frame | ||
227 | ;; and get syscall handler addr from sys_call_table: | ||
228 | LDW .D2T2 *+SP(REGS_B4+8),B4 | ||
229 | || MVKL .S2 sys_call_table,B1 | ||
230 | LDW .D2T1 *+SP(REGS_A6+8),A6 | ||
231 | || MVKH .S2 sys_call_table,B1 | ||
232 | LDW .D2T2 *+B1[B0],B0 | ||
233 | || MVKL .S2 ret_from_syscall_function,B3 | ||
234 | LDW .D2T2 *+SP(REGS_B6+8),B6 | ||
235 | || MVKH .S2 ret_from_syscall_function,B3 | ||
236 | LDW .D2T1 *+SP(REGS_A8+8),A8 | ||
237 | LDW .D2T2 *+SP(REGS_B8+8),B8 | ||
238 | NOP | ||
239 | ; B0 = sys_call_table[__NR_*] | ||
240 | BNOP .S2 B0,5 ; branch to syscall handler | ||
241 | || LDW .D2T1 *+SP(REGS_ORIG_A4+8),A4 | ||
242 | |||
243 | syscall_exit_work: | ||
244 | AND .D1 _TIF_SYSCALL_TRACE,A2,A0 | ||
245 | [!A0] BNOP .S1 work_pending,5 | ||
246 | [A0] B .S2 syscall_trace_exit | ||
247 | ADDKPC .S2 resume_userspace,B3,1 | ||
248 | MVC .S2 CSR,B1 | ||
249 | SET .S2 B1,0,0,B1 | ||
250 | MVC .S2 B1,CSR ; enable ints | ||
251 | |||
252 | work_pending: | ||
253 | AND .D1 _TIF_NEED_RESCHED,A2,A0 | ||
254 | [!A0] BNOP .S1 work_notifysig,5 | ||
255 | |||
256 | work_resched: | ||
257 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
258 | MVKL .S1 schedule,A1 | ||
259 | MVKH .S1 schedule,A1 | ||
260 | B .S2X A1 | ||
261 | #else | ||
262 | B .S2 schedule | ||
263 | #endif | ||
264 | ADDKPC .S2 work_rescheduled,B3,4 | ||
265 | work_rescheduled: | ||
266 | ;; make sure we don't miss an interrupt setting need_resched or | ||
267 | ;; sigpending between sampling and the rti | ||
268 | MASK_INT B2 | ||
269 | GET_THREAD_INFO A12 | ||
270 | LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2 | ||
271 | MVK .S1 _TIF_WORK_MASK,A1 | ||
272 | MVK .S1 _TIF_NEED_RESCHED,A3 | ||
273 | NOP 2 | ||
274 | AND .D1 A1,A2,A0 | ||
275 | || AND .S1 A3,A2,A1 | ||
276 | [!A0] BNOP .S1 restore_all,5 | ||
277 | [A1] BNOP .S1 work_resched,5 | ||
278 | |||
279 | work_notifysig: | ||
280 | B .S2 do_notify_resume | ||
281 | LDW .D2T1 *+SP(REGS__END+8),A6 ; syscall flag | ||
282 | ADDKPC .S2 resume_userspace,B3,1 | ||
283 | ADD .S1X 8,SP,A4 ; pt_regs pointer is first arg | ||
284 | MV .D2X A2,B4 ; thread_info flags is second arg | ||
285 | |||
286 | ;; | ||
287 | ;; On C64x+, the return way from exception and interrupt | ||
288 | ;; is a little bit different | ||
289 | ;; | ||
290 | ENTRY(ret_from_exception) | ||
291 | #ifdef CONFIG_PREEMPT | ||
292 | MASK_INT B2 | ||
293 | #endif | ||
294 | |||
295 | ENTRY(ret_from_interrupt) | ||
296 | ;; | ||
297 | ;; Check if we are comming from user mode. | ||
298 | ;; | ||
299 | LDW .D2T2 *+SP(REGS_TSR+8),B0 | ||
300 | MVK .S2 0x40,B1 | ||
301 | NOP 3 | ||
302 | AND .D2 B0,B1,B0 | ||
303 | [!B0] BNOP .S2 resume_kernel,5 | ||
304 | |||
305 | resume_userspace: | ||
306 | ;; make sure we don't miss an interrupt setting need_resched or | ||
307 | ;; sigpending between sampling and the rti | ||
308 | MASK_INT B2 | ||
309 | GET_THREAD_INFO A12 | ||
310 | LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2 | ||
311 | MVK .S1 _TIF_WORK_MASK,A1 | ||
312 | MVK .S1 _TIF_NEED_RESCHED,A3 | ||
313 | NOP 2 | ||
314 | AND .D1 A1,A2,A0 | ||
315 | [A0] BNOP .S1 work_pending,5 | ||
316 | BNOP .S1 restore_all,5 | ||
317 | |||
318 | ;; | ||
319 | ;; System call handling | ||
320 | ;; B0 = syscall number (in sys_call_table) | ||
321 | ;; A4,B4,A6,B6,A8,B8 = arguments of the syscall function | ||
322 | ;; A4 is the return value register | ||
323 | ;; | ||
324 | system_call_saved: | ||
325 | MVK .L2 1,B2 | ||
326 | STW .D2T2 B2,*+SP(REGS__END+8) ; set syscall flag | ||
327 | MVC .S2 B2,ECR ; ack the software exception | ||
328 | |||
329 | UNMASK_INT B2 ; re-enable global IT | ||
330 | |||
331 | system_call_saved_noack: | ||
332 | ;; Check system call number | ||
333 | MVK .S2 __NR_syscalls,B1 | ||
334 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
335 | || MVKL .S1 sys_ni_syscall,A0 | ||
336 | #endif | ||
337 | CMPLTU .L2 B0,B1,B1 | ||
338 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
339 | || MVKH .S1 sys_ni_syscall,A0 | ||
340 | #endif | ||
341 | |||
342 | ;; Check for ptrace | ||
343 | GET_THREAD_INFO A12 | ||
344 | |||
345 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
346 | [!B1] B .S2X A0 | ||
347 | #else | ||
348 | [!B1] B .S2 sys_ni_syscall | ||
349 | #endif | ||
350 | [!B1] ADDKPC .S2 ret_from_syscall_function,B3,4 | ||
351 | |||
352 | ;; Get syscall handler addr from sys_call_table | ||
353 | ;; call tracesys_on or call syscall handler | ||
354 | LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2 | ||
355 | || MVKL .S2 sys_call_table,B1 | ||
356 | MVKH .S2 sys_call_table,B1 | ||
357 | LDW .D2T2 *+B1[B0],B0 | ||
358 | NOP 2 | ||
359 | ; A2 = thread_info flags | ||
360 | AND .D1 _TIF_SYSCALL_TRACE,A2,A2 | ||
361 | [A2] BNOP .S1 tracesys_on,5 | ||
362 | ;; B0 = _sys_call_table[__NR_*] | ||
363 | B .S2 B0 | ||
364 | ADDKPC .S2 ret_from_syscall_function,B3,4 | ||
365 | |||
366 | ret_from_syscall_function: | ||
367 | STW .D2T1 A4,*+SP(REGS_A4+8) ; save return value in A4 | ||
368 | ; original A4 is in orig_A4 | ||
369 | syscall_exit: | ||
370 | ;; make sure we don't miss an interrupt setting need_resched or | ||
371 | ;; sigpending between sampling and the rti | ||
372 | MASK_INT B2 | ||
373 | LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2 | ||
374 | MVK .S1 _TIF_ALLWORK_MASK,A1 | ||
375 | NOP 3 | ||
376 | AND .D1 A1,A2,A2 ; check for work to do | ||
377 | [A2] BNOP .S1 syscall_exit_work,5 | ||
378 | |||
379 | restore_all: | ||
380 | RESTORE_ALL NRP,NTSR | ||
381 | |||
382 | ;; | ||
383 | ;; After a fork we jump here directly from resume, | ||
384 | ;; so that A4 contains the previous task structure. | ||
385 | ;; | ||
386 | ENTRY(ret_from_fork) | ||
387 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
388 | MVKL .S1 schedule_tail,A0 | ||
389 | MVKH .S1 schedule_tail,A0 | ||
390 | B .S2X A0 | ||
391 | #else | ||
392 | B .S2 schedule_tail | ||
393 | #endif | ||
394 | ADDKPC .S2 ret_from_fork_2,B3,4 | ||
395 | ret_from_fork_2: | ||
396 | ;; return 0 in A4 for child process | ||
397 | GET_THREAD_INFO A12 | ||
398 | BNOP .S2 syscall_exit,3 | ||
399 | MVK .L2 0,B0 | ||
400 | STW .D2T2 B0,*+SP(REGS_A4+8) | ||
401 | ENDPROC(ret_from_fork) | ||
402 | |||
403 | ;; | ||
404 | ;; These are the interrupt handlers, responsible for calling __do_IRQ() | ||
405 | ;; int6 is used for syscalls (see _system_call entry) | ||
406 | ;; | ||
407 | .macro SAVE_ALL_INT | ||
408 | SAVE_ALL IRP,ITSR | ||
409 | .endm | ||
410 | |||
411 | .macro CALL_INT int | ||
412 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
413 | MVKL .S1 c6x_do_IRQ,A0 | ||
414 | MVKH .S1 c6x_do_IRQ,A0 | ||
415 | BNOP .S2X A0,1 | ||
416 | MVK .S1 int,A4 | ||
417 | ADDAW .D2 SP,2,B4 | ||
418 | MVKL .S2 ret_from_interrupt,B3 | ||
419 | MVKH .S2 ret_from_interrupt,B3 | ||
420 | #else | ||
421 | CALLP .S2 c6x_do_IRQ,B3 | ||
422 | || MVK .S1 int,A4 | ||
423 | || ADDAW .D2 SP,2,B4 | ||
424 | B .S1 ret_from_interrupt | ||
425 | NOP 5 | ||
426 | #endif | ||
427 | .endm | ||
428 | |||
429 | ENTRY(_int4_handler) | ||
430 | SAVE_ALL_INT | ||
431 | CALL_INT 4 | ||
432 | ENDPROC(_int4_handler) | ||
433 | |||
434 | ENTRY(_int5_handler) | ||
435 | SAVE_ALL_INT | ||
436 | CALL_INT 5 | ||
437 | ENDPROC(_int5_handler) | ||
438 | |||
439 | ENTRY(_int6_handler) | ||
440 | SAVE_ALL_INT | ||
441 | CALL_INT 6 | ||
442 | ENDPROC(_int6_handler) | ||
443 | |||
444 | ENTRY(_int7_handler) | ||
445 | SAVE_ALL_INT | ||
446 | CALL_INT 7 | ||
447 | ENDPROC(_int7_handler) | ||
448 | |||
449 | ENTRY(_int8_handler) | ||
450 | SAVE_ALL_INT | ||
451 | CALL_INT 8 | ||
452 | ENDPROC(_int8_handler) | ||
453 | |||
454 | ENTRY(_int9_handler) | ||
455 | SAVE_ALL_INT | ||
456 | CALL_INT 9 | ||
457 | ENDPROC(_int9_handler) | ||
458 | |||
459 | ENTRY(_int10_handler) | ||
460 | SAVE_ALL_INT | ||
461 | CALL_INT 10 | ||
462 | ENDPROC(_int10_handler) | ||
463 | |||
464 | ENTRY(_int11_handler) | ||
465 | SAVE_ALL_INT | ||
466 | CALL_INT 11 | ||
467 | ENDPROC(_int11_handler) | ||
468 | |||
469 | ENTRY(_int12_handler) | ||
470 | SAVE_ALL_INT | ||
471 | CALL_INT 12 | ||
472 | ENDPROC(_int12_handler) | ||
473 | |||
474 | ENTRY(_int13_handler) | ||
475 | SAVE_ALL_INT | ||
476 | CALL_INT 13 | ||
477 | ENDPROC(_int13_handler) | ||
478 | |||
479 | ENTRY(_int14_handler) | ||
480 | SAVE_ALL_INT | ||
481 | CALL_INT 14 | ||
482 | ENDPROC(_int14_handler) | ||
483 | |||
484 | ENTRY(_int15_handler) | ||
485 | SAVE_ALL_INT | ||
486 | CALL_INT 15 | ||
487 | ENDPROC(_int15_handler) | ||
488 | |||
489 | ;; | ||
490 | ;; Handler for uninitialized and spurious interrupts | ||
491 | ;; | ||
492 | ENTRY(_bad_interrupt) | ||
493 | B .S2 IRP | ||
494 | NOP 5 | ||
495 | ENDPROC(_bad_interrupt) | ||
496 | |||
497 | ;; | ||
498 | ;; Entry for NMI/exceptions/syscall | ||
499 | ;; | ||
500 | ENTRY(_nmi_handler) | ||
501 | SAVE_ALL NRP,NTSR | ||
502 | |||
503 | MVC .S2 EFR,B2 | ||
504 | CMPEQ .L2 1,B2,B2 | ||
505 | || MVC .S2 TSR,B1 | ||
506 | CLR .S2 B1,10,10,B1 | ||
507 | MVC .S2 B1,TSR | ||
508 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
509 | [!B2] MVKL .S1 process_exception,A0 | ||
510 | [!B2] MVKH .S1 process_exception,A0 | ||
511 | [!B2] B .S2X A0 | ||
512 | #else | ||
513 | [!B2] B .S2 process_exception | ||
514 | #endif | ||
515 | [B2] B .S2 system_call_saved | ||
516 | [!B2] ADDAW .D2 SP,2,B1 | ||
517 | [!B2] MV .D1X B1,A4 | ||
518 | ADDKPC .S2 ret_from_trap,B3,2 | ||
519 | |||
520 | ret_from_trap: | ||
521 | MV .D2X A4,B0 | ||
522 | [!B0] BNOP .S2 ret_from_exception,5 | ||
523 | |||
524 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
525 | MVKL .S2 system_call_saved_noack,B3 | ||
526 | MVKH .S2 system_call_saved_noack,B3 | ||
527 | #endif | ||
528 | LDW .D2T2 *+SP(REGS_B0+8),B0 | ||
529 | LDW .D2T1 *+SP(REGS_A4+8),A4 | ||
530 | LDW .D2T2 *+SP(REGS_B4+8),B4 | ||
531 | LDW .D2T1 *+SP(REGS_A6+8),A6 | ||
532 | LDW .D2T2 *+SP(REGS_B6+8),B6 | ||
533 | LDW .D2T1 *+SP(REGS_A8+8),A8 | ||
534 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
535 | || B .S2 B3 | ||
536 | #else | ||
537 | || B .S2 system_call_saved_noack | ||
538 | #endif | ||
539 | LDW .D2T2 *+SP(REGS_B8+8),B8 | ||
540 | NOP 4 | ||
541 | ENDPROC(_nmi_handler) | ||
542 | |||
543 | ;; | ||
544 | ;; Jump to schedule() then return to ret_from_isr | ||
545 | ;; | ||
546 | #ifdef CONFIG_PREEMPT | ||
547 | resume_kernel: | ||
548 | GET_THREAD_INFO A12 | ||
549 | LDW .D1T1 *+A12(THREAD_INFO_PREEMPT_COUNT),A1 | ||
550 | NOP 4 | ||
551 | [A1] BNOP .S2 restore_all,5 | ||
552 | |||
553 | preempt_schedule: | ||
554 | GET_THREAD_INFO A2 | ||
555 | LDW .D1T1 *+A2(THREAD_INFO_FLAGS),A1 | ||
556 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
557 | MVKL .S2 preempt_schedule_irq,B0 | ||
558 | MVKH .S2 preempt_schedule_irq,B0 | ||
559 | NOP 2 | ||
560 | #else | ||
561 | NOP 4 | ||
562 | #endif | ||
563 | AND .D1 _TIF_NEED_RESCHED,A1,A1 | ||
564 | [!A1] BNOP .S2 restore_all,5 | ||
565 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
566 | B .S2 B0 | ||
567 | #else | ||
568 | B .S2 preempt_schedule_irq | ||
569 | #endif | ||
570 | ADDKPC .S2 preempt_schedule,B3,4 | ||
571 | #endif /* CONFIG_PREEMPT */ | ||
572 | |||
573 | ENTRY(enable_exception) | ||
574 | DINT | ||
575 | MVC .S2 TSR,B0 | ||
576 | MVC .S2 B3,NRP | ||
577 | MVK .L2 0xc,B1 | ||
578 | OR .D2 B0,B1,B0 | ||
579 | MVC .S2 B0,TSR ; Set GEE and XEN in TSR | ||
580 | B .S2 NRP | ||
581 | NOP 5 | ||
582 | ENDPROC(enable_exception) | ||
583 | |||
584 | ENTRY(sys_sigaltstack) | ||
585 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
586 | MVKL .S1 do_sigaltstack,A0 ; branch to do_sigaltstack | ||
587 | MVKH .S1 do_sigaltstack,A0 | ||
588 | B .S2X A0 | ||
589 | #else | ||
590 | B .S2 do_sigaltstack | ||
591 | #endif | ||
592 | LDW .D2T1 *+SP(REGS_SP+8),A6 | ||
593 | NOP 4 | ||
594 | ENDPROC(sys_sigaltstack) | ||
595 | |||
596 | ;; kernel_execve | ||
597 | ENTRY(kernel_execve) | ||
598 | MVK .S2 __NR_execve,B0 | ||
599 | SWE | ||
600 | BNOP .S2 B3,5 | ||
601 | ENDPROC(kernel_execve) | ||
602 | |||
603 | ;; | ||
604 | ;; Special system calls | ||
605 | ;; return address is in B3 | ||
606 | ;; | ||
607 | ENTRY(sys_clone) | ||
608 | ADD .D1X SP,8,A4 | ||
609 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
610 | || MVKL .S1 sys_c6x_clone,A0 | ||
611 | MVKH .S1 sys_c6x_clone,A0 | ||
612 | BNOP .S2X A0,5 | ||
613 | #else | ||
614 | || B .S2 sys_c6x_clone | ||
615 | NOP 5 | ||
616 | #endif | ||
617 | ENDPROC(sys_clone) | ||
618 | |||
619 | ENTRY(sys_rt_sigreturn) | ||
620 | ADD .D1X SP,8,A4 | ||
621 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
622 | || MVKL .S1 do_rt_sigreturn,A0 | ||
623 | MVKH .S1 do_rt_sigreturn,A0 | ||
624 | BNOP .S2X A0,5 | ||
625 | #else | ||
626 | || B .S2 do_rt_sigreturn | ||
627 | NOP 5 | ||
628 | #endif | ||
629 | ENDPROC(sys_rt_sigreturn) | ||
630 | |||
631 | ENTRY(sys_execve) | ||
632 | ADDAW .D2 SP,2,B6 ; put regs addr in 4th parameter | ||
633 | ; & adjust regs stack addr | ||
634 | LDW .D2T2 *+SP(REGS_B4+8),B4 | ||
635 | |||
636 | ;; c6x_execve(char *name, char **argv, | ||
637 | ;; char **envp, struct pt_regs *regs) | ||
638 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
639 | || MVKL .S1 sys_c6x_execve,A0 | ||
640 | MVKH .S1 sys_c6x_execve,A0 | ||
641 | B .S2X A0 | ||
642 | #else | ||
643 | || B .S2 sys_c6x_execve | ||
644 | #endif | ||
645 | STW .D2T2 B3,*SP--[2] | ||
646 | ADDKPC .S2 ret_from_c6x_execve,B3,3 | ||
647 | |||
648 | ret_from_c6x_execve: | ||
649 | LDW .D2T2 *++SP[2],B3 | ||
650 | NOP 4 | ||
651 | BNOP .S2 B3,5 | ||
652 | ENDPROC(sys_execve) | ||
653 | |||
654 | ENTRY(sys_pread_c6x) | ||
655 | MV .D2X A8,B7 | ||
656 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
657 | || MVKL .S1 sys_pread64,A0 | ||
658 | MVKH .S1 sys_pread64,A0 | ||
659 | BNOP .S2X A0,5 | ||
660 | #else | ||
661 | || B .S2 sys_pread64 | ||
662 | NOP 5 | ||
663 | #endif | ||
664 | ENDPROC(sys_pread_c6x) | ||
665 | |||
666 | ENTRY(sys_pwrite_c6x) | ||
667 | MV .D2X A8,B7 | ||
668 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
669 | || MVKL .S1 sys_pwrite64,A0 | ||
670 | MVKH .S1 sys_pwrite64,A0 | ||
671 | BNOP .S2X A0,5 | ||
672 | #else | ||
673 | || B .S2 sys_pwrite64 | ||
674 | NOP 5 | ||
675 | #endif | ||
676 | ENDPROC(sys_pwrite_c6x) | ||
677 | |||
678 | ;; On Entry | ||
679 | ;; A4 - path | ||
680 | ;; B4 - offset_lo (LE), offset_hi (BE) | ||
681 | ;; A6 - offset_lo (BE), offset_hi (LE) | ||
682 | ENTRY(sys_truncate64_c6x) | ||
683 | #ifdef CONFIG_CPU_BIG_ENDIAN | ||
684 | MV .S2 B4,B5 | ||
685 | MV .D2X A6,B4 | ||
686 | #else | ||
687 | MV .D2X A6,B5 | ||
688 | #endif | ||
689 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
690 | || MVKL .S1 sys_truncate64,A0 | ||
691 | MVKH .S1 sys_truncate64,A0 | ||
692 | BNOP .S2X A0,5 | ||
693 | #else | ||
694 | || B .S2 sys_truncate64 | ||
695 | NOP 5 | ||
696 | #endif | ||
697 | ENDPROC(sys_truncate64_c6x) | ||
698 | |||
699 | ;; On Entry | ||
700 | ;; A4 - fd | ||
701 | ;; B4 - offset_lo (LE), offset_hi (BE) | ||
702 | ;; A6 - offset_lo (BE), offset_hi (LE) | ||
703 | ENTRY(sys_ftruncate64_c6x) | ||
704 | #ifdef CONFIG_CPU_BIG_ENDIAN | ||
705 | MV .S2 B4,B5 | ||
706 | MV .D2X A6,B4 | ||
707 | #else | ||
708 | MV .D2X A6,B5 | ||
709 | #endif | ||
710 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
711 | || MVKL .S1 sys_ftruncate64,A0 | ||
712 | MVKH .S1 sys_ftruncate64,A0 | ||
713 | BNOP .S2X A0,5 | ||
714 | #else | ||
715 | || B .S2 sys_ftruncate64 | ||
716 | NOP 5 | ||
717 | #endif | ||
718 | ENDPROC(sys_ftruncate64_c6x) | ||
719 | |||
720 | #ifdef __ARCH_WANT_SYSCALL_OFF_T | ||
721 | ;; On Entry | ||
722 | ;; A4 - fd | ||
723 | ;; B4 - offset_lo (LE), offset_hi (BE) | ||
724 | ;; A6 - offset_lo (BE), offset_hi (LE) | ||
725 | ;; B6 - len | ||
726 | ;; A8 - advice | ||
727 | ENTRY(sys_fadvise64_c6x) | ||
728 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
729 | MVKL .S1 sys_fadvise64,A0 | ||
730 | MVKH .S1 sys_fadvise64,A0 | ||
731 | BNOP .S2X A0,2 | ||
732 | #else | ||
733 | B .S2 sys_fadvise64 | ||
734 | NOP 2 | ||
735 | #endif | ||
736 | #ifdef CONFIG_CPU_BIG_ENDIAN | ||
737 | MV .L2 B4,B5 | ||
738 | || MV .D2X A6,B4 | ||
739 | #else | ||
740 | MV .D2X A6,B5 | ||
741 | #endif | ||
742 | MV .D1X B6,A6 | ||
743 | MV .D2X A8,B6 | ||
744 | #endif | ||
745 | ENDPROC(sys_fadvise64_c6x) | ||
746 | |||
747 | ;; On Entry | ||
748 | ;; A4 - fd | ||
749 | ;; B4 - offset_lo (LE), offset_hi (BE) | ||
750 | ;; A6 - offset_lo (BE), offset_hi (LE) | ||
751 | ;; B6 - len_lo (LE), len_hi (BE) | ||
752 | ;; A8 - len_lo (BE), len_hi (LE) | ||
753 | ;; B8 - advice | ||
754 | ENTRY(sys_fadvise64_64_c6x) | ||
755 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
756 | MVKL .S1 sys_fadvise64_64,A0 | ||
757 | MVKH .S1 sys_fadvise64_64,A0 | ||
758 | BNOP .S2X A0,2 | ||
759 | #else | ||
760 | B .S2 sys_fadvise64_64 | ||
761 | NOP 2 | ||
762 | #endif | ||
763 | #ifdef CONFIG_CPU_BIG_ENDIAN | ||
764 | MV .L2 B4,B5 | ||
765 | || MV .D2X A6,B4 | ||
766 | MV .L1 A8,A6 | ||
767 | || MV .D1X B6,A7 | ||
768 | #else | ||
769 | MV .D2X A6,B5 | ||
770 | MV .L1 A8,A7 | ||
771 | || MV .D1X B6,A6 | ||
772 | #endif | ||
773 | MV .L2 B8,B6 | ||
774 | ENDPROC(sys_fadvise64_64_c6x) | ||
775 | |||
776 | ;; On Entry | ||
777 | ;; A4 - fd | ||
778 | ;; B4 - mode | ||
779 | ;; A6 - offset_hi | ||
780 | ;; B6 - offset_lo | ||
781 | ;; A8 - len_hi | ||
782 | ;; B8 - len_lo | ||
783 | ENTRY(sys_fallocate_c6x) | ||
784 | #ifdef CONFIG_C6X_BIG_KERNEL | ||
785 | MVKL .S1 sys_fallocate,A0 | ||
786 | MVKH .S1 sys_fallocate,A0 | ||
787 | BNOP .S2X A0,1 | ||
788 | #else | ||
789 | B .S2 sys_fallocate | ||
790 | NOP | ||
791 | #endif | ||
792 | MV .D1 A6,A7 | ||
793 | MV .D1X B6,A6 | ||
794 | MV .D2X A8,B7 | ||
795 | MV .D2 B8,B6 | ||
796 | ENDPROC(sys_fallocate_c6x) | ||
797 | |||
798 | ;; put this in .neardata for faster access when using DSBT mode | ||
799 | .section .neardata,"aw",@progbits | ||
800 | .global current_ksp | ||
801 | .hidden current_ksp | ||
802 | current_ksp: | ||
803 | .word init_thread_union + THREAD_START_SP | ||
diff --git a/arch/c6x/kernel/traps.c b/arch/c6x/kernel/traps.c new file mode 100644 index 000000000000..f50e3edd6dad --- /dev/null +++ b/arch/c6x/kernel/traps.c | |||
@@ -0,0 +1,423 @@ | |||
1 | /* | ||
2 | * Port on Texas Instruments TMS320C6x architecture | ||
3 | * | ||
4 | * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated | ||
5 | * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/ptrace.h> | ||
13 | #include <linux/kallsyms.h> | ||
14 | #include <linux/bug.h> | ||
15 | |||
16 | #include <asm/soc.h> | ||
17 | #include <asm/traps.h> | ||
18 | |||
19 | int (*c6x_nmi_handler)(struct pt_regs *regs); | ||
20 | |||
21 | void __init trap_init(void) | ||
22 | { | ||
23 | ack_exception(EXCEPT_TYPE_NXF); | ||
24 | ack_exception(EXCEPT_TYPE_EXC); | ||
25 | ack_exception(EXCEPT_TYPE_IXF); | ||
26 | ack_exception(EXCEPT_TYPE_SXF); | ||
27 | enable_exception(); | ||
28 | } | ||
29 | |||
30 | void show_regs(struct pt_regs *regs) | ||
31 | { | ||
32 | pr_err("\n"); | ||
33 | pr_err("PC: %08lx SP: %08lx\n", regs->pc, regs->sp); | ||
34 | pr_err("Status: %08lx ORIG_A4: %08lx\n", regs->csr, regs->orig_a4); | ||
35 | pr_err("A0: %08lx B0: %08lx\n", regs->a0, regs->b0); | ||
36 | pr_err("A1: %08lx B1: %08lx\n", regs->a1, regs->b1); | ||
37 | pr_err("A2: %08lx B2: %08lx\n", regs->a2, regs->b2); | ||
38 | pr_err("A3: %08lx B3: %08lx\n", regs->a3, regs->b3); | ||
39 | pr_err("A4: %08lx B4: %08lx\n", regs->a4, regs->b4); | ||
40 | pr_err("A5: %08lx B5: %08lx\n", regs->a5, regs->b5); | ||
41 | pr_err("A6: %08lx B6: %08lx\n", regs->a6, regs->b6); | ||
42 | pr_err("A7: %08lx B7: %08lx\n", regs->a7, regs->b7); | ||
43 | pr_err("A8: %08lx B8: %08lx\n", regs->a8, regs->b8); | ||
44 | pr_err("A9: %08lx B9: %08lx\n", regs->a9, regs->b9); | ||
45 | pr_err("A10: %08lx B10: %08lx\n", regs->a10, regs->b10); | ||
46 | pr_err("A11: %08lx B11: %08lx\n", regs->a11, regs->b11); | ||
47 | pr_err("A12: %08lx B12: %08lx\n", regs->a12, regs->b12); | ||
48 | pr_err("A13: %08lx B13: %08lx\n", regs->a13, regs->b13); | ||
49 | pr_err("A14: %08lx B14: %08lx\n", regs->a14, regs->dp); | ||
50 | pr_err("A15: %08lx B15: %08lx\n", regs->a15, regs->sp); | ||
51 | pr_err("A16: %08lx B16: %08lx\n", regs->a16, regs->b16); | ||
52 | pr_err("A17: %08lx B17: %08lx\n", regs->a17, regs->b17); | ||
53 | pr_err("A18: %08lx B18: %08lx\n", regs->a18, regs->b18); | ||
54 | pr_err("A19: %08lx B19: %08lx\n", regs->a19, regs->b19); | ||
55 | pr_err("A20: %08lx B20: %08lx\n", regs->a20, regs->b20); | ||
56 | pr_err("A21: %08lx B21: %08lx\n", regs->a21, regs->b21); | ||
57 | pr_err("A22: %08lx B22: %08lx\n", regs->a22, regs->b22); | ||
58 | pr_err("A23: %08lx B23: %08lx\n", regs->a23, regs->b23); | ||
59 | pr_err("A24: %08lx B24: %08lx\n", regs->a24, regs->b24); | ||
60 | pr_err("A25: %08lx B25: %08lx\n", regs->a25, regs->b25); | ||
61 | pr_err("A26: %08lx B26: %08lx\n", regs->a26, regs->b26); | ||
62 | pr_err("A27: %08lx B27: %08lx\n", regs->a27, regs->b27); | ||
63 | pr_err("A28: %08lx B28: %08lx\n", regs->a28, regs->b28); | ||
64 | pr_err("A29: %08lx B29: %08lx\n", regs->a29, regs->b29); | ||
65 | pr_err("A30: %08lx B30: %08lx\n", regs->a30, regs->b30); | ||
66 | pr_err("A31: %08lx B31: %08lx\n", regs->a31, regs->b31); | ||
67 | } | ||
68 | |||
69 | void dump_stack(void) | ||
70 | { | ||
71 | unsigned long stack; | ||
72 | |||
73 | show_stack(current, &stack); | ||
74 | } | ||
75 | EXPORT_SYMBOL(dump_stack); | ||
76 | |||
77 | |||
78 | void die(char *str, struct pt_regs *fp, int nr) | ||
79 | { | ||
80 | console_verbose(); | ||
81 | pr_err("%s: %08x\n", str, nr); | ||
82 | show_regs(fp); | ||
83 | |||
84 | pr_err("Process %s (pid: %d, stackpage=%08lx)\n", | ||
85 | current->comm, current->pid, (PAGE_SIZE + | ||
86 | (unsigned long) current)); | ||
87 | |||
88 | dump_stack(); | ||
89 | while (1) | ||
90 | ; | ||
91 | } | ||
92 | |||
93 | static void die_if_kernel(char *str, struct pt_regs *fp, int nr) | ||
94 | { | ||
95 | if (user_mode(fp)) | ||
96 | return; | ||
97 | |||
98 | die(str, fp, nr); | ||
99 | } | ||
100 | |||
101 | |||
102 | /* Internal exceptions */ | ||
103 | static struct exception_info iexcept_table[10] = { | ||
104 | { "Oops - instruction fetch", SIGBUS, BUS_ADRERR }, | ||
105 | { "Oops - fetch packet", SIGBUS, BUS_ADRERR }, | ||
106 | { "Oops - execute packet", SIGILL, ILL_ILLOPC }, | ||
107 | { "Oops - undefined instruction", SIGILL, ILL_ILLOPC }, | ||
108 | { "Oops - resource conflict", SIGILL, ILL_ILLOPC }, | ||
109 | { "Oops - resource access", SIGILL, ILL_PRVREG }, | ||
110 | { "Oops - privilege", SIGILL, ILL_PRVOPC }, | ||
111 | { "Oops - loops buffer", SIGILL, ILL_ILLOPC }, | ||
112 | { "Oops - software exception", SIGILL, ILL_ILLTRP }, | ||
113 | { "Oops - unknown exception", SIGILL, ILL_ILLOPC } | ||
114 | }; | ||
115 | |||
116 | /* External exceptions */ | ||
117 | static struct exception_info eexcept_table[128] = { | ||
118 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
119 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
120 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
121 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
122 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
123 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
124 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
125 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
126 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
127 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
128 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
129 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
130 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
131 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
132 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
133 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
134 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
135 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
136 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
137 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
138 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
139 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
140 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
141 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
142 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
143 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
144 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
145 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
146 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
147 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
148 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
149 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
150 | |||
151 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
152 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
153 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
154 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
155 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
156 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
157 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
158 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
159 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
160 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
161 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
162 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
163 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
164 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
165 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
166 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
167 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
168 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
169 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
170 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
171 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
172 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
173 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
174 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
175 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
176 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
177 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
178 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
179 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
180 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
181 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
182 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
183 | |||
184 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
185 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
186 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
187 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
188 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
189 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
190 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
191 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
192 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
193 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
194 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
195 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
196 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
197 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
198 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
199 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
200 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
201 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
202 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
203 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
204 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
205 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
206 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
207 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
208 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
209 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
210 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
211 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
212 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
213 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
214 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
215 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
216 | |||
217 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
218 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
219 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
220 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
221 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
222 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
223 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
224 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
225 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
226 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
227 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
228 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
229 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
230 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
231 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
232 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
233 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
234 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
235 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
236 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
237 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
238 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
239 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | ||
240 | { "Oops - CPU memory protection fault", SIGSEGV, SEGV_ACCERR }, | ||
241 | { "Oops - CPU memory protection fault in L1P", SIGSEGV, SEGV_ACCERR }, | ||
242 | { "Oops - DMA memory protection fault in L1P", SIGSEGV, SEGV_ACCERR }, | ||
243 | { "Oops - CPU memory protection fault in L1D", SIGSEGV, SEGV_ACCERR }, | ||
244 | { "Oops - DMA memory protection fault in L1D", SIGSEGV, SEGV_ACCERR }, | ||
245 | { "Oops - CPU memory protection fault in L2", SIGSEGV, SEGV_ACCERR }, | ||
246 | { "Oops - DMA memory protection fault in L2", SIGSEGV, SEGV_ACCERR }, | ||
247 | { "Oops - EMC CPU memory protection fault", SIGSEGV, SEGV_ACCERR }, | ||
248 | { "Oops - EMC bus error", SIGBUS, BUS_ADRERR } | ||
249 | }; | ||
250 | |||
251 | static void do_trap(struct exception_info *except_info, struct pt_regs *regs) | ||
252 | { | ||
253 | unsigned long addr = instruction_pointer(regs); | ||
254 | siginfo_t info; | ||
255 | |||
256 | if (except_info->code != TRAP_BRKPT) | ||
257 | pr_err("TRAP: %s PC[0x%lx] signo[%d] code[%d]\n", | ||
258 | except_info->kernel_str, regs->pc, | ||
259 | except_info->signo, except_info->code); | ||
260 | |||
261 | die_if_kernel(except_info->kernel_str, regs, addr); | ||
262 | |||
263 | info.si_signo = except_info->signo; | ||
264 | info.si_errno = 0; | ||
265 | info.si_code = except_info->code; | ||
266 | info.si_addr = (void __user *)addr; | ||
267 | |||
268 | force_sig_info(except_info->signo, &info, current); | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * Process an internal exception (non maskable) | ||
273 | */ | ||
274 | static int process_iexcept(struct pt_regs *regs) | ||
275 | { | ||
276 | unsigned int iexcept_report = get_iexcept(); | ||
277 | unsigned int iexcept_num; | ||
278 | |||
279 | ack_exception(EXCEPT_TYPE_IXF); | ||
280 | |||
281 | pr_err("IEXCEPT: PC[0x%lx]\n", regs->pc); | ||
282 | |||
283 | while (iexcept_report) { | ||
284 | iexcept_num = __ffs(iexcept_report); | ||
285 | iexcept_report &= ~(1 << iexcept_num); | ||
286 | set_iexcept(iexcept_report); | ||
287 | if (*(unsigned int *)regs->pc == BKPT_OPCODE) { | ||
288 | /* This is a breakpoint */ | ||
289 | struct exception_info bkpt_exception = { | ||
290 | "Oops - undefined instruction", | ||
291 | SIGTRAP, TRAP_BRKPT | ||
292 | }; | ||
293 | do_trap(&bkpt_exception, regs); | ||
294 | iexcept_report &= ~(0xFF); | ||
295 | set_iexcept(iexcept_report); | ||
296 | continue; | ||
297 | } | ||
298 | |||
299 | do_trap(&iexcept_table[iexcept_num], regs); | ||
300 | } | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * Process an external exception (maskable) | ||
306 | */ | ||
307 | static void process_eexcept(struct pt_regs *regs) | ||
308 | { | ||
309 | int evt; | ||
310 | |||
311 | pr_err("EEXCEPT: PC[0x%lx]\n", regs->pc); | ||
312 | |||
313 | while ((evt = soc_get_exception()) >= 0) | ||
314 | do_trap(&eexcept_table[evt], regs); | ||
315 | |||
316 | ack_exception(EXCEPT_TYPE_EXC); | ||
317 | } | ||
318 | |||
319 | /* | ||
320 | * Main exception processing | ||
321 | */ | ||
322 | asmlinkage int process_exception(struct pt_regs *regs) | ||
323 | { | ||
324 | unsigned int type; | ||
325 | unsigned int type_num; | ||
326 | unsigned int ie_num = 9; /* default is unknown exception */ | ||
327 | |||
328 | while ((type = get_except_type()) != 0) { | ||
329 | type_num = fls(type) - 1; | ||
330 | |||
331 | switch (type_num) { | ||
332 | case EXCEPT_TYPE_NXF: | ||
333 | ack_exception(EXCEPT_TYPE_NXF); | ||
334 | if (c6x_nmi_handler) | ||
335 | (c6x_nmi_handler)(regs); | ||
336 | else | ||
337 | pr_alert("NMI interrupt!\n"); | ||
338 | break; | ||
339 | |||
340 | case EXCEPT_TYPE_IXF: | ||
341 | if (process_iexcept(regs)) | ||
342 | return 1; | ||
343 | break; | ||
344 | |||
345 | case EXCEPT_TYPE_EXC: | ||
346 | process_eexcept(regs); | ||
347 | break; | ||
348 | |||
349 | case EXCEPT_TYPE_SXF: | ||
350 | ie_num = 8; | ||
351 | default: | ||
352 | ack_exception(type_num); | ||
353 | do_trap(&iexcept_table[ie_num], regs); | ||
354 | break; | ||
355 | } | ||
356 | } | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int kstack_depth_to_print = 48; | ||
361 | |||
362 | static void show_trace(unsigned long *stack, unsigned long *endstack) | ||
363 | { | ||
364 | unsigned long addr; | ||
365 | int i; | ||
366 | |||
367 | pr_debug("Call trace:"); | ||
368 | i = 0; | ||
369 | while (stack + 1 <= endstack) { | ||
370 | addr = *stack++; | ||
371 | /* | ||
372 | * If the address is either in the text segment of the | ||
373 | * kernel, or in the region which contains vmalloc'ed | ||
374 | * memory, it *may* be the address of a calling | ||
375 | * routine; if so, print it so that someone tracing | ||
376 | * down the cause of the crash will be able to figure | ||
377 | * out the call path that was taken. | ||
378 | */ | ||
379 | if (__kernel_text_address(addr)) { | ||
380 | #ifndef CONFIG_KALLSYMS | ||
381 | if (i % 5 == 0) | ||
382 | pr_debug("\n "); | ||
383 | #endif | ||
384 | pr_debug(" [<%08lx>]", addr); | ||
385 | print_symbol(" %s\n", addr); | ||
386 | i++; | ||
387 | } | ||
388 | } | ||
389 | pr_debug("\n"); | ||
390 | } | ||
391 | |||
392 | void show_stack(struct task_struct *task, unsigned long *stack) | ||
393 | { | ||
394 | unsigned long *p, *endstack; | ||
395 | int i; | ||
396 | |||
397 | if (!stack) { | ||
398 | if (task && task != current) | ||
399 | /* We know this is a kernel stack, | ||
400 | so this is the start/end */ | ||
401 | stack = (unsigned long *)thread_saved_ksp(task); | ||
402 | else | ||
403 | stack = (unsigned long *)&stack; | ||
404 | } | ||
405 | endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) | ||
406 | & -THREAD_SIZE); | ||
407 | |||
408 | pr_debug("Stack from %08lx:", (unsigned long)stack); | ||
409 | for (i = 0, p = stack; i < kstack_depth_to_print; i++) { | ||
410 | if (p + 1 > endstack) | ||
411 | break; | ||
412 | if (i % 8 == 0) | ||
413 | pr_cont("\n "); | ||
414 | pr_cont(" %08lx", *p++); | ||
415 | } | ||
416 | pr_cont("\n"); | ||
417 | show_trace(stack, endstack); | ||
418 | } | ||
419 | |||
420 | int is_valid_bugaddr(unsigned long addr) | ||
421 | { | ||
422 | return __kernel_text_address(addr); | ||
423 | } | ||