diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/cris/arch-v10/kernel |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/cris/arch-v10/kernel')
-rw-r--r-- | arch/cris/arch-v10/kernel/Makefile | 17 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/asm-offsets.c | 47 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/crisksyms.c | 17 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/debugport.c | 531 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/entry.S | 1132 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/fasttimer.c | 977 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/head.S | 882 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/irq.c | 204 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/kgdb.c | 1568 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/process.c | 270 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/ptrace.c | 314 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/setup.c | 103 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/shadows.c | 36 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/signal.c | 580 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/time.c | 369 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/traps.c | 132 |
16 files changed, 7179 insertions, 0 deletions
diff --git a/arch/cris/arch-v10/kernel/Makefile b/arch/cris/arch-v10/kernel/Makefile new file mode 100644 index 000000000000..52761603b6a5 --- /dev/null +++ b/arch/cris/arch-v10/kernel/Makefile | |||
@@ -0,0 +1,17 @@ | |||
1 | # $Id: Makefile,v 1.5 2004/06/02 08:24:38 starvik Exp $ | ||
2 | # | ||
3 | # Makefile for the linux kernel. | ||
4 | # | ||
5 | |||
6 | extra-y := head.o | ||
7 | |||
8 | |||
9 | obj-y := entry.o traps.o shadows.o debugport.o irq.o \ | ||
10 | process.o setup.o signal.o traps.o time.o ptrace.o | ||
11 | |||
12 | obj-$(CONFIG_ETRAX_KGDB) += kgdb.o | ||
13 | obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o | ||
14 | obj-$(CONFIG_MODULES) += crisksyms.o | ||
15 | |||
16 | clean: | ||
17 | |||
diff --git a/arch/cris/arch-v10/kernel/asm-offsets.c b/arch/cris/arch-v10/kernel/asm-offsets.c new file mode 100644 index 000000000000..1aa3cc4e7107 --- /dev/null +++ b/arch/cris/arch-v10/kernel/asm-offsets.c | |||
@@ -0,0 +1,47 @@ | |||
1 | #include <linux/sched.h> | ||
2 | #include <asm/thread_info.h> | ||
3 | |||
4 | /* | ||
5 | * Generate definitions needed by assembly language modules. | ||
6 | * This code generates raw asm output which is post-processed to extract | ||
7 | * and format the required data. | ||
8 | */ | ||
9 | |||
10 | #define DEFINE(sym, val) \ | ||
11 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
12 | |||
13 | #define BLANK() asm volatile("\n->" : : ) | ||
14 | |||
15 | int main(void) | ||
16 | { | ||
17 | #define ENTRY(entry) DEFINE(PT_ ## entry, offsetof(struct pt_regs, entry)) | ||
18 | ENTRY(orig_r10); | ||
19 | ENTRY(r13); | ||
20 | ENTRY(r12); | ||
21 | ENTRY(r11); | ||
22 | ENTRY(r10); | ||
23 | ENTRY(r9); | ||
24 | ENTRY(mof); | ||
25 | ENTRY(dccr); | ||
26 | ENTRY(srp); | ||
27 | BLANK(); | ||
28 | #undef ENTRY | ||
29 | #define ENTRY(entry) DEFINE(TI_ ## entry, offsetof(struct thread_info, entry)) | ||
30 | ENTRY(task); | ||
31 | ENTRY(flags); | ||
32 | ENTRY(preempt_count); | ||
33 | BLANK(); | ||
34 | #undef ENTRY | ||
35 | #define ENTRY(entry) DEFINE(THREAD_ ## entry, offsetof(struct thread_struct, entry)) | ||
36 | ENTRY(ksp); | ||
37 | ENTRY(usp); | ||
38 | ENTRY(dccr); | ||
39 | BLANK(); | ||
40 | #undef ENTRY | ||
41 | #define ENTRY(entry) DEFINE(TASK_ ## entry, offsetof(struct task_struct, entry)) | ||
42 | ENTRY(pid); | ||
43 | BLANK(); | ||
44 | DEFINE(LCLONE_VM, CLONE_VM); | ||
45 | DEFINE(LCLONE_UNTRACED, CLONE_UNTRACED); | ||
46 | return 0; | ||
47 | } | ||
diff --git a/arch/cris/arch-v10/kernel/crisksyms.c b/arch/cris/arch-v10/kernel/crisksyms.c new file mode 100644 index 000000000000..b332bf9b312b --- /dev/null +++ b/arch/cris/arch-v10/kernel/crisksyms.c | |||
@@ -0,0 +1,17 @@ | |||
1 | #include <linux/config.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <asm/io.h> | ||
4 | #include <asm/arch/svinto.h> | ||
5 | |||
6 | /* Export shadow registers for the CPU I/O pins */ | ||
7 | EXPORT_SYMBOL(genconfig_shadow); | ||
8 | EXPORT_SYMBOL(port_pa_data_shadow); | ||
9 | EXPORT_SYMBOL(port_pa_dir_shadow); | ||
10 | EXPORT_SYMBOL(port_pb_data_shadow); | ||
11 | EXPORT_SYMBOL(port_pb_dir_shadow); | ||
12 | EXPORT_SYMBOL(port_pb_config_shadow); | ||
13 | EXPORT_SYMBOL(port_g_data_shadow); | ||
14 | |||
15 | /* Cache flush functions */ | ||
16 | EXPORT_SYMBOL(flush_etrax_cache); | ||
17 | EXPORT_SYMBOL(prepare_rx_descriptor); | ||
diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c new file mode 100644 index 000000000000..6cf069e5e7b6 --- /dev/null +++ b/arch/cris/arch-v10/kernel/debugport.c | |||
@@ -0,0 +1,531 @@ | |||
1 | /* Serialport functions for debugging | ||
2 | * | ||
3 | * Copyright (c) 2000 Axis Communications AB | ||
4 | * | ||
5 | * Authors: Bjorn Wesen | ||
6 | * | ||
7 | * Exports: | ||
8 | * console_print_etrax(char *buf) | ||
9 | * int getDebugChar() | ||
10 | * putDebugChar(int) | ||
11 | * enableDebugIRQ() | ||
12 | * init_etrax_debug() | ||
13 | * | ||
14 | * $Log: debugport.c,v $ | ||
15 | * Revision 1.19 2004/10/21 07:26:16 starvik | ||
16 | * Made it possible to specify console settings on kernel command line. | ||
17 | * | ||
18 | * Revision 1.18 2004/10/19 13:07:37 starvik | ||
19 | * Merge of Linux 2.6.9 | ||
20 | * | ||
21 | * Revision 1.17 2004/09/29 10:33:46 starvik | ||
22 | * Resolved a dealock when printing debug from kernel. | ||
23 | * | ||
24 | * Revision 1.16 2004/08/24 06:12:19 starvik | ||
25 | * Whitespace cleanup | ||
26 | * | ||
27 | * Revision 1.15 2004/08/16 12:37:19 starvik | ||
28 | * Merge of Linux 2.6.8 | ||
29 | * | ||
30 | * Revision 1.14 2004/05/17 13:11:29 starvik | ||
31 | * Disable DMA until real serial driver is up | ||
32 | * | ||
33 | * Revision 1.13 2004/05/14 07:58:01 starvik | ||
34 | * Merge of changes from 2.4 | ||
35 | * | ||
36 | * Revision 1.12 2003/09/11 07:29:49 starvik | ||
37 | * Merge of Linux 2.6.0-test5 | ||
38 | * | ||
39 | * Revision 1.11 2003/07/07 09:53:36 starvik | ||
40 | * Revert all the 2.5.74 merge changes to make the console work again | ||
41 | * | ||
42 | * Revision 1.9 2003/02/17 17:07:23 starvik | ||
43 | * Solved the problem with corrupted debug output (from Linux 2.4) | ||
44 | * * Wait until DMA, FIFO and pipe is empty before and after transmissions | ||
45 | * * Buffer data until a FIFO flush can be triggered. | ||
46 | * | ||
47 | * Revision 1.8 2003/01/22 06:48:36 starvik | ||
48 | * Fixed warnings issued by GCC 3.2.1 | ||
49 | * | ||
50 | * Revision 1.7 2002/12/12 08:26:32 starvik | ||
51 | * Don't use C-comments inside CVS comments | ||
52 | * | ||
53 | * Revision 1.6 2002/12/11 15:42:02 starvik | ||
54 | * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/ | ||
55 | * | ||
56 | * Revision 1.5 2002/11/20 06:58:03 starvik | ||
57 | * Compiles with kgdb | ||
58 | * | ||
59 | * Revision 1.4 2002/11/19 14:35:24 starvik | ||
60 | * Changes from linux 2.4 | ||
61 | * Changed struct initializer syntax to the currently prefered notation | ||
62 | * | ||
63 | * Revision 1.3 2002/11/06 09:47:03 starvik | ||
64 | * Modified for new interrupt macros | ||
65 | * | ||
66 | * Revision 1.2 2002/01/21 15:21:50 bjornw | ||
67 | * Update for kdev_t changes | ||
68 | * | ||
69 | * Revision 1.6 2001/04/17 13:58:39 orjanf | ||
70 | * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. | ||
71 | * | ||
72 | * Revision 1.5 2001/03/26 14:22:05 bjornw | ||
73 | * Namechange of some config options | ||
74 | * | ||
75 | * Revision 1.4 2000/10/06 12:37:26 bjornw | ||
76 | * Use physical addresses when talking to DMA | ||
77 | * | ||
78 | * | ||
79 | */ | ||
80 | |||
81 | #include <linux/config.h> | ||
82 | #include <linux/console.h> | ||
83 | #include <linux/init.h> | ||
84 | #include <linux/major.h> | ||
85 | #include <linux/delay.h> | ||
86 | #include <linux/tty.h> | ||
87 | #include <asm/system.h> | ||
88 | #include <asm/arch/svinto.h> | ||
89 | #include <asm/io.h> /* Get SIMCOUT. */ | ||
90 | |||
91 | struct dbg_port | ||
92 | { | ||
93 | unsigned int index; | ||
94 | const volatile unsigned* read; | ||
95 | volatile char* write; | ||
96 | volatile unsigned* xoff; | ||
97 | volatile char* baud; | ||
98 | volatile char* tr_ctrl; | ||
99 | volatile char* rec_ctrl; | ||
100 | unsigned long irq; | ||
101 | unsigned int started; | ||
102 | unsigned long baudrate; | ||
103 | unsigned char parity; | ||
104 | unsigned int bits; | ||
105 | }; | ||
106 | |||
107 | struct dbg_port ports[]= | ||
108 | { | ||
109 | { | ||
110 | 0, | ||
111 | R_SERIAL0_READ, | ||
112 | R_SERIAL0_TR_DATA, | ||
113 | R_SERIAL0_XOFF, | ||
114 | R_SERIAL0_BAUD, | ||
115 | R_SERIAL0_TR_CTRL, | ||
116 | R_SERIAL0_REC_CTRL, | ||
117 | IO_STATE(R_IRQ_MASK1_SET, ser0_data, set) | ||
118 | }, | ||
119 | { | ||
120 | 1, | ||
121 | R_SERIAL1_READ, | ||
122 | R_SERIAL1_TR_DATA, | ||
123 | R_SERIAL1_XOFF, | ||
124 | R_SERIAL1_BAUD, | ||
125 | R_SERIAL1_TR_CTRL, | ||
126 | R_SERIAL1_REC_CTRL, | ||
127 | IO_STATE(R_IRQ_MASK1_SET, ser1_data, set) | ||
128 | }, | ||
129 | { | ||
130 | 2, | ||
131 | R_SERIAL2_READ, | ||
132 | R_SERIAL2_TR_DATA, | ||
133 | R_SERIAL2_XOFF, | ||
134 | R_SERIAL2_BAUD, | ||
135 | R_SERIAL2_TR_CTRL, | ||
136 | R_SERIAL2_REC_CTRL, | ||
137 | IO_STATE(R_IRQ_MASK1_SET, ser2_data, set) | ||
138 | }, | ||
139 | { | ||
140 | 3, | ||
141 | R_SERIAL3_READ, | ||
142 | R_SERIAL3_TR_DATA, | ||
143 | R_SERIAL3_XOFF, | ||
144 | R_SERIAL3_BAUD, | ||
145 | R_SERIAL3_TR_CTRL, | ||
146 | R_SERIAL3_REC_CTRL, | ||
147 | IO_STATE(R_IRQ_MASK1_SET, ser3_data, set) | ||
148 | } | ||
149 | }; | ||
150 | |||
151 | static struct tty_driver *serial_driver; | ||
152 | |||
153 | struct dbg_port* port = | ||
154 | #if defined(CONFIG_ETRAX_DEBUG_PORT0) | ||
155 | &ports[0]; | ||
156 | #elif defined(CONFIG_ETRAX_DEBUG_PORT1) | ||
157 | &ports[1]; | ||
158 | #elif defined(CONFIG_ETRAX_DEBUG_PORT2) | ||
159 | &ports[2]; | ||
160 | #elif defined(CONFIG_ETRAX_DEBUG_PORT3) | ||
161 | &ports[3]; | ||
162 | #else | ||
163 | NULL; | ||
164 | #endif | ||
165 | /* Used by serial.c to register a debug_write_function so that the normal | ||
166 | * serial driver is used for kernel debug output | ||
167 | */ | ||
168 | typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len); | ||
169 | |||
170 | debugport_write_function debug_write_function = NULL; | ||
171 | |||
172 | static void | ||
173 | start_port(void) | ||
174 | { | ||
175 | unsigned long rec_ctrl = 0; | ||
176 | unsigned long tr_ctrl = 0; | ||
177 | |||
178 | if (!port) | ||
179 | return; | ||
180 | |||
181 | if (port->started) | ||
182 | return; | ||
183 | port->started = 1; | ||
184 | |||
185 | if (port->index == 0) | ||
186 | { | ||
187 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); | ||
188 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); | ||
189 | } | ||
190 | else if (port->index == 1) | ||
191 | { | ||
192 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); | ||
193 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); | ||
194 | } | ||
195 | else if (port->index == 2) | ||
196 | { | ||
197 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); | ||
198 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); | ||
199 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3); | ||
200 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0); | ||
201 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, ser2, select); | ||
202 | } | ||
203 | else | ||
204 | { | ||
205 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); | ||
206 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1); | ||
207 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5); | ||
208 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1); | ||
209 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, ser3, select); | ||
210 | } | ||
211 | |||
212 | *R_GEN_CONFIG = genconfig_shadow; | ||
213 | |||
214 | *port->xoff = | ||
215 | IO_STATE(R_SERIAL0_XOFF, tx_stop, enable) | | ||
216 | IO_STATE(R_SERIAL0_XOFF, auto_xoff, disable) | | ||
217 | IO_FIELD(R_SERIAL0_XOFF, xoff_char, 0); | ||
218 | |||
219 | switch (port->baudrate) | ||
220 | { | ||
221 | case 0: | ||
222 | case 115200: | ||
223 | *port->baud = | ||
224 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) | | ||
225 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz); | ||
226 | break; | ||
227 | case 1200: | ||
228 | *port->baud = | ||
229 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c1200Hz) | | ||
230 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c1200Hz); | ||
231 | break; | ||
232 | case 2400: | ||
233 | *port->baud = | ||
234 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c2400Hz) | | ||
235 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c2400Hz); | ||
236 | break; | ||
237 | case 4800: | ||
238 | *port->baud = | ||
239 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c4800Hz) | | ||
240 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c4800Hz); | ||
241 | break; | ||
242 | case 9600: | ||
243 | *port->baud = | ||
244 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c9600Hz) | | ||
245 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c9600Hz); | ||
246 | break; | ||
247 | case 19200: | ||
248 | *port->baud = | ||
249 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c19k2Hz) | | ||
250 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c19k2Hz); | ||
251 | break; | ||
252 | case 38400: | ||
253 | *port->baud = | ||
254 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c38k4Hz) | | ||
255 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c38k4Hz); | ||
256 | break; | ||
257 | case 57600: | ||
258 | *port->baud = | ||
259 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c57k6Hz) | | ||
260 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c57k6Hz); | ||
261 | break; | ||
262 | default: | ||
263 | *port->baud = | ||
264 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) | | ||
265 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz); | ||
266 | break; | ||
267 | } | ||
268 | |||
269 | if (port->parity == 'E') { | ||
270 | rec_ctrl = | ||
271 | IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) | | ||
272 | IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); | ||
273 | tr_ctrl = | ||
274 | IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) | | ||
275 | IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); | ||
276 | } else if (port->parity == 'O') { | ||
277 | rec_ctrl = | ||
278 | IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd) | | ||
279 | IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); | ||
280 | tr_ctrl = | ||
281 | IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd) | | ||
282 | IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); | ||
283 | } else { | ||
284 | rec_ctrl = | ||
285 | IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) | | ||
286 | IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, disable); | ||
287 | tr_ctrl = | ||
288 | IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) | | ||
289 | IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, disable); | ||
290 | } | ||
291 | |||
292 | if (port->bits == 7) | ||
293 | { | ||
294 | rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit); | ||
295 | tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit); | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit); | ||
300 | tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit); | ||
301 | } | ||
302 | |||
303 | *port->rec_ctrl = | ||
304 | IO_STATE(R_SERIAL0_REC_CTRL, dma_err, stop) | | ||
305 | IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable) | | ||
306 | IO_STATE(R_SERIAL0_REC_CTRL, rts_, active) | | ||
307 | IO_STATE(R_SERIAL0_REC_CTRL, sampling, middle) | | ||
308 | IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, normal) | | ||
309 | rec_ctrl; | ||
310 | |||
311 | *port->tr_ctrl = | ||
312 | IO_FIELD(R_SERIAL0_TR_CTRL, txd, 0) | | ||
313 | IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable) | | ||
314 | IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, disabled) | | ||
315 | IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, one_bit) | | ||
316 | IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, normal) | | ||
317 | tr_ctrl; | ||
318 | } | ||
319 | |||
320 | static void | ||
321 | console_write_direct(struct console *co, const char *buf, unsigned int len) | ||
322 | { | ||
323 | int i; | ||
324 | unsigned long flags; | ||
325 | local_irq_save(flags); | ||
326 | /* Send data */ | ||
327 | for (i = 0; i < len; i++) { | ||
328 | /* Wait until transmitter is ready and send.*/ | ||
329 | while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready))) | ||
330 | ; | ||
331 | *port->write = buf[i]; | ||
332 | } | ||
333 | local_irq_restore(flags); | ||
334 | } | ||
335 | |||
336 | static void | ||
337 | console_write(struct console *co, const char *buf, unsigned int len) | ||
338 | { | ||
339 | if (!port) | ||
340 | return; | ||
341 | |||
342 | #ifdef CONFIG_SVINTO_SIM | ||
343 | /* no use to simulate the serial debug output */ | ||
344 | SIMCOUT(buf, len); | ||
345 | return; | ||
346 | #endif | ||
347 | |||
348 | start_port(); | ||
349 | |||
350 | #ifdef CONFIG_ETRAX_KGDB | ||
351 | /* kgdb needs to output debug info using the gdb protocol */ | ||
352 | putDebugString(buf, len); | ||
353 | return; | ||
354 | #endif | ||
355 | |||
356 | if (debug_write_function) | ||
357 | debug_write_function(co->index, buf, len); | ||
358 | else | ||
359 | console_write_direct(co, buf, len); | ||
360 | } | ||
361 | |||
362 | /* legacy function */ | ||
363 | |||
364 | void | ||
365 | console_print_etrax(const char *buf) | ||
366 | { | ||
367 | console_write(NULL, buf, strlen(buf)); | ||
368 | } | ||
369 | |||
370 | /* Use polling to get a single character FROM the debug port */ | ||
371 | |||
372 | int | ||
373 | getDebugChar(void) | ||
374 | { | ||
375 | unsigned long readval; | ||
376 | |||
377 | do { | ||
378 | readval = *port->read; | ||
379 | } while (!(readval & IO_MASK(R_SERIAL0_READ, data_avail))); | ||
380 | |||
381 | return (readval & IO_MASK(R_SERIAL0_READ, data_in)); | ||
382 | } | ||
383 | |||
384 | /* Use polling to put a single character to the debug port */ | ||
385 | |||
386 | void | ||
387 | putDebugChar(int val) | ||
388 | { | ||
389 | while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready))) | ||
390 | ; | ||
391 | *port->write = val; | ||
392 | } | ||
393 | |||
394 | /* Enable irq for receiving chars on the debug port, used by kgdb */ | ||
395 | |||
396 | void | ||
397 | enableDebugIRQ(void) | ||
398 | { | ||
399 | *R_IRQ_MASK1_SET = port->irq; | ||
400 | /* use R_VECT_MASK directly, since we really bypass Linux normal | ||
401 | * IRQ handling in kgdb anyway, we don't need to use enable_irq | ||
402 | */ | ||
403 | *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set); | ||
404 | |||
405 | *port->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); | ||
406 | } | ||
407 | |||
408 | static struct tty_driver* | ||
409 | etrax_console_device(struct console* co, int *index) | ||
410 | { | ||
411 | return serial_driver; | ||
412 | } | ||
413 | |||
414 | static int __init | ||
415 | console_setup(struct console *co, char *options) | ||
416 | { | ||
417 | char* s; | ||
418 | |||
419 | if (options) { | ||
420 | port = &ports[co->index]; | ||
421 | port->baudrate = 115200; | ||
422 | port->parity = 'N'; | ||
423 | port->bits = 8; | ||
424 | port->baudrate = simple_strtoul(options, NULL, 10); | ||
425 | s = options; | ||
426 | while(*s >= '0' && *s <= '9') | ||
427 | s++; | ||
428 | if (*s) port->parity = *s++; | ||
429 | if (*s) port->bits = *s++ - '0'; | ||
430 | port->started = 0; | ||
431 | start_port(); | ||
432 | } | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static struct console sercons = { | ||
437 | name : "ttyS", | ||
438 | write: console_write, | ||
439 | read : NULL, | ||
440 | device : etrax_console_device, | ||
441 | unblank : NULL, | ||
442 | setup : console_setup, | ||
443 | flags : CON_PRINTBUFFER, | ||
444 | index : -1, | ||
445 | cflag : 0, | ||
446 | next : NULL | ||
447 | }; | ||
448 | static struct console sercons0 = { | ||
449 | name : "ttyS", | ||
450 | write: console_write, | ||
451 | read : NULL, | ||
452 | device : etrax_console_device, | ||
453 | unblank : NULL, | ||
454 | setup : console_setup, | ||
455 | flags : CON_PRINTBUFFER, | ||
456 | index : 0, | ||
457 | cflag : 0, | ||
458 | next : NULL | ||
459 | }; | ||
460 | |||
461 | static struct console sercons1 = { | ||
462 | name : "ttyS", | ||
463 | write: console_write, | ||
464 | read : NULL, | ||
465 | device : etrax_console_device, | ||
466 | unblank : NULL, | ||
467 | setup : console_setup, | ||
468 | flags : CON_PRINTBUFFER, | ||
469 | index : 1, | ||
470 | cflag : 0, | ||
471 | next : NULL | ||
472 | }; | ||
473 | static struct console sercons2 = { | ||
474 | name : "ttyS", | ||
475 | write: console_write, | ||
476 | read : NULL, | ||
477 | device : etrax_console_device, | ||
478 | unblank : NULL, | ||
479 | setup : console_setup, | ||
480 | flags : CON_PRINTBUFFER, | ||
481 | index : 2, | ||
482 | cflag : 0, | ||
483 | next : NULL | ||
484 | }; | ||
485 | static struct console sercons3 = { | ||
486 | name : "ttyS", | ||
487 | write: console_write, | ||
488 | read : NULL, | ||
489 | device : etrax_console_device, | ||
490 | unblank : NULL, | ||
491 | setup : console_setup, | ||
492 | flags : CON_PRINTBUFFER, | ||
493 | index : 3, | ||
494 | cflag : 0, | ||
495 | next : NULL | ||
496 | }; | ||
497 | /* | ||
498 | * Register console (for printk's etc) | ||
499 | */ | ||
500 | |||
501 | int __init | ||
502 | init_etrax_debug(void) | ||
503 | { | ||
504 | static int first = 1; | ||
505 | |||
506 | if (!first) { | ||
507 | if (!port) { | ||
508 | register_console(&sercons0); | ||
509 | register_console(&sercons1); | ||
510 | register_console(&sercons2); | ||
511 | register_console(&sercons3); | ||
512 | unregister_console(&sercons); | ||
513 | } | ||
514 | return 0; | ||
515 | } | ||
516 | first = 0; | ||
517 | if (port) | ||
518 | register_console(&sercons); | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | int __init | ||
523 | init_console(void) | ||
524 | { | ||
525 | serial_driver = alloc_tty_driver(1); | ||
526 | if (!serial_driver) | ||
527 | return -ENOMEM; | ||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | __initcall(init_etrax_debug); | ||
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S new file mode 100644 index 000000000000..1bc44f481c34 --- /dev/null +++ b/arch/cris/arch-v10/kernel/entry.S | |||
@@ -0,0 +1,1132 @@ | |||
1 | /* $Id: entry.S,v 1.23 2004/10/19 13:07:37 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/entry.S | ||
4 | * | ||
5 | * Copyright (C) 2000, 2001, 2002 Axis Communications AB | ||
6 | * | ||
7 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
8 | * | ||
9 | * $Log: entry.S,v $ | ||
10 | * Revision 1.23 2004/10/19 13:07:37 starvik | ||
11 | * Merge of Linux 2.6.9 | ||
12 | * | ||
13 | * Revision 1.22 2004/06/21 10:29:55 starvik | ||
14 | * Merge of Linux 2.6.7 | ||
15 | * | ||
16 | * Revision 1.21 2004/06/09 05:30:27 starvik | ||
17 | * Clean up multiple interrupt handling. | ||
18 | * Prevent interrupts from interrupting each other. | ||
19 | * Handle all active interrupts. | ||
20 | * | ||
21 | * Revision 1.20 2004/06/08 08:55:32 starvik | ||
22 | * Removed unused code | ||
23 | * | ||
24 | * Revision 1.19 2004/06/04 11:56:15 starvik | ||
25 | * Implemented page table lookup for refills in assembler for improved performance. | ||
26 | * | ||
27 | * Revision 1.18 2004/05/11 12:28:25 starvik | ||
28 | * Merge of Linux 2.6.6 | ||
29 | * | ||
30 | * Revision 1.17 2003/09/11 07:29:49 starvik | ||
31 | * Merge of Linux 2.6.0-test5 | ||
32 | * | ||
33 | * Revision 1.16 2003/07/04 08:27:41 starvik | ||
34 | * Merge of Linux 2.5.74 | ||
35 | * | ||
36 | * Revision 1.15 2003/04/09 07:32:55 starvik | ||
37 | * resume should return task_struct, not thread_info | ||
38 | * | ||
39 | * Revision 1.14 2003/04/09 05:20:44 starvik | ||
40 | * Merge of Linux 2.5.67 | ||
41 | * | ||
42 | * Revision 1.13 2002/12/11 15:42:02 starvik | ||
43 | * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c | ||
44 | * | ||
45 | * Revision 1.12 2002/12/10 09:00:10 starvik | ||
46 | * Merge of Linux 2.5.51 | ||
47 | * | ||
48 | * Revision 1.11 2002/12/05 07:53:10 starvik | ||
49 | * Corrected constants used with btstq | ||
50 | * | ||
51 | * Revision 1.10 2002/11/27 08:45:10 starvik | ||
52 | * pid is in task_struct, not thread_info | ||
53 | * | ||
54 | * Revision 1.9 2002/11/26 09:52:05 starvik | ||
55 | * Added preemptive kernel scheduling (if CONFIG_PREEMPT) | ||
56 | * | ||
57 | * Revision 1.8 2002/11/20 11:56:11 starvik | ||
58 | * Merge of Linux 2.5.48 | ||
59 | * | ||
60 | * Revision 1.7 2002/11/18 13:02:42 starvik | ||
61 | * Added fourth parameter to do_notify_resume | ||
62 | * Minor cleanup | ||
63 | * | ||
64 | * Revision 1.6 2002/11/11 10:37:50 starvik | ||
65 | * Use new asm-offset defines | ||
66 | * Modified for new location of current->work etc | ||
67 | * Removed SYMBOL_NAME from syscalls | ||
68 | * Added some new syscalls | ||
69 | * | ||
70 | * Revision 1.5 2002/11/05 06:45:11 starvik | ||
71 | * Merge of Linux 2.5.45 | ||
72 | * | ||
73 | * Revision 1.4 2002/02/05 15:41:31 bjornw | ||
74 | * Rewritten to conform better to current 2.5 code (similar to arch/i386) | ||
75 | * | ||
76 | * Revision 1.3 2002/01/21 15:22:20 bjornw | ||
77 | * NICE_DOGGY fix from 2.4 arch/cris | ||
78 | * | ||
79 | * Revision 1.37 2001/12/07 17:03:55 bjornw | ||
80 | * Call a c-hook called watchdog_bite_hook instead of show_registers directly | ||
81 | * | ||
82 | * Revision 1.36 2001/11/22 13:36:36 bjornw | ||
83 | * * In ret_from_intr, check regs->dccr for usermode reentrance instead of | ||
84 | * DCCR explicitely (because the latter might not reflect current reality) | ||
85 | * * In mmu_bus_fault, set $r9 _after_ calling the C-code instead of before | ||
86 | * since $r9 is call-clobbered and is potentially needed afterwards | ||
87 | * | ||
88 | * Revision 1.35 2001/10/30 17:10:15 bjornw | ||
89 | * Add some syscalls | ||
90 | * | ||
91 | * Revision 1.34 2001/10/01 14:45:03 bjornw | ||
92 | * Removed underscores and added register prefixes | ||
93 | * | ||
94 | * Revision 1.33 2001/08/21 13:48:01 jonashg | ||
95 | * Added fix by HP to avoid oops when doing a hard_reset_now. | ||
96 | * | ||
97 | * Revision 1.32 2001/08/14 04:32:02 hp | ||
98 | * In _resume, add comment why R9 is saved; don't sound like it's call-saved. | ||
99 | * | ||
100 | * Revision 1.31 2001/07/25 16:07:42 bjornw | ||
101 | * softirq_active/mask -> softirq_pending only | ||
102 | * | ||
103 | * Revision 1.30 2001/07/05 01:03:32 hp | ||
104 | * - include asm/errno.h to get ENOSYS. | ||
105 | * - Use ENOSYS, not local constant LENOSYS; tweak comments. | ||
106 | * - Explain why .include, not #include is used. | ||
107 | * - Make oops-register-dump if watchdog bits and it's not expected. | ||
108 | * - Don't jsr, use jump _hard_reset_now, and skip spurious nop. | ||
109 | * - Use correct section attribute for section .rodata. | ||
110 | * - Adjust sys_ni_syscall fill number. | ||
111 | * | ||
112 | * Revision 1.29 2001/06/25 14:07:00 hp | ||
113 | * Fix review comment. | ||
114 | * * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of | ||
115 | * magic numbers. Add comment that -traditional must not be used. | ||
116 | * * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation. | ||
117 | * Correct and update comment. | ||
118 | * * Makefile (.S.o): Don't use -traditional. Add comment why the | ||
119 | * toplevel rule can't be used (now that there's a reason). | ||
120 | * | ||
121 | * Revision 1.28 2001/06/21 02:00:40 hp | ||
122 | * * entry.S: Include asm/unistd.h. | ||
123 | * (_sys_call_table): Use section .rodata, not .data. | ||
124 | * (_kernel_thread): Move from... | ||
125 | * * process.c: ... here. | ||
126 | * * entryoffsets.c (VAL): Break out from... | ||
127 | * (OF): Use VAL. | ||
128 | * (LCLONE_VM): New asmified value from CLONE_VM. | ||
129 | * | ||
130 | * Revision 1.27 2001/05/29 11:25:27 markusl | ||
131 | * In case of "spurious_interrupt", do hard_reset instead of hanging system in a loop... | ||
132 | * | ||
133 | * Revision 1.26 2001/05/15 15:46:03 bjornw | ||
134 | * Include config.h now that we use some CONFIG_ options | ||
135 | * | ||
136 | * Revision 1.25 2001/05/15 05:38:47 hp | ||
137 | * Tweaked code in _ret_from_sys_call | ||
138 | * | ||
139 | * Revision 1.24 2001/05/15 05:27:49 hp | ||
140 | * Save r9 in r1 over function call rather than on stack. | ||
141 | * | ||
142 | * Revision 1.23 2001/05/15 05:10:00 hp | ||
143 | * Generate entry.S structure offsets from C | ||
144 | * | ||
145 | * Revision 1.22 2001/04/17 13:58:39 orjanf | ||
146 | * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. | ||
147 | * | ||
148 | * Revision 1.21 2001/04/17 11:33:29 orjanf | ||
149 | * Updated according to review: | ||
150 | * * Included asm/sv_addr_ag.h to get macro for internal register. | ||
151 | * * Corrected comment regarding system call argument passing. | ||
152 | * * Removed comment about instruction being in a delay slot. | ||
153 | * * Added comment about SYMBOL_NAME macro. | ||
154 | * | ||
155 | * Revision 1.20 2001/04/12 08:51:07 hp | ||
156 | * - Add entry for sys_fcntl64. In fact copy last piece from i386 including ... | ||
157 | * - .rept to fill table to safe state with sys_ni_syscall. | ||
158 | * | ||
159 | * Revision 1.19 2001/04/04 09:43:32 orjanf | ||
160 | * * Moved do_sigtrap from traps.c to entry.S. | ||
161 | * * LTASK_PID need not be global anymore. | ||
162 | * | ||
163 | * Revision 1.18 2001/03/26 09:25:02 markusl | ||
164 | * Updated after review, should now handle USB interrupts correctly. | ||
165 | * | ||
166 | * Revision 1.17 2001/03/21 16:12:55 bjornw | ||
167 | * * Always make room for the cpu status record in the frame, in order to | ||
168 | * use the same framelength and layout for both mmu busfaults and normal | ||
169 | * irqs. No need to check for the explicit CRIS_FRAME_FIXUP type anymore. | ||
170 | * * Fixed bug with using addq for popping the stack in the epilogue - it | ||
171 | * destroyed the flag register. Use instructions that don't affect the | ||
172 | * flag register instead. | ||
173 | * * Removed write to R_PORT_PA_DATA during spurious_interrupt | ||
174 | * | ||
175 | * Revision 1.16 2001/03/20 19:43:02 bjornw | ||
176 | * * Get rid of esp0 setting | ||
177 | * * Give a 7th argument to a systemcall - the stackframe | ||
178 | * | ||
179 | * Revision 1.15 2001/03/05 13:14:30 bjornw | ||
180 | * Spelling fix | ||
181 | * | ||
182 | * Revision 1.14 2001/02/23 08:36:36 perf | ||
183 | * New ABI; syscallnr=r9, arg5=mof, arg6=srp. | ||
184 | * Corrected tracesys call check. | ||
185 | * | ||
186 | * Revision 1.13 2001/02/15 08:40:55 perf | ||
187 | * H-P by way of perf; | ||
188 | * - (_system_call): Don't read system call function address into r1. | ||
189 | * - (RBFExit): There is no such thing as a null pop. Adjust sp by addq. | ||
190 | * - (_system_call): Don't use r10 and don't save and restore it. | ||
191 | * - (THREAD_ESP0): New constant. | ||
192 | * - (_system_call): Inline set_esp0. | ||
193 | * | ||
194 | * Revision 1.12 2001/01/31 17:56:25 orjanf | ||
195 | * Added definition of LTASK_PID and made it global. | ||
196 | * | ||
197 | * Revision 1.11 2001/01/10 21:13:29 bjornw | ||
198 | * SYMBOL_NAME is defined incorrectly for the compiler options we currently use | ||
199 | * | ||
200 | * Revision 1.10 2000/12/18 23:47:56 bjornw | ||
201 | * * Added syscall trace support (ptrace), completely untested of course | ||
202 | * * Removed redundant check for NULL entries in syscall_table | ||
203 | * | ||
204 | * Revision 1.9 2000/11/21 16:40:51 bjornw | ||
205 | * * New frame type used when an SBFS frame needs to be popped without | ||
206 | * actually restarting the instruction | ||
207 | * * Enable interrupts in signal_return (they did so in x86, I hope it's a good | ||
208 | * idea) | ||
209 | * | ||
210 | * Revision 1.8 2000/11/17 16:53:35 bjornw | ||
211 | * Added detection of frame-type in Rexit, so that mmu_bus_fault can | ||
212 | * use ret_from_intr in the return-path to check for signals (like SEGV) | ||
213 | * and other foul things that might have occurred during the fault. | ||
214 | * | ||
215 | * Revision 1.7 2000/10/06 15:04:28 bjornw | ||
216 | * Include mof in register savings | ||
217 | * | ||
218 | * Revision 1.6 2000/09/12 16:02:44 bjornw | ||
219 | * Linux-2.4.0-test7 derived updates | ||
220 | * | ||
221 | * Revision 1.5 2000/08/17 15:35:15 bjornw | ||
222 | * 2.4.0-test6 changed local_irq_count and friends API | ||
223 | * | ||
224 | * Revision 1.4 2000/08/02 13:59:30 bjornw | ||
225 | * Removed olduname and uname from the syscall list | ||
226 | * | ||
227 | * Revision 1.3 2000/07/31 13:32:58 bjornw | ||
228 | * * Export ret_from_intr | ||
229 | * * _resume updated (prev/last tjohejsan) | ||
230 | * * timer_interrupt obsolete | ||
231 | * * SIGSEGV detection in mmu_bus_fault temporarily disabled | ||
232 | * | ||
233 | * | ||
234 | */ | ||
235 | |||
236 | /* | ||
237 | * entry.S contains the system-call and fault low-level handling routines. | ||
238 | * | ||
239 | * NOTE: This code handles signal-recognition, which happens every time | ||
240 | * after a timer-interrupt and after each system call. | ||
241 | * | ||
242 | * Stack layout in 'ret_from_system_call': | ||
243 | * ptrace needs to have all regs on the stack. | ||
244 | * if the order here is changed, it needs to be | ||
245 | * updated in fork.c:copy_process, signal.c:do_signal, | ||
246 | * ptrace.c and ptrace.h | ||
247 | * | ||
248 | */ | ||
249 | |||
250 | #include <linux/config.h> | ||
251 | #include <linux/linkage.h> | ||
252 | #include <linux/sys.h> | ||
253 | #include <asm/unistd.h> | ||
254 | #include <asm/arch/sv_addr_ag.h> | ||
255 | #include <asm/errno.h> | ||
256 | #include <asm/thread_info.h> | ||
257 | #include <asm/arch/offset.h> | ||
258 | #include <asm/page.h> | ||
259 | #include <asm/pgtable.h> | ||
260 | |||
261 | ;; functions exported from this file | ||
262 | |||
263 | .globl system_call | ||
264 | .globl ret_from_intr | ||
265 | .globl ret_from_fork | ||
266 | .globl resume | ||
267 | .globl multiple_interrupt | ||
268 | .globl hwbreakpoint | ||
269 | .globl IRQ1_interrupt | ||
270 | .globl spurious_interrupt | ||
271 | .globl hw_bp_trigs | ||
272 | .globl mmu_bus_fault | ||
273 | .globl do_sigtrap | ||
274 | .globl gdb_handle_breakpoint | ||
275 | .globl sys_call_table | ||
276 | |||
277 | ;; below are various parts of system_call which are not in the fast-path | ||
278 | |||
279 | #ifdef CONFIG_PREEMPT | ||
280 | ; Check if preemptive kernel scheduling should be done | ||
281 | _resume_kernel: | ||
282 | ; Load current task struct | ||
283 | movs.w -8192, $r0 ; THREAD_SIZE = 8192 | ||
284 | and.d $sp, $r0 | ||
285 | move.d [$r0+TI_preempt_count], $r10 ; Preemption disabled? | ||
286 | bne _Rexit | ||
287 | nop | ||
288 | _need_resched: | ||
289 | move.d [$r0+TI_flags], $r10 | ||
290 | btstq TIF_NEED_RESCHED, $r10 ; Check if need_resched is set | ||
291 | bpl _Rexit | ||
292 | nop | ||
293 | ; Ok, lets's do some preemptive kernel scheduling | ||
294 | move.d PREEMPT_ACTIVE, $r10 | ||
295 | move.d $r10, [$r0+TI_preempt_count] ; Mark as active | ||
296 | ei | ||
297 | jsr schedule | ||
298 | clear.d [$r0+TI_preempt_count] ; Mark as inactive | ||
299 | di | ||
300 | ; Load new task struct | ||
301 | movs.w -8192, $r0 ; THREAD_SIZE = 8192 | ||
302 | and.d $sp, $r0 | ||
303 | ; One more time (with new task) | ||
304 | ba _need_resched | ||
305 | nop | ||
306 | #else | ||
307 | #define _resume_kernel _Rexit | ||
308 | #endif | ||
309 | |||
310 | ; Called at exit from fork. schedule_tail must be called to drop | ||
311 | ; spinlock if CONFIG_PREEMPT | ||
312 | ret_from_fork: | ||
313 | jsr schedule_tail | ||
314 | ba ret_from_sys_call | ||
315 | nop | ||
316 | |||
317 | ret_from_intr: | ||
318 | ;; check for resched if preemptive kernel or if we're going back to user-mode | ||
319 | ;; this test matches the user_regs(regs) macro | ||
320 | ;; we cannot simply test $dccr, because that does not necessarily | ||
321 | ;; reflect what mode we'll return into. | ||
322 | |||
323 | move.d [$sp + PT_dccr], $r0; regs->dccr | ||
324 | btstq 8, $r0 ; U-flag | ||
325 | bpl _resume_kernel | ||
326 | ; Note that di below is in delay slot | ||
327 | |||
328 | _resume_userspace: | ||
329 | di ; so need_resched and sigpending don't change | ||
330 | |||
331 | movs.w -8192, $r0 ; THREAD_SIZE == 8192 | ||
332 | and.d $sp, $r0 | ||
333 | |||
334 | move.d [$r0+TI_flags], $r10 ; current->work | ||
335 | and.d _TIF_WORK_MASK, $r10 ; is there any work to be done on return | ||
336 | bne _work_pending | ||
337 | nop | ||
338 | ba _Rexit | ||
339 | nop | ||
340 | |||
341 | ;; The system_call is called by a BREAK instruction, which works like | ||
342 | ;; an interrupt call but it stores the return PC in BRP instead of IRP. | ||
343 | ;; Since we dont really want to have two epilogues (one for system calls | ||
344 | ;; and one for interrupts) we push the contents of BRP instead of IRP in the | ||
345 | ;; system call prologue, to make it look like an ordinary interrupt on the | ||
346 | ;; stackframe. | ||
347 | ;; | ||
348 | ;; Since we can't have system calls inside interrupts, it should not matter | ||
349 | ;; that we don't stack IRP. | ||
350 | ;; | ||
351 | ;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp | ||
352 | ;; | ||
353 | ;; This function looks on the _surface_ like spaghetti programming, but it's | ||
354 | ;; really designed so that the fast-path does not force cache-loading of non-used | ||
355 | ;; instructions. Only the non-common cases cause the outlined code to run.. | ||
356 | |||
357 | system_call: | ||
358 | ;; stack-frame similar to the irq heads, which is reversed in ret_from_sys_call | ||
359 | move $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame | ||
360 | push $srp | ||
361 | push $dccr | ||
362 | push $mof | ||
363 | subq 14*4, $sp ; make room for r0-r13 | ||
364 | movem $r13, [$sp] ; push r0-r13 | ||
365 | push $r10 ; push orig_r10 | ||
366 | clear.d [$sp=$sp-4] ; frametype == 0, normal stackframe | ||
367 | |||
368 | movs.w -ENOSYS, $r0 | ||
369 | move.d $r0, [$sp+PT_r10] ; put the default return value in r10 in the frame | ||
370 | |||
371 | ;; check if this process is syscall-traced | ||
372 | |||
373 | movs.w -8192, $r0 ; THREAD_SIZE == 8192 | ||
374 | and.d $sp, $r0 | ||
375 | |||
376 | move.d [$r0+TI_flags], $r0 | ||
377 | btstq TIF_SYSCALL_TRACE, $r0 | ||
378 | bmi _syscall_trace_entry | ||
379 | nop | ||
380 | |||
381 | _syscall_traced: | ||
382 | |||
383 | ;; check for sanity in the requested syscall number | ||
384 | |||
385 | cmpu.w NR_syscalls, $r9 | ||
386 | bcc ret_from_sys_call | ||
387 | lslq 2, $r9 ; multiply by 4, in the delay slot | ||
388 | |||
389 | ;; as a bonus 7th parameter, we give the location on the stack | ||
390 | ;; of the register structure itself. some syscalls need this. | ||
391 | |||
392 | push $sp | ||
393 | |||
394 | ;; the parameter carrying registers r10, r11, r12 and 13 are intact. | ||
395 | ;; the fifth and sixth parameters (if any) was in mof and srp | ||
396 | ;; respectively, and we need to put them on the stack. | ||
397 | |||
398 | push $srp | ||
399 | push $mof | ||
400 | |||
401 | jsr [$r9+sys_call_table] ; actually do the system call | ||
402 | addq 3*4, $sp ; pop the mof, srp and regs parameters | ||
403 | move.d $r10, [$sp+PT_r10] ; save the return value | ||
404 | |||
405 | moveq 1, $r9 ; "parameter" to ret_from_sys_call to show it was a sys call | ||
406 | |||
407 | ;; fall through into ret_from_sys_call to return | ||
408 | |||
409 | ret_from_sys_call: | ||
410 | ;; r9 is a parameter - if >=1 we came from a syscall, if 0, from an irq | ||
411 | |||
412 | ;; get the current task-struct pointer (see top for defs) | ||
413 | |||
414 | movs.w -8192, $r0 ; THREAD_SIZE == 8192 | ||
415 | and.d $sp, $r0 | ||
416 | |||
417 | di ; make sure need_resched and sigpending don't change | ||
418 | move.d [$r0+TI_flags],$r1 | ||
419 | and.d _TIF_ALLWORK_MASK, $r1 | ||
420 | bne _syscall_exit_work | ||
421 | nop | ||
422 | |||
423 | _Rexit: | ||
424 | ;; this epilogue MUST match the prologues in multiple_interrupt, irq.h and ptregs.h | ||
425 | pop $r10 ; frametype | ||
426 | bne _RBFexit ; was not CRIS_FRAME_NORMAL, handle otherwise | ||
427 | addq 4, $sp ; skip orig_r10, in delayslot | ||
428 | movem [$sp+], $r13 ; registers r0-r13 | ||
429 | pop $mof ; multiply overflow register | ||
430 | pop $dccr ; condition codes | ||
431 | pop $srp ; subroutine return pointer | ||
432 | ;; now we have a 4-word SBFS frame which we do not want to restore | ||
433 | ;; using RBF since it was not stacked with SBFS. instead we would like to | ||
434 | ;; just get the PC value to restart it with, and skip the rest of | ||
435 | ;; the frame. | ||
436 | ;; Also notice that it's important to use instructions here that | ||
437 | ;; keep the interrupts disabled (since we've already popped DCCR) | ||
438 | move [$sp=$sp+16], $p8; pop the SBFS frame from the sp | ||
439 | jmpu [$sp-16] ; return through the irp field in the sbfs frame | ||
440 | |||
441 | _RBFexit: | ||
442 | movem [$sp+], $r13 ; registers r0-r13, in delay slot | ||
443 | pop $mof ; multiply overflow register | ||
444 | pop $dccr ; condition codes | ||
445 | pop $srp ; subroutine return pointer | ||
446 | rbf [$sp+] ; return by popping the CPU status | ||
447 | |||
448 | ;; We get here after doing a syscall if extra work might need to be done | ||
449 | ;; perform syscall exit tracing if needed | ||
450 | |||
451 | _syscall_exit_work: | ||
452 | ;; $r0 contains current at this point and irq's are disabled | ||
453 | |||
454 | move.d [$r0+TI_flags], $r1 | ||
455 | btstq TIF_SYSCALL_TRACE, $r1 | ||
456 | bpl _work_pending | ||
457 | nop | ||
458 | |||
459 | ei | ||
460 | |||
461 | move.d $r9, $r1 ; preserve r9 | ||
462 | jsr do_syscall_trace | ||
463 | move.d $r1, $r9 | ||
464 | |||
465 | ba _resume_userspace | ||
466 | nop | ||
467 | |||
468 | _work_pending: | ||
469 | move.d [$r0+TI_flags], $r1 | ||
470 | btstq TIF_NEED_RESCHED, $r1 | ||
471 | bpl _work_notifysig ; was neither trace nor sched, must be signal/notify | ||
472 | nop | ||
473 | |||
474 | _work_resched: | ||
475 | move.d $r9, $r1 ; preserve r9 | ||
476 | jsr schedule | ||
477 | move.d $r1, $r9 | ||
478 | di | ||
479 | |||
480 | move.d [$r0+TI_flags], $r1 | ||
481 | and.d _TIF_WORK_MASK, $r1; ignore the syscall trace counter | ||
482 | beq _Rexit | ||
483 | nop | ||
484 | btstq TIF_NEED_RESCHED, $r1 | ||
485 | bmi _work_resched ; current->work.need_resched | ||
486 | nop | ||
487 | |||
488 | _work_notifysig: | ||
489 | ;; deal with pending signals and notify-resume requests | ||
490 | |||
491 | move.d $r9, $r10 ; do_notify_resume syscall/irq param | ||
492 | moveq 0, $r11 ; oldset param - 0 in this case | ||
493 | move.d $sp, $r12 ; the regs param | ||
494 | move.d $r1, $r13 ; the thread_info_flags parameter | ||
495 | jsr do_notify_resume | ||
496 | |||
497 | ba _Rexit | ||
498 | nop | ||
499 | |||
500 | ;; We get here as a sidetrack when we've entered a syscall with the | ||
501 | ;; trace-bit set. We need to call do_syscall_trace and then continue | ||
502 | ;; with the call. | ||
503 | |||
504 | _syscall_trace_entry: | ||
505 | ;; PT_r10 in the frame contains -ENOSYS as required, at this point | ||
506 | |||
507 | jsr do_syscall_trace | ||
508 | |||
509 | ;; now re-enter the syscall code to do the syscall itself | ||
510 | ;; we need to restore $r9 here to contain the wanted syscall, and | ||
511 | ;; the other parameter-bearing registers | ||
512 | |||
513 | move.d [$sp+PT_r9], $r9 | ||
514 | move.d [$sp+PT_orig_r10], $r10 ; PT_r10 is already filled with -ENOSYS. | ||
515 | move.d [$sp+PT_r11], $r11 | ||
516 | move.d [$sp+PT_r12], $r12 | ||
517 | move.d [$sp+PT_r13], $r13 | ||
518 | move [$sp+PT_mof], $mof | ||
519 | move [$sp+PT_srp], $srp | ||
520 | |||
521 | ba _syscall_traced | ||
522 | nop | ||
523 | |||
524 | ;; resume performs the actual task-switching, by switching stack pointers | ||
525 | ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct | ||
526 | ;; returns old current in r10 | ||
527 | ;; | ||
528 | ;; TODO: see the i386 version. The switch_to which calls resume in our version | ||
529 | ;; could really be an inline asm of this. | ||
530 | |||
531 | resume: | ||
532 | push $srp ; we keep the old/new PC on the stack | ||
533 | add.d $r12, $r10 ; r10 = current tasks tss | ||
534 | move $dccr, [$r10+THREAD_dccr]; save irq enable state | ||
535 | di | ||
536 | |||
537 | move $usp, [$r10+ THREAD_usp] ; save user-mode stackpointer | ||
538 | |||
539 | ;; See copy_thread for the reason why register R9 is saved. | ||
540 | subq 10*4, $sp | ||
541 | movem $r9, [$sp] ; save non-scratch registers and R9. | ||
542 | |||
543 | move.d $sp, [$r10+THREAD_ksp] ; save the kernel stack pointer for the old task | ||
544 | move.d $sp, $r10 ; return last running task in r10 | ||
545 | and.d -8192, $r10 ; get thread_info from stackpointer | ||
546 | move.d [$r10+TI_task], $r10 ; get task | ||
547 | add.d $r12, $r11 ; find the new tasks tss | ||
548 | move.d [$r11+THREAD_ksp], $sp ; switch into the new stackframe by restoring kernel sp | ||
549 | |||
550 | movem [$sp+], $r9 ; restore non-scratch registers and R9. | ||
551 | |||
552 | move [$r11+THREAD_usp], $usp ; restore user-mode stackpointer | ||
553 | |||
554 | move [$r11+THREAD_dccr], $dccr ; restore irq enable status | ||
555 | jump [$sp+] ; restore PC | ||
556 | |||
557 | ;; This is the MMU bus fault handler. | ||
558 | ;; It needs to stack the CPU status and overall is different | ||
559 | ;; from the other interrupt handlers. | ||
560 | |||
561 | mmu_bus_fault: | ||
562 | ;; For refills we try to do a quick page table lookup. If it is | ||
563 | ;; a real fault we let the mm subsystem handle it. | ||
564 | |||
565 | ;; the first longword in the sbfs frame was the interrupted PC | ||
566 | ;; which fits nicely with the "IRP" slot in pt_regs normally used to | ||
567 | ;; contain the return address. used by Oops to print kernel errors. | ||
568 | sbfs [$sp=$sp-16] ; push the internal CPU status | ||
569 | push $dccr | ||
570 | di | ||
571 | subq 2*4, $sp | ||
572 | movem $r1, [$sp] | ||
573 | move.d [R_MMU_CAUSE], $r1 | ||
574 | ;; ETRAX 100LX TR89 bugfix: if the second half of an unaligned | ||
575 | ;; write causes a MMU-fault, it will not be restarted correctly. | ||
576 | ;; This could happen if a write crosses a page-boundary and the | ||
577 | ;; second page is not yet COW'ed or even loaded. The workaround | ||
578 | ;; is to clear the unaligned bit in the CPU status record, so | ||
579 | ;; that the CPU will rerun both the first and second halves of | ||
580 | ;; the instruction. This will not have any sideeffects unless | ||
581 | ;; the first half goes to any device or memory that can't be | ||
582 | ;; written twice, and which is mapped through the MMU. | ||
583 | ;; | ||
584 | ;; We only need to do this for writes. | ||
585 | btstq 8, $r1 ; Write access? | ||
586 | bpl 1f | ||
587 | nop | ||
588 | move.d [$sp+16], $r0 ; Clear unaligned bit in csrinstr | ||
589 | and.d ~(1<<5), $r0 | ||
590 | move.d $r0, [$sp+16] | ||
591 | 1: btstq 12, $r1 ; Refill? | ||
592 | bpl 2f | ||
593 | lsrq PMD_SHIFT, $r1 ; Get PMD index into PGD (bit 24-31) | ||
594 | move.d [current_pgd], $r0 ; PGD for the current process | ||
595 | move.d [$r0+$r1.d], $r0 ; Get PMD | ||
596 | beq 2f | ||
597 | nop | ||
598 | and.w PAGE_MASK, $r0 ; Remove PMD flags | ||
599 | move.d [R_MMU_CAUSE], $r1 | ||
600 | lsrq PAGE_SHIFT, $r1 | ||
601 | and.d 0x7ff, $r1 ; Get PTE index into PMD (bit 13-24) | ||
602 | move.d [$r0+$r1.d], $r1 ; Get PTE | ||
603 | beq 2f | ||
604 | nop | ||
605 | ;; Store in TLB | ||
606 | move.d $r1, [R_TLB_LO] | ||
607 | ;; Return | ||
608 | movem [$sp+], $r1 | ||
609 | pop $dccr | ||
610 | rbf [$sp+] ; return by popping the CPU status | ||
611 | |||
612 | 2: ; PMD or PTE missing, let the mm subsystem fix it up. | ||
613 | movem [$sp+], $r1 | ||
614 | pop $dccr | ||
615 | |||
616 | ; Ok, not that easy, pass it on to the mm subsystem | ||
617 | ; The MMU status record is now on the stack | ||
618 | push $srp ; make a stackframe similar to pt_regs | ||
619 | push $dccr | ||
620 | push $mof | ||
621 | di | ||
622 | subq 14*4, $sp | ||
623 | movem $r13, [$sp] | ||
624 | push $r10 ; dummy orig_r10 | ||
625 | moveq 1, $r10 | ||
626 | push $r10 ; frametype == 1, BUSFAULT frame type | ||
627 | |||
628 | move.d $sp, $r10 ; pt_regs argument to handle_mmu_bus_fault | ||
629 | |||
630 | jsr handle_mmu_bus_fault ; in arch/cris/arch-v10/mm/fault.c | ||
631 | |||
632 | ;; now we need to return through the normal path, we cannot just | ||
633 | ;; do the RBFexit since we might have killed off the running | ||
634 | ;; process due to a SEGV, scheduled due to a page blocking or | ||
635 | ;; whatever. | ||
636 | |||
637 | moveq 0, $r9 ; busfault is equivalent to an irq | ||
638 | |||
639 | ba ret_from_intr | ||
640 | nop | ||
641 | |||
642 | ;; special handlers for breakpoint and NMI | ||
643 | hwbreakpoint: | ||
644 | push $dccr | ||
645 | di | ||
646 | push $r10 | ||
647 | push $r11 | ||
648 | move.d [hw_bp_trig_ptr],$r10 | ||
649 | move $brp,$r11 | ||
650 | move.d $r11,[$r10+] | ||
651 | move.d $r10,[hw_bp_trig_ptr] | ||
652 | 1: pop $r11 | ||
653 | pop $r10 | ||
654 | pop $dccr | ||
655 | retb | ||
656 | nop | ||
657 | |||
658 | IRQ1_interrupt: | ||
659 | |||
660 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
661 | ;; If we receive a watchdog interrupt while it is not expected, then set | ||
662 | ;; up a canonical frame and dump register contents before dying. | ||
663 | |||
664 | ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! | ||
665 | move $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame | ||
666 | push $srp | ||
667 | push $dccr | ||
668 | push $mof | ||
669 | di | ||
670 | subq 14*4, $sp | ||
671 | movem $r13, [$sp] | ||
672 | push $r10 ; push orig_r10 | ||
673 | clear.d [$sp=$sp-4] ; frametype == 0, normal frame | ||
674 | |||
675 | ;; We don't check that we actually were bit by the watchdog as opposed to | ||
676 | ;; an external NMI, since there is currently no handler for external NMI. | ||
677 | |||
678 | ;; Check if we're waiting for reset to happen, as signalled by | ||
679 | ;; hard_reset_now setting cause_of_death to a magic value. If so, just | ||
680 | ;; get stuck until reset happens. | ||
681 | .comm cause_of_death, 4 ;; Don't declare this anywhere. | ||
682 | move.d [cause_of_death], $r10 | ||
683 | cmp.d 0xbedead, $r10 | ||
684 | _killed_by_death: | ||
685 | beq _killed_by_death | ||
686 | nop | ||
687 | |||
688 | ;; We'll see this in ksymoops dumps. | ||
689 | Watchdog_bite: | ||
690 | |||
691 | #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY | ||
692 | ;; We just restart the watchdog here to be sure we dont get | ||
693 | ;; hit while printing the watchdogmsg below | ||
694 | ;; This restart is compatible with the rest of the C-code, so | ||
695 | ;; the C-code can keep restarting the watchdog after this point. | ||
696 | ;; The non-NICE_DOGGY code below though, disables the possibility | ||
697 | ;; to restart since it changes the watchdog key, to avoid any | ||
698 | ;; buggy loops etc. keeping the watchdog alive after this. | ||
699 | jsr reset_watchdog | ||
700 | #else | ||
701 | |||
702 | ;; We need to extend the 3.3ms after the NMI at watchdog bite, so we have | ||
703 | ;; time for an oops-dump over a 115k2 serial wire. Another 100ms should do. | ||
704 | |||
705 | ;; Change the watchdog key to an arbitrary 3-bit value and restart the | ||
706 | ;; watchdog. | ||
707 | #define WD_INIT 2 | ||
708 | moveq IO_FIELD (R_WATCHDOG, key, WD_INIT), $r10 | ||
709 | move.d R_WATCHDOG, $r11 | ||
710 | |||
711 | move.d $r10, [$r11] | ||
712 | moveq IO_FIELD (R_WATCHDOG, key, \ | ||
713 | IO_EXTRACT (R_WATCHDOG, key, \ | ||
714 | IO_MASK (R_WATCHDOG, key)) \ | ||
715 | ^ WD_INIT) \ | ||
716 | | IO_STATE (R_WATCHDOG, enable, start), $r10 | ||
717 | move.d $r10, [$r11] | ||
718 | |||
719 | #endif | ||
720 | |||
721 | ;; Note that we don't do "setf m" here (or after two necessary NOPs), | ||
722 | ;; since *not* doing that saves us from re-entrancy checks. We don't want | ||
723 | ;; to get here again due to possible subsequent NMIs; we want the watchdog | ||
724 | ;; to reset us. | ||
725 | |||
726 | move.d _watchdogmsg,$r10 | ||
727 | jsr printk | ||
728 | |||
729 | move.d $sp, $r10 | ||
730 | jsr watchdog_bite_hook | ||
731 | |||
732 | ;; This nop is here so we see the "Watchdog_bite" label in ksymoops dumps | ||
733 | ;; rather than "spurious_interrupt". | ||
734 | nop | ||
735 | ;; At this point we drop down into spurious_interrupt, which will do a | ||
736 | ;; hard reset. | ||
737 | |||
738 | .section .rodata,"a" | ||
739 | _watchdogmsg: | ||
740 | .ascii "Oops: bitten by watchdog\n\0" | ||
741 | .previous | ||
742 | |||
743 | #endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */ | ||
744 | |||
745 | spurious_interrupt: | ||
746 | di | ||
747 | jump hard_reset_now | ||
748 | |||
749 | ;; this handles the case when multiple interrupts arrive at the same time | ||
750 | ;; we jump to the first set interrupt bit in a priority fashion | ||
751 | ;; the hardware will call the unserved interrupts after the handler finishes | ||
752 | |||
753 | multiple_interrupt: | ||
754 | ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! | ||
755 | move $irp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame | ||
756 | push $srp | ||
757 | push $dccr | ||
758 | push $mof | ||
759 | di | ||
760 | subq 14*4, $sp | ||
761 | movem $r13, [$sp] | ||
762 | push $r10 ; push orig_r10 | ||
763 | clear.d [$sp=$sp-4] ; frametype == 0, normal frame | ||
764 | |||
765 | moveq 2, $r2 ; first bit we care about is the timer0 irq | ||
766 | move.d [R_VECT_MASK_RD], $r0; read the irq bits that triggered the multiple irq | ||
767 | move.d $r0, [R_VECT_MASK_CLR] ; Block all active IRQs | ||
768 | 1: | ||
769 | btst $r2, $r0 ; check for the irq given by bit r2 | ||
770 | bpl 2f | ||
771 | move.d $r2, $r10 ; First argument to do_IRQ | ||
772 | move.d $sp, $r11 ; second argument to do_IRQ | ||
773 | jsr do_IRQ | ||
774 | 2: | ||
775 | addq 1, $r2 ; next vector bit | ||
776 | cmp.b 32, $r2 | ||
777 | bne 1b ; process all irq's up to and including number 31 | ||
778 | moveq 0, $r9 ; make ret_from_intr realise we came from an ir | ||
779 | |||
780 | move.d $r0, [R_VECT_MASK_SET] ; Unblock all the IRQs | ||
781 | jump ret_from_intr | ||
782 | |||
783 | do_sigtrap: | ||
784 | ;; | ||
785 | ;; SIGTRAP the process that executed the break instruction. | ||
786 | ;; Make a frame that Rexit in entry.S expects. | ||
787 | ;; | ||
788 | move $brp, [$sp=$sp-16] ; Push BRP while faking a cpu status record. | ||
789 | push $srp ; Push subroutine return pointer. | ||
790 | push $dccr ; Push condition codes. | ||
791 | push $mof ; Push multiply overflow reg. | ||
792 | di ; Need to disable irq's at this point. | ||
793 | subq 14*4, $sp ; Make room for r0-r13. | ||
794 | movem $r13, [$sp] ; Push the r0-r13 registers. | ||
795 | push $r10 ; Push orig_r10. | ||
796 | clear.d [$sp=$sp-4] ; Frametype - this is a normal stackframe. | ||
797 | |||
798 | movs.w -8192,$r9 ; THREAD_SIZE == 8192 | ||
799 | and.d $sp, $r9 | ||
800 | move.d [$r9+TI_task], $r10 | ||
801 | move.d [$r10+TASK_pid], $r10 ; current->pid as arg1. | ||
802 | moveq 5, $r11 ; SIGTRAP as arg2. | ||
803 | jsr sys_kill | ||
804 | jump ret_from_intr ; Use the return routine for interrupts. | ||
805 | |||
806 | gdb_handle_breakpoint: | ||
807 | push $dccr | ||
808 | push $r0 | ||
809 | #ifdef CONFIG_ETRAX_KGDB | ||
810 | move $dccr, $r0 ; U-flag not affected by previous insns. | ||
811 | btstq 8, $r0 ; Test the U-flag. | ||
812 | bmi _ugdb_handle_breakpoint ; Go to user mode debugging. | ||
813 | nop ; Empty delay slot (cannot pop r0 here). | ||
814 | pop $r0 ; Restore r0. | ||
815 | ba kgdb_handle_breakpoint ; Go to kernel debugging. | ||
816 | pop $dccr ; Restore dccr in delay slot. | ||
817 | #endif | ||
818 | |||
819 | _ugdb_handle_breakpoint: | ||
820 | move $brp, $r0 ; Use r0 temporarily for calculation. | ||
821 | subq 2, $r0 ; Set to address of previous instruction. | ||
822 | move $r0, $brp | ||
823 | pop $r0 ; Restore r0. | ||
824 | ba do_sigtrap ; SIGTRAP the offending process. | ||
825 | pop $dccr ; Restore dccr in delay slot. | ||
826 | |||
827 | .data | ||
828 | |||
829 | hw_bp_trigs: | ||
830 | .space 64*4 | ||
831 | hw_bp_trig_ptr: | ||
832 | .dword hw_bp_trigs | ||
833 | |||
834 | .section .rodata,"a" | ||
835 | sys_call_table: | ||
836 | .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ | ||
837 | .long sys_exit | ||
838 | .long sys_fork | ||
839 | .long sys_read | ||
840 | .long sys_write | ||
841 | .long sys_open /* 5 */ | ||
842 | .long sys_close | ||
843 | .long sys_waitpid | ||
844 | .long sys_creat | ||
845 | .long sys_link | ||
846 | .long sys_unlink /* 10 */ | ||
847 | .long sys_execve | ||
848 | .long sys_chdir | ||
849 | .long sys_time | ||
850 | .long sys_mknod | ||
851 | .long sys_chmod /* 15 */ | ||
852 | .long sys_lchown16 | ||
853 | .long sys_ni_syscall /* old break syscall holder */ | ||
854 | .long sys_stat | ||
855 | .long sys_lseek | ||
856 | .long sys_getpid /* 20 */ | ||
857 | .long sys_mount | ||
858 | .long sys_oldumount | ||
859 | .long sys_setuid16 | ||
860 | .long sys_getuid16 | ||
861 | .long sys_stime /* 25 */ | ||
862 | .long sys_ptrace | ||
863 | .long sys_alarm | ||
864 | .long sys_fstat | ||
865 | .long sys_pause | ||
866 | .long sys_utime /* 30 */ | ||
867 | .long sys_ni_syscall /* old stty syscall holder */ | ||
868 | .long sys_ni_syscall /* old gtty syscall holder */ | ||
869 | .long sys_access | ||
870 | .long sys_nice | ||
871 | .long sys_ni_syscall /* 35 old ftime syscall holder */ | ||
872 | .long sys_sync | ||
873 | .long sys_kill | ||
874 | .long sys_rename | ||
875 | .long sys_mkdir | ||
876 | .long sys_rmdir /* 40 */ | ||
877 | .long sys_dup | ||
878 | .long sys_pipe | ||
879 | .long sys_times | ||
880 | .long sys_ni_syscall /* old prof syscall holder */ | ||
881 | .long sys_brk /* 45 */ | ||
882 | .long sys_setgid16 | ||
883 | .long sys_getgid16 | ||
884 | .long sys_signal | ||
885 | .long sys_geteuid16 | ||
886 | .long sys_getegid16 /* 50 */ | ||
887 | .long sys_acct | ||
888 | .long sys_umount /* recycled never used phys( */ | ||
889 | .long sys_ni_syscall /* old lock syscall holder */ | ||
890 | .long sys_ioctl | ||
891 | .long sys_fcntl /* 55 */ | ||
892 | .long sys_ni_syscall /* old mpx syscall holder */ | ||
893 | .long sys_setpgid | ||
894 | .long sys_ni_syscall /* old ulimit syscall holder */ | ||
895 | .long sys_ni_syscall /* old sys_olduname holder */ | ||
896 | .long sys_umask /* 60 */ | ||
897 | .long sys_chroot | ||
898 | .long sys_ustat | ||
899 | .long sys_dup2 | ||
900 | .long sys_getppid | ||
901 | .long sys_getpgrp /* 65 */ | ||
902 | .long sys_setsid | ||
903 | .long sys_sigaction | ||
904 | .long sys_sgetmask | ||
905 | .long sys_ssetmask | ||
906 | .long sys_setreuid16 /* 70 */ | ||
907 | .long sys_setregid16 | ||
908 | .long sys_sigsuspend | ||
909 | .long sys_sigpending | ||
910 | .long sys_sethostname | ||
911 | .long sys_setrlimit /* 75 */ | ||
912 | .long sys_old_getrlimit | ||
913 | .long sys_getrusage | ||
914 | .long sys_gettimeofday | ||
915 | .long sys_settimeofday | ||
916 | .long sys_getgroups16 /* 80 */ | ||
917 | .long sys_setgroups16 | ||
918 | .long sys_select /* was old_select in Linux/E100 */ | ||
919 | .long sys_symlink | ||
920 | .long sys_lstat | ||
921 | .long sys_readlink /* 85 */ | ||
922 | .long sys_uselib | ||
923 | .long sys_swapon | ||
924 | .long sys_reboot | ||
925 | .long old_readdir | ||
926 | .long old_mmap /* 90 */ | ||
927 | .long sys_munmap | ||
928 | .long sys_truncate | ||
929 | .long sys_ftruncate | ||
930 | .long sys_fchmod | ||
931 | .long sys_fchown16 /* 95 */ | ||
932 | .long sys_getpriority | ||
933 | .long sys_setpriority | ||
934 | .long sys_ni_syscall /* old profil syscall holder */ | ||
935 | .long sys_statfs | ||
936 | .long sys_fstatfs /* 100 */ | ||
937 | .long sys_ni_syscall /* sys_ioperm in i386 */ | ||
938 | .long sys_socketcall | ||
939 | .long sys_syslog | ||
940 | .long sys_setitimer | ||
941 | .long sys_getitimer /* 105 */ | ||
942 | .long sys_newstat | ||
943 | .long sys_newlstat | ||
944 | .long sys_newfstat | ||
945 | .long sys_ni_syscall /* old sys_uname holder */ | ||
946 | .long sys_ni_syscall /* sys_iopl in i386 */ | ||
947 | .long sys_vhangup | ||
948 | .long sys_ni_syscall /* old "idle" system call */ | ||
949 | .long sys_ni_syscall /* vm86old in i386 */ | ||
950 | .long sys_wait4 | ||
951 | .long sys_swapoff /* 115 */ | ||
952 | .long sys_sysinfo | ||
953 | .long sys_ipc | ||
954 | .long sys_fsync | ||
955 | .long sys_sigreturn | ||
956 | .long sys_clone /* 120 */ | ||
957 | .long sys_setdomainname | ||
958 | .long sys_newuname | ||
959 | .long sys_ni_syscall /* sys_modify_ldt */ | ||
960 | .long sys_adjtimex | ||
961 | .long sys_mprotect /* 125 */ | ||
962 | .long sys_sigprocmask | ||
963 | .long sys_ni_syscall /* old "create_module" */ | ||
964 | .long sys_init_module | ||
965 | .long sys_delete_module | ||
966 | .long sys_ni_syscall /* 130: old "get_kernel_syms" */ | ||
967 | .long sys_quotactl | ||
968 | .long sys_getpgid | ||
969 | .long sys_fchdir | ||
970 | .long sys_bdflush | ||
971 | .long sys_sysfs /* 135 */ | ||
972 | .long sys_personality | ||
973 | .long sys_ni_syscall /* for afs_syscall */ | ||
974 | .long sys_setfsuid16 | ||
975 | .long sys_setfsgid16 | ||
976 | .long sys_llseek /* 140 */ | ||
977 | .long sys_getdents | ||
978 | .long sys_select | ||
979 | .long sys_flock | ||
980 | .long sys_msync | ||
981 | .long sys_readv /* 145 */ | ||
982 | .long sys_writev | ||
983 | .long sys_getsid | ||
984 | .long sys_fdatasync | ||
985 | .long sys_sysctl | ||
986 | .long sys_mlock /* 150 */ | ||
987 | .long sys_munlock | ||
988 | .long sys_mlockall | ||
989 | .long sys_munlockall | ||
990 | .long sys_sched_setparam | ||
991 | .long sys_sched_getparam /* 155 */ | ||
992 | .long sys_sched_setscheduler | ||
993 | .long sys_sched_getscheduler | ||
994 | .long sys_sched_yield | ||
995 | .long sys_sched_get_priority_max | ||
996 | .long sys_sched_get_priority_min /* 160 */ | ||
997 | .long sys_sched_rr_get_interval | ||
998 | .long sys_nanosleep | ||
999 | .long sys_mremap | ||
1000 | .long sys_setresuid16 | ||
1001 | .long sys_getresuid16 /* 165 */ | ||
1002 | .long sys_ni_syscall /* sys_vm86 */ | ||
1003 | .long sys_ni_syscall /* Old sys_query_module */ | ||
1004 | .long sys_poll | ||
1005 | .long sys_nfsservctl | ||
1006 | .long sys_setresgid16 /* 170 */ | ||
1007 | .long sys_getresgid16 | ||
1008 | .long sys_prctl | ||
1009 | .long sys_rt_sigreturn | ||
1010 | .long sys_rt_sigaction | ||
1011 | .long sys_rt_sigprocmask /* 175 */ | ||
1012 | .long sys_rt_sigpending | ||
1013 | .long sys_rt_sigtimedwait | ||
1014 | .long sys_rt_sigqueueinfo | ||
1015 | .long sys_rt_sigsuspend | ||
1016 | .long sys_pread64 /* 180 */ | ||
1017 | .long sys_pwrite64 | ||
1018 | .long sys_chown16 | ||
1019 | .long sys_getcwd | ||
1020 | .long sys_capget | ||
1021 | .long sys_capset /* 185 */ | ||
1022 | .long sys_sigaltstack | ||
1023 | .long sys_sendfile | ||
1024 | .long sys_ni_syscall /* streams1 */ | ||
1025 | .long sys_ni_syscall /* streams2 */ | ||
1026 | .long sys_vfork /* 190 */ | ||
1027 | .long sys_getrlimit | ||
1028 | .long sys_mmap2 | ||
1029 | .long sys_truncate64 | ||
1030 | .long sys_ftruncate64 | ||
1031 | .long sys_stat64 /* 195 */ | ||
1032 | .long sys_lstat64 | ||
1033 | .long sys_fstat64 | ||
1034 | .long sys_lchown | ||
1035 | .long sys_getuid | ||
1036 | .long sys_getgid /* 200 */ | ||
1037 | .long sys_geteuid | ||
1038 | .long sys_getegid | ||
1039 | .long sys_setreuid | ||
1040 | .long sys_setregid | ||
1041 | .long sys_getgroups /* 205 */ | ||
1042 | .long sys_setgroups | ||
1043 | .long sys_fchown | ||
1044 | .long sys_setresuid | ||
1045 | .long sys_getresuid | ||
1046 | .long sys_setresgid /* 210 */ | ||
1047 | .long sys_getresgid | ||
1048 | .long sys_chown | ||
1049 | .long sys_setuid | ||
1050 | .long sys_setgid | ||
1051 | .long sys_setfsuid /* 215 */ | ||
1052 | .long sys_setfsgid | ||
1053 | .long sys_pivot_root | ||
1054 | .long sys_mincore | ||
1055 | .long sys_madvise | ||
1056 | .long sys_getdents64 /* 220 */ | ||
1057 | .long sys_fcntl64 | ||
1058 | .long sys_ni_syscall /* reserved for TUX */ | ||
1059 | .long sys_ni_syscall | ||
1060 | .long sys_gettid | ||
1061 | .long sys_readahead /* 225 */ | ||
1062 | .long sys_setxattr | ||
1063 | .long sys_lsetxattr | ||
1064 | .long sys_fsetxattr | ||
1065 | .long sys_getxattr | ||
1066 | .long sys_lgetxattr /* 230 */ | ||
1067 | .long sys_fgetxattr | ||
1068 | .long sys_listxattr | ||
1069 | .long sys_llistxattr | ||
1070 | .long sys_flistxattr | ||
1071 | .long sys_removexattr /* 235 */ | ||
1072 | .long sys_lremovexattr | ||
1073 | .long sys_fremovexattr | ||
1074 | .long sys_tkill | ||
1075 | .long sys_sendfile64 | ||
1076 | .long sys_futex /* 240 */ | ||
1077 | .long sys_sched_setaffinity | ||
1078 | .long sys_sched_getaffinity | ||
1079 | .long sys_ni_syscall /* sys_set_thread_area */ | ||
1080 | .long sys_ni_syscall /* sys_get_thread_area */ | ||
1081 | .long sys_io_setup /* 245 */ | ||
1082 | .long sys_io_destroy | ||
1083 | .long sys_io_getevents | ||
1084 | .long sys_io_submit | ||
1085 | .long sys_io_cancel | ||
1086 | .long sys_fadvise64 /* 250 */ | ||
1087 | .long sys_ni_syscall | ||
1088 | .long sys_exit_group | ||
1089 | .long sys_lookup_dcookie | ||
1090 | .long sys_epoll_create | ||
1091 | .long sys_epoll_ctl /* 255 */ | ||
1092 | .long sys_epoll_wait | ||
1093 | .long sys_remap_file_pages | ||
1094 | .long sys_set_tid_address | ||
1095 | .long sys_timer_create | ||
1096 | .long sys_timer_settime /* 260 */ | ||
1097 | .long sys_timer_gettime | ||
1098 | .long sys_timer_getoverrun | ||
1099 | .long sys_timer_delete | ||
1100 | .long sys_clock_settime | ||
1101 | .long sys_clock_gettime /* 265 */ | ||
1102 | .long sys_clock_getres | ||
1103 | .long sys_clock_nanosleep | ||
1104 | .long sys_statfs64 | ||
1105 | .long sys_fstatfs64 | ||
1106 | .long sys_tgkill /* 270 */ | ||
1107 | .long sys_utimes | ||
1108 | .long sys_fadvise64_64 | ||
1109 | .long sys_ni_syscall /* sys_vserver */ | ||
1110 | .long sys_ni_syscall /* sys_mbind */ | ||
1111 | .long sys_ni_syscall /* 275 sys_get_mempolicy */ | ||
1112 | .long sys_ni_syscall /* sys_set_mempolicy */ | ||
1113 | .long sys_mq_open | ||
1114 | .long sys_mq_unlink | ||
1115 | .long sys_mq_timedsend | ||
1116 | .long sys_mq_timedreceive /* 280 */ | ||
1117 | .long sys_mq_notify | ||
1118 | .long sys_mq_getsetattr | ||
1119 | .long sys_ni_syscall /* reserved for kexec */ | ||
1120 | .long sys_waitid | ||
1121 | |||
1122 | /* | ||
1123 | * NOTE!! This doesn't have to be exact - we just have | ||
1124 | * to make sure we have _enough_ of the "sys_ni_syscall" | ||
1125 | * entries. Don't panic if you notice that this hasn't | ||
1126 | * been shrunk every time we add a new system call. | ||
1127 | */ | ||
1128 | |||
1129 | .rept NR_syscalls-(.-sys_call_table)/4 | ||
1130 | .long sys_ni_syscall | ||
1131 | .endr | ||
1132 | |||
diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c new file mode 100644 index 000000000000..4717f7ae8e51 --- /dev/null +++ b/arch/cris/arch-v10/kernel/fasttimer.c | |||
@@ -0,0 +1,977 @@ | |||
1 | /* $Id: fasttimer.c,v 1.6 2004/05/14 10:18:39 starvik Exp $ | ||
2 | * linux/arch/cris/kernel/fasttimer.c | ||
3 | * | ||
4 | * Fast timers for ETRAX100/ETRAX100LX | ||
5 | * This may be useful in other OS than Linux so use 2 space indentation... | ||
6 | * | ||
7 | * $Log: fasttimer.c,v $ | ||
8 | * Revision 1.6 2004/05/14 10:18:39 starvik | ||
9 | * Export fast_timer_list | ||
10 | * | ||
11 | * Revision 1.5 2004/05/14 07:58:01 starvik | ||
12 | * Merge of changes from 2.4 | ||
13 | * | ||
14 | * Revision 1.4 2003/07/04 08:27:41 starvik | ||
15 | * Merge of Linux 2.5.74 | ||
16 | * | ||
17 | * Revision 1.3 2002/12/12 08:26:32 starvik | ||
18 | * Don't use C-comments inside CVS comments | ||
19 | * | ||
20 | * Revision 1.2 2002/12/11 15:42:02 starvik | ||
21 | * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/ | ||
22 | * | ||
23 | * Revision 1.1 2002/11/18 07:58:06 starvik | ||
24 | * Fast timers (from Linux 2.4) | ||
25 | * | ||
26 | * Revision 1.5 2002/10/15 06:21:39 starvik | ||
27 | * Added call to init_waitqueue_head | ||
28 | * | ||
29 | * Revision 1.4 2002/05/28 17:47:59 johana | ||
30 | * Added del_fast_timer() | ||
31 | * | ||
32 | * Revision 1.3 2002/05/28 16:16:07 johana | ||
33 | * Handle empty fast_timer_list | ||
34 | * | ||
35 | * Revision 1.2 2002/05/27 15:38:42 johana | ||
36 | * Made it compile without warnings on Linux 2.4. | ||
37 | * (includes, wait_queue, PROC_FS and snprintf) | ||
38 | * | ||
39 | * Revision 1.1 2002/05/27 15:32:25 johana | ||
40 | * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree. | ||
41 | * | ||
42 | * Revision 1.8 2001/11/27 13:50:40 pkj | ||
43 | * Disable interrupts while stopping the timer and while modifying the | ||
44 | * list of active timers in timer1_handler() as it may be interrupted | ||
45 | * by other interrupts (e.g., the serial interrupt) which may add fast | ||
46 | * timers. | ||
47 | * | ||
48 | * Revision 1.7 2001/11/22 11:50:32 pkj | ||
49 | * * Only store information about the last 16 timers. | ||
50 | * * proc_fasttimer_read() now uses an allocated buffer, since it | ||
51 | * requires more space than just a page even for only writing the | ||
52 | * last 16 timers. The buffer is only allocated on request, so | ||
53 | * unless /proc/fasttimer is read, it is never allocated. | ||
54 | * * Renamed fast_timer_started to fast_timers_started to match | ||
55 | * fast_timers_added and fast_timers_expired. | ||
56 | * * Some clean-up. | ||
57 | * | ||
58 | * Revision 1.6 2000/12/13 14:02:08 johana | ||
59 | * Removed volatile for fast_timer_list | ||
60 | * | ||
61 | * Revision 1.5 2000/12/13 13:55:35 johana | ||
62 | * Added DEBUG_LOG, added som cli() and cleanup | ||
63 | * | ||
64 | * Revision 1.4 2000/12/05 13:48:50 johana | ||
65 | * Added range check when writing proc file, modified timer int handling | ||
66 | * | ||
67 | * Revision 1.3 2000/11/23 10:10:20 johana | ||
68 | * More debug/logging possibilities. | ||
69 | * Moved GET_JIFFIES_USEC() to timex.h and time.c | ||
70 | * | ||
71 | * Revision 1.2 2000/11/01 13:41:04 johana | ||
72 | * Clean up and bugfixes. | ||
73 | * Created new do_gettimeofday_fast() that gets a timeval struct | ||
74 | * with time based on jiffies and *R_TIMER0_DATA, uses a table | ||
75 | * for fast conversion of timer value to microseconds. | ||
76 | * (Much faster the standard do_gettimeofday() and we don't really | ||
77 | * wan't to use the true time - we wan't the "uptime" so timers don't screw up | ||
78 | * when we change the time. | ||
79 | * TODO: Add efficient support for continuous timers as well. | ||
80 | * | ||
81 | * Revision 1.1 2000/10/26 15:49:16 johana | ||
82 | * Added fasttimer, highresolution timers. | ||
83 | * | ||
84 | * Copyright (C) 2000,2001 2002 Axis Communications AB, Lund, Sweden | ||
85 | */ | ||
86 | |||
87 | #include <linux/errno.h> | ||
88 | #include <linux/sched.h> | ||
89 | #include <linux/kernel.h> | ||
90 | #include <linux/param.h> | ||
91 | #include <linux/string.h> | ||
92 | #include <linux/mm.h> | ||
93 | #include <linux/vmalloc.h> | ||
94 | #include <linux/interrupt.h> | ||
95 | #include <linux/time.h> | ||
96 | #include <linux/delay.h> | ||
97 | |||
98 | #include <asm/segment.h> | ||
99 | #include <asm/io.h> | ||
100 | #include <asm/irq.h> | ||
101 | #include <asm/delay.h> | ||
102 | #include <asm/rtc.h> | ||
103 | |||
104 | #include <linux/config.h> | ||
105 | #include <linux/version.h> | ||
106 | |||
107 | #include <asm/arch/svinto.h> | ||
108 | #include <asm/fasttimer.h> | ||
109 | #include <linux/proc_fs.h> | ||
110 | |||
111 | |||
112 | #define DEBUG_LOG_INCLUDED | ||
113 | #define FAST_TIMER_LOG | ||
114 | //#define FAST_TIMER_TEST | ||
115 | |||
116 | #define FAST_TIMER_SANITY_CHECKS | ||
117 | |||
118 | #ifdef FAST_TIMER_SANITY_CHECKS | ||
119 | #define SANITYCHECK(x) x | ||
120 | static int sanity_failed = 0; | ||
121 | #else | ||
122 | #define SANITYCHECK(x) | ||
123 | #endif | ||
124 | |||
125 | #define D1(x) | ||
126 | #define D2(x) | ||
127 | #define DP(x) | ||
128 | |||
129 | #define __INLINE__ inline | ||
130 | |||
131 | static int fast_timer_running = 0; | ||
132 | static int fast_timers_added = 0; | ||
133 | static int fast_timers_started = 0; | ||
134 | static int fast_timers_expired = 0; | ||
135 | static int fast_timers_deleted = 0; | ||
136 | static int fast_timer_is_init = 0; | ||
137 | static int fast_timer_ints = 0; | ||
138 | |||
139 | struct fast_timer *fast_timer_list = NULL; | ||
140 | |||
141 | #ifdef DEBUG_LOG_INCLUDED | ||
142 | #define DEBUG_LOG_MAX 128 | ||
143 | static const char * debug_log_string[DEBUG_LOG_MAX]; | ||
144 | static unsigned long debug_log_value[DEBUG_LOG_MAX]; | ||
145 | static int debug_log_cnt = 0; | ||
146 | static int debug_log_cnt_wrapped = 0; | ||
147 | |||
148 | #define DEBUG_LOG(string, value) \ | ||
149 | { \ | ||
150 | unsigned long log_flags; \ | ||
151 | save_flags(log_flags); \ | ||
152 | cli(); \ | ||
153 | debug_log_string[debug_log_cnt] = (string); \ | ||
154 | debug_log_value[debug_log_cnt] = (unsigned long)(value); \ | ||
155 | if (++debug_log_cnt >= DEBUG_LOG_MAX) \ | ||
156 | { \ | ||
157 | debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \ | ||
158 | debug_log_cnt_wrapped = 1; \ | ||
159 | } \ | ||
160 | restore_flags(log_flags); \ | ||
161 | } | ||
162 | #else | ||
163 | #define DEBUG_LOG(string, value) | ||
164 | #endif | ||
165 | |||
166 | |||
167 | /* The frequencies for index = clkselx number in R_TIMER_CTRL */ | ||
168 | #define NUM_TIMER_FREQ 15 | ||
169 | #define MAX_USABLE_TIMER_FREQ 7 | ||
170 | #define MAX_DELAY_US 853333L | ||
171 | const unsigned long timer_freq_100[NUM_TIMER_FREQ] = | ||
172 | { | ||
173 | 3, /* 0 3333 - 853333 us */ | ||
174 | 6, /* 1 1666 - 426666 us */ | ||
175 | 12, /* 2 833 - 213333 us */ | ||
176 | 24, /* 3 416 - 106666 us */ | ||
177 | 48, /* 4 208 - 53333 us */ | ||
178 | 96, /* 5 104 - 26666 us */ | ||
179 | 192, /* 6 52 - 13333 us */ | ||
180 | 384, /* 7 26 - 6666 us */ | ||
181 | 576, | ||
182 | 1152, | ||
183 | 2304, | ||
184 | 4608, | ||
185 | 9216, | ||
186 | 18432, | ||
187 | 62500, | ||
188 | /* 15 = cascade */ | ||
189 | }; | ||
190 | #define NUM_TIMER_STATS 16 | ||
191 | #ifdef FAST_TIMER_LOG | ||
192 | struct fast_timer timer_added_log[NUM_TIMER_STATS]; | ||
193 | struct fast_timer timer_started_log[NUM_TIMER_STATS]; | ||
194 | struct fast_timer timer_expired_log[NUM_TIMER_STATS]; | ||
195 | #endif | ||
196 | |||
197 | int timer_div_settings[NUM_TIMER_STATS]; | ||
198 | int timer_freq_settings[NUM_TIMER_STATS]; | ||
199 | int timer_delay_settings[NUM_TIMER_STATS]; | ||
200 | |||
201 | /* Not true gettimeofday, only checks the jiffies (uptime) + useconds */ | ||
202 | void __INLINE__ do_gettimeofday_fast(struct timeval *tv) | ||
203 | { | ||
204 | unsigned long sec = jiffies; | ||
205 | unsigned long usec = GET_JIFFIES_USEC(); | ||
206 | |||
207 | usec += (sec % HZ) * (1000000 / HZ); | ||
208 | sec = sec / HZ; | ||
209 | |||
210 | if (usec > 1000000) | ||
211 | { | ||
212 | usec -= 1000000; | ||
213 | sec++; | ||
214 | } | ||
215 | tv->tv_sec = sec; | ||
216 | tv->tv_usec = usec; | ||
217 | } | ||
218 | |||
219 | int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1) | ||
220 | { | ||
221 | if (t0->tv_sec < t1->tv_sec) | ||
222 | { | ||
223 | return -1; | ||
224 | } | ||
225 | else if (t0->tv_sec > t1->tv_sec) | ||
226 | { | ||
227 | return 1; | ||
228 | } | ||
229 | if (t0->tv_usec < t1->tv_usec) | ||
230 | { | ||
231 | return -1; | ||
232 | } | ||
233 | else if (t0->tv_usec > t1->tv_usec) | ||
234 | { | ||
235 | return 1; | ||
236 | } | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | void __INLINE__ start_timer1(unsigned long delay_us) | ||
241 | { | ||
242 | int freq_index = 0; /* This is the lowest resolution */ | ||
243 | unsigned long upper_limit = MAX_DELAY_US; | ||
244 | |||
245 | unsigned long div; | ||
246 | /* Start/Restart the timer to the new shorter value */ | ||
247 | /* t = 1/freq = 1/19200 = 53us | ||
248 | * T=div*t, div = T/t = delay_us*freq/1000000 | ||
249 | */ | ||
250 | #if 1 /* Adaptive timer settings */ | ||
251 | while (delay_us < upper_limit && freq_index < MAX_USABLE_TIMER_FREQ) | ||
252 | { | ||
253 | freq_index++; | ||
254 | upper_limit >>= 1; /* Divide by 2 using shift */ | ||
255 | } | ||
256 | if (freq_index > 0) | ||
257 | { | ||
258 | freq_index--; | ||
259 | } | ||
260 | #else | ||
261 | freq_index = 6; | ||
262 | #endif | ||
263 | div = delay_us * timer_freq_100[freq_index]/10000; | ||
264 | if (div < 2) | ||
265 | { | ||
266 | /* Maybe increase timer freq? */ | ||
267 | div = 2; | ||
268 | } | ||
269 | if (div > 255) | ||
270 | { | ||
271 | div = 0; /* This means 256, the max the timer takes */ | ||
272 | /* If a longer timeout than the timer can handle is used, | ||
273 | * then we must restart it when it goes off. | ||
274 | */ | ||
275 | } | ||
276 | |||
277 | timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = div; | ||
278 | timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index; | ||
279 | timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us; | ||
280 | |||
281 | D1(printk("start_timer1 : %d us freq: %i div: %i\n", | ||
282 | delay_us, freq_index, div)); | ||
283 | /* Clear timer1 irq */ | ||
284 | *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); | ||
285 | |||
286 | /* Set timer values */ | ||
287 | *R_TIMER_CTRL = r_timer_ctrl_shadow = | ||
288 | (r_timer_ctrl_shadow & | ||
289 | ~IO_MASK(R_TIMER_CTRL, timerdiv1) & | ||
290 | ~IO_MASK(R_TIMER_CTRL, tm1) & | ||
291 | ~IO_MASK(R_TIMER_CTRL, clksel1)) | | ||
292 | IO_FIELD(R_TIMER_CTRL, timerdiv1, div) | | ||
293 | IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | | ||
294 | IO_FIELD(R_TIMER_CTRL, clksel1, freq_index ); /* 6=c19k2Hz */ | ||
295 | |||
296 | /* Ack interrupt */ | ||
297 | *R_TIMER_CTRL = r_timer_ctrl_shadow | | ||
298 | IO_STATE(R_TIMER_CTRL, i1, clr); | ||
299 | |||
300 | /* Start timer */ | ||
301 | *R_TIMER_CTRL = r_timer_ctrl_shadow = | ||
302 | (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) | | ||
303 | IO_STATE(R_TIMER_CTRL, tm1, run); | ||
304 | |||
305 | /* Enable timer1 irq */ | ||
306 | *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set); | ||
307 | fast_timers_started++; | ||
308 | fast_timer_running = 1; | ||
309 | } | ||
310 | |||
311 | /* In version 1.4 this function takes 27 - 50 us */ | ||
312 | void start_one_shot_timer(struct fast_timer *t, | ||
313 | fast_timer_function_type *function, | ||
314 | unsigned long data, | ||
315 | unsigned long delay_us, | ||
316 | const char *name) | ||
317 | { | ||
318 | unsigned long flags; | ||
319 | struct fast_timer *tmp; | ||
320 | |||
321 | D1(printk("sft %s %d us\n", name, delay_us)); | ||
322 | |||
323 | save_flags(flags); | ||
324 | cli(); | ||
325 | |||
326 | do_gettimeofday_fast(&t->tv_set); | ||
327 | tmp = fast_timer_list; | ||
328 | |||
329 | SANITYCHECK({ /* Check so this is not in the list already... */ | ||
330 | while (tmp != NULL) | ||
331 | { | ||
332 | if (tmp == t) | ||
333 | { | ||
334 | printk(KERN_WARNING | ||
335 | "timer name: %s data: 0x%08lX already in list!\n", name, data); | ||
336 | sanity_failed++; | ||
337 | return; | ||
338 | } | ||
339 | else | ||
340 | { | ||
341 | tmp = tmp->next; | ||
342 | } | ||
343 | } | ||
344 | tmp = fast_timer_list; | ||
345 | }); | ||
346 | |||
347 | t->delay_us = delay_us; | ||
348 | t->function = function; | ||
349 | t->data = data; | ||
350 | t->name = name; | ||
351 | |||
352 | t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000; | ||
353 | t->tv_expires.tv_sec = t->tv_set.tv_sec + delay_us / 1000000; | ||
354 | if (t->tv_expires.tv_usec > 1000000) | ||
355 | { | ||
356 | t->tv_expires.tv_usec -= 1000000; | ||
357 | t->tv_expires.tv_sec++; | ||
358 | } | ||
359 | #ifdef FAST_TIMER_LOG | ||
360 | timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t; | ||
361 | #endif | ||
362 | fast_timers_added++; | ||
363 | |||
364 | /* Check if this should timeout before anything else */ | ||
365 | if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0) | ||
366 | { | ||
367 | /* Put first in list and modify the timer value */ | ||
368 | t->prev = NULL; | ||
369 | t->next = fast_timer_list; | ||
370 | if (fast_timer_list) | ||
371 | { | ||
372 | fast_timer_list->prev = t; | ||
373 | } | ||
374 | fast_timer_list = t; | ||
375 | #ifdef FAST_TIMER_LOG | ||
376 | timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; | ||
377 | #endif | ||
378 | start_timer1(delay_us); | ||
379 | } else { | ||
380 | /* Put in correct place in list */ | ||
381 | while (tmp->next && | ||
382 | timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0) | ||
383 | { | ||
384 | tmp = tmp->next; | ||
385 | } | ||
386 | /* Insert t after tmp */ | ||
387 | t->prev = tmp; | ||
388 | t->next = tmp->next; | ||
389 | if (tmp->next) | ||
390 | { | ||
391 | tmp->next->prev = t; | ||
392 | } | ||
393 | tmp->next = t; | ||
394 | } | ||
395 | |||
396 | D2(printk("start_one_shot_timer: %d us done\n", delay_us)); | ||
397 | |||
398 | restore_flags(flags); | ||
399 | } /* start_one_shot_timer */ | ||
400 | |||
401 | static inline int fast_timer_pending (const struct fast_timer * t) | ||
402 | { | ||
403 | return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list); | ||
404 | } | ||
405 | |||
406 | static inline int detach_fast_timer (struct fast_timer *t) | ||
407 | { | ||
408 | struct fast_timer *next, *prev; | ||
409 | if (!fast_timer_pending(t)) | ||
410 | return 0; | ||
411 | next = t->next; | ||
412 | prev = t->prev; | ||
413 | if (next) | ||
414 | next->prev = prev; | ||
415 | if (prev) | ||
416 | prev->next = next; | ||
417 | else | ||
418 | fast_timer_list = next; | ||
419 | fast_timers_deleted++; | ||
420 | return 1; | ||
421 | } | ||
422 | |||
423 | int del_fast_timer(struct fast_timer * t) | ||
424 | { | ||
425 | unsigned long flags; | ||
426 | int ret; | ||
427 | |||
428 | save_flags(flags); | ||
429 | cli(); | ||
430 | ret = detach_fast_timer(t); | ||
431 | t->next = t->prev = NULL; | ||
432 | restore_flags(flags); | ||
433 | return ret; | ||
434 | } /* del_fast_timer */ | ||
435 | |||
436 | |||
437 | /* Interrupt routines or functions called in interrupt context */ | ||
438 | |||
439 | /* Timer 1 interrupt handler */ | ||
440 | |||
441 | static irqreturn_t | ||
442 | timer1_handler(int irq, void *dev_id, struct pt_regs *regs) | ||
443 | { | ||
444 | struct fast_timer *t; | ||
445 | unsigned long flags; | ||
446 | |||
447 | save_flags(flags); | ||
448 | cli(); | ||
449 | |||
450 | /* Clear timer1 irq */ | ||
451 | *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); | ||
452 | |||
453 | /* First stop timer, then ack interrupt */ | ||
454 | /* Stop timer */ | ||
455 | *R_TIMER_CTRL = r_timer_ctrl_shadow = | ||
456 | (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) | | ||
457 | IO_STATE(R_TIMER_CTRL, tm1, stop_ld); | ||
458 | |||
459 | /* Ack interrupt */ | ||
460 | *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr); | ||
461 | |||
462 | fast_timer_running = 0; | ||
463 | fast_timer_ints++; | ||
464 | |||
465 | restore_flags(flags); | ||
466 | |||
467 | t = fast_timer_list; | ||
468 | while (t) | ||
469 | { | ||
470 | struct timeval tv; | ||
471 | |||
472 | /* Has it really expired? */ | ||
473 | do_gettimeofday_fast(&tv); | ||
474 | D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec)); | ||
475 | |||
476 | if (timeval_cmp(&t->tv_expires, &tv) <= 0) | ||
477 | { | ||
478 | /* Yes it has expired */ | ||
479 | #ifdef FAST_TIMER_LOG | ||
480 | timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t; | ||
481 | #endif | ||
482 | fast_timers_expired++; | ||
483 | |||
484 | /* Remove this timer before call, since it may reuse the timer */ | ||
485 | save_flags(flags); | ||
486 | cli(); | ||
487 | if (t->prev) | ||
488 | { | ||
489 | t->prev->next = t->next; | ||
490 | } | ||
491 | else | ||
492 | { | ||
493 | fast_timer_list = t->next; | ||
494 | } | ||
495 | if (t->next) | ||
496 | { | ||
497 | t->next->prev = t->prev; | ||
498 | } | ||
499 | t->prev = NULL; | ||
500 | t->next = NULL; | ||
501 | restore_flags(flags); | ||
502 | |||
503 | if (t->function != NULL) | ||
504 | { | ||
505 | t->function(t->data); | ||
506 | } | ||
507 | else | ||
508 | { | ||
509 | DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints); | ||
510 | } | ||
511 | } | ||
512 | else | ||
513 | { | ||
514 | /* Timer is to early, let's set it again using the normal routines */ | ||
515 | D1(printk(".\n")); | ||
516 | } | ||
517 | |||
518 | save_flags(flags); | ||
519 | cli(); | ||
520 | if ((t = fast_timer_list) != NULL) | ||
521 | { | ||
522 | /* Start next timer.. */ | ||
523 | long us; | ||
524 | struct timeval tv; | ||
525 | |||
526 | do_gettimeofday_fast(&tv); | ||
527 | us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 + | ||
528 | t->tv_expires.tv_usec - tv.tv_usec); | ||
529 | if (us > 0) | ||
530 | { | ||
531 | if (!fast_timer_running) | ||
532 | { | ||
533 | #ifdef FAST_TIMER_LOG | ||
534 | timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; | ||
535 | #endif | ||
536 | start_timer1(us); | ||
537 | } | ||
538 | restore_flags(flags); | ||
539 | break; | ||
540 | } | ||
541 | else | ||
542 | { | ||
543 | /* Timer already expired, let's handle it better late than never. | ||
544 | * The normal loop handles it | ||
545 | */ | ||
546 | D1(printk("e! %d\n", us)); | ||
547 | } | ||
548 | } | ||
549 | restore_flags(flags); | ||
550 | } | ||
551 | |||
552 | if (!t) | ||
553 | { | ||
554 | D1(printk("t1 stop!\n")); | ||
555 | } | ||
556 | |||
557 | return IRQ_HANDLED; | ||
558 | } | ||
559 | |||
560 | static void wake_up_func(unsigned long data) | ||
561 | { | ||
562 | #ifdef DECLARE_WAITQUEUE | ||
563 | wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data; | ||
564 | #else | ||
565 | struct wait_queue **sleep_wait_p = (struct wait_queue **)data; | ||
566 | #endif | ||
567 | wake_up(sleep_wait_p); | ||
568 | } | ||
569 | |||
570 | |||
571 | /* Useful API */ | ||
572 | |||
573 | void schedule_usleep(unsigned long us) | ||
574 | { | ||
575 | struct fast_timer t; | ||
576 | #ifdef DECLARE_WAITQUEUE | ||
577 | wait_queue_head_t sleep_wait; | ||
578 | init_waitqueue_head(&sleep_wait); | ||
579 | { | ||
580 | DECLARE_WAITQUEUE(wait, current); | ||
581 | #else | ||
582 | struct wait_queue *sleep_wait = NULL; | ||
583 | struct wait_queue wait = { current, NULL }; | ||
584 | #endif | ||
585 | |||
586 | D1(printk("schedule_usleep(%d)\n", us)); | ||
587 | add_wait_queue(&sleep_wait, &wait); | ||
588 | set_current_state(TASK_INTERRUPTIBLE); | ||
589 | start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us, | ||
590 | "usleep"); | ||
591 | schedule(); | ||
592 | set_current_state(TASK_RUNNING); | ||
593 | remove_wait_queue(&sleep_wait, &wait); | ||
594 | D1(printk("done schedule_usleep(%d)\n", us)); | ||
595 | #ifdef DECLARE_WAITQUEUE | ||
596 | } | ||
597 | #endif | ||
598 | } | ||
599 | |||
600 | #ifdef CONFIG_PROC_FS | ||
601 | static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | ||
602 | ,int *eof, void *data_unused); | ||
603 | static struct proc_dir_entry *fasttimer_proc_entry; | ||
604 | #endif /* CONFIG_PROC_FS */ | ||
605 | |||
606 | #ifdef CONFIG_PROC_FS | ||
607 | |||
608 | /* This value is very much based on testing */ | ||
609 | #define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300) | ||
610 | |||
611 | static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | ||
612 | ,int *eof, void *data_unused) | ||
613 | { | ||
614 | unsigned long flags; | ||
615 | int i = 0; | ||
616 | int num_to_show; | ||
617 | struct timeval tv; | ||
618 | struct fast_timer *t, *nextt; | ||
619 | static char *bigbuf = NULL; | ||
620 | static unsigned long used; | ||
621 | |||
622 | if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE))) | ||
623 | { | ||
624 | used = 0; | ||
625 | bigbuf[0] = '\0'; | ||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | if (!offset || !used) | ||
630 | { | ||
631 | do_gettimeofday_fast(&tv); | ||
632 | |||
633 | used = 0; | ||
634 | used += sprintf(bigbuf + used, "Fast timers added: %i\n", | ||
635 | fast_timers_added); | ||
636 | used += sprintf(bigbuf + used, "Fast timers started: %i\n", | ||
637 | fast_timers_started); | ||
638 | used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n", | ||
639 | fast_timer_ints); | ||
640 | used += sprintf(bigbuf + used, "Fast timers expired: %i\n", | ||
641 | fast_timers_expired); | ||
642 | used += sprintf(bigbuf + used, "Fast timers deleted: %i\n", | ||
643 | fast_timers_deleted); | ||
644 | used += sprintf(bigbuf + used, "Fast timer running: %s\n", | ||
645 | fast_timer_running ? "yes" : "no"); | ||
646 | used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n", | ||
647 | (unsigned long)tv.tv_sec, | ||
648 | (unsigned long)tv.tv_usec); | ||
649 | #ifdef FAST_TIMER_SANITY_CHECKS | ||
650 | used += sprintf(bigbuf + used, "Sanity failed: %i\n", | ||
651 | sanity_failed); | ||
652 | #endif | ||
653 | used += sprintf(bigbuf + used, "\n"); | ||
654 | |||
655 | #ifdef DEBUG_LOG_INCLUDED | ||
656 | { | ||
657 | int end_i = debug_log_cnt; | ||
658 | i = 0; | ||
659 | |||
660 | if (debug_log_cnt_wrapped) | ||
661 | { | ||
662 | i = debug_log_cnt; | ||
663 | } | ||
664 | |||
665 | while ((i != end_i || (debug_log_cnt_wrapped && !used)) && | ||
666 | used+100 < BIG_BUF_SIZE) | ||
667 | { | ||
668 | used += sprintf(bigbuf + used, debug_log_string[i], | ||
669 | debug_log_value[i]); | ||
670 | i = (i+1) % DEBUG_LOG_MAX; | ||
671 | } | ||
672 | } | ||
673 | used += sprintf(bigbuf + used, "\n"); | ||
674 | #endif | ||
675 | |||
676 | num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started: | ||
677 | NUM_TIMER_STATS); | ||
678 | used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started); | ||
679 | for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++) | ||
680 | { | ||
681 | int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS; | ||
682 | |||
683 | #if 1 //ndef FAST_TIMER_LOG | ||
684 | used += sprintf(bigbuf + used, "div: %i freq: %i delay: %i" | ||
685 | "\n", | ||
686 | timer_div_settings[cur], | ||
687 | timer_freq_settings[cur], | ||
688 | timer_delay_settings[cur] | ||
689 | ); | ||
690 | #endif | ||
691 | #ifdef FAST_TIMER_LOG | ||
692 | t = &timer_started_log[cur]; | ||
693 | used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " | ||
694 | "d: %6li us data: 0x%08lX" | ||
695 | "\n", | ||
696 | t->name, | ||
697 | (unsigned long)t->tv_set.tv_sec, | ||
698 | (unsigned long)t->tv_set.tv_usec, | ||
699 | (unsigned long)t->tv_expires.tv_sec, | ||
700 | (unsigned long)t->tv_expires.tv_usec, | ||
701 | t->delay_us, | ||
702 | t->data | ||
703 | ); | ||
704 | #endif | ||
705 | } | ||
706 | used += sprintf(bigbuf + used, "\n"); | ||
707 | |||
708 | #ifdef FAST_TIMER_LOG | ||
709 | num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added: | ||
710 | NUM_TIMER_STATS); | ||
711 | used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added); | ||
712 | for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++) | ||
713 | { | ||
714 | t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS]; | ||
715 | used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " | ||
716 | "d: %6li us data: 0x%08lX" | ||
717 | "\n", | ||
718 | t->name, | ||
719 | (unsigned long)t->tv_set.tv_sec, | ||
720 | (unsigned long)t->tv_set.tv_usec, | ||
721 | (unsigned long)t->tv_expires.tv_sec, | ||
722 | (unsigned long)t->tv_expires.tv_usec, | ||
723 | t->delay_us, | ||
724 | t->data | ||
725 | ); | ||
726 | } | ||
727 | used += sprintf(bigbuf + used, "\n"); | ||
728 | |||
729 | num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired: | ||
730 | NUM_TIMER_STATS); | ||
731 | used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired); | ||
732 | for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++) | ||
733 | { | ||
734 | t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS]; | ||
735 | used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " | ||
736 | "d: %6li us data: 0x%08lX" | ||
737 | "\n", | ||
738 | t->name, | ||
739 | (unsigned long)t->tv_set.tv_sec, | ||
740 | (unsigned long)t->tv_set.tv_usec, | ||
741 | (unsigned long)t->tv_expires.tv_sec, | ||
742 | (unsigned long)t->tv_expires.tv_usec, | ||
743 | t->delay_us, | ||
744 | t->data | ||
745 | ); | ||
746 | } | ||
747 | used += sprintf(bigbuf + used, "\n"); | ||
748 | #endif | ||
749 | |||
750 | used += sprintf(bigbuf + used, "Active timers:\n"); | ||
751 | save_flags(flags); | ||
752 | cli(); | ||
753 | t = fast_timer_list; | ||
754 | while (t != NULL && (used+100 < BIG_BUF_SIZE)) | ||
755 | { | ||
756 | nextt = t->next; | ||
757 | restore_flags(flags); | ||
758 | used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " | ||
759 | "d: %6li us data: 0x%08lX" | ||
760 | /* " func: 0x%08lX" */ | ||
761 | "\n", | ||
762 | t->name, | ||
763 | (unsigned long)t->tv_set.tv_sec, | ||
764 | (unsigned long)t->tv_set.tv_usec, | ||
765 | (unsigned long)t->tv_expires.tv_sec, | ||
766 | (unsigned long)t->tv_expires.tv_usec, | ||
767 | t->delay_us, | ||
768 | t->data | ||
769 | /* , t->function */ | ||
770 | ); | ||
771 | cli(); | ||
772 | if (t->next != nextt) | ||
773 | { | ||
774 | printk(KERN_WARNING "timer removed!\n"); | ||
775 | } | ||
776 | t = nextt; | ||
777 | } | ||
778 | restore_flags(flags); | ||
779 | } | ||
780 | |||
781 | if (used - offset < len) | ||
782 | { | ||
783 | len = used - offset; | ||
784 | } | ||
785 | |||
786 | memcpy(buf, bigbuf + offset, len); | ||
787 | *start = buf; | ||
788 | *eof = 1; | ||
789 | |||
790 | return len; | ||
791 | } | ||
792 | #endif /* PROC_FS */ | ||
793 | |||
794 | #ifdef FAST_TIMER_TEST | ||
795 | static volatile unsigned long i = 0; | ||
796 | static volatile int num_test_timeout = 0; | ||
797 | static struct fast_timer tr[10]; | ||
798 | static int exp_num[10]; | ||
799 | |||
800 | static struct timeval tv_exp[100]; | ||
801 | |||
802 | static void test_timeout(unsigned long data) | ||
803 | { | ||
804 | do_gettimeofday_fast(&tv_exp[data]); | ||
805 | exp_num[data] = num_test_timeout; | ||
806 | |||
807 | num_test_timeout++; | ||
808 | } | ||
809 | |||
810 | static void test_timeout1(unsigned long data) | ||
811 | { | ||
812 | do_gettimeofday_fast(&tv_exp[data]); | ||
813 | exp_num[data] = num_test_timeout; | ||
814 | if (data < 7) | ||
815 | { | ||
816 | start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1"); | ||
817 | i++; | ||
818 | } | ||
819 | num_test_timeout++; | ||
820 | } | ||
821 | |||
822 | DP( | ||
823 | static char buf0[2000]; | ||
824 | static char buf1[2000]; | ||
825 | static char buf2[2000]; | ||
826 | static char buf3[2000]; | ||
827 | static char buf4[2000]; | ||
828 | ); | ||
829 | |||
830 | static char buf5[6000]; | ||
831 | static int j_u[1000]; | ||
832 | |||
833 | static void fast_timer_test(void) | ||
834 | { | ||
835 | int prev_num; | ||
836 | int j; | ||
837 | |||
838 | struct timeval tv, tv0, tv1, tv2; | ||
839 | |||
840 | printk("fast_timer_test() start\n"); | ||
841 | do_gettimeofday_fast(&tv); | ||
842 | |||
843 | for (j = 0; j < 1000; j++) | ||
844 | { | ||
845 | j_u[j] = GET_JIFFIES_USEC(); | ||
846 | } | ||
847 | for (j = 0; j < 100; j++) | ||
848 | { | ||
849 | do_gettimeofday_fast(&tv_exp[j]); | ||
850 | } | ||
851 | printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec); | ||
852 | |||
853 | for (j = 0; j < 1000; j++) | ||
854 | { | ||
855 | printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]); | ||
856 | j += 4; | ||
857 | } | ||
858 | for (j = 0; j < 100; j++) | ||
859 | { | ||
860 | printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n", | ||
861 | tv_exp[j].tv_sec,tv_exp[j].tv_usec, | ||
862 | tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec, | ||
863 | tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec, | ||
864 | tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec, | ||
865 | tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec); | ||
866 | j += 4; | ||
867 | } | ||
868 | do_gettimeofday_fast(&tv0); | ||
869 | start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0"); | ||
870 | DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0)); | ||
871 | i++; | ||
872 | start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1"); | ||
873 | DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0)); | ||
874 | i++; | ||
875 | start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2"); | ||
876 | DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0)); | ||
877 | i++; | ||
878 | start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3"); | ||
879 | DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0)); | ||
880 | i++; | ||
881 | start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx"); | ||
882 | DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0)); | ||
883 | i++; | ||
884 | do_gettimeofday_fast(&tv1); | ||
885 | |||
886 | proc_fasttimer_read(buf5, NULL, 0, 0, 0); | ||
887 | |||
888 | prev_num = num_test_timeout; | ||
889 | while (num_test_timeout < i) | ||
890 | { | ||
891 | if (num_test_timeout != prev_num) | ||
892 | { | ||
893 | prev_num = num_test_timeout; | ||
894 | } | ||
895 | } | ||
896 | do_gettimeofday_fast(&tv2); | ||
897 | printk("Timers started %is %06i\n", tv0.tv_sec, tv0.tv_usec); | ||
898 | printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec); | ||
899 | printk("Timers done %is %06i\n", tv2.tv_sec, tv2.tv_usec); | ||
900 | DP(printk("buf0:\n"); | ||
901 | printk(buf0); | ||
902 | printk("buf1:\n"); | ||
903 | printk(buf1); | ||
904 | printk("buf2:\n"); | ||
905 | printk(buf2); | ||
906 | printk("buf3:\n"); | ||
907 | printk(buf3); | ||
908 | printk("buf4:\n"); | ||
909 | printk(buf4); | ||
910 | ); | ||
911 | printk("buf5:\n"); | ||
912 | printk(buf5); | ||
913 | |||
914 | printk("timers set:\n"); | ||
915 | for(j = 0; j<i; j++) | ||
916 | { | ||
917 | struct fast_timer *t = &tr[j]; | ||
918 | printk("%-10s set: %6is %06ius exp: %6is %06ius " | ||
919 | "data: 0x%08X func: 0x%08X\n", | ||
920 | t->name, | ||
921 | t->tv_set.tv_sec, | ||
922 | t->tv_set.tv_usec, | ||
923 | t->tv_expires.tv_sec, | ||
924 | t->tv_expires.tv_usec, | ||
925 | t->data, | ||
926 | t->function | ||
927 | ); | ||
928 | |||
929 | printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n", | ||
930 | t->delay_us, | ||
931 | tv_exp[j].tv_sec, | ||
932 | tv_exp[j].tv_usec, | ||
933 | exp_num[j], | ||
934 | (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec); | ||
935 | } | ||
936 | proc_fasttimer_read(buf5, NULL, 0, 0, 0); | ||
937 | printk("buf5 after all done:\n"); | ||
938 | printk(buf5); | ||
939 | printk("fast_timer_test() done\n"); | ||
940 | } | ||
941 | #endif | ||
942 | |||
943 | |||
944 | void fast_timer_init(void) | ||
945 | { | ||
946 | /* For some reason, request_irq() hangs when called froom time_init() */ | ||
947 | if (!fast_timer_is_init) | ||
948 | { | ||
949 | #if 0 && defined(FAST_TIMER_TEST) | ||
950 | int i; | ||
951 | #endif | ||
952 | |||
953 | printk(KERN_INFO "fast_timer_init()\n"); | ||
954 | |||
955 | #if 0 && defined(FAST_TIMER_TEST) | ||
956 | for (i = 0; i <= TIMER0_DIV; i++) | ||
957 | { | ||
958 | /* We must be careful not to get overflow... */ | ||
959 | printk("%3i %6u\n", i, timer0_value_us[i]); | ||
960 | } | ||
961 | #endif | ||
962 | #ifdef CONFIG_PROC_FS | ||
963 | if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 ))) | ||
964 | fasttimer_proc_entry->read_proc = proc_fasttimer_read; | ||
965 | #endif /* PROC_FS */ | ||
966 | if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ, | ||
967 | "fast timer int", NULL)) | ||
968 | { | ||
969 | printk("err: timer1 irq\n"); | ||
970 | } | ||
971 | fast_timer_is_init = 1; | ||
972 | #ifdef FAST_TIMER_TEST | ||
973 | printk("do test\n"); | ||
974 | fast_timer_test(); | ||
975 | #endif | ||
976 | } | ||
977 | } | ||
diff --git a/arch/cris/arch-v10/kernel/head.S b/arch/cris/arch-v10/kernel/head.S new file mode 100644 index 000000000000..2c1dd1184a8f --- /dev/null +++ b/arch/cris/arch-v10/kernel/head.S | |||
@@ -0,0 +1,882 @@ | |||
1 | /* $Id: head.S,v 1.7 2004/05/14 07:58:01 starvik Exp $ | ||
2 | * | ||
3 | * Head of the kernel - alter with care | ||
4 | * | ||
5 | * Copyright (C) 2000, 2001 Axis Communications AB | ||
6 | * | ||
7 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
8 | * | ||
9 | * $Log: head.S,v $ | ||
10 | * Revision 1.7 2004/05/14 07:58:01 starvik | ||
11 | * Merge of changes from 2.4 | ||
12 | * | ||
13 | * Revision 1.6 2003/04/28 05:31:46 starvik | ||
14 | * Added section attributes | ||
15 | * | ||
16 | * Revision 1.5 2002/12/11 15:42:02 starvik | ||
17 | * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c | ||
18 | * | ||
19 | * Revision 1.4 2002/11/07 09:00:44 starvik | ||
20 | * Names changed for init sections | ||
21 | * init_task_union -> init_thread_union | ||
22 | * | ||
23 | * Revision 1.3 2002/02/05 15:38:23 bjornw | ||
24 | * Oops.. non-CRAMFS_MAGIC should jump over the copying, not into it... | ||
25 | * | ||
26 | * Revision 1.2 2001/12/18 13:35:19 bjornw | ||
27 | * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). | ||
28 | * | ||
29 | * Revision 1.43 2001/11/08 15:09:43 starvik | ||
30 | * Only start MII clock if Ethernet is configured | ||
31 | * | ||
32 | * Revision 1.42 2001/11/08 14:37:34 starvik | ||
33 | * Start MII clock early to make sure that it is running at tranceiver reset | ||
34 | * | ||
35 | * Revision 1.41 2001/10/29 14:55:58 pkj | ||
36 | * Corrected pa$r0 to par0. | ||
37 | * | ||
38 | * Revision 1.40 2001/10/03 14:59:57 pkj | ||
39 | * Added support for resetting the Bluetooth hardware. | ||
40 | * | ||
41 | * Revision 1.39 2001/10/01 14:45:03 bjornw | ||
42 | * Removed underscores and added register prefixes | ||
43 | * | ||
44 | * Revision 1.38 2001/09/21 07:14:11 jonashg | ||
45 | * Made root filesystem (cramfs) use mtdblock driver when booting from flash. | ||
46 | * | ||
47 | * Revision 1.37 2001/09/11 13:44:29 orjanf | ||
48 | * Decouple usage of serial ports for debug and kgdb. | ||
49 | * | ||
50 | * Revision 1.36 2001/06/29 12:39:31 pkj | ||
51 | * Added support for mirroring the first flash to just below the | ||
52 | * second one, to make them look consecutive to cramfs. | ||
53 | * | ||
54 | * Revision 1.35 2001/06/25 14:07:00 hp | ||
55 | * Fix review comment. | ||
56 | * * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of | ||
57 | * magic numbers. Add comment that -traditional must not be used. | ||
58 | * * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation. | ||
59 | * Correct and update comment. | ||
60 | * * Makefile (.S.o): Don't use -traditional. Add comment why the | ||
61 | * toplevel rule can't be used (now that there's a reason). | ||
62 | * | ||
63 | * Revision 1.34 2001/05/15 07:08:14 hp | ||
64 | * Tweak "notice" to reflect that both r8 r9 are used | ||
65 | * | ||
66 | * Revision 1.33 2001/05/15 06:40:05 hp | ||
67 | * Put bulk of code in .text.init, data in .data.init | ||
68 | * | ||
69 | * Revision 1.32 2001/05/15 06:18:56 hp | ||
70 | * Execute review comment: s/bcc/bhs/g; s/bcs/blo/g | ||
71 | * | ||
72 | * Revision 1.31 2001/05/15 06:08:40 hp | ||
73 | * Add sentence about autodetecting the bit31-MMU-bug | ||
74 | * | ||
75 | * Revision 1.30 2001/05/15 06:00:05 hp | ||
76 | * Update comment: LOW_MAP is not forced on xsim anymore. | ||
77 | * | ||
78 | * Revision 1.29 2001/04/18 12:51:59 orjanf | ||
79 | * * Reverted review change regarding the use of bcs/bcc. | ||
80 | * * Removed non-working LED-clearing code. | ||
81 | * | ||
82 | * Revision 1.28 2001/04/17 13:58:39 orjanf | ||
83 | * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. | ||
84 | * | ||
85 | * Revision 1.27 2001/04/17 11:42:35 orjanf | ||
86 | * Changed according to review: | ||
87 | * * Added comment explaining memory map bug. | ||
88 | * * Changed bcs and bcc to blo and bhs, respectively. | ||
89 | * * Removed mentioning of Stallone and Olga boards. | ||
90 | * | ||
91 | * Revision 1.26 2001/04/06 12:31:07 jonashg | ||
92 | * Check for cramfs in flash before RAM instead of RAM before flash. | ||
93 | * | ||
94 | * Revision 1.25 2001/04/04 06:23:53 starvik | ||
95 | * Initialize DRAM if not already initialized | ||
96 | * | ||
97 | * Revision 1.24 2001/04/03 11:12:00 starvik | ||
98 | * Removed dram init (done by rescue or etrax100boot | ||
99 | * Corrected include | ||
100 | * | ||
101 | * Revision 1.23 2001/04/03 09:53:03 starvik | ||
102 | * Include hw_settings.S | ||
103 | * | ||
104 | * Revision 1.22 2001/03/26 14:23:26 bjornw | ||
105 | * Namechange of some config options | ||
106 | * | ||
107 | * Revision 1.21 2001/03/08 12:14:41 bjornw | ||
108 | * * Config name for ETRAX IDE was renamed | ||
109 | * * Removed G27 auto-setting when JULIETTE is chosen (need to make this | ||
110 | * a new config option later) | ||
111 | * | ||
112 | * Revision 1.20 2001/02/23 12:47:56 bjornw | ||
113 | * MMU regs during LOW_MAP updated to reflect a newer reality | ||
114 | * | ||
115 | * Revision 1.19 2001/02/19 11:12:07 bjornw | ||
116 | * Changed comment header format | ||
117 | * | ||
118 | * Revision 1.18 2001/02/15 07:25:38 starvik | ||
119 | * Added support for synchronous serial ports | ||
120 | * | ||
121 | * Revision 1.17 2001/02/08 15:53:13 starvik | ||
122 | * Last commit removed some important ifdefs | ||
123 | * | ||
124 | * Revision 1.16 2001/02/08 15:20:38 starvik | ||
125 | * Include dram_init.S as inline | ||
126 | * | ||
127 | * Revision 1.15 2001/01/29 18:12:01 bjornw | ||
128 | * Corrected some comments | ||
129 | * | ||
130 | * Revision 1.14 2001/01/29 13:11:29 starvik | ||
131 | * Include dram_init.S (with DRAM/SDRAM initialization) | ||
132 | * | ||
133 | * Revision 1.13 2001/01/23 14:54:57 markusl | ||
134 | * Updated for USB | ||
135 | * i.e. added r_gen_config settings | ||
136 | * | ||
137 | * Revision 1.12 2001/01/19 16:16:29 perf | ||
138 | * Added temporary mapping of 0x0c->0x0c to avoid flash loading confusion. | ||
139 | * Renamed serial options from ETRAX100 to ETRAX. | ||
140 | * | ||
141 | * Revision 1.11 2001/01/16 16:31:38 bjornw | ||
142 | * * Changed name and semantics of running_from_flash to romfs_in_flash, | ||
143 | * set by head.S to indicate to setup.c whether there is a cramfs image | ||
144 | * after the kernels BSS or not. Should work for all three boot-cases | ||
145 | * (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot), | ||
146 | * and flash with cramfs in flash) | ||
147 | * | ||
148 | * Revision 1.10 2001/01/16 14:12:21 bjornw | ||
149 | * * Check for cramfs start passed in r9 from the decompressor, if all other | ||
150 | * cramfs options fail (if we boot from DRAM but don't find a cramfs image | ||
151 | * after the kernel in DRAM, it is probably still in the flash) | ||
152 | * * Check magic in cramfs detection when booting from flash directly | ||
153 | * | ||
154 | * Revision 1.9 2001/01/15 17:17:02 bjornw | ||
155 | * * Corrected the code that detects the cramfs lengths | ||
156 | * * Added a comment saying that the above does not work due to other | ||
157 | * reasons.. | ||
158 | * | ||
159 | * Revision 1.8 2001/01/15 16:27:51 jonashg | ||
160 | * Made boot after flashing work. | ||
161 | * * end destination is __vmlinux_end in RAM. | ||
162 | * * _romfs_start moved because of virtual memory. | ||
163 | * | ||
164 | * Revision 1.7 2000/11/21 13:55:29 bjornw | ||
165 | * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type | ||
166 | * | ||
167 | * Revision 1.6 2000/10/06 12:36:55 bjornw | ||
168 | * Forgot swapper_pg_dir when changing memory map.. | ||
169 | * | ||
170 | * Revision 1.5 2000/10/04 16:49:30 bjornw | ||
171 | * * Fixed memory mapping in LX | ||
172 | * * Check for cramfs instead of romfs | ||
173 | * | ||
174 | */ | ||
175 | |||
176 | #include <linux/config.h> | ||
177 | #define ASSEMBLER_MACROS_ONLY | ||
178 | /* The IO_* macros use the ## token concatenation operator, so | ||
179 | -traditional must not be used when assembling this file. */ | ||
180 | #include <asm/arch/sv_addr_ag.h> | ||
181 | |||
182 | #define CRAMFS_MAGIC 0x28cd3d45 | ||
183 | #define RAM_INIT_MAGIC 0x56902387 | ||
184 | |||
185 | #define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\ | ||
186 | IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | ||
187 | |||
188 | ;; exported symbols | ||
189 | |||
190 | .globl etrax_irv | ||
191 | .globl romfs_start | ||
192 | .globl romfs_length | ||
193 | .globl romfs_in_flash | ||
194 | .globl swapper_pg_dir | ||
195 | |||
196 | .text | ||
197 | |||
198 | ;; This is the entry point of the kernel. We are in supervisor mode. | ||
199 | ;; 0x00000000 if Flash, 0x40004000 if DRAM | ||
200 | ;; since etrax actually starts at address 2 when booting from flash, we | ||
201 | ;; put a nop (2 bytes) here first so we dont accidentally skip the di | ||
202 | ;; | ||
203 | ;; NOTICE! The registers r8 and r9 are used as parameters carrying | ||
204 | ;; information from the decompressor (if the kernel was compressed). | ||
205 | ;; They should not be used in the code below until read. | ||
206 | |||
207 | nop | ||
208 | di | ||
209 | |||
210 | ;; First setup the kseg_c mapping from where the kernel is linked | ||
211 | ;; to 0x40000000 (where the actual DRAM resides) otherwise | ||
212 | ;; we cannot do very much! See arch/cris/README.mm | ||
213 | ;; | ||
214 | ;; Notice that since we're potentially running at 0x00 or 0x40 right now, | ||
215 | ;; we will get a fault as soon as we enable the MMU if we dont | ||
216 | ;; temporarily map those segments linearily. | ||
217 | ;; | ||
218 | ;; Due to a bug in Etrax-100 LX version 1 we need to map the memory | ||
219 | ;; slightly different. The bug is that you can't remap bit 31 of | ||
220 | ;; an address. Though we can check the version register for | ||
221 | ;; whether the bug is present, some constants would then have to | ||
222 | ;; be variables, so we don't. The drawback is that you can "only" map | ||
223 | ;; 1G per process with CONFIG_CRIS_LOW_MAP. | ||
224 | |||
225 | #ifdef CONFIG_CRIS_LOW_MAP | ||
226 | ; kseg mappings, temporary map of 0xc0->0x40 | ||
227 | move.d IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \ | ||
228 | | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb) \ | ||
229 | | IO_FIELD (R_MMU_KBASE_HI, base_9, 9) \ | ||
230 | | IO_FIELD (R_MMU_KBASE_HI, base_8, 8), $r0 | ||
231 | move.d $r0, [R_MMU_KBASE_HI] | ||
232 | |||
233 | ; temporary map of 0x40->0x40 and 0x60->0x40 | ||
234 | move.d IO_FIELD (R_MMU_KBASE_LO, base_6, 4) \ | ||
235 | | IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0 | ||
236 | move.d $r0, [R_MMU_KBASE_LO] | ||
237 | |||
238 | ; mmu enable, segs e,c,b,a,6,5,4,0 segment mapped | ||
239 | move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ | ||
240 | | IO_STATE (R_MMU_CONFIG, inv_excp, enable) \ | ||
241 | | IO_STATE (R_MMU_CONFIG, acc_excp, enable) \ | ||
242 | | IO_STATE (R_MMU_CONFIG, we_excp, enable) \ | ||
243 | | IO_STATE (R_MMU_CONFIG, seg_f, page) \ | ||
244 | | IO_STATE (R_MMU_CONFIG, seg_e, seg) \ | ||
245 | | IO_STATE (R_MMU_CONFIG, seg_d, page) \ | ||
246 | | IO_STATE (R_MMU_CONFIG, seg_c, seg) \ | ||
247 | | IO_STATE (R_MMU_CONFIG, seg_b, seg) \ | ||
248 | | IO_STATE (R_MMU_CONFIG, seg_a, seg) \ | ||
249 | | IO_STATE (R_MMU_CONFIG, seg_9, page) \ | ||
250 | | IO_STATE (R_MMU_CONFIG, seg_8, page) \ | ||
251 | | IO_STATE (R_MMU_CONFIG, seg_7, page) \ | ||
252 | | IO_STATE (R_MMU_CONFIG, seg_6, seg) \ | ||
253 | | IO_STATE (R_MMU_CONFIG, seg_5, seg) \ | ||
254 | | IO_STATE (R_MMU_CONFIG, seg_4, seg) \ | ||
255 | | IO_STATE (R_MMU_CONFIG, seg_3, page) \ | ||
256 | | IO_STATE (R_MMU_CONFIG, seg_2, page) \ | ||
257 | | IO_STATE (R_MMU_CONFIG, seg_1, page) \ | ||
258 | | IO_STATE (R_MMU_CONFIG, seg_0, seg), $r0 | ||
259 | move.d $r0, [R_MMU_CONFIG] | ||
260 | #else | ||
261 | ; kseg mappings | ||
262 | move.d IO_FIELD (R_MMU_KBASE_HI, base_e, 8) \ | ||
263 | | IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \ | ||
264 | | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb), $r0 | ||
265 | move.d $r0, [R_MMU_KBASE_HI] | ||
266 | |||
267 | ; temporary map of 0x40->0x40 and 0x00->0x00 | ||
268 | move.d IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0 | ||
269 | move.d $r0, [R_MMU_KBASE_LO] | ||
270 | |||
271 | ; mmu enable, segs f,e,c,b,4,0 segment mapped | ||
272 | move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ | ||
273 | | IO_STATE (R_MMU_CONFIG, inv_excp, enable) \ | ||
274 | | IO_STATE (R_MMU_CONFIG, acc_excp, enable) \ | ||
275 | | IO_STATE (R_MMU_CONFIG, we_excp, enable) \ | ||
276 | | IO_STATE (R_MMU_CONFIG, seg_f, seg) \ | ||
277 | | IO_STATE (R_MMU_CONFIG, seg_e, seg) \ | ||
278 | | IO_STATE (R_MMU_CONFIG, seg_d, page) \ | ||
279 | | IO_STATE (R_MMU_CONFIG, seg_c, seg) \ | ||
280 | | IO_STATE (R_MMU_CONFIG, seg_b, seg) \ | ||
281 | | IO_STATE (R_MMU_CONFIG, seg_a, page) \ | ||
282 | | IO_STATE (R_MMU_CONFIG, seg_9, page) \ | ||
283 | | IO_STATE (R_MMU_CONFIG, seg_8, page) \ | ||
284 | | IO_STATE (R_MMU_CONFIG, seg_7, page) \ | ||
285 | | IO_STATE (R_MMU_CONFIG, seg_6, page) \ | ||
286 | | IO_STATE (R_MMU_CONFIG, seg_5, page) \ | ||
287 | | IO_STATE (R_MMU_CONFIG, seg_4, seg) \ | ||
288 | | IO_STATE (R_MMU_CONFIG, seg_3, page) \ | ||
289 | | IO_STATE (R_MMU_CONFIG, seg_2, page) \ | ||
290 | | IO_STATE (R_MMU_CONFIG, seg_1, page) \ | ||
291 | | IO_STATE (R_MMU_CONFIG, seg_0, seg), $r0 | ||
292 | move.d $r0, [R_MMU_CONFIG] | ||
293 | #endif | ||
294 | |||
295 | ;; Now we need to sort out the segments and their locations in RAM or | ||
296 | ;; Flash. The image in the Flash (or in DRAM) consists of 3 pieces: | ||
297 | ;; 1) kernel text, 2) kernel data, 3) ROM filesystem image | ||
298 | ;; But the linker has linked the kernel to expect this layout in | ||
299 | ;; DRAM memory: | ||
300 | ;; 1) kernel text, 2) kernel data, 3) kernel BSS | ||
301 | ;; (the location of the ROM filesystem is determined by the krom driver) | ||
302 | ;; If we boot this from Flash, we want to keep the ROM filesystem in | ||
303 | ;; the flash, we want to copy the text and need to copy the data to DRAM. | ||
304 | ;; But if we boot from DRAM, we need to move the ROMFS image | ||
305 | ;; from its position after kernel data, to after kernel BSS, BEFORE the | ||
306 | ;; kernel starts using the BSS area (since its "overlayed" with the ROMFS) | ||
307 | ;; | ||
308 | ;; In both cases, we start in un-cached mode, and need to jump into a | ||
309 | ;; cached PC after we're done fiddling around with the segments. | ||
310 | ;; | ||
311 | ;; arch/etrax100/etrax100.ld sets some symbols that define the start | ||
312 | ;; and end of each segment. | ||
313 | |||
314 | ;; Check if we start from DRAM or FLASH by testing PC | ||
315 | |||
316 | move.d $pc,$r0 | ||
317 | and.d 0x7fffffff,$r0 ; get rid of the non-cache bit | ||
318 | cmp.d 0x10000,$r0 ; arbitrary... just something above this code | ||
319 | blo _inflash0 | ||
320 | nop | ||
321 | |||
322 | jump _inram ; enter cached ram | ||
323 | |||
324 | ;; Jumpgate for branches. | ||
325 | _inflash0: | ||
326 | jump _inflash | ||
327 | |||
328 | ;; Put this in a suitable section where we can reclaim storage | ||
329 | ;; after init. | ||
330 | .section ".init.text", "ax" | ||
331 | _inflash: | ||
332 | #ifdef CONFIG_ETRAX_ETHERNET | ||
333 | ;; Start MII clock to make sure it is running when tranceiver is reset | ||
334 | move.d START_ETHERNET_CLOCK, $r0 | ||
335 | move.d $r0, [R_NETWORK_GEN_CONFIG] | ||
336 | #endif | ||
337 | |||
338 | ;; Set up waitstates etc according to kernel configuration. | ||
339 | #ifndef CONFIG_SVINTO_SIM | ||
340 | move.d CONFIG_ETRAX_DEF_R_WAITSTATES, $r0 | ||
341 | move.d $r0, [R_WAITSTATES] | ||
342 | |||
343 | move.d CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0 | ||
344 | move.d $r0, [R_BUS_CONFIG] | ||
345 | #endif | ||
346 | |||
347 | ;; We need to initialze DRAM registers before we start using the DRAM | ||
348 | |||
349 | cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? | ||
350 | beq _dram_init_finished | ||
351 | nop | ||
352 | |||
353 | #include "../lib/dram_init.S" | ||
354 | |||
355 | _dram_init_finished: | ||
356 | ;; Copy text+data to DRAM | ||
357 | ;; This is fragile - the calculation of r4 as the image size depends | ||
358 | ;; on that the labels below actually are the first and last positions | ||
359 | ;; in the linker-script. | ||
360 | ;; | ||
361 | ;; Then the locating of the cramfs image depends on the aforementioned | ||
362 | ;; image being located in the flash at 0. This is most often not true, | ||
363 | ;; thus the following does not work (normally there is a rescue-block | ||
364 | ;; between the physical start of the flash and the flash-image start, | ||
365 | ;; and when run with compression, the kernel is actually unpacked to | ||
366 | ;; DRAM and we never get here in the first place :)) | ||
367 | |||
368 | moveq 0, $r0 ; source | ||
369 | move.d text_start, $r1 ; destination | ||
370 | move.d __vmlinux_end, $r2 ; end destination | ||
371 | move.d $r2, $r4 | ||
372 | sub.d $r1, $r4 ; r4=__vmlinux_end in flash, used below | ||
373 | 1: move.w [$r0+], $r3 | ||
374 | move.w $r3, [$r1+] | ||
375 | cmp.d $r2, $r1 | ||
376 | blo 1b | ||
377 | nop | ||
378 | |||
379 | ;; We keep the cramfs in the flash. | ||
380 | ;; There might be none, but that does not matter because | ||
381 | ;; we don't do anything than read some bytes here. | ||
382 | |||
383 | moveq 0, $r0 | ||
384 | move.d $r0, [romfs_length] ; default if there is no cramfs | ||
385 | |||
386 | move.d [$r4], $r0 ; cramfs_super.magic | ||
387 | cmp.d CRAMFS_MAGIC, $r0 | ||
388 | bne 1f | ||
389 | nop | ||
390 | move.d [$r4 + 4], $r0 ; cramfs_super.size | ||
391 | move.d $r0, [romfs_length] | ||
392 | #ifdef CONFIG_CRIS_LOW_MAP | ||
393 | add.d 0x50000000, $r4 ; add flash start in virtual memory (cached) | ||
394 | #else | ||
395 | add.d 0xf0000000, $r4 ; add flash start in virtual memory (cached) | ||
396 | #endif | ||
397 | move.d $r4, [romfs_start] | ||
398 | 1: | ||
399 | moveq 1, $r0 | ||
400 | move.d $r0, [romfs_in_flash] | ||
401 | |||
402 | jump _start_it ; enter code, cached this time | ||
403 | |||
404 | _inram: | ||
405 | ;; Move the ROM fs to after BSS end. This assumes that the cramfs | ||
406 | ;; second longword contains the length of the cramfs | ||
407 | |||
408 | moveq 0, $r0 | ||
409 | move.d $r0, [romfs_length] ; default if there is no cramfs | ||
410 | |||
411 | ;; The kernel could have been unpacked to DRAM by the loader, but | ||
412 | ;; the cramfs image could still be in the Flash directly after the | ||
413 | ;; compressed kernel image. The loader passes the address of the | ||
414 | ;; byte succeeding the last compressed byte in the flash in the | ||
415 | ;; register r9 when starting the kernel. Check if r9 points to a | ||
416 | ;; decent cramfs image! | ||
417 | ;; (Notice that if this is not booted from the loader, r9 will be | ||
418 | ;; garbage but we do sanity checks on it, the chance that it points | ||
419 | ;; to a cramfs magic is small.. ) | ||
420 | |||
421 | cmp.d 0x0ffffff8, $r9 | ||
422 | bhs _no_romfs_in_flash ; r9 points outside the flash area | ||
423 | nop | ||
424 | move.d [$r9], $r0 ; cramfs_super.magic | ||
425 | cmp.d CRAMFS_MAGIC, $r0 | ||
426 | bne _no_romfs_in_flash | ||
427 | nop | ||
428 | move.d [$r9+4], $r0 ; cramfs_super.length | ||
429 | move.d $r0, [romfs_length] | ||
430 | #ifdef CONFIG_CRIS_LOW_MAP | ||
431 | add.d 0x50000000, $r9 ; add flash start in virtual memory (cached) | ||
432 | #else | ||
433 | add.d 0xf0000000, $r9 ; add flash start in virtual memory (cached) | ||
434 | #endif | ||
435 | move.d $r9, [romfs_start] | ||
436 | |||
437 | moveq 1, $r0 | ||
438 | move.d $r0, [romfs_in_flash] | ||
439 | |||
440 | jump _start_it ; enter code, cached this time | ||
441 | |||
442 | _no_romfs_in_flash: | ||
443 | |||
444 | ;; Check if there is a cramfs (magic value). | ||
445 | ;; Notice that we check for cramfs magic value - which is | ||
446 | ;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does | ||
447 | ;; not need this mechanism anyway) | ||
448 | |||
449 | move.d __vmlinux_end, $r0; the image will be after the vmlinux end address | ||
450 | move.d [$r0], $r1 ; cramfs assumes same endian on host/target | ||
451 | cmp.d CRAMFS_MAGIC, $r1; magic value in cramfs superblock | ||
452 | bne 2f | ||
453 | nop | ||
454 | |||
455 | ;; Ok. What is its size ? | ||
456 | |||
457 | move.d [$r0 + 4], $r2 ; cramfs_super.size (again, no need to swapwb) | ||
458 | |||
459 | ;; We want to copy it to the end of the BSS | ||
460 | |||
461 | move.d _end, $r1 | ||
462 | |||
463 | ;; Remember values so cramfs and setup can find this info | ||
464 | |||
465 | move.d $r1, [romfs_start] ; new romfs location | ||
466 | move.d $r2, [romfs_length] | ||
467 | |||
468 | ;; We need to copy it backwards, since they can be overlapping | ||
469 | |||
470 | add.d $r2, $r0 | ||
471 | add.d $r2, $r1 | ||
472 | |||
473 | ;; Go ahead. Make my loop. | ||
474 | |||
475 | lsrq 1, $r2 ; size is in bytes, we copy words | ||
476 | |||
477 | 1: move.w [$r0=$r0-2],$r3 | ||
478 | move.w $r3,[$r1=$r1-2] | ||
479 | subq 1, $r2 | ||
480 | bne 1b | ||
481 | nop | ||
482 | |||
483 | 2: | ||
484 | ;; Dont worry that the BSS is tainted. It will be cleared later. | ||
485 | |||
486 | moveq 0, $r0 | ||
487 | move.d $r0, [romfs_in_flash] | ||
488 | |||
489 | jump _start_it ; better skip the additional cramfs check below | ||
490 | |||
491 | _start_it: | ||
492 | |||
493 | ;; the kernel stack is overlayed with the task structure for each | ||
494 | ;; task. thus the initial kernel stack is in the same page as the | ||
495 | ;; init_task (but starts in the top of the page, size 8192) | ||
496 | move.d init_thread_union + 8192, $sp | ||
497 | move.d ibr_start,$r0 ; this symbol is set by the linker script | ||
498 | move $r0,$ibr | ||
499 | move.d $r0,[etrax_irv] ; set the interrupt base register and pointer | ||
500 | |||
501 | ;; Clear BSS region, from _bss_start to _end | ||
502 | |||
503 | move.d __bss_start, $r0 | ||
504 | move.d _end, $r1 | ||
505 | 1: clear.d [$r0+] | ||
506 | cmp.d $r1, $r0 | ||
507 | blo 1b | ||
508 | nop | ||
509 | |||
510 | #ifdef CONFIG_BLK_DEV_ETRAXIDE | ||
511 | ;; disable ATA before enabling it in genconfig below | ||
512 | moveq 0,$r0 | ||
513 | move.d $r0,[R_ATA_CTRL_DATA] | ||
514 | move.d $r0,[R_ATA_TRANSFER_CNT] | ||
515 | move.d $r0,[R_ATA_CONFIG] | ||
516 | #if 0 | ||
517 | move.d R_PORT_G_DATA, $r1 | ||
518 | move.d $r0, [$r1]; assert ATA bus-reset | ||
519 | nop | ||
520 | nop | ||
521 | nop | ||
522 | nop | ||
523 | nop | ||
524 | nop | ||
525 | move.d 0x08000000,$r0 | ||
526 | move.d $r0,[$r1] | ||
527 | #endif | ||
528 | #endif | ||
529 | |||
530 | #ifdef CONFIG_JULIETTE | ||
531 | ;; configure external DMA channel 0 before enabling it in genconfig | ||
532 | |||
533 | moveq 0,$r0 | ||
534 | move.d $r0,[R_EXT_DMA_0_ADDR] | ||
535 | ; cnt enable, word size, output, stop, size 0 | ||
536 | move.d IO_STATE (R_EXT_DMA_0_CMD, cnt, enable) \ | ||
537 | | IO_STATE (R_EXT_DMA_0_CMD, rqpol, ahigh) \ | ||
538 | | IO_STATE (R_EXT_DMA_0_CMD, apol, ahigh) \ | ||
539 | | IO_STATE (R_EXT_DMA_0_CMD, rq_ack, burst) \ | ||
540 | | IO_STATE (R_EXT_DMA_0_CMD, wid, word) \ | ||
541 | | IO_STATE (R_EXT_DMA_0_CMD, dir, output) \ | ||
542 | | IO_STATE (R_EXT_DMA_0_CMD, run, stop) \ | ||
543 | | IO_FIELD (R_EXT_DMA_0_CMD, trf_count, 0),$r0 | ||
544 | move.d $r0,[R_EXT_DMA_0_CMD] | ||
545 | |||
546 | ;; reset dma4 and wait for completion | ||
547 | |||
548 | moveq IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0 | ||
549 | move.b $r0,[R_DMA_CH4_CMD] | ||
550 | 1: move.b [R_DMA_CH4_CMD],$r0 | ||
551 | and.b IO_MASK (R_DMA_CH4_CMD, cmd),$r0 | ||
552 | cmp.b IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0 | ||
553 | beq 1b | ||
554 | nop | ||
555 | |||
556 | ;; reset dma5 and wait for completion | ||
557 | |||
558 | moveq IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0 | ||
559 | move.b $r0,[R_DMA_CH5_CMD] | ||
560 | 1: move.b [R_DMA_CH5_CMD],$r0 | ||
561 | and.b IO_MASK (R_DMA_CH5_CMD, cmd),$r0 | ||
562 | cmp.b IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0 | ||
563 | beq 1b | ||
564 | nop | ||
565 | #endif | ||
566 | |||
567 | ;; Etrax product HW genconfig setup | ||
568 | |||
569 | moveq 0,$r0 | ||
570 | #if (!defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT0)) \ | ||
571 | && !defined(CONFIG_DMA_MEMCPY) | ||
572 | ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA | ||
573 | or.d IO_STATE (R_GEN_CONFIG, dma7, serial0) \ | ||
574 | | IO_STATE (R_GEN_CONFIG, dma6, serial0),$r0 | ||
575 | #endif | ||
576 | #if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1) | ||
577 | ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA | ||
578 | or.d IO_STATE (R_GEN_CONFIG, dma9, serial1) \ | ||
579 | | IO_STATE (R_GEN_CONFIG, dma8, serial1),$r0 | ||
580 | #endif | ||
581 | #ifdef CONFIG_DMA_MEMCPY | ||
582 | ; 6/7 memory-memory DMA | ||
583 | or.d IO_STATE (R_GEN_CONFIG, dma7, intdma6) \ | ||
584 | | IO_STATE (R_GEN_CONFIG, dma6, intdma7),$r0 | ||
585 | #endif | ||
586 | #ifdef CONFIG_ETRAX_SERIAL_PORT2 | ||
587 | ; Enable serial port 2 | ||
588 | or.w IO_STATE (R_GEN_CONFIG, ser2, select),$r0 | ||
589 | #if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT2) | ||
590 | ; DMA channels 2 and 3 to ser2, kgdb doesnt want DMA | ||
591 | or.d IO_STATE (R_GEN_CONFIG, dma3, serial2) \ | ||
592 | | IO_STATE (R_GEN_CONFIG, dma2, serial2),$r0 | ||
593 | #endif | ||
594 | #endif | ||
595 | #if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) | ||
596 | ; Enable serial port 3 | ||
597 | or.w IO_STATE (R_GEN_CONFIG, ser3, select),$r0 | ||
598 | #if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT3) | ||
599 | ; DMA channels 4 and 5 to ser3, kgdb doesnt want DMA | ||
600 | or.d IO_STATE (R_GEN_CONFIG, dma5, serial3) \ | ||
601 | | IO_STATE (R_GEN_CONFIG, dma4, serial3),$r0 | ||
602 | #endif | ||
603 | #endif | ||
604 | #if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) | ||
605 | ; parport 0 enabled using DMA 2/3 | ||
606 | or.w IO_STATE (R_GEN_CONFIG, par0, select),$r0 | ||
607 | #endif | ||
608 | #if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) | ||
609 | ; parport 1 enabled using DMA 4/5 | ||
610 | or.w IO_STATE (R_GEN_CONFIG, par1, select),$r0 | ||
611 | #endif | ||
612 | #ifdef CONFIG_ETRAX_IDE | ||
613 | ; DMA channels 2 and 3 to ATA, ATA enabled | ||
614 | or.d IO_STATE (R_GEN_CONFIG, dma3, ata) \ | ||
615 | | IO_STATE (R_GEN_CONFIG, dma2, ata) \ | ||
616 | | IO_STATE (R_GEN_CONFIG, ata, select),$r0 | ||
617 | #endif | ||
618 | |||
619 | #ifdef CONFIG_ETRAX_USB_HOST_PORT1 | ||
620 | ; Set the USB port 1 enable bit | ||
621 | or.d IO_STATE (R_GEN_CONFIG, usb1, select),$r0 | ||
622 | #endif | ||
623 | #ifdef CONFIG_ETRAX_USB_HOST_PORT2 | ||
624 | ; Set the USB port 2 enable bit | ||
625 | or.d IO_STATE (R_GEN_CONFIG, usb2, select),$r0 | ||
626 | #endif | ||
627 | #ifdef CONFIG_ETRAX_USB_HOST | ||
628 | ; Connect DMA channels 8 and 9 to USB | ||
629 | and.d (~(IO_MASK (R_GEN_CONFIG, dma9) \ | ||
630 | | IO_MASK (R_GEN_CONFIG, dma8))) \ | ||
631 | | IO_STATE (R_GEN_CONFIG, dma9, usb) \ | ||
632 | | IO_STATE (R_GEN_CONFIG, dma8, usb),$r0 | ||
633 | #endif | ||
634 | |||
635 | #ifdef CONFIG_JULIETTE | ||
636 | ; DMA channels 4 and 5 to EXTDMA0, for Juliette | ||
637 | or.d IO_STATE (R_GEN_CONFIG, dma5, extdma0) \ | ||
638 | | IO_STATE (R_GEN_CONFIG, dma4, extdma0),$r0 | ||
639 | #endif | ||
640 | |||
641 | #if defined(CONFIG_ETRAX_DEF_R_PORT_G0_DIR_OUT) | ||
642 | or.d IO_STATE (R_GEN_CONFIG, g0dir, out),$r0 | ||
643 | #endif | ||
644 | |||
645 | #if defined(CONFIG_ETRAX_DEF_R_PORT_G8_15_DIR_OUT) | ||
646 | or.d IO_STATE (R_GEN_CONFIG, g8_15dir, out),$r0 | ||
647 | #endif | ||
648 | #if defined(CONFIG_ETRAX_DEF_R_PORT_G16_23_DIR_OUT) | ||
649 | or.d IO_STATE (R_GEN_CONFIG, g16_23dir, out),$r0 | ||
650 | #endif | ||
651 | |||
652 | #if defined(CONFIG_ETRAX_DEF_R_PORT_G24_DIR_OUT) | ||
653 | or.d IO_STATE (R_GEN_CONFIG, g24dir, out),$r0 | ||
654 | #endif | ||
655 | |||
656 | move.d $r0,[genconfig_shadow] ; init a shadow register of R_GEN_CONFIG | ||
657 | |||
658 | #ifndef CONFIG_SVINTO_SIM | ||
659 | move.d $r0,[R_GEN_CONFIG] | ||
660 | |||
661 | #if 0 | ||
662 | moveq 4,$r0 | ||
663 | move.b $r0,[R_DMA_CH6_CMD] ; reset (ser0 dma out) | ||
664 | move.b $r0,[R_DMA_CH7_CMD] ; reset (ser0 dma in) | ||
665 | 1: move.b [R_DMA_CH6_CMD],$r0 ; wait for reset cycle to finish | ||
666 | and.b 7,$r0 | ||
667 | cmp.b 4,$r0 | ||
668 | beq 1b | ||
669 | nop | ||
670 | 1: move.b [R_DMA_CH7_CMD],$r0 ; wait for reset cycle to finish | ||
671 | and.b 7,$r0 | ||
672 | cmp.b 4,$r0 | ||
673 | beq 1b | ||
674 | nop | ||
675 | #endif | ||
676 | |||
677 | moveq IO_STATE (R_DMA_CH8_CMD, cmd, reset),$r0 | ||
678 | move.b $r0,[R_DMA_CH8_CMD] ; reset (ser1 dma out) | ||
679 | move.b $r0,[R_DMA_CH9_CMD] ; reset (ser1 dma in) | ||
680 | 1: move.b [R_DMA_CH8_CMD],$r0 ; wait for reset cycle to finish | ||
681 | andq IO_MASK (R_DMA_CH8_CMD, cmd),$r0 | ||
682 | cmpq IO_STATE (R_DMA_CH8_CMD, cmd, reset),$r0 | ||
683 | beq 1b | ||
684 | nop | ||
685 | 1: move.b [R_DMA_CH9_CMD],$r0 ; wait for reset cycle to finish | ||
686 | andq IO_MASK (R_DMA_CH9_CMD, cmd),$r0 | ||
687 | cmpq IO_STATE (R_DMA_CH9_CMD, cmd, reset),$r0 | ||
688 | beq 1b | ||
689 | nop | ||
690 | |||
691 | ;; setup port PA and PB default initial directions and data | ||
692 | ;; including their shadow registers | ||
693 | |||
694 | move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR,$r0 | ||
695 | #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7) | ||
696 | or.b IO_STATE (R_PORT_PA_DIR, dir7, output),$r0 | ||
697 | #endif | ||
698 | move.b $r0,[port_pa_dir_shadow] | ||
699 | move.b $r0,[R_PORT_PA_DIR] | ||
700 | move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA,$r0 | ||
701 | #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7) | ||
702 | #if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH) | ||
703 | and.b ~(1 << 7),$r0 | ||
704 | #else | ||
705 | or.b (1 << 7),$r0 | ||
706 | #endif | ||
707 | #endif | ||
708 | move.b $r0,[port_pa_data_shadow] | ||
709 | move.b $r0,[R_PORT_PA_DATA] | ||
710 | |||
711 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,$r0 | ||
712 | move.b $r0,[port_pb_config_shadow] | ||
713 | move.b $r0,[R_PORT_PB_CONFIG] | ||
714 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR,$r0 | ||
715 | #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PB5) | ||
716 | or.b IO_STATE (R_PORT_PB_DIR, dir5, output),$r0 | ||
717 | #endif | ||
718 | move.b $r0,[port_pb_dir_shadow] | ||
719 | move.b $r0,[R_PORT_PB_DIR] | ||
720 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA,$r0 | ||
721 | #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PB5) | ||
722 | #if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH) | ||
723 | and.b ~(1 << 5),$r0 | ||
724 | #else | ||
725 | or.b (1 << 5),$r0 | ||
726 | #endif | ||
727 | #endif | ||
728 | move.b $r0,[port_pb_data_shadow] | ||
729 | move.b $r0,[R_PORT_PB_DATA] | ||
730 | |||
731 | moveq 0, $r0 | ||
732 | move.d $r0,[port_pb_i2c_shadow] | ||
733 | move.d $r0, [R_PORT_PB_I2C] | ||
734 | |||
735 | moveq 0,$r0 | ||
736 | #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_G10) | ||
737 | #if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH) | ||
738 | and.d ~(1 << 10),$r0 | ||
739 | #else | ||
740 | or.d (1 << 10),$r0 | ||
741 | #endif | ||
742 | #endif | ||
743 | #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_G11) | ||
744 | #if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH) | ||
745 | and.d ~(1 << 11),$r0 | ||
746 | #else | ||
747 | or.d (1 << 11),$r0 | ||
748 | #endif | ||
749 | #endif | ||
750 | move.d $r0,[port_g_data_shadow] | ||
751 | move.d $r0,[R_PORT_G_DATA] | ||
752 | |||
753 | ;; setup the serial port 0 at 115200 baud for debug purposes | ||
754 | |||
755 | moveq IO_STATE (R_SERIAL0_XOFF, tx_stop, enable) \ | ||
756 | | IO_STATE (R_SERIAL0_XOFF, auto_xoff, disable) \ | ||
757 | | IO_FIELD (R_SERIAL0_XOFF, xoff_char, 0),$r0 | ||
758 | move.d $r0,[R_SERIAL0_XOFF] | ||
759 | |||
760 | ; 115.2kbaud for both transmit and receive | ||
761 | move.b IO_STATE (R_SERIAL0_BAUD, tr_baud, c115k2Hz) \ | ||
762 | | IO_STATE (R_SERIAL0_BAUD, rec_baud, c115k2Hz),$r0 | ||
763 | move.b $r0,[R_SERIAL0_BAUD] | ||
764 | |||
765 | ; Set up and enable the serial0 receiver. | ||
766 | move.b IO_STATE (R_SERIAL0_REC_CTRL, dma_err, stop) \ | ||
767 | | IO_STATE (R_SERIAL0_REC_CTRL, rec_enable, enable) \ | ||
768 | | IO_STATE (R_SERIAL0_REC_CTRL, rts_, active) \ | ||
769 | | IO_STATE (R_SERIAL0_REC_CTRL, sampling, middle) \ | ||
770 | | IO_STATE (R_SERIAL0_REC_CTRL, rec_stick_par, normal) \ | ||
771 | | IO_STATE (R_SERIAL0_REC_CTRL, rec_par, even) \ | ||
772 | | IO_STATE (R_SERIAL0_REC_CTRL, rec_par_en, disable) \ | ||
773 | | IO_STATE (R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit),$r0 | ||
774 | move.b $r0,[R_SERIAL0_REC_CTRL] | ||
775 | |||
776 | ; Set up and enable the serial0 transmitter. | ||
777 | move.b IO_FIELD (R_SERIAL0_TR_CTRL, txd, 0) \ | ||
778 | | IO_STATE (R_SERIAL0_TR_CTRL, tr_enable, enable) \ | ||
779 | | IO_STATE (R_SERIAL0_TR_CTRL, auto_cts, disabled) \ | ||
780 | | IO_STATE (R_SERIAL0_TR_CTRL, stop_bits, one_bit) \ | ||
781 | | IO_STATE (R_SERIAL0_TR_CTRL, tr_stick_par, normal) \ | ||
782 | | IO_STATE (R_SERIAL0_TR_CTRL, tr_par, even) \ | ||
783 | | IO_STATE (R_SERIAL0_TR_CTRL, tr_par_en, disable) \ | ||
784 | | IO_STATE (R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit),$r0 | ||
785 | move.b $r0,[R_SERIAL0_TR_CTRL] | ||
786 | |||
787 | ;; setup the serial port 1 at 115200 baud for debug purposes | ||
788 | |||
789 | moveq IO_STATE (R_SERIAL1_XOFF, tx_stop, enable) \ | ||
790 | | IO_STATE (R_SERIAL1_XOFF, auto_xoff, disable) \ | ||
791 | | IO_FIELD (R_SERIAL1_XOFF, xoff_char, 0),$r0 | ||
792 | move.d $r0,[R_SERIAL1_XOFF] | ||
793 | |||
794 | ; 115.2kbaud for both transmit and receive | ||
795 | move.b IO_STATE (R_SERIAL1_BAUD, tr_baud, c115k2Hz) \ | ||
796 | | IO_STATE (R_SERIAL1_BAUD, rec_baud, c115k2Hz),$r0 | ||
797 | move.b $r0,[R_SERIAL1_BAUD] | ||
798 | |||
799 | ; Set up and enable the serial1 receiver. | ||
800 | move.b IO_STATE (R_SERIAL1_REC_CTRL, dma_err, stop) \ | ||
801 | | IO_STATE (R_SERIAL1_REC_CTRL, rec_enable, enable) \ | ||
802 | | IO_STATE (R_SERIAL1_REC_CTRL, rts_, active) \ | ||
803 | | IO_STATE (R_SERIAL1_REC_CTRL, sampling, middle) \ | ||
804 | | IO_STATE (R_SERIAL1_REC_CTRL, rec_stick_par, normal) \ | ||
805 | | IO_STATE (R_SERIAL1_REC_CTRL, rec_par, even) \ | ||
806 | | IO_STATE (R_SERIAL1_REC_CTRL, rec_par_en, disable) \ | ||
807 | | IO_STATE (R_SERIAL1_REC_CTRL, rec_bitnr, rec_8bit),$r0 | ||
808 | move.b $r0,[R_SERIAL1_REC_CTRL] | ||
809 | |||
810 | ; Set up and enable the serial1 transmitter. | ||
811 | move.b IO_FIELD (R_SERIAL1_TR_CTRL, txd, 0) \ | ||
812 | | IO_STATE (R_SERIAL1_TR_CTRL, tr_enable, enable) \ | ||
813 | | IO_STATE (R_SERIAL1_TR_CTRL, auto_cts, disabled) \ | ||
814 | | IO_STATE (R_SERIAL1_TR_CTRL, stop_bits, one_bit) \ | ||
815 | | IO_STATE (R_SERIAL1_TR_CTRL, tr_stick_par, normal) \ | ||
816 | | IO_STATE (R_SERIAL1_TR_CTRL, tr_par, even) \ | ||
817 | | IO_STATE (R_SERIAL1_TR_CTRL, tr_par_en, disable) \ | ||
818 | | IO_STATE (R_SERIAL1_TR_CTRL, tr_bitnr, tr_8bit),$r0 | ||
819 | move.b $r0,[R_SERIAL1_TR_CTRL] | ||
820 | |||
821 | |||
822 | #ifdef CONFIG_ETRAX_SERIAL_PORT3 | ||
823 | ;; setup the serial port 3 at 115200 baud for debug purposes | ||
824 | |||
825 | moveq IO_STATE (R_SERIAL3_XOFF, tx_stop, enable) \ | ||
826 | | IO_STATE (R_SERIAL3_XOFF, auto_xoff, disable) \ | ||
827 | | IO_FIELD (R_SERIAL3_XOFF, xoff_char, 0),$r0 | ||
828 | move.d $r0,[R_SERIAL3_XOFF] | ||
829 | |||
830 | ; 115.2kbaud for both transmit and receive | ||
831 | move.b IO_STATE (R_SERIAL3_BAUD, tr_baud, c115k2Hz) \ | ||
832 | | IO_STATE (R_SERIAL3_BAUD, rec_baud, c115k2Hz),$r0 | ||
833 | move.b $r0,[R_SERIAL3_BAUD] | ||
834 | |||
835 | ; Set up and enable the serial3 receiver. | ||
836 | move.b IO_STATE (R_SERIAL3_REC_CTRL, dma_err, stop) \ | ||
837 | | IO_STATE (R_SERIAL3_REC_CTRL, rec_enable, enable) \ | ||
838 | | IO_STATE (R_SERIAL3_REC_CTRL, rts_, active) \ | ||
839 | | IO_STATE (R_SERIAL3_REC_CTRL, sampling, middle) \ | ||
840 | | IO_STATE (R_SERIAL3_REC_CTRL, rec_stick_par, normal) \ | ||
841 | | IO_STATE (R_SERIAL3_REC_CTRL, rec_par, even) \ | ||
842 | | IO_STATE (R_SERIAL3_REC_CTRL, rec_par_en, disable) \ | ||
843 | | IO_STATE (R_SERIAL3_REC_CTRL, rec_bitnr, rec_8bit),$r0 | ||
844 | move.b $r0,[R_SERIAL3_REC_CTRL] | ||
845 | |||
846 | ; Set up and enable the serial3 transmitter. | ||
847 | move.b IO_FIELD (R_SERIAL3_TR_CTRL, txd, 0) \ | ||
848 | | IO_STATE (R_SERIAL3_TR_CTRL, tr_enable, enable) \ | ||
849 | | IO_STATE (R_SERIAL3_TR_CTRL, auto_cts, disabled) \ | ||
850 | | IO_STATE (R_SERIAL3_TR_CTRL, stop_bits, one_bit) \ | ||
851 | | IO_STATE (R_SERIAL3_TR_CTRL, tr_stick_par, normal) \ | ||
852 | | IO_STATE (R_SERIAL3_TR_CTRL, tr_par, even) \ | ||
853 | | IO_STATE (R_SERIAL3_TR_CTRL, tr_par_en, disable) \ | ||
854 | | IO_STATE (R_SERIAL3_TR_CTRL, tr_bitnr, tr_8bit),$r0 | ||
855 | move.b $r0,[R_SERIAL3_TR_CTRL] | ||
856 | #endif | ||
857 | |||
858 | #endif /* CONFIG_SVINTO_SIM */ | ||
859 | |||
860 | jump start_kernel ; jump into the C-function start_kernel in init/main.c | ||
861 | |||
862 | .data | ||
863 | etrax_irv: | ||
864 | .dword 0 | ||
865 | romfs_start: | ||
866 | .dword 0 | ||
867 | romfs_length: | ||
868 | .dword 0 | ||
869 | romfs_in_flash: | ||
870 | .dword 0 | ||
871 | |||
872 | ;; put some special pages at the beginning of the kernel aligned | ||
873 | ;; to page boundaries - the kernel cannot start until after this | ||
874 | |||
875 | #ifdef CONFIG_CRIS_LOW_MAP | ||
876 | swapper_pg_dir = 0x60002000 | ||
877 | #else | ||
878 | swapper_pg_dir = 0xc0002000 | ||
879 | #endif | ||
880 | |||
881 | .section ".init.data", "aw" | ||
882 | #include "../lib/hw_settings.S" | ||
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c new file mode 100644 index 000000000000..b2f16d6fc871 --- /dev/null +++ b/arch/cris/arch-v10/kernel/irq.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* $Id: irq.c,v 1.2 2004/06/09 05:30:27 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/kernel/irq.c | ||
4 | * | ||
5 | * Copyright (c) 2000-2002 Axis Communications AB | ||
6 | * | ||
7 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
8 | * | ||
9 | * This file contains the interrupt vectors and some | ||
10 | * helper functions | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <asm/irq.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/config.h> | ||
18 | |||
19 | irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */ | ||
20 | |||
21 | /* don't use set_int_vector, it bypasses the linux interrupt handlers. it is | ||
22 | * global just so that the kernel gdb can use it. | ||
23 | */ | ||
24 | |||
25 | void | ||
26 | set_int_vector(int n, irqvectptr addr) | ||
27 | { | ||
28 | etrax_irv->v[n + 0x20] = (irqvectptr)addr; | ||
29 | } | ||
30 | |||
31 | /* the breakpoint vector is obviously not made just like the normal irq handlers | ||
32 | * but needs to contain _code_ to jump to addr. | ||
33 | * | ||
34 | * the BREAK n instruction jumps to IBR + n * 8 | ||
35 | */ | ||
36 | |||
37 | void | ||
38 | set_break_vector(int n, irqvectptr addr) | ||
39 | { | ||
40 | unsigned short *jinstr = (unsigned short *)&etrax_irv->v[n*2]; | ||
41 | unsigned long *jaddr = (unsigned long *)(jinstr + 1); | ||
42 | |||
43 | /* if you don't know what this does, do not touch it! */ | ||
44 | |||
45 | *jinstr = 0x0d3f; | ||
46 | *jaddr = (unsigned long)addr; | ||
47 | |||
48 | /* 00000026 <clrlop+1a> 3f0d82000000 jump 0x82 */ | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * This builds up the IRQ handler stubs using some ugly macros in irq.h | ||
53 | * | ||
54 | * These macros create the low-level assembly IRQ routines that do all | ||
55 | * the operations that are needed. They are also written to be fast - and to | ||
56 | * disable interrupts as little as humanly possible. | ||
57 | * | ||
58 | */ | ||
59 | |||
60 | /* IRQ0 and 1 are special traps */ | ||
61 | void hwbreakpoint(void); | ||
62 | void IRQ1_interrupt(void); | ||
63 | BUILD_TIMER_IRQ(2, 0x04) /* the timer interrupt is somewhat special */ | ||
64 | BUILD_IRQ(3, 0x08) | ||
65 | BUILD_IRQ(4, 0x10) | ||
66 | BUILD_IRQ(5, 0x20) | ||
67 | BUILD_IRQ(6, 0x40) | ||
68 | BUILD_IRQ(7, 0x80) | ||
69 | BUILD_IRQ(8, 0x100) | ||
70 | BUILD_IRQ(9, 0x200) | ||
71 | BUILD_IRQ(10, 0x400) | ||
72 | BUILD_IRQ(11, 0x800) | ||
73 | BUILD_IRQ(12, 0x1000) | ||
74 | BUILD_IRQ(13, 0x2000) | ||
75 | void mmu_bus_fault(void); /* IRQ 14 is the bus fault interrupt */ | ||
76 | void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */ | ||
77 | BUILD_IRQ(16, 0x10000) | ||
78 | BUILD_IRQ(17, 0x20000) | ||
79 | BUILD_IRQ(18, 0x40000) | ||
80 | BUILD_IRQ(19, 0x80000) | ||
81 | BUILD_IRQ(20, 0x100000) | ||
82 | BUILD_IRQ(21, 0x200000) | ||
83 | BUILD_IRQ(22, 0x400000) | ||
84 | BUILD_IRQ(23, 0x800000) | ||
85 | BUILD_IRQ(24, 0x1000000) | ||
86 | BUILD_IRQ(25, 0x2000000) | ||
87 | /* IRQ 26-30 are reserved */ | ||
88 | BUILD_IRQ(31, 0x80000000) | ||
89 | |||
90 | /* | ||
91 | * Pointers to the low-level handlers | ||
92 | */ | ||
93 | |||
94 | static void (*interrupt[NR_IRQS])(void) = { | ||
95 | NULL, NULL, IRQ2_interrupt, IRQ3_interrupt, | ||
96 | IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt, | ||
97 | IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt, | ||
98 | IRQ12_interrupt, IRQ13_interrupt, NULL, NULL, | ||
99 | IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt, | ||
100 | IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt, | ||
101 | IRQ24_interrupt, IRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, | ||
102 | IRQ31_interrupt | ||
103 | }; | ||
104 | |||
105 | static void (*bad_interrupt[NR_IRQS])(void) = { | ||
106 | NULL, NULL, | ||
107 | NULL, bad_IRQ3_interrupt, | ||
108 | bad_IRQ4_interrupt, bad_IRQ5_interrupt, | ||
109 | bad_IRQ6_interrupt, bad_IRQ7_interrupt, | ||
110 | bad_IRQ8_interrupt, bad_IRQ9_interrupt, | ||
111 | bad_IRQ10_interrupt, bad_IRQ11_interrupt, | ||
112 | bad_IRQ12_interrupt, bad_IRQ13_interrupt, | ||
113 | NULL, NULL, | ||
114 | bad_IRQ16_interrupt, bad_IRQ17_interrupt, | ||
115 | bad_IRQ18_interrupt, bad_IRQ19_interrupt, | ||
116 | bad_IRQ20_interrupt, bad_IRQ21_interrupt, | ||
117 | bad_IRQ22_interrupt, bad_IRQ23_interrupt, | ||
118 | bad_IRQ24_interrupt, bad_IRQ25_interrupt, | ||
119 | NULL, NULL, NULL, NULL, NULL, | ||
120 | bad_IRQ31_interrupt | ||
121 | }; | ||
122 | |||
123 | void arch_setup_irq(int irq) | ||
124 | { | ||
125 | set_int_vector(irq, interrupt[irq]); | ||
126 | } | ||
127 | |||
128 | void arch_free_irq(int irq) | ||
129 | { | ||
130 | set_int_vector(irq, bad_interrupt[irq]); | ||
131 | } | ||
132 | |||
133 | void weird_irq(void); | ||
134 | void system_call(void); /* from entry.S */ | ||
135 | void do_sigtrap(void); /* from entry.S */ | ||
136 | void gdb_handle_breakpoint(void); /* from entry.S */ | ||
137 | |||
138 | /* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and | ||
139 | setting the irq vector table to point to bad_interrupt ptrs. | ||
140 | */ | ||
141 | |||
142 | void __init | ||
143 | init_IRQ(void) | ||
144 | { | ||
145 | int i; | ||
146 | |||
147 | /* clear all interrupt masks */ | ||
148 | |||
149 | #ifndef CONFIG_SVINTO_SIM | ||
150 | *R_IRQ_MASK0_CLR = 0xffffffff; | ||
151 | *R_IRQ_MASK1_CLR = 0xffffffff; | ||
152 | *R_IRQ_MASK2_CLR = 0xffffffff; | ||
153 | #endif | ||
154 | |||
155 | *R_VECT_MASK_CLR = 0xffffffff; | ||
156 | |||
157 | /* clear the shortcut entry points */ | ||
158 | |||
159 | for(i = 0; i < NR_IRQS; i++) | ||
160 | irq_shortcuts[i] = NULL; | ||
161 | |||
162 | for (i = 0; i < 256; i++) | ||
163 | etrax_irv->v[i] = weird_irq; | ||
164 | |||
165 | /* the entries in the break vector contain actual code to be | ||
166 | executed by the associated break handler, rather than just a jump | ||
167 | address. therefore we need to setup a default breakpoint handler | ||
168 | for all breakpoints */ | ||
169 | |||
170 | for (i = 0; i < 16; i++) | ||
171 | set_break_vector(i, do_sigtrap); | ||
172 | |||
173 | /* set all etrax irq's to the bad handlers */ | ||
174 | for (i = 2; i < NR_IRQS; i++) | ||
175 | set_int_vector(i, bad_interrupt[i]); | ||
176 | |||
177 | /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ | ||
178 | |||
179 | set_int_vector(15, multiple_interrupt); | ||
180 | |||
181 | /* 0 and 1 which are special breakpoint/NMI traps */ | ||
182 | |||
183 | set_int_vector(0, hwbreakpoint); | ||
184 | set_int_vector(1, IRQ1_interrupt); | ||
185 | |||
186 | /* and irq 14 which is the mmu bus fault handler */ | ||
187 | |||
188 | set_int_vector(14, mmu_bus_fault); | ||
189 | |||
190 | /* setup the system-call trap, which is reached by BREAK 13 */ | ||
191 | |||
192 | set_break_vector(13, system_call); | ||
193 | |||
194 | /* setup a breakpoint handler for debugging used for both user and | ||
195 | kernel mode debugging (which is why it is not inside an ifdef | ||
196 | CONFIG_ETRAX_KGDB) */ | ||
197 | set_break_vector(8, gdb_handle_breakpoint); | ||
198 | |||
199 | #ifdef CONFIG_ETRAX_KGDB | ||
200 | /* setup kgdb if its enabled, and break into the debugger */ | ||
201 | kgdb_init(); | ||
202 | breakpoint(); | ||
203 | #endif | ||
204 | } | ||
diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c new file mode 100644 index 000000000000..7d368c877ee9 --- /dev/null +++ b/arch/cris/arch-v10/kernel/kgdb.c | |||
@@ -0,0 +1,1568 @@ | |||
1 | /*!************************************************************************** | ||
2 | *! | ||
3 | *! FILE NAME : kgdb.c | ||
4 | *! | ||
5 | *! DESCRIPTION: Implementation of the gdb stub with respect to ETRAX 100. | ||
6 | *! It is a mix of arch/m68k/kernel/kgdb.c and cris_stub.c. | ||
7 | *! | ||
8 | *!--------------------------------------------------------------------------- | ||
9 | *! HISTORY | ||
10 | *! | ||
11 | *! DATE NAME CHANGES | ||
12 | *! ---- ---- ------- | ||
13 | *! Apr 26 1999 Hendrik Ruijter Initial version. | ||
14 | *! May 6 1999 Hendrik Ruijter Removed call to strlen in libc and removed | ||
15 | *! struct assignment as it generates calls to | ||
16 | *! memcpy in libc. | ||
17 | *! Jun 17 1999 Hendrik Ruijter Added gdb 4.18 support. 'X', 'qC' and 'qL'. | ||
18 | *! Jul 21 1999 Bjorn Wesen eLinux port | ||
19 | *! | ||
20 | *! $Log: kgdb.c,v $ | ||
21 | *! Revision 1.5 2004/10/07 13:59:08 starvik | ||
22 | *! Corrected call to set_int_vector | ||
23 | *! | ||
24 | *! Revision 1.4 2003/04/09 05:20:44 starvik | ||
25 | *! Merge of Linux 2.5.67 | ||
26 | *! | ||
27 | *! Revision 1.3 2003/01/21 19:11:08 starvik | ||
28 | *! Modified include path for new dir layout | ||
29 | *! | ||
30 | *! Revision 1.2 2002/11/19 14:35:24 starvik | ||
31 | *! Changes from linux 2.4 | ||
32 | *! Changed struct initializer syntax to the currently prefered notation | ||
33 | *! | ||
34 | *! Revision 1.1 2001/12/17 13:59:27 bjornw | ||
35 | *! Initial revision | ||
36 | *! | ||
37 | *! Revision 1.6 2001/10/09 13:10:03 matsfg | ||
38 | *! Added $ on registers and removed some underscores | ||
39 | *! | ||
40 | *! Revision 1.5 2001/04/17 13:58:39 orjanf | ||
41 | *! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. | ||
42 | *! | ||
43 | *! Revision 1.4 2001/02/23 13:45:19 bjornw | ||
44 | *! config.h check | ||
45 | *! | ||
46 | *! Revision 1.3 2001/01/31 18:08:23 orjanf | ||
47 | *! Removed kgdb_handle_breakpoint from being the break 8 handler. | ||
48 | *! | ||
49 | *! Revision 1.2 2001/01/12 14:22:25 orjanf | ||
50 | *! Updated kernel debugging support to work with ETRAX 100LX. | ||
51 | *! | ||
52 | *! Revision 1.1 2000/07/10 16:25:21 bjornw | ||
53 | *! Initial revision | ||
54 | *! | ||
55 | *! Revision 1.1.1.1 1999/12/03 14:57:31 bjornw | ||
56 | *! * Initial version of arch/cris, the latest CRIS architecture with an MMU. | ||
57 | *! Mostly copied from arch/etrax100 with appropriate renames of files. | ||
58 | *! The mm/ subdir is copied from arch/i386. | ||
59 | *! This does not compile yet at all. | ||
60 | *! | ||
61 | *! | ||
62 | *! Revision 1.4 1999/07/22 17:25:25 bjornw | ||
63 | *! Dont wait for + in putpacket if we havent hit the initial breakpoint yet. Added a kgdb_init function which sets up the break and irq vectors. | ||
64 | *! | ||
65 | *! Revision 1.3 1999/07/21 19:51:18 bjornw | ||
66 | *! Check if the interrupting char is a ctrl-C, ignore otherwise. | ||
67 | *! | ||
68 | *! Revision 1.2 1999/07/21 18:09:39 bjornw | ||
69 | *! Ported to eLinux architecture, and added some kgdb documentation. | ||
70 | *! | ||
71 | *! | ||
72 | *!--------------------------------------------------------------------------- | ||
73 | *! | ||
74 | *! $Id: kgdb.c,v 1.5 2004/10/07 13:59:08 starvik Exp $ | ||
75 | *! | ||
76 | *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN | ||
77 | *! | ||
78 | *!**************************************************************************/ | ||
79 | /* @(#) cris_stub.c 1.3 06/17/99 */ | ||
80 | |||
81 | /* | ||
82 | * kgdb usage notes: | ||
83 | * ----------------- | ||
84 | * | ||
85 | * If you select CONFIG_ETRAX_KGDB in the configuration, the kernel will be | ||
86 | * built with different gcc flags: "-g" is added to get debug infos, and | ||
87 | * "-fomit-frame-pointer" is omitted to make debugging easier. Since the | ||
88 | * resulting kernel will be quite big (approx. > 7 MB), it will be stripped | ||
89 | * before compresion. Such a kernel will behave just as usually, except if | ||
90 | * given a "debug=<device>" command line option. (Only serial devices are | ||
91 | * allowed for <device>, i.e. no printers or the like; possible values are | ||
92 | * machine depedend and are the same as for the usual debug device, the one | ||
93 | * for logging kernel messages.) If that option is given and the device can be | ||
94 | * initialized, the kernel will connect to the remote gdb in trap_init(). The | ||
95 | * serial parameters are fixed to 8N1 and 115200 bps, for easyness of | ||
96 | * implementation. | ||
97 | * | ||
98 | * To start a debugging session, start that gdb with the debugging kernel | ||
99 | * image (the one with the symbols, vmlinux.debug) named on the command line. | ||
100 | * This file will be used by gdb to get symbol and debugging infos about the | ||
101 | * kernel. Next, select remote debug mode by | ||
102 | * target remote <device> | ||
103 | * where <device> is the name of the serial device over which the debugged | ||
104 | * machine is connected. Maybe you have to adjust the baud rate by | ||
105 | * set remotebaud <rate> | ||
106 | * or also other parameters with stty: | ||
107 | * shell stty ... </dev/... | ||
108 | * If the kernel to debug has already booted, it waited for gdb and now | ||
109 | * connects, and you'll see a breakpoint being reported. If the kernel isn't | ||
110 | * running yet, start it now. The order of gdb and the kernel doesn't matter. | ||
111 | * Another thing worth knowing about in the getting-started phase is how to | ||
112 | * debug the remote protocol itself. This is activated with | ||
113 | * set remotedebug 1 | ||
114 | * gdb will then print out each packet sent or received. You'll also get some | ||
115 | * messages about the gdb stub on the console of the debugged machine. | ||
116 | * | ||
117 | * If all that works, you can use lots of the usual debugging techniques on | ||
118 | * the kernel, e.g. inspecting and changing variables/memory, setting | ||
119 | * breakpoints, single stepping and so on. It's also possible to interrupt the | ||
120 | * debugged kernel by pressing C-c in gdb. Have fun! :-) | ||
121 | * | ||
122 | * The gdb stub is entered (and thus the remote gdb gets control) in the | ||
123 | * following situations: | ||
124 | * | ||
125 | * - If breakpoint() is called. This is just after kgdb initialization, or if | ||
126 | * a breakpoint() call has been put somewhere into the kernel source. | ||
127 | * (Breakpoints can of course also be set the usual way in gdb.) | ||
128 | * In eLinux, we call breakpoint() in init/main.c after IRQ initialization. | ||
129 | * | ||
130 | * - If there is a kernel exception, i.e. bad_super_trap() or die_if_kernel() | ||
131 | * are entered. All the CPU exceptions are mapped to (more or less..., see | ||
132 | * the hard_trap_info array below) appropriate signal, which are reported | ||
133 | * to gdb. die_if_kernel() is usually called after some kind of access | ||
134 | * error and thus is reported as SIGSEGV. | ||
135 | * | ||
136 | * - When panic() is called. This is reported as SIGABRT. | ||
137 | * | ||
138 | * - If C-c is received over the serial line, which is treated as | ||
139 | * SIGINT. | ||
140 | * | ||
141 | * Of course, all these signals are just faked for gdb, since there is no | ||
142 | * signal concept as such for the kernel. It also isn't possible --obviously-- | ||
143 | * to set signal handlers from inside gdb, or restart the kernel with a | ||
144 | * signal. | ||
145 | * | ||
146 | * Current limitations: | ||
147 | * | ||
148 | * - While the kernel is stopped, interrupts are disabled for safety reasons | ||
149 | * (i.e., variables not changing magically or the like). But this also | ||
150 | * means that the clock isn't running anymore, and that interrupts from the | ||
151 | * hardware may get lost/not be served in time. This can cause some device | ||
152 | * errors... | ||
153 | * | ||
154 | * - When single-stepping, only one instruction of the current thread is | ||
155 | * executed, but interrupts are allowed for that time and will be serviced | ||
156 | * if pending. Be prepared for that. | ||
157 | * | ||
158 | * - All debugging happens in kernel virtual address space. There's no way to | ||
159 | * access physical memory not mapped in kernel space, or to access user | ||
160 | * space. A way to work around this is using get_user_long & Co. in gdb | ||
161 | * expressions, but only for the current process. | ||
162 | * | ||
163 | * - Interrupting the kernel only works if interrupts are currently allowed, | ||
164 | * and the interrupt of the serial line isn't blocked by some other means | ||
165 | * (IPL too high, disabled, ...) | ||
166 | * | ||
167 | * - The gdb stub is currently not reentrant, i.e. errors that happen therein | ||
168 | * (e.g. accessing invalid memory) may not be caught correctly. This could | ||
169 | * be removed in future by introducing a stack of struct registers. | ||
170 | * | ||
171 | */ | ||
172 | |||
173 | /* | ||
174 | * To enable debugger support, two things need to happen. One, a | ||
175 | * call to kgdb_init() is necessary in order to allow any breakpoints | ||
176 | * or error conditions to be properly intercepted and reported to gdb. | ||
177 | * Two, a breakpoint needs to be generated to begin communication. This | ||
178 | * is most easily accomplished by a call to breakpoint(). | ||
179 | * | ||
180 | * The following gdb commands are supported: | ||
181 | * | ||
182 | * command function Return value | ||
183 | * | ||
184 | * g return the value of the CPU registers hex data or ENN | ||
185 | * G set the value of the CPU registers OK or ENN | ||
186 | * | ||
187 | * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN | ||
188 | * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN | ||
189 | * | ||
190 | * c Resume at current address SNN ( signal NN) | ||
191 | * cAA..AA Continue at address AA..AA SNN | ||
192 | * | ||
193 | * s Step one instruction SNN | ||
194 | * sAA..AA Step one instruction from AA..AA SNN | ||
195 | * | ||
196 | * k kill | ||
197 | * | ||
198 | * ? What was the last sigval ? SNN (signal NN) | ||
199 | * | ||
200 | * bBB..BB Set baud rate to BB..BB OK or BNN, then sets | ||
201 | * baud rate | ||
202 | * | ||
203 | * All commands and responses are sent with a packet which includes a | ||
204 | * checksum. A packet consists of | ||
205 | * | ||
206 | * $<packet info>#<checksum>. | ||
207 | * | ||
208 | * where | ||
209 | * <packet info> :: <characters representing the command or response> | ||
210 | * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> | ||
211 | * | ||
212 | * When a packet is received, it is first acknowledged with either '+' or '-'. | ||
213 | * '+' indicates a successful transfer. '-' indicates a failed transfer. | ||
214 | * | ||
215 | * Example: | ||
216 | * | ||
217 | * Host: Reply: | ||
218 | * $m0,10#2a +$00010203040506070809101112131415#42 | ||
219 | * | ||
220 | */ | ||
221 | |||
222 | |||
223 | #include <linux/string.h> | ||
224 | #include <linux/signal.h> | ||
225 | #include <linux/kernel.h> | ||
226 | #include <linux/delay.h> | ||
227 | #include <linux/linkage.h> | ||
228 | |||
229 | #include <asm/setup.h> | ||
230 | #include <asm/ptrace.h> | ||
231 | |||
232 | #include <asm/arch/svinto.h> | ||
233 | #include <asm/irq.h> | ||
234 | |||
235 | static int kgdb_started = 0; | ||
236 | |||
237 | /********************************* Register image ****************************/ | ||
238 | /* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's | ||
239 | Reference", p. 1-1, with the additional register definitions of the | ||
240 | ETRAX 100LX in cris-opc.h. | ||
241 | There are 16 general 32-bit registers, R0-R15, where R14 is the stack | ||
242 | pointer, SP, and R15 is the program counter, PC. | ||
243 | There are 16 special registers, P0-P15, where three of the unimplemented | ||
244 | registers, P0, P4 and P8, are reserved as zero-registers. A read from | ||
245 | any of these registers returns zero and a write has no effect. */ | ||
246 | |||
247 | typedef | ||
248 | struct register_image | ||
249 | { | ||
250 | /* Offset */ | ||
251 | unsigned int r0; /* 0x00 */ | ||
252 | unsigned int r1; /* 0x04 */ | ||
253 | unsigned int r2; /* 0x08 */ | ||
254 | unsigned int r3; /* 0x0C */ | ||
255 | unsigned int r4; /* 0x10 */ | ||
256 | unsigned int r5; /* 0x14 */ | ||
257 | unsigned int r6; /* 0x18 */ | ||
258 | unsigned int r7; /* 0x1C */ | ||
259 | unsigned int r8; /* 0x20 Frame pointer */ | ||
260 | unsigned int r9; /* 0x24 */ | ||
261 | unsigned int r10; /* 0x28 */ | ||
262 | unsigned int r11; /* 0x2C */ | ||
263 | unsigned int r12; /* 0x30 */ | ||
264 | unsigned int r13; /* 0x34 */ | ||
265 | unsigned int sp; /* 0x38 Stack pointer */ | ||
266 | unsigned int pc; /* 0x3C Program counter */ | ||
267 | |||
268 | unsigned char p0; /* 0x40 8-bit zero-register */ | ||
269 | unsigned char vr; /* 0x41 Version register */ | ||
270 | |||
271 | unsigned short p4; /* 0x42 16-bit zero-register */ | ||
272 | unsigned short ccr; /* 0x44 Condition code register */ | ||
273 | |||
274 | unsigned int mof; /* 0x46 Multiply overflow register */ | ||
275 | |||
276 | unsigned int p8; /* 0x4A 32-bit zero-register */ | ||
277 | unsigned int ibr; /* 0x4E Interrupt base register */ | ||
278 | unsigned int irp; /* 0x52 Interrupt return pointer */ | ||
279 | unsigned int srp; /* 0x56 Subroutine return pointer */ | ||
280 | unsigned int bar; /* 0x5A Breakpoint address register */ | ||
281 | unsigned int dccr; /* 0x5E Double condition code register */ | ||
282 | unsigned int brp; /* 0x62 Breakpoint return pointer (pc in caller) */ | ||
283 | unsigned int usp; /* 0x66 User mode stack pointer */ | ||
284 | } registers; | ||
285 | |||
286 | /************** Prototypes for local library functions ***********************/ | ||
287 | |||
288 | /* Copy of strcpy from libc. */ | ||
289 | static char *gdb_cris_strcpy (char *s1, const char *s2); | ||
290 | |||
291 | /* Copy of strlen from libc. */ | ||
292 | static int gdb_cris_strlen (const char *s); | ||
293 | |||
294 | /* Copy of memchr from libc. */ | ||
295 | static void *gdb_cris_memchr (const void *s, int c, int n); | ||
296 | |||
297 | /* Copy of strtol from libc. Does only support base 16. */ | ||
298 | static int gdb_cris_strtol (const char *s, char **endptr, int base); | ||
299 | |||
300 | /********************** Prototypes for local functions. **********************/ | ||
301 | /* Copy the content of a register image into another. The size n is | ||
302 | the size of the register image. Due to struct assignment generation of | ||
303 | memcpy in libc. */ | ||
304 | static void copy_registers (registers *dptr, registers *sptr, int n); | ||
305 | |||
306 | /* Copy the stored registers from the stack. Put the register contents | ||
307 | of thread thread_id in the struct reg. */ | ||
308 | static void copy_registers_from_stack (int thread_id, registers *reg); | ||
309 | |||
310 | /* Copy the registers to the stack. Put the register contents of thread | ||
311 | thread_id from struct reg to the stack. */ | ||
312 | static void copy_registers_to_stack (int thread_id, registers *reg); | ||
313 | |||
314 | /* Write a value to a specified register regno in the register image | ||
315 | of the current thread. */ | ||
316 | static int write_register (int regno, char *val); | ||
317 | |||
318 | /* Write a value to a specified register in the stack of a thread other | ||
319 | than the current thread. */ | ||
320 | static write_stack_register (int thread_id, int regno, char *valptr); | ||
321 | |||
322 | /* Read a value from a specified register in the register image. Returns the | ||
323 | status of the read operation. The register value is returned in valptr. */ | ||
324 | static int read_register (char regno, unsigned int *valptr); | ||
325 | |||
326 | /* Serial port, reads one character. ETRAX 100 specific. from debugport.c */ | ||
327 | int getDebugChar (void); | ||
328 | |||
329 | /* Serial port, writes one character. ETRAX 100 specific. from debugport.c */ | ||
330 | void putDebugChar (int val); | ||
331 | |||
332 | void enableDebugIRQ (void); | ||
333 | |||
334 | /* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte, | ||
335 | represented by int x. */ | ||
336 | static char highhex (int x); | ||
337 | |||
338 | /* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte, | ||
339 | represented by int x. */ | ||
340 | static char lowhex (int x); | ||
341 | |||
342 | /* Returns the integer equivalent of a hexadecimal character. */ | ||
343 | static int hex (char ch); | ||
344 | |||
345 | /* Convert the memory, pointed to by mem into hexadecimal representation. | ||
346 | Put the result in buf, and return a pointer to the last character | ||
347 | in buf (null). */ | ||
348 | static char *mem2hex (char *buf, unsigned char *mem, int count); | ||
349 | |||
350 | /* Convert the array, in hexadecimal representation, pointed to by buf into | ||
351 | binary representation. Put the result in mem, and return a pointer to | ||
352 | the character after the last byte written. */ | ||
353 | static unsigned char *hex2mem (unsigned char *mem, char *buf, int count); | ||
354 | |||
355 | /* Put the content of the array, in binary representation, pointed to by buf | ||
356 | into memory pointed to by mem, and return a pointer to | ||
357 | the character after the last byte written. */ | ||
358 | static unsigned char *bin2mem (unsigned char *mem, unsigned char *buf, int count); | ||
359 | |||
360 | /* Await the sequence $<data>#<checksum> and store <data> in the array buffer | ||
361 | returned. */ | ||
362 | static void getpacket (char *buffer); | ||
363 | |||
364 | /* Send $<data>#<checksum> from the <data> in the array buffer. */ | ||
365 | static void putpacket (char *buffer); | ||
366 | |||
367 | /* Build and send a response packet in order to inform the host the | ||
368 | stub is stopped. */ | ||
369 | static void stub_is_stopped (int sigval); | ||
370 | |||
371 | /* All expected commands are sent from remote.c. Send a response according | ||
372 | to the description in remote.c. */ | ||
373 | static void handle_exception (int sigval); | ||
374 | |||
375 | /* Performs a complete re-start from scratch. ETRAX specific. */ | ||
376 | static void kill_restart (void); | ||
377 | |||
378 | /******************** Prototypes for global functions. ***********************/ | ||
379 | |||
380 | /* The string str is prepended with the GDB printout token and sent. */ | ||
381 | void putDebugString (const unsigned char *str, int length); /* used by etrax100ser.c */ | ||
382 | |||
383 | /* The hook for both static (compiled) and dynamic breakpoints set by GDB. | ||
384 | ETRAX 100 specific. */ | ||
385 | void handle_breakpoint (void); /* used by irq.c */ | ||
386 | |||
387 | /* The hook for an interrupt generated by GDB. ETRAX 100 specific. */ | ||
388 | void handle_interrupt (void); /* used by irq.c */ | ||
389 | |||
390 | /* A static breakpoint to be used at startup. */ | ||
391 | void breakpoint (void); /* called by init/main.c */ | ||
392 | |||
393 | /* From osys_int.c, executing_task contains the number of the current | ||
394 | executing task in osys. Does not know of object-oriented threads. */ | ||
395 | extern unsigned char executing_task; | ||
396 | |||
397 | /* The number of characters used for a 64 bit thread identifier. */ | ||
398 | #define HEXCHARS_IN_THREAD_ID 16 | ||
399 | |||
400 | /* Avoid warning as the internal_stack is not used in the C-code. */ | ||
401 | #define USEDVAR(name) { if (name) { ; } } | ||
402 | #define USEDFUN(name) { void (*pf)(void) = (void *)name; USEDVAR(pf) } | ||
403 | |||
404 | /********************************** Packet I/O ******************************/ | ||
405 | /* BUFMAX defines the maximum number of characters in | ||
406 | inbound/outbound buffers */ | ||
407 | #define BUFMAX 512 | ||
408 | |||
409 | /* Run-length encoding maximum length. Send 64 at most. */ | ||
410 | #define RUNLENMAX 64 | ||
411 | |||
412 | /* Definition of all valid hexadecimal characters */ | ||
413 | static const char hexchars[] = "0123456789abcdef"; | ||
414 | |||
415 | /* The inbound/outbound buffers used in packet I/O */ | ||
416 | static char remcomInBuffer[BUFMAX]; | ||
417 | static char remcomOutBuffer[BUFMAX]; | ||
418 | |||
419 | /* Error and warning messages. */ | ||
420 | enum error_type | ||
421 | { | ||
422 | SUCCESS, E01, E02, E03, E04, E05, E06, E07 | ||
423 | }; | ||
424 | static char *error_message[] = | ||
425 | { | ||
426 | "", | ||
427 | "E01 Set current or general thread - H[c,g] - internal error.", | ||
428 | "E02 Change register content - P - cannot change read-only register.", | ||
429 | "E03 Thread is not alive.", /* T, not used. */ | ||
430 | "E04 The command is not supported - [s,C,S,!,R,d,r] - internal error.", | ||
431 | "E05 Change register content - P - the register is not implemented..", | ||
432 | "E06 Change memory content - M - internal error.", | ||
433 | "E07 Change register content - P - the register is not stored on the stack" | ||
434 | }; | ||
435 | /********************************* Register image ****************************/ | ||
436 | /* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's | ||
437 | Reference", p. 1-1, with the additional register definitions of the | ||
438 | ETRAX 100LX in cris-opc.h. | ||
439 | There are 16 general 32-bit registers, R0-R15, where R14 is the stack | ||
440 | pointer, SP, and R15 is the program counter, PC. | ||
441 | There are 16 special registers, P0-P15, where three of the unimplemented | ||
442 | registers, P0, P4 and P8, are reserved as zero-registers. A read from | ||
443 | any of these registers returns zero and a write has no effect. */ | ||
444 | enum register_name | ||
445 | { | ||
446 | R0, R1, R2, R3, | ||
447 | R4, R5, R6, R7, | ||
448 | R8, R9, R10, R11, | ||
449 | R12, R13, SP, PC, | ||
450 | P0, VR, P2, P3, | ||
451 | P4, CCR, P6, MOF, | ||
452 | P8, IBR, IRP, SRP, | ||
453 | BAR, DCCR, BRP, USP | ||
454 | }; | ||
455 | |||
456 | /* The register sizes of the registers in register_name. An unimplemented register | ||
457 | is designated by size 0 in this array. */ | ||
458 | static int register_size[] = | ||
459 | { | ||
460 | 4, 4, 4, 4, | ||
461 | 4, 4, 4, 4, | ||
462 | 4, 4, 4, 4, | ||
463 | 4, 4, 4, 4, | ||
464 | 1, 1, 0, 0, | ||
465 | 2, 2, 0, 4, | ||
466 | 4, 4, 4, 4, | ||
467 | 4, 4, 4, 4 | ||
468 | }; | ||
469 | |||
470 | /* Contains the register image of the executing thread in the assembler | ||
471 | part of the code in order to avoid horrible addressing modes. */ | ||
472 | static registers reg; | ||
473 | |||
474 | /* FIXME: Should this be used? Delete otherwise. */ | ||
475 | /* Contains the assumed consistency state of the register image. Uses the | ||
476 | enum error_type for state information. */ | ||
477 | static int consistency_status = SUCCESS; | ||
478 | |||
479 | /********************************** Handle exceptions ************************/ | ||
480 | /* The variable reg contains the register image associated with the | ||
481 | current_thread_c variable. It is a complete register image created at | ||
482 | entry. The reg_g contains a register image of a task where the general | ||
483 | registers are taken from the stack and all special registers are taken | ||
484 | from the executing task. It is associated with current_thread_g and used | ||
485 | in order to provide access mainly for 'g', 'G' and 'P'. | ||
486 | */ | ||
487 | |||
488 | /* Need two task id pointers in order to handle Hct and Hgt commands. */ | ||
489 | static int current_thread_c = 0; | ||
490 | static int current_thread_g = 0; | ||
491 | |||
492 | /* Need two register images in order to handle Hct and Hgt commands. The | ||
493 | variable reg_g is in addition to reg above. */ | ||
494 | static registers reg_g; | ||
495 | |||
496 | /********************************** Breakpoint *******************************/ | ||
497 | /* Use an internal stack in the breakpoint and interrupt response routines */ | ||
498 | #define INTERNAL_STACK_SIZE 1024 | ||
499 | static char internal_stack[INTERNAL_STACK_SIZE]; | ||
500 | |||
501 | /* Due to the breakpoint return pointer, a state variable is needed to keep | ||
502 | track of whether it is a static (compiled) or dynamic (gdb-invoked) | ||
503 | breakpoint to be handled. A static breakpoint uses the content of register | ||
504 | BRP as it is whereas a dynamic breakpoint requires subtraction with 2 | ||
505 | in order to execute the instruction. The first breakpoint is static. */ | ||
506 | static unsigned char is_dyn_brkp = 0; | ||
507 | |||
508 | /********************************* String library ****************************/ | ||
509 | /* Single-step over library functions creates trap loops. */ | ||
510 | |||
511 | /* Copy char s2[] to s1[]. */ | ||
512 | static char* | ||
513 | gdb_cris_strcpy (char *s1, const char *s2) | ||
514 | { | ||
515 | char *s = s1; | ||
516 | |||
517 | for (s = s1; (*s++ = *s2++) != '\0'; ) | ||
518 | ; | ||
519 | return (s1); | ||
520 | } | ||
521 | |||
522 | /* Find length of s[]. */ | ||
523 | static int | ||
524 | gdb_cris_strlen (const char *s) | ||
525 | { | ||
526 | const char *sc; | ||
527 | |||
528 | for (sc = s; *sc != '\0'; sc++) | ||
529 | ; | ||
530 | return (sc - s); | ||
531 | } | ||
532 | |||
533 | /* Find first occurrence of c in s[n]. */ | ||
534 | static void* | ||
535 | gdb_cris_memchr (const void *s, int c, int n) | ||
536 | { | ||
537 | const unsigned char uc = c; | ||
538 | const unsigned char *su; | ||
539 | |||
540 | for (su = s; 0 < n; ++su, --n) | ||
541 | if (*su == uc) | ||
542 | return ((void *)su); | ||
543 | return (NULL); | ||
544 | } | ||
545 | /******************************* Standard library ****************************/ | ||
546 | /* Single-step over library functions creates trap loops. */ | ||
547 | /* Convert string to long. */ | ||
548 | static int | ||
549 | gdb_cris_strtol (const char *s, char **endptr, int base) | ||
550 | { | ||
551 | char *s1; | ||
552 | char *sd; | ||
553 | int x = 0; | ||
554 | |||
555 | for (s1 = (char*)s; (sd = gdb_cris_memchr(hexchars, *s1, base)) != NULL; ++s1) | ||
556 | x = x * base + (sd - hexchars); | ||
557 | |||
558 | if (endptr) | ||
559 | { | ||
560 | /* Unconverted suffix is stored in endptr unless endptr is NULL. */ | ||
561 | *endptr = s1; | ||
562 | } | ||
563 | |||
564 | return x; | ||
565 | } | ||
566 | |||
567 | int | ||
568 | double_this(int x) | ||
569 | { | ||
570 | return 2 * x; | ||
571 | } | ||
572 | |||
573 | /********************************* Register image ****************************/ | ||
574 | /* Copy the content of a register image into another. The size n is | ||
575 | the size of the register image. Due to struct assignment generation of | ||
576 | memcpy in libc. */ | ||
577 | static void | ||
578 | copy_registers (registers *dptr, registers *sptr, int n) | ||
579 | { | ||
580 | unsigned char *dreg; | ||
581 | unsigned char *sreg; | ||
582 | |||
583 | for (dreg = (unsigned char*)dptr, sreg = (unsigned char*)sptr; n > 0; n--) | ||
584 | *dreg++ = *sreg++; | ||
585 | } | ||
586 | |||
587 | #ifdef PROCESS_SUPPORT | ||
588 | /* Copy the stored registers from the stack. Put the register contents | ||
589 | of thread thread_id in the struct reg. */ | ||
590 | static void | ||
591 | copy_registers_from_stack (int thread_id, registers *regptr) | ||
592 | { | ||
593 | int j; | ||
594 | stack_registers *s = (stack_registers *)stack_list[thread_id]; | ||
595 | unsigned int *d = (unsigned int *)regptr; | ||
596 | |||
597 | for (j = 13; j >= 0; j--) | ||
598 | *d++ = s->r[j]; | ||
599 | regptr->sp = (unsigned int)stack_list[thread_id]; | ||
600 | regptr->pc = s->pc; | ||
601 | regptr->dccr = s->dccr; | ||
602 | regptr->srp = s->srp; | ||
603 | } | ||
604 | |||
605 | /* Copy the registers to the stack. Put the register contents of thread | ||
606 | thread_id from struct reg to the stack. */ | ||
607 | static void | ||
608 | copy_registers_to_stack (int thread_id, registers *regptr) | ||
609 | { | ||
610 | int i; | ||
611 | stack_registers *d = (stack_registers *)stack_list[thread_id]; | ||
612 | unsigned int *s = (unsigned int *)regptr; | ||
613 | |||
614 | for (i = 0; i < 14; i++) { | ||
615 | d->r[i] = *s++; | ||
616 | } | ||
617 | d->pc = regptr->pc; | ||
618 | d->dccr = regptr->dccr; | ||
619 | d->srp = regptr->srp; | ||
620 | } | ||
621 | #endif | ||
622 | |||
623 | /* Write a value to a specified register in the register image of the current | ||
624 | thread. Returns status code SUCCESS, E02 or E05. */ | ||
625 | static int | ||
626 | write_register (int regno, char *val) | ||
627 | { | ||
628 | int status = SUCCESS; | ||
629 | registers *current_reg = ® | ||
630 | |||
631 | if (regno >= R0 && regno <= PC) { | ||
632 | /* 32-bit register with simple offset. */ | ||
633 | hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int), | ||
634 | val, sizeof(unsigned int)); | ||
635 | } | ||
636 | else if (regno == P0 || regno == VR || regno == P4 || regno == P8) { | ||
637 | /* Do not support read-only registers. */ | ||
638 | status = E02; | ||
639 | } | ||
640 | else if (regno == CCR) { | ||
641 | /* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented, | ||
642 | and P7 (MOF) is 32 bits in ETRAX 100LX. */ | ||
643 | hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short), | ||
644 | val, sizeof(unsigned short)); | ||
645 | } | ||
646 | else if (regno >= MOF && regno <= USP) { | ||
647 | /* 32 bit register with complex offset. (P8 has been taken care of.) */ | ||
648 | hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int), | ||
649 | val, sizeof(unsigned int)); | ||
650 | } | ||
651 | else { | ||
652 | /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */ | ||
653 | status = E05; | ||
654 | } | ||
655 | return status; | ||
656 | } | ||
657 | |||
658 | #ifdef PROCESS_SUPPORT | ||
659 | /* Write a value to a specified register in the stack of a thread other | ||
660 | than the current thread. Returns status code SUCCESS or E07. */ | ||
661 | static int | ||
662 | write_stack_register (int thread_id, int regno, char *valptr) | ||
663 | { | ||
664 | int status = SUCCESS; | ||
665 | stack_registers *d = (stack_registers *)stack_list[thread_id]; | ||
666 | unsigned int val; | ||
667 | |||
668 | hex2mem ((unsigned char *)&val, valptr, sizeof(unsigned int)); | ||
669 | if (regno >= R0 && regno < SP) { | ||
670 | d->r[regno] = val; | ||
671 | } | ||
672 | else if (regno == SP) { | ||
673 | stack_list[thread_id] = val; | ||
674 | } | ||
675 | else if (regno == PC) { | ||
676 | d->pc = val; | ||
677 | } | ||
678 | else if (regno == SRP) { | ||
679 | d->srp = val; | ||
680 | } | ||
681 | else if (regno == DCCR) { | ||
682 | d->dccr = val; | ||
683 | } | ||
684 | else { | ||
685 | /* Do not support registers in the current thread. */ | ||
686 | status = E07; | ||
687 | } | ||
688 | return status; | ||
689 | } | ||
690 | #endif | ||
691 | |||
692 | /* Read a value from a specified register in the register image. Returns the | ||
693 | value in the register or -1 for non-implemented registers. | ||
694 | Should check consistency_status after a call which may be E05 after changes | ||
695 | in the implementation. */ | ||
696 | static int | ||
697 | read_register (char regno, unsigned int *valptr) | ||
698 | { | ||
699 | registers *current_reg = ® | ||
700 | |||
701 | if (regno >= R0 && regno <= PC) { | ||
702 | /* 32-bit register with simple offset. */ | ||
703 | *valptr = *(unsigned int *)((char *)current_reg + regno * sizeof(unsigned int)); | ||
704 | return SUCCESS; | ||
705 | } | ||
706 | else if (regno == P0 || regno == VR) { | ||
707 | /* 8 bit register with complex offset. */ | ||
708 | *valptr = (unsigned int)(*(unsigned char *) | ||
709 | ((char *)&(current_reg->p0) + (regno-P0) * sizeof(char))); | ||
710 | return SUCCESS; | ||
711 | } | ||
712 | else if (regno == P4 || regno == CCR) { | ||
713 | /* 16 bit register with complex offset. */ | ||
714 | *valptr = (unsigned int)(*(unsigned short *) | ||
715 | ((char *)&(current_reg->p4) + (regno-P4) * sizeof(unsigned short))); | ||
716 | return SUCCESS; | ||
717 | } | ||
718 | else if (regno >= MOF && regno <= USP) { | ||
719 | /* 32 bit register with complex offset. */ | ||
720 | *valptr = *(unsigned int *)((char *)&(current_reg->p8) | ||
721 | + (regno-P8) * sizeof(unsigned int)); | ||
722 | return SUCCESS; | ||
723 | } | ||
724 | else { | ||
725 | /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */ | ||
726 | consistency_status = E05; | ||
727 | return E05; | ||
728 | } | ||
729 | } | ||
730 | |||
731 | /********************************** Packet I/O ******************************/ | ||
732 | /* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte, | ||
733 | represented by int x. */ | ||
734 | static inline char | ||
735 | highhex(int x) | ||
736 | { | ||
737 | return hexchars[(x >> 4) & 0xf]; | ||
738 | } | ||
739 | |||
740 | /* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte, | ||
741 | represented by int x. */ | ||
742 | static inline char | ||
743 | lowhex(int x) | ||
744 | { | ||
745 | return hexchars[x & 0xf]; | ||
746 | } | ||
747 | |||
748 | /* Returns the integer equivalent of a hexadecimal character. */ | ||
749 | static int | ||
750 | hex (char ch) | ||
751 | { | ||
752 | if ((ch >= 'a') && (ch <= 'f')) | ||
753 | return (ch - 'a' + 10); | ||
754 | if ((ch >= '0') && (ch <= '9')) | ||
755 | return (ch - '0'); | ||
756 | if ((ch >= 'A') && (ch <= 'F')) | ||
757 | return (ch - 'A' + 10); | ||
758 | return (-1); | ||
759 | } | ||
760 | |||
761 | /* Convert the memory, pointed to by mem into hexadecimal representation. | ||
762 | Put the result in buf, and return a pointer to the last character | ||
763 | in buf (null). */ | ||
764 | |||
765 | static int do_printk = 0; | ||
766 | |||
767 | static char * | ||
768 | mem2hex(char *buf, unsigned char *mem, int count) | ||
769 | { | ||
770 | int i; | ||
771 | int ch; | ||
772 | |||
773 | if (mem == NULL) { | ||
774 | /* Bogus read from m0. FIXME: What constitutes a valid address? */ | ||
775 | for (i = 0; i < count; i++) { | ||
776 | *buf++ = '0'; | ||
777 | *buf++ = '0'; | ||
778 | } | ||
779 | } else { | ||
780 | /* Valid mem address. */ | ||
781 | for (i = 0; i < count; i++) { | ||
782 | ch = *mem++; | ||
783 | *buf++ = highhex (ch); | ||
784 | *buf++ = lowhex (ch); | ||
785 | } | ||
786 | } | ||
787 | |||
788 | /* Terminate properly. */ | ||
789 | *buf = '\0'; | ||
790 | return (buf); | ||
791 | } | ||
792 | |||
793 | /* Convert the array, in hexadecimal representation, pointed to by buf into | ||
794 | binary representation. Put the result in mem, and return a pointer to | ||
795 | the character after the last byte written. */ | ||
796 | static unsigned char* | ||
797 | hex2mem (unsigned char *mem, char *buf, int count) | ||
798 | { | ||
799 | int i; | ||
800 | unsigned char ch; | ||
801 | for (i = 0; i < count; i++) { | ||
802 | ch = hex (*buf++) << 4; | ||
803 | ch = ch + hex (*buf++); | ||
804 | *mem++ = ch; | ||
805 | } | ||
806 | return (mem); | ||
807 | } | ||
808 | |||
809 | /* Put the content of the array, in binary representation, pointed to by buf | ||
810 | into memory pointed to by mem, and return a pointer to the character after | ||
811 | the last byte written. | ||
812 | Gdb will escape $, #, and the escape char (0x7d). */ | ||
813 | static unsigned char* | ||
814 | bin2mem (unsigned char *mem, unsigned char *buf, int count) | ||
815 | { | ||
816 | int i; | ||
817 | unsigned char *next; | ||
818 | for (i = 0; i < count; i++) { | ||
819 | /* Check for any escaped characters. Be paranoid and | ||
820 | only unescape chars that should be escaped. */ | ||
821 | if (*buf == 0x7d) { | ||
822 | next = buf + 1; | ||
823 | if (*next == 0x3 || *next == 0x4 || *next == 0x5D) /* #, $, ESC */ | ||
824 | { | ||
825 | buf++; | ||
826 | *buf += 0x20; | ||
827 | } | ||
828 | } | ||
829 | *mem++ = *buf++; | ||
830 | } | ||
831 | return (mem); | ||
832 | } | ||
833 | |||
834 | /* Await the sequence $<data>#<checksum> and store <data> in the array buffer | ||
835 | returned. */ | ||
836 | static void | ||
837 | getpacket (char *buffer) | ||
838 | { | ||
839 | unsigned char checksum; | ||
840 | unsigned char xmitcsum; | ||
841 | int i; | ||
842 | int count; | ||
843 | char ch; | ||
844 | do { | ||
845 | while ((ch = getDebugChar ()) != '$') | ||
846 | /* Wait for the start character $ and ignore all other characters */; | ||
847 | checksum = 0; | ||
848 | xmitcsum = -1; | ||
849 | count = 0; | ||
850 | /* Read until a # or the end of the buffer is reached */ | ||
851 | while (count < BUFMAX) { | ||
852 | ch = getDebugChar (); | ||
853 | if (ch == '#') | ||
854 | break; | ||
855 | checksum = checksum + ch; | ||
856 | buffer[count] = ch; | ||
857 | count = count + 1; | ||
858 | } | ||
859 | buffer[count] = '\0'; | ||
860 | |||
861 | if (ch == '#') { | ||
862 | xmitcsum = hex (getDebugChar ()) << 4; | ||
863 | xmitcsum += hex (getDebugChar ()); | ||
864 | if (checksum != xmitcsum) { | ||
865 | /* Wrong checksum */ | ||
866 | putDebugChar ('-'); | ||
867 | } | ||
868 | else { | ||
869 | /* Correct checksum */ | ||
870 | putDebugChar ('+'); | ||
871 | /* If sequence characters are received, reply with them */ | ||
872 | if (buffer[2] == ':') { | ||
873 | putDebugChar (buffer[0]); | ||
874 | putDebugChar (buffer[1]); | ||
875 | /* Remove the sequence characters from the buffer */ | ||
876 | count = gdb_cris_strlen (buffer); | ||
877 | for (i = 3; i <= count; i++) | ||
878 | buffer[i - 3] = buffer[i]; | ||
879 | } | ||
880 | } | ||
881 | } | ||
882 | } while (checksum != xmitcsum); | ||
883 | } | ||
884 | |||
885 | /* Send $<data>#<checksum> from the <data> in the array buffer. */ | ||
886 | |||
887 | static void | ||
888 | putpacket(char *buffer) | ||
889 | { | ||
890 | int checksum; | ||
891 | int runlen; | ||
892 | int encode; | ||
893 | |||
894 | do { | ||
895 | char *src = buffer; | ||
896 | putDebugChar ('$'); | ||
897 | checksum = 0; | ||
898 | while (*src) { | ||
899 | /* Do run length encoding */ | ||
900 | putDebugChar (*src); | ||
901 | checksum += *src; | ||
902 | runlen = 0; | ||
903 | while (runlen < RUNLENMAX && *src == src[runlen]) { | ||
904 | runlen++; | ||
905 | } | ||
906 | if (runlen > 3) { | ||
907 | /* Got a useful amount */ | ||
908 | putDebugChar ('*'); | ||
909 | checksum += '*'; | ||
910 | encode = runlen + ' ' - 4; | ||
911 | putDebugChar (encode); | ||
912 | checksum += encode; | ||
913 | src += runlen; | ||
914 | } | ||
915 | else { | ||
916 | src++; | ||
917 | } | ||
918 | } | ||
919 | putDebugChar ('#'); | ||
920 | putDebugChar (highhex (checksum)); | ||
921 | putDebugChar (lowhex (checksum)); | ||
922 | } while(kgdb_started && (getDebugChar() != '+')); | ||
923 | } | ||
924 | |||
925 | /* The string str is prepended with the GDB printout token and sent. Required | ||
926 | in traditional implementations. */ | ||
927 | void | ||
928 | putDebugString (const unsigned char *str, int length) | ||
929 | { | ||
930 | remcomOutBuffer[0] = 'O'; | ||
931 | mem2hex(&remcomOutBuffer[1], (unsigned char *)str, length); | ||
932 | putpacket(remcomOutBuffer); | ||
933 | } | ||
934 | |||
935 | /********************************** Handle exceptions ************************/ | ||
936 | /* Build and send a response packet in order to inform the host the | ||
937 | stub is stopped. TAAn...:r...;n...:r...;n...:r...; | ||
938 | AA = signal number | ||
939 | n... = register number (hex) | ||
940 | r... = register contents | ||
941 | n... = `thread' | ||
942 | r... = thread process ID. This is a hex integer. | ||
943 | n... = other string not starting with valid hex digit. | ||
944 | gdb should ignore this n,r pair and go on to the next. | ||
945 | This way we can extend the protocol. */ | ||
946 | static void | ||
947 | stub_is_stopped(int sigval) | ||
948 | { | ||
949 | char *ptr = remcomOutBuffer; | ||
950 | int regno; | ||
951 | |||
952 | unsigned int reg_cont; | ||
953 | int status; | ||
954 | |||
955 | /* Send trap type (converted to signal) */ | ||
956 | |||
957 | *ptr++ = 'T'; | ||
958 | *ptr++ = highhex (sigval); | ||
959 | *ptr++ = lowhex (sigval); | ||
960 | |||
961 | /* Send register contents. We probably only need to send the | ||
962 | * PC, frame pointer and stack pointer here. Other registers will be | ||
963 | * explicitely asked for. But for now, send all. | ||
964 | */ | ||
965 | |||
966 | for (regno = R0; regno <= USP; regno++) { | ||
967 | /* Store n...:r...; for the registers in the buffer. */ | ||
968 | |||
969 | status = read_register (regno, ®_cont); | ||
970 | |||
971 | if (status == SUCCESS) { | ||
972 | |||
973 | *ptr++ = highhex (regno); | ||
974 | *ptr++ = lowhex (regno); | ||
975 | *ptr++ = ':'; | ||
976 | |||
977 | ptr = mem2hex(ptr, (unsigned char *)®_cont, | ||
978 | register_size[regno]); | ||
979 | *ptr++ = ';'; | ||
980 | } | ||
981 | |||
982 | } | ||
983 | |||
984 | #ifdef PROCESS_SUPPORT | ||
985 | /* Store the registers of the executing thread. Assume that both step, | ||
986 | continue, and register content requests are with respect to this | ||
987 | thread. The executing task is from the operating system scheduler. */ | ||
988 | |||
989 | current_thread_c = executing_task; | ||
990 | current_thread_g = executing_task; | ||
991 | |||
992 | /* A struct assignment translates into a libc memcpy call. Avoid | ||
993 | all libc functions in order to prevent recursive break points. */ | ||
994 | copy_registers (®_g, ®, sizeof(registers)); | ||
995 | |||
996 | /* Store thread:r...; with the executing task TID. */ | ||
997 | gdb_cris_strcpy (&remcomOutBuffer[pos], "thread:"); | ||
998 | pos += gdb_cris_strlen ("thread:"); | ||
999 | remcomOutBuffer[pos++] = highhex (executing_task); | ||
1000 | remcomOutBuffer[pos++] = lowhex (executing_task); | ||
1001 | gdb_cris_strcpy (&remcomOutBuffer[pos], ";"); | ||
1002 | #endif | ||
1003 | |||
1004 | /* null-terminate and send it off */ | ||
1005 | |||
1006 | *ptr = 0; | ||
1007 | |||
1008 | putpacket (remcomOutBuffer); | ||
1009 | } | ||
1010 | |||
1011 | /* All expected commands are sent from remote.c. Send a response according | ||
1012 | to the description in remote.c. */ | ||
1013 | static void | ||
1014 | handle_exception (int sigval) | ||
1015 | { | ||
1016 | /* Avoid warning of not used. */ | ||
1017 | |||
1018 | USEDFUN(handle_exception); | ||
1019 | USEDVAR(internal_stack[0]); | ||
1020 | |||
1021 | /* Send response. */ | ||
1022 | |||
1023 | stub_is_stopped (sigval); | ||
1024 | |||
1025 | for (;;) { | ||
1026 | remcomOutBuffer[0] = '\0'; | ||
1027 | getpacket (remcomInBuffer); | ||
1028 | switch (remcomInBuffer[0]) { | ||
1029 | case 'g': | ||
1030 | /* Read registers: g | ||
1031 | Success: Each byte of register data is described by two hex digits. | ||
1032 | Registers are in the internal order for GDB, and the bytes | ||
1033 | in a register are in the same order the machine uses. | ||
1034 | Failure: void. */ | ||
1035 | |||
1036 | { | ||
1037 | #ifdef PROCESS_SUPPORT | ||
1038 | /* Use the special register content in the executing thread. */ | ||
1039 | copy_registers (®_g, ®, sizeof(registers)); | ||
1040 | /* Replace the content available on the stack. */ | ||
1041 | if (current_thread_g != executing_task) { | ||
1042 | copy_registers_from_stack (current_thread_g, ®_g); | ||
1043 | } | ||
1044 | mem2hex ((unsigned char *)remcomOutBuffer, (unsigned char *)®_g, sizeof(registers)); | ||
1045 | #else | ||
1046 | mem2hex(remcomOutBuffer, (char *)®, sizeof(registers)); | ||
1047 | #endif | ||
1048 | } | ||
1049 | break; | ||
1050 | |||
1051 | case 'G': | ||
1052 | /* Write registers. GXX..XX | ||
1053 | Each byte of register data is described by two hex digits. | ||
1054 | Success: OK | ||
1055 | Failure: void. */ | ||
1056 | #ifdef PROCESS_SUPPORT | ||
1057 | hex2mem ((unsigned char *)®_g, &remcomInBuffer[1], sizeof(registers)); | ||
1058 | if (current_thread_g == executing_task) { | ||
1059 | copy_registers (®, ®_g, sizeof(registers)); | ||
1060 | } | ||
1061 | else { | ||
1062 | copy_registers_to_stack(current_thread_g, ®_g); | ||
1063 | } | ||
1064 | #else | ||
1065 | hex2mem((char *)®, &remcomInBuffer[1], sizeof(registers)); | ||
1066 | #endif | ||
1067 | gdb_cris_strcpy (remcomOutBuffer, "OK"); | ||
1068 | break; | ||
1069 | |||
1070 | case 'P': | ||
1071 | /* Write register. Pn...=r... | ||
1072 | Write register n..., hex value without 0x, with value r..., | ||
1073 | which contains a hex value without 0x and two hex digits | ||
1074 | for each byte in the register (target byte order). P1f=11223344 means | ||
1075 | set register 31 to 44332211. | ||
1076 | Success: OK | ||
1077 | Failure: E02, E05 */ | ||
1078 | { | ||
1079 | char *suffix; | ||
1080 | int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16); | ||
1081 | int status; | ||
1082 | #ifdef PROCESS_SUPPORT | ||
1083 | if (current_thread_g != executing_task) | ||
1084 | status = write_stack_register (current_thread_g, regno, suffix+1); | ||
1085 | else | ||
1086 | #endif | ||
1087 | status = write_register (regno, suffix+1); | ||
1088 | |||
1089 | switch (status) { | ||
1090 | case E02: | ||
1091 | /* Do not support read-only registers. */ | ||
1092 | gdb_cris_strcpy (remcomOutBuffer, error_message[E02]); | ||
1093 | break; | ||
1094 | case E05: | ||
1095 | /* Do not support non-existing registers. */ | ||
1096 | gdb_cris_strcpy (remcomOutBuffer, error_message[E05]); | ||
1097 | break; | ||
1098 | case E07: | ||
1099 | /* Do not support non-existing registers on the stack. */ | ||
1100 | gdb_cris_strcpy (remcomOutBuffer, error_message[E07]); | ||
1101 | break; | ||
1102 | default: | ||
1103 | /* Valid register number. */ | ||
1104 | gdb_cris_strcpy (remcomOutBuffer, "OK"); | ||
1105 | break; | ||
1106 | } | ||
1107 | } | ||
1108 | break; | ||
1109 | |||
1110 | case 'm': | ||
1111 | /* Read from memory. mAA..AA,LLLL | ||
1112 | AA..AA is the address and LLLL is the length. | ||
1113 | Success: XX..XX is the memory content. Can be fewer bytes than | ||
1114 | requested if only part of the data may be read. m6000120a,6c means | ||
1115 | retrieve 108 byte from base address 6000120a. | ||
1116 | Failure: void. */ | ||
1117 | { | ||
1118 | char *suffix; | ||
1119 | unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1], | ||
1120 | &suffix, 16); int length = gdb_cris_strtol(suffix+1, 0, 16); | ||
1121 | |||
1122 | mem2hex(remcomOutBuffer, addr, length); | ||
1123 | } | ||
1124 | break; | ||
1125 | |||
1126 | case 'X': | ||
1127 | /* Write to memory. XAA..AA,LLLL:XX..XX | ||
1128 | AA..AA is the start address, LLLL is the number of bytes, and | ||
1129 | XX..XX is the binary data. | ||
1130 | Success: OK | ||
1131 | Failure: void. */ | ||
1132 | case 'M': | ||
1133 | /* Write to memory. MAA..AA,LLLL:XX..XX | ||
1134 | AA..AA is the start address, LLLL is the number of bytes, and | ||
1135 | XX..XX is the hexadecimal data. | ||
1136 | Success: OK | ||
1137 | Failure: void. */ | ||
1138 | { | ||
1139 | char *lenptr; | ||
1140 | char *dataptr; | ||
1141 | unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1], | ||
1142 | &lenptr, 16); | ||
1143 | int length = gdb_cris_strtol(lenptr+1, &dataptr, 16); | ||
1144 | if (*lenptr == ',' && *dataptr == ':') { | ||
1145 | if (remcomInBuffer[0] == 'M') { | ||
1146 | hex2mem(addr, dataptr + 1, length); | ||
1147 | } | ||
1148 | else /* X */ { | ||
1149 | bin2mem(addr, dataptr + 1, length); | ||
1150 | } | ||
1151 | gdb_cris_strcpy (remcomOutBuffer, "OK"); | ||
1152 | } | ||
1153 | else { | ||
1154 | gdb_cris_strcpy (remcomOutBuffer, error_message[E06]); | ||
1155 | } | ||
1156 | } | ||
1157 | break; | ||
1158 | |||
1159 | case 'c': | ||
1160 | /* Continue execution. cAA..AA | ||
1161 | AA..AA is the address where execution is resumed. If AA..AA is | ||
1162 | omitted, resume at the present address. | ||
1163 | Success: return to the executing thread. | ||
1164 | Failure: will never know. */ | ||
1165 | if (remcomInBuffer[1] != '\0') { | ||
1166 | reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16); | ||
1167 | } | ||
1168 | enableDebugIRQ(); | ||
1169 | return; | ||
1170 | |||
1171 | case 's': | ||
1172 | /* Step. sAA..AA | ||
1173 | AA..AA is the address where execution is resumed. If AA..AA is | ||
1174 | omitted, resume at the present address. Success: return to the | ||
1175 | executing thread. Failure: will never know. | ||
1176 | |||
1177 | Should never be invoked. The single-step is implemented on | ||
1178 | the host side. If ever invoked, it is an internal error E04. */ | ||
1179 | gdb_cris_strcpy (remcomOutBuffer, error_message[E04]); | ||
1180 | putpacket (remcomOutBuffer); | ||
1181 | return; | ||
1182 | |||
1183 | case '?': | ||
1184 | /* The last signal which caused a stop. ? | ||
1185 | Success: SAA, where AA is the signal number. | ||
1186 | Failure: void. */ | ||
1187 | remcomOutBuffer[0] = 'S'; | ||
1188 | remcomOutBuffer[1] = highhex (sigval); | ||
1189 | remcomOutBuffer[2] = lowhex (sigval); | ||
1190 | remcomOutBuffer[3] = 0; | ||
1191 | break; | ||
1192 | |||
1193 | case 'D': | ||
1194 | /* Detach from host. D | ||
1195 | Success: OK, and return to the executing thread. | ||
1196 | Failure: will never know */ | ||
1197 | putpacket ("OK"); | ||
1198 | return; | ||
1199 | |||
1200 | case 'k': | ||
1201 | case 'r': | ||
1202 | /* kill request or reset request. | ||
1203 | Success: restart of target. | ||
1204 | Failure: will never know. */ | ||
1205 | kill_restart (); | ||
1206 | break; | ||
1207 | |||
1208 | case 'C': | ||
1209 | case 'S': | ||
1210 | case '!': | ||
1211 | case 'R': | ||
1212 | case 'd': | ||
1213 | /* Continue with signal sig. Csig;AA..AA | ||
1214 | Step with signal sig. Ssig;AA..AA | ||
1215 | Use the extended remote protocol. ! | ||
1216 | Restart the target system. R0 | ||
1217 | Toggle debug flag. d | ||
1218 | Search backwards. tAA:PP,MM | ||
1219 | Not supported: E04 */ | ||
1220 | gdb_cris_strcpy (remcomOutBuffer, error_message[E04]); | ||
1221 | break; | ||
1222 | #ifdef PROCESS_SUPPORT | ||
1223 | |||
1224 | case 'T': | ||
1225 | /* Thread alive. TXX | ||
1226 | Is thread XX alive? | ||
1227 | Success: OK, thread XX is alive. | ||
1228 | Failure: E03, thread XX is dead. */ | ||
1229 | { | ||
1230 | int thread_id = (int)gdb_cris_strtol (&remcomInBuffer[1], 0, 16); | ||
1231 | /* Cannot tell whether it is alive or not. */ | ||
1232 | if (thread_id >= 0 && thread_id < number_of_tasks) | ||
1233 | gdb_cris_strcpy (remcomOutBuffer, "OK"); | ||
1234 | } | ||
1235 | break; | ||
1236 | |||
1237 | case 'H': | ||
1238 | /* Set thread for subsequent operations: Hct | ||
1239 | c = 'c' for thread used in step and continue; | ||
1240 | t can be -1 for all threads. | ||
1241 | c = 'g' for thread used in other operations. | ||
1242 | t = 0 means pick any thread. | ||
1243 | Success: OK | ||
1244 | Failure: E01 */ | ||
1245 | { | ||
1246 | int thread_id = gdb_cris_strtol (&remcomInBuffer[2], 0, 16); | ||
1247 | if (remcomInBuffer[1] == 'c') { | ||
1248 | /* c = 'c' for thread used in step and continue */ | ||
1249 | /* Do not change current_thread_c here. It would create a mess in | ||
1250 | the scheduler. */ | ||
1251 | gdb_cris_strcpy (remcomOutBuffer, "OK"); | ||
1252 | } | ||
1253 | else if (remcomInBuffer[1] == 'g') { | ||
1254 | /* c = 'g' for thread used in other operations. | ||
1255 | t = 0 means pick any thread. Impossible since the scheduler does | ||
1256 | not allow that. */ | ||
1257 | if (thread_id >= 0 && thread_id < number_of_tasks) { | ||
1258 | current_thread_g = thread_id; | ||
1259 | gdb_cris_strcpy (remcomOutBuffer, "OK"); | ||
1260 | } | ||
1261 | else { | ||
1262 | /* Not expected - send an error message. */ | ||
1263 | gdb_cris_strcpy (remcomOutBuffer, error_message[E01]); | ||
1264 | } | ||
1265 | } | ||
1266 | else { | ||
1267 | /* Not expected - send an error message. */ | ||
1268 | gdb_cris_strcpy (remcomOutBuffer, error_message[E01]); | ||
1269 | } | ||
1270 | } | ||
1271 | break; | ||
1272 | |||
1273 | case 'q': | ||
1274 | case 'Q': | ||
1275 | /* Query of general interest. qXXXX | ||
1276 | Set general value XXXX. QXXXX=yyyy */ | ||
1277 | { | ||
1278 | int pos; | ||
1279 | int nextpos; | ||
1280 | int thread_id; | ||
1281 | |||
1282 | switch (remcomInBuffer[1]) { | ||
1283 | case 'C': | ||
1284 | /* Identify the remote current thread. */ | ||
1285 | gdb_cris_strcpy (&remcomOutBuffer[0], "QC"); | ||
1286 | remcomOutBuffer[2] = highhex (current_thread_c); | ||
1287 | remcomOutBuffer[3] = lowhex (current_thread_c); | ||
1288 | remcomOutBuffer[4] = '\0'; | ||
1289 | break; | ||
1290 | case 'L': | ||
1291 | gdb_cris_strcpy (&remcomOutBuffer[0], "QM"); | ||
1292 | /* Reply with number of threads. */ | ||
1293 | if (os_is_started()) { | ||
1294 | remcomOutBuffer[2] = highhex (number_of_tasks); | ||
1295 | remcomOutBuffer[3] = lowhex (number_of_tasks); | ||
1296 | } | ||
1297 | else { | ||
1298 | remcomOutBuffer[2] = highhex (0); | ||
1299 | remcomOutBuffer[3] = lowhex (1); | ||
1300 | } | ||
1301 | /* Done with the reply. */ | ||
1302 | remcomOutBuffer[4] = lowhex (1); | ||
1303 | pos = 5; | ||
1304 | /* Expects the argument thread id. */ | ||
1305 | for (; pos < (5 + HEXCHARS_IN_THREAD_ID); pos++) | ||
1306 | remcomOutBuffer[pos] = remcomInBuffer[pos]; | ||
1307 | /* Reply with the thread identifiers. */ | ||
1308 | if (os_is_started()) { | ||
1309 | /* Store the thread identifiers of all tasks. */ | ||
1310 | for (thread_id = 0; thread_id < number_of_tasks; thread_id++) { | ||
1311 | nextpos = pos + HEXCHARS_IN_THREAD_ID - 1; | ||
1312 | for (; pos < nextpos; pos ++) | ||
1313 | remcomOutBuffer[pos] = lowhex (0); | ||
1314 | remcomOutBuffer[pos++] = lowhex (thread_id); | ||
1315 | } | ||
1316 | } | ||
1317 | else { | ||
1318 | /* Store the thread identifier of the boot task. */ | ||
1319 | nextpos = pos + HEXCHARS_IN_THREAD_ID - 1; | ||
1320 | for (; pos < nextpos; pos ++) | ||
1321 | remcomOutBuffer[pos] = lowhex (0); | ||
1322 | remcomOutBuffer[pos++] = lowhex (current_thread_c); | ||
1323 | } | ||
1324 | remcomOutBuffer[pos] = '\0'; | ||
1325 | break; | ||
1326 | default: | ||
1327 | /* Not supported: "" */ | ||
1328 | /* Request information about section offsets: qOffsets. */ | ||
1329 | remcomOutBuffer[0] = 0; | ||
1330 | break; | ||
1331 | } | ||
1332 | } | ||
1333 | break; | ||
1334 | #endif /* PROCESS_SUPPORT */ | ||
1335 | |||
1336 | default: | ||
1337 | /* The stub should ignore other request and send an empty | ||
1338 | response ($#<checksum>). This way we can extend the protocol and GDB | ||
1339 | can tell whether the stub it is talking to uses the old or the new. */ | ||
1340 | remcomOutBuffer[0] = 0; | ||
1341 | break; | ||
1342 | } | ||
1343 | putpacket(remcomOutBuffer); | ||
1344 | } | ||
1345 | } | ||
1346 | |||
1347 | /* The jump is to the address 0x00000002. Performs a complete re-start | ||
1348 | from scratch. */ | ||
1349 | static void | ||
1350 | kill_restart () | ||
1351 | { | ||
1352 | __asm__ volatile ("jump 2"); | ||
1353 | } | ||
1354 | |||
1355 | /********************************** Breakpoint *******************************/ | ||
1356 | /* The hook for both a static (compiled) and a dynamic breakpoint set by GDB. | ||
1357 | An internal stack is used by the stub. The register image of the caller is | ||
1358 | stored in the structure register_image. | ||
1359 | Interactive communication with the host is handled by handle_exception and | ||
1360 | finally the register image is restored. */ | ||
1361 | |||
1362 | void kgdb_handle_breakpoint(void); | ||
1363 | |||
1364 | asm (" | ||
1365 | .global kgdb_handle_breakpoint | ||
1366 | kgdb_handle_breakpoint: | ||
1367 | ;; | ||
1368 | ;; Response to the break-instruction | ||
1369 | ;; | ||
1370 | ;; Create a register image of the caller | ||
1371 | ;; | ||
1372 | move $dccr,[reg+0x5E] ; Save the flags in DCCR before disable interrupts | ||
1373 | di ; Disable interrupts | ||
1374 | move.d $r0,[reg] ; Save R0 | ||
1375 | move.d $r1,[reg+0x04] ; Save R1 | ||
1376 | move.d $r2,[reg+0x08] ; Save R2 | ||
1377 | move.d $r3,[reg+0x0C] ; Save R3 | ||
1378 | move.d $r4,[reg+0x10] ; Save R4 | ||
1379 | move.d $r5,[reg+0x14] ; Save R5 | ||
1380 | move.d $r6,[reg+0x18] ; Save R6 | ||
1381 | move.d $r7,[reg+0x1C] ; Save R7 | ||
1382 | move.d $r8,[reg+0x20] ; Save R8 | ||
1383 | move.d $r9,[reg+0x24] ; Save R9 | ||
1384 | move.d $r10,[reg+0x28] ; Save R10 | ||
1385 | move.d $r11,[reg+0x2C] ; Save R11 | ||
1386 | move.d $r12,[reg+0x30] ; Save R12 | ||
1387 | move.d $r13,[reg+0x34] ; Save R13 | ||
1388 | move.d $sp,[reg+0x38] ; Save SP (R14) | ||
1389 | ;; Due to the old assembler-versions BRP might not be recognized | ||
1390 | .word 0xE670 ; move brp,$r0 | ||
1391 | subq 2,$r0 ; Set to address of previous instruction. | ||
1392 | move.d $r0,[reg+0x3c] ; Save the address in PC (R15) | ||
1393 | clear.b [reg+0x40] ; Clear P0 | ||
1394 | move $vr,[reg+0x41] ; Save special register P1 | ||
1395 | clear.w [reg+0x42] ; Clear P4 | ||
1396 | move $ccr,[reg+0x44] ; Save special register CCR | ||
1397 | move $mof,[reg+0x46] ; P7 | ||
1398 | clear.d [reg+0x4A] ; Clear P8 | ||
1399 | move $ibr,[reg+0x4E] ; P9, | ||
1400 | move $irp,[reg+0x52] ; P10, | ||
1401 | move $srp,[reg+0x56] ; P11, | ||
1402 | move $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR | ||
1403 | ; P13, register DCCR already saved | ||
1404 | ;; Due to the old assembler-versions BRP might not be recognized | ||
1405 | .word 0xE670 ; move brp,r0 | ||
1406 | ;; Static (compiled) breakpoints must return to the next instruction in order | ||
1407 | ;; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction | ||
1408 | ;; in order to execute it when execution is continued. | ||
1409 | test.b [is_dyn_brkp] ; Is this a dynamic breakpoint? | ||
1410 | beq is_static ; No, a static breakpoint | ||
1411 | nop | ||
1412 | subq 2,$r0 ; rerun the instruction the break replaced | ||
1413 | is_static: | ||
1414 | moveq 1,$r1 | ||
1415 | move.b $r1,[is_dyn_brkp] ; Set the state variable to dynamic breakpoint | ||
1416 | move.d $r0,[reg+0x62] ; Save the return address in BRP | ||
1417 | move $usp,[reg+0x66] ; USP | ||
1418 | ;; | ||
1419 | ;; Handle the communication | ||
1420 | ;; | ||
1421 | move.d internal_stack+1020,$sp ; Use the internal stack which grows upward | ||
1422 | moveq 5,$r10 ; SIGTRAP | ||
1423 | jsr handle_exception ; Interactive routine | ||
1424 | ;; | ||
1425 | ;; Return to the caller | ||
1426 | ;; | ||
1427 | move.d [reg],$r0 ; Restore R0 | ||
1428 | move.d [reg+0x04],$r1 ; Restore R1 | ||
1429 | move.d [reg+0x08],$r2 ; Restore R2 | ||
1430 | move.d [reg+0x0C],$r3 ; Restore R3 | ||
1431 | move.d [reg+0x10],$r4 ; Restore R4 | ||
1432 | move.d [reg+0x14],$r5 ; Restore R5 | ||
1433 | move.d [reg+0x18],$r6 ; Restore R6 | ||
1434 | move.d [reg+0x1C],$r7 ; Restore R7 | ||
1435 | move.d [reg+0x20],$r8 ; Restore R8 | ||
1436 | move.d [reg+0x24],$r9 ; Restore R9 | ||
1437 | move.d [reg+0x28],$r10 ; Restore R10 | ||
1438 | move.d [reg+0x2C],$r11 ; Restore R11 | ||
1439 | move.d [reg+0x30],$r12 ; Restore R12 | ||
1440 | move.d [reg+0x34],$r13 ; Restore R13 | ||
1441 | ;; | ||
1442 | ;; FIXME: Which registers should be restored? | ||
1443 | ;; | ||
1444 | move.d [reg+0x38],$sp ; Restore SP (R14) | ||
1445 | move [reg+0x56],$srp ; Restore the subroutine return pointer. | ||
1446 | move [reg+0x5E],$dccr ; Restore DCCR | ||
1447 | move [reg+0x66],$usp ; Restore USP | ||
1448 | jump [reg+0x62] ; A jump to the content in register BRP works. | ||
1449 | nop ; | ||
1450 | "); | ||
1451 | |||
1452 | /* The hook for an interrupt generated by GDB. An internal stack is used | ||
1453 | by the stub. The register image of the caller is stored in the structure | ||
1454 | register_image. Interactive communication with the host is handled by | ||
1455 | handle_exception and finally the register image is restored. Due to the | ||
1456 | old assembler which does not recognise the break instruction and the | ||
1457 | breakpoint return pointer hex-code is used. */ | ||
1458 | |||
1459 | void kgdb_handle_serial(void); | ||
1460 | |||
1461 | asm (" | ||
1462 | .global kgdb_handle_serial | ||
1463 | kgdb_handle_serial: | ||
1464 | ;; | ||
1465 | ;; Response to a serial interrupt | ||
1466 | ;; | ||
1467 | |||
1468 | move $dccr,[reg+0x5E] ; Save the flags in DCCR | ||
1469 | di ; Disable interrupts | ||
1470 | move.d $r0,[reg] ; Save R0 | ||
1471 | move.d $r1,[reg+0x04] ; Save R1 | ||
1472 | move.d $r2,[reg+0x08] ; Save R2 | ||
1473 | move.d $r3,[reg+0x0C] ; Save R3 | ||
1474 | move.d $r4,[reg+0x10] ; Save R4 | ||
1475 | move.d $r5,[reg+0x14] ; Save R5 | ||
1476 | move.d $r6,[reg+0x18] ; Save R6 | ||
1477 | move.d $r7,[reg+0x1C] ; Save R7 | ||
1478 | move.d $r8,[reg+0x20] ; Save R8 | ||
1479 | move.d $r9,[reg+0x24] ; Save R9 | ||
1480 | move.d $r10,[reg+0x28] ; Save R10 | ||
1481 | move.d $r11,[reg+0x2C] ; Save R11 | ||
1482 | move.d $r12,[reg+0x30] ; Save R12 | ||
1483 | move.d $r13,[reg+0x34] ; Save R13 | ||
1484 | move.d $sp,[reg+0x38] ; Save SP (R14) | ||
1485 | move $irp,[reg+0x3c] ; Save the address in PC (R15) | ||
1486 | clear.b [reg+0x40] ; Clear P0 | ||
1487 | move $vr,[reg+0x41] ; Save special register P1, | ||
1488 | clear.w [reg+0x42] ; Clear P4 | ||
1489 | move $ccr,[reg+0x44] ; Save special register CCR | ||
1490 | move $mof,[reg+0x46] ; P7 | ||
1491 | clear.d [reg+0x4A] ; Clear P8 | ||
1492 | move $ibr,[reg+0x4E] ; P9, | ||
1493 | move $irp,[reg+0x52] ; P10, | ||
1494 | move $srp,[reg+0x56] ; P11, | ||
1495 | move $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR | ||
1496 | ; P13, register DCCR already saved | ||
1497 | ;; Due to the old assembler-versions BRP might not be recognized | ||
1498 | .word 0xE670 ; move brp,r0 | ||
1499 | move.d $r0,[reg+0x62] ; Save the return address in BRP | ||
1500 | move $usp,[reg+0x66] ; USP | ||
1501 | |||
1502 | ;; get the serial character (from debugport.c) and check if it is a ctrl-c | ||
1503 | |||
1504 | jsr getDebugChar | ||
1505 | cmp.b 3, $r10 | ||
1506 | bne goback | ||
1507 | nop | ||
1508 | |||
1509 | ;; | ||
1510 | ;; Handle the communication | ||
1511 | ;; | ||
1512 | move.d internal_stack+1020,$sp ; Use the internal stack | ||
1513 | moveq 2,$r10 ; SIGINT | ||
1514 | jsr handle_exception ; Interactive routine | ||
1515 | |||
1516 | goback: | ||
1517 | ;; | ||
1518 | ;; Return to the caller | ||
1519 | ;; | ||
1520 | move.d [reg],$r0 ; Restore R0 | ||
1521 | move.d [reg+0x04],$r1 ; Restore R1 | ||
1522 | move.d [reg+0x08],$r2 ; Restore R2 | ||
1523 | move.d [reg+0x0C],$r3 ; Restore R3 | ||
1524 | move.d [reg+0x10],$r4 ; Restore R4 | ||
1525 | move.d [reg+0x14],$r5 ; Restore R5 | ||
1526 | move.d [reg+0x18],$r6 ; Restore R6 | ||
1527 | move.d [reg+0x1C],$r7 ; Restore R7 | ||
1528 | move.d [reg+0x20],$r8 ; Restore R8 | ||
1529 | move.d [reg+0x24],$r9 ; Restore R9 | ||
1530 | move.d [reg+0x28],$r10 ; Restore R10 | ||
1531 | move.d [reg+0x2C],$r11 ; Restore R11 | ||
1532 | move.d [reg+0x30],$r12 ; Restore R12 | ||
1533 | move.d [reg+0x34],$r13 ; Restore R13 | ||
1534 | ;; | ||
1535 | ;; FIXME: Which registers should be restored? | ||
1536 | ;; | ||
1537 | move.d [reg+0x38],$sp ; Restore SP (R14) | ||
1538 | move [reg+0x56],$srp ; Restore the subroutine return pointer. | ||
1539 | move [reg+0x5E],$dccr ; Restore DCCR | ||
1540 | move [reg+0x66],$usp ; Restore USP | ||
1541 | reti ; Return from the interrupt routine | ||
1542 | nop | ||
1543 | "); | ||
1544 | |||
1545 | /* Use this static breakpoint in the start-up only. */ | ||
1546 | |||
1547 | void | ||
1548 | breakpoint(void) | ||
1549 | { | ||
1550 | kgdb_started = 1; | ||
1551 | is_dyn_brkp = 0; /* This is a static, not a dynamic breakpoint. */ | ||
1552 | __asm__ volatile ("break 8"); /* Jump to handle_breakpoint. */ | ||
1553 | } | ||
1554 | |||
1555 | /* initialize kgdb. doesn't break into the debugger, but sets up irq and ports */ | ||
1556 | |||
1557 | void | ||
1558 | kgdb_init(void) | ||
1559 | { | ||
1560 | /* could initialize debug port as well but it's done in head.S already... */ | ||
1561 | |||
1562 | /* breakpoint handler is now set in irq.c */ | ||
1563 | set_int_vector(8, kgdb_handle_serial); | ||
1564 | |||
1565 | enableDebugIRQ(); | ||
1566 | } | ||
1567 | |||
1568 | /****************************** End of file **********************************/ | ||
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c new file mode 100644 index 000000000000..87ff37790827 --- /dev/null +++ b/arch/cris/arch-v10/kernel/process.c | |||
@@ -0,0 +1,270 @@ | |||
1 | /* $Id: process.c,v 1.9 2004/10/19 13:07:37 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/kernel/process.c | ||
4 | * | ||
5 | * Copyright (C) 1995 Linus Torvalds | ||
6 | * Copyright (C) 2000-2002 Axis Communications AB | ||
7 | * | ||
8 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
9 | * Mikael Starvik (starvik@axis.com) | ||
10 | * | ||
11 | * This file handles the architecture-dependent parts of process handling.. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <asm/arch/svinto.h> | ||
20 | #include <linux/init.h> | ||
21 | |||
22 | #ifdef CONFIG_ETRAX_GPIO | ||
23 | void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */ | ||
24 | #endif | ||
25 | |||
26 | /* | ||
27 | * We use this if we don't have any better | ||
28 | * idle routine.. | ||
29 | */ | ||
30 | void default_idle(void) | ||
31 | { | ||
32 | #ifdef CONFIG_ETRAX_GPIO | ||
33 | etrax_gpio_wake_up_check(); | ||
34 | #endif | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * Free current thread data structures etc.. | ||
39 | */ | ||
40 | |||
41 | void exit_thread(void) | ||
42 | { | ||
43 | /* Nothing needs to be done. */ | ||
44 | } | ||
45 | |||
46 | /* if the watchdog is enabled, we can simply disable interrupts and go | ||
47 | * into an eternal loop, and the watchdog will reset the CPU after 0.1s | ||
48 | * if on the other hand the watchdog wasn't enabled, we just enable it and wait | ||
49 | */ | ||
50 | |||
51 | void hard_reset_now (void) | ||
52 | { | ||
53 | /* | ||
54 | * Don't declare this variable elsewhere. We don't want any other | ||
55 | * code to know about it than the watchdog handler in entry.S and | ||
56 | * this code, implementing hard reset through the watchdog. | ||
57 | */ | ||
58 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
59 | extern int cause_of_death; | ||
60 | #endif | ||
61 | |||
62 | printk("*** HARD RESET ***\n"); | ||
63 | local_irq_disable(); | ||
64 | |||
65 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
66 | cause_of_death = 0xbedead; | ||
67 | #else | ||
68 | /* Since we dont plan to keep on reseting the watchdog, | ||
69 | the key can be arbitrary hence three */ | ||
70 | *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, 3) | | ||
71 | IO_STATE(R_WATCHDOG, enable, start); | ||
72 | #endif | ||
73 | |||
74 | while(1) /* waiting for RETRIBUTION! */ ; | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * Return saved PC of a blocked thread. | ||
79 | */ | ||
80 | unsigned long thread_saved_pc(struct task_struct *t) | ||
81 | { | ||
82 | return (unsigned long)user_regs(t->thread_info)->irp; | ||
83 | } | ||
84 | |||
85 | static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg) | ||
86 | { | ||
87 | fn(arg); | ||
88 | do_exit(-1); /* Should never be called, return bad exit value */ | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Create a kernel thread | ||
93 | */ | ||
94 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
95 | { | ||
96 | struct pt_regs regs; | ||
97 | |||
98 | memset(®s, 0, sizeof(regs)); | ||
99 | |||
100 | /* Don't use r10 since that is set to 0 in copy_thread */ | ||
101 | regs.r11 = (unsigned long)fn; | ||
102 | regs.r12 = (unsigned long)arg; | ||
103 | regs.irp = (unsigned long)kernel_thread_helper; | ||
104 | |||
105 | /* Ok, create the new process.. */ | ||
106 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
107 | } | ||
108 | |||
109 | /* setup the child's kernel stack with a pt_regs and switch_stack on it. | ||
110 | * it will be un-nested during _resume and _ret_from_sys_call when the | ||
111 | * new thread is scheduled. | ||
112 | * | ||
113 | * also setup the thread switching structure which is used to keep | ||
114 | * thread-specific data during _resumes. | ||
115 | * | ||
116 | */ | ||
117 | asmlinkage void ret_from_fork(void); | ||
118 | |||
119 | int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, | ||
120 | unsigned long unused, | ||
121 | struct task_struct *p, struct pt_regs *regs) | ||
122 | { | ||
123 | struct pt_regs * childregs; | ||
124 | struct switch_stack *swstack; | ||
125 | |||
126 | /* put the pt_regs structure at the end of the new kernel stack page and fix it up | ||
127 | * remember that the task_struct doubles as the kernel stack for the task | ||
128 | */ | ||
129 | |||
130 | childregs = user_regs(p->thread_info); | ||
131 | |||
132 | *childregs = *regs; /* struct copy of pt_regs */ | ||
133 | |||
134 | p->set_child_tid = p->clear_child_tid = NULL; | ||
135 | |||
136 | childregs->r10 = 0; /* child returns 0 after a fork/clone */ | ||
137 | |||
138 | /* put the switch stack right below the pt_regs */ | ||
139 | |||
140 | swstack = ((struct switch_stack *)childregs) - 1; | ||
141 | |||
142 | swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ | ||
143 | |||
144 | /* we want to return into ret_from_sys_call after the _resume */ | ||
145 | |||
146 | swstack->return_ip = (unsigned long) ret_from_fork; /* Will call ret_from_sys_call */ | ||
147 | |||
148 | /* fix the user-mode stackpointer */ | ||
149 | |||
150 | p->thread.usp = usp; | ||
151 | |||
152 | /* and the kernel-mode one */ | ||
153 | |||
154 | p->thread.ksp = (unsigned long) swstack; | ||
155 | |||
156 | #ifdef DEBUG | ||
157 | printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs); | ||
158 | show_registers(childregs); | ||
159 | #endif | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * Be aware of the "magic" 7th argument in the four system-calls below. | ||
166 | * They need the latest stackframe, which is put as the 7th argument by | ||
167 | * entry.S. The previous arguments are dummies or actually used, but need | ||
168 | * to be defined to reach the 7th argument. | ||
169 | * | ||
170 | * N.B.: Another method to get the stackframe is to use current_regs(). But | ||
171 | * it returns the latest stack-frame stacked when going from _user mode_ and | ||
172 | * some of these (at least sys_clone) are called from kernel-mode sometimes | ||
173 | * (for example during kernel_thread, above) and thus cannot use it. Thus, | ||
174 | * to be sure not to get any surprises, we use the method for the other calls | ||
175 | * as well. | ||
176 | */ | ||
177 | |||
178 | asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, | ||
179 | struct pt_regs *regs) | ||
180 | { | ||
181 | return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
182 | } | ||
183 | |||
184 | /* if newusp is 0, we just grab the old usp */ | ||
185 | /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ | ||
186 | asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, | ||
187 | int* parent_tid, int* child_tid, long mof, long srp, | ||
188 | struct pt_regs *regs) | ||
189 | { | ||
190 | if (!newusp) | ||
191 | newusp = rdusp(); | ||
192 | return do_fork(flags, newusp, regs, 0, parent_tid, child_tid); | ||
193 | } | ||
194 | |||
195 | /* vfork is a system call in i386 because of register-pressure - maybe | ||
196 | * we can remove it and handle it in libc but we put it here until then. | ||
197 | */ | ||
198 | |||
199 | asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, | ||
200 | struct pt_regs *regs) | ||
201 | { | ||
202 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * sys_execve() executes a new program. | ||
207 | */ | ||
208 | asmlinkage int sys_execve(const char *fname, char **argv, char **envp, | ||
209 | long r13, long mof, long srp, | ||
210 | struct pt_regs *regs) | ||
211 | { | ||
212 | int error; | ||
213 | char *filename; | ||
214 | |||
215 | filename = getname(fname); | ||
216 | error = PTR_ERR(filename); | ||
217 | |||
218 | if (IS_ERR(filename)) | ||
219 | goto out; | ||
220 | error = do_execve(filename, argv, envp, regs); | ||
221 | putname(filename); | ||
222 | out: | ||
223 | return error; | ||
224 | } | ||
225 | |||
226 | unsigned long get_wchan(struct task_struct *p) | ||
227 | { | ||
228 | #if 0 | ||
229 | /* YURGH. TODO. */ | ||
230 | |||
231 | unsigned long ebp, esp, eip; | ||
232 | unsigned long stack_page; | ||
233 | int count = 0; | ||
234 | if (!p || p == current || p->state == TASK_RUNNING) | ||
235 | return 0; | ||
236 | stack_page = (unsigned long)p; | ||
237 | esp = p->thread.esp; | ||
238 | if (!stack_page || esp < stack_page || esp > 8188+stack_page) | ||
239 | return 0; | ||
240 | /* include/asm-i386/system.h:switch_to() pushes ebp last. */ | ||
241 | ebp = *(unsigned long *) esp; | ||
242 | do { | ||
243 | if (ebp < stack_page || ebp > 8184+stack_page) | ||
244 | return 0; | ||
245 | eip = *(unsigned long *) (ebp+4); | ||
246 | if (!in_sched_functions(eip)) | ||
247 | return eip; | ||
248 | ebp = *(unsigned long *) ebp; | ||
249 | } while (count++ < 16); | ||
250 | #endif | ||
251 | return 0; | ||
252 | } | ||
253 | #undef last_sched | ||
254 | #undef first_sched | ||
255 | |||
256 | void show_regs(struct pt_regs * regs) | ||
257 | { | ||
258 | unsigned long usp = rdusp(); | ||
259 | printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", | ||
260 | regs->irp, regs->srp, regs->dccr, usp, regs->mof ); | ||
261 | printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", | ||
262 | regs->r0, regs->r1, regs->r2, regs->r3); | ||
263 | printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", | ||
264 | regs->r4, regs->r5, regs->r6, regs->r7); | ||
265 | printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", | ||
266 | regs->r8, regs->r9, regs->r10, regs->r11); | ||
267 | printk("r12: %08lx r13: %08lx oR10: %08lx\n", | ||
268 | regs->r12, regs->r13, regs->orig_r10); | ||
269 | } | ||
270 | |||
diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c new file mode 100644 index 000000000000..da15db8ae482 --- /dev/null +++ b/arch/cris/arch-v10/kernel/ptrace.c | |||
@@ -0,0 +1,314 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000-2003, Axis Communications AB. | ||
3 | */ | ||
4 | |||
5 | #include <linux/kernel.h> | ||
6 | #include <linux/sched.h> | ||
7 | #include <linux/mm.h> | ||
8 | #include <linux/smp.h> | ||
9 | #include <linux/smp_lock.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/ptrace.h> | ||
12 | #include <linux/user.h> | ||
13 | |||
14 | #include <asm/uaccess.h> | ||
15 | #include <asm/page.h> | ||
16 | #include <asm/pgtable.h> | ||
17 | #include <asm/system.h> | ||
18 | #include <asm/processor.h> | ||
19 | |||
20 | /* | ||
21 | * Determines which bits in DCCR the user has access to. | ||
22 | * 1 = access, 0 = no access. | ||
23 | */ | ||
24 | #define DCCR_MASK 0x0000001f /* XNZVC */ | ||
25 | |||
26 | /* | ||
27 | * Get contents of register REGNO in task TASK. | ||
28 | */ | ||
29 | inline long get_reg(struct task_struct *task, unsigned int regno) | ||
30 | { | ||
31 | /* USP is a special case, it's not in the pt_regs struct but | ||
32 | * in the tasks thread struct | ||
33 | */ | ||
34 | |||
35 | if (regno == PT_USP) | ||
36 | return task->thread.usp; | ||
37 | else if (regno < PT_MAX) | ||
38 | return ((unsigned long *)user_regs(task->thread_info))[regno]; | ||
39 | else | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | /* | ||
44 | * Write contents of register REGNO in task TASK. | ||
45 | */ | ||
46 | inline int put_reg(struct task_struct *task, unsigned int regno, | ||
47 | unsigned long data) | ||
48 | { | ||
49 | if (regno == PT_USP) | ||
50 | task->thread.usp = data; | ||
51 | else if (regno < PT_MAX) | ||
52 | ((unsigned long *)user_regs(task->thread_info))[regno] = data; | ||
53 | else | ||
54 | return -1; | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | /* | ||
59 | * Called by kernel/ptrace.c when detaching. | ||
60 | * | ||
61 | * Make sure the single step bit is not set. | ||
62 | */ | ||
63 | void | ||
64 | ptrace_disable(struct task_struct *child) | ||
65 | { | ||
66 | /* Todo - pending singlesteps? */ | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * Note that this implementation of ptrace behaves differently from vanilla | ||
71 | * ptrace. Contrary to what the man page says, in the PTRACE_PEEKTEXT, | ||
72 | * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not | ||
73 | * ignored. Instead, the data variable is expected to point at a location | ||
74 | * (in user space) where the result of the ptrace call is written (instead of | ||
75 | * being returned). | ||
76 | */ | ||
77 | asmlinkage int | ||
78 | sys_ptrace(long request, long pid, long addr, long data) | ||
79 | { | ||
80 | struct task_struct *child; | ||
81 | int ret; | ||
82 | unsigned long __user *datap = (unsigned long __user *)data; | ||
83 | |||
84 | lock_kernel(); | ||
85 | ret = -EPERM; | ||
86 | |||
87 | if (request == PTRACE_TRACEME) { | ||
88 | if (current->ptrace & PT_PTRACED) | ||
89 | goto out; | ||
90 | |||
91 | current->ptrace |= PT_PTRACED; | ||
92 | ret = 0; | ||
93 | goto out; | ||
94 | } | ||
95 | |||
96 | ret = -ESRCH; | ||
97 | read_lock(&tasklist_lock); | ||
98 | child = find_task_by_pid(pid); | ||
99 | |||
100 | if (child) | ||
101 | get_task_struct(child); | ||
102 | |||
103 | read_unlock(&tasklist_lock); | ||
104 | |||
105 | if (!child) | ||
106 | goto out; | ||
107 | |||
108 | ret = -EPERM; | ||
109 | |||
110 | if (pid == 1) /* Leave the init process alone! */ | ||
111 | goto out_tsk; | ||
112 | |||
113 | if (request == PTRACE_ATTACH) { | ||
114 | ret = ptrace_attach(child); | ||
115 | goto out_tsk; | ||
116 | } | ||
117 | |||
118 | ret = ptrace_check_attach(child, request == PTRACE_KILL); | ||
119 | if (ret < 0) | ||
120 | goto out_tsk; | ||
121 | |||
122 | switch (request) { | ||
123 | /* Read word at location address. */ | ||
124 | case PTRACE_PEEKTEXT: | ||
125 | case PTRACE_PEEKDATA: { | ||
126 | unsigned long tmp; | ||
127 | int copied; | ||
128 | |||
129 | copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); | ||
130 | ret = -EIO; | ||
131 | |||
132 | if (copied != sizeof(tmp)) | ||
133 | break; | ||
134 | |||
135 | ret = put_user(tmp,datap); | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | /* Read the word at location address in the USER area. */ | ||
140 | case PTRACE_PEEKUSR: { | ||
141 | unsigned long tmp; | ||
142 | |||
143 | ret = -EIO; | ||
144 | if ((addr & 3) || addr < 0 || addr > PT_MAX << 2) | ||
145 | break; | ||
146 | |||
147 | tmp = get_reg(child, addr >> 2); | ||
148 | ret = put_user(tmp, datap); | ||
149 | break; | ||
150 | } | ||
151 | |||
152 | /* Write the word at location address. */ | ||
153 | case PTRACE_POKETEXT: | ||
154 | case PTRACE_POKEDATA: | ||
155 | ret = 0; | ||
156 | |||
157 | if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) | ||
158 | break; | ||
159 | |||
160 | ret = -EIO; | ||
161 | break; | ||
162 | |||
163 | /* Write the word at location address in the USER area. */ | ||
164 | case PTRACE_POKEUSR: | ||
165 | ret = -EIO; | ||
166 | if ((addr & 3) || addr < 0 || addr > PT_MAX << 2) | ||
167 | break; | ||
168 | |||
169 | addr >>= 2; | ||
170 | |||
171 | if (addr == PT_DCCR) { | ||
172 | /* don't allow the tracing process to change stuff like | ||
173 | * interrupt enable, kernel/user bit, dma enables etc. | ||
174 | */ | ||
175 | data &= DCCR_MASK; | ||
176 | data |= get_reg(child, PT_DCCR) & ~DCCR_MASK; | ||
177 | } | ||
178 | if (put_reg(child, addr, data)) | ||
179 | break; | ||
180 | ret = 0; | ||
181 | break; | ||
182 | |||
183 | case PTRACE_SYSCALL: | ||
184 | case PTRACE_CONT: | ||
185 | ret = -EIO; | ||
186 | |||
187 | if ((unsigned long) data > _NSIG) | ||
188 | break; | ||
189 | |||
190 | if (request == PTRACE_SYSCALL) { | ||
191 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
192 | } | ||
193 | else { | ||
194 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
195 | } | ||
196 | |||
197 | child->exit_code = data; | ||
198 | |||
199 | /* TODO: make sure any pending breakpoint is killed */ | ||
200 | wake_up_process(child); | ||
201 | ret = 0; | ||
202 | |||
203 | break; | ||
204 | |||
205 | /* Make the child exit by sending it a sigkill. */ | ||
206 | case PTRACE_KILL: | ||
207 | ret = 0; | ||
208 | |||
209 | if (child->state == TASK_ZOMBIE) | ||
210 | break; | ||
211 | |||
212 | child->exit_code = SIGKILL; | ||
213 | |||
214 | /* TODO: make sure any pending breakpoint is killed */ | ||
215 | wake_up_process(child); | ||
216 | break; | ||
217 | |||
218 | /* Set the trap flag. */ | ||
219 | case PTRACE_SINGLESTEP: | ||
220 | ret = -EIO; | ||
221 | |||
222 | if ((unsigned long) data > _NSIG) | ||
223 | break; | ||
224 | |||
225 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
226 | |||
227 | /* TODO: set some clever breakpoint mechanism... */ | ||
228 | |||
229 | child->exit_code = data; | ||
230 | wake_up_process(child); | ||
231 | ret = 0; | ||
232 | break; | ||
233 | |||
234 | case PTRACE_DETACH: | ||
235 | ret = ptrace_detach(child, data); | ||
236 | break; | ||
237 | |||
238 | /* Get all GP registers from the child. */ | ||
239 | case PTRACE_GETREGS: { | ||
240 | int i; | ||
241 | unsigned long tmp; | ||
242 | |||
243 | for (i = 0; i <= PT_MAX; i++) { | ||
244 | tmp = get_reg(child, i); | ||
245 | |||
246 | if (put_user(tmp, datap)) { | ||
247 | ret = -EFAULT; | ||
248 | goto out_tsk; | ||
249 | } | ||
250 | |||
251 | data += sizeof(long); | ||
252 | } | ||
253 | |||
254 | ret = 0; | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | /* Set all GP registers in the child. */ | ||
259 | case PTRACE_SETREGS: { | ||
260 | int i; | ||
261 | unsigned long tmp; | ||
262 | |||
263 | for (i = 0; i <= PT_MAX; i++) { | ||
264 | if (get_user(tmp, datap)) { | ||
265 | ret = -EFAULT; | ||
266 | goto out_tsk; | ||
267 | } | ||
268 | |||
269 | if (i == PT_DCCR) { | ||
270 | tmp &= DCCR_MASK; | ||
271 | tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK; | ||
272 | } | ||
273 | |||
274 | put_reg(child, i, tmp); | ||
275 | data += sizeof(long); | ||
276 | } | ||
277 | |||
278 | ret = 0; | ||
279 | break; | ||
280 | } | ||
281 | |||
282 | default: | ||
283 | ret = ptrace_request(child, request, addr, data); | ||
284 | break; | ||
285 | } | ||
286 | out_tsk: | ||
287 | put_task_struct(child); | ||
288 | out: | ||
289 | unlock_kernel(); | ||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | void do_syscall_trace(void) | ||
294 | { | ||
295 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | ||
296 | return; | ||
297 | |||
298 | if (!(current->ptrace & PT_PTRACED)) | ||
299 | return; | ||
300 | |||
301 | /* the 0x80 provides a way for the tracing parent to distinguish | ||
302 | between a syscall stop and SIGTRAP delivery */ | ||
303 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
304 | ? 0x80 : 0)); | ||
305 | |||
306 | /* | ||
307 | * This isn't the same as continuing with a signal, but it will do for | ||
308 | * normal use. | ||
309 | */ | ||
310 | if (current->exit_code) { | ||
311 | send_sig(current->exit_code, current, 1); | ||
312 | current->exit_code = 0; | ||
313 | } | ||
314 | } | ||
diff --git a/arch/cris/arch-v10/kernel/setup.c b/arch/cris/arch-v10/kernel/setup.c new file mode 100644 index 000000000000..b668d7fb68ee --- /dev/null +++ b/arch/cris/arch-v10/kernel/setup.c | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * | ||
3 | * linux/arch/cris/arch-v10/kernel/setup.c | ||
4 | * | ||
5 | * Copyright (C) 1995 Linus Torvalds | ||
6 | * Copyright (c) 2001-2002 Axis Communications AB | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This file handles the architecture-dependent parts of initialization | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/seq_file.h> | ||
15 | #include <linux/proc_fs.h> | ||
16 | #include <linux/delay.h> | ||
17 | |||
18 | #ifdef CONFIG_PROC_FS | ||
19 | #define HAS_FPU 0x0001 | ||
20 | #define HAS_MMU 0x0002 | ||
21 | #define HAS_ETHERNET100 0x0004 | ||
22 | #define HAS_TOKENRING 0x0008 | ||
23 | #define HAS_SCSI 0x0010 | ||
24 | #define HAS_ATA 0x0020 | ||
25 | #define HAS_USB 0x0040 | ||
26 | #define HAS_IRQ_BUG 0x0080 | ||
27 | #define HAS_MMU_BUG 0x0100 | ||
28 | |||
29 | static struct cpu_info { | ||
30 | char *model; | ||
31 | unsigned short cache; | ||
32 | unsigned short flags; | ||
33 | } cpu_info[] = { | ||
34 | /* The first four models will never ever run this code and are | ||
35 | only here for display. */ | ||
36 | { "ETRAX 1", 0, 0 }, | ||
37 | { "ETRAX 2", 0, 0 }, | ||
38 | { "ETRAX 3", 0, HAS_TOKENRING }, | ||
39 | { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI }, | ||
40 | { "Unknown", 0, 0 }, | ||
41 | { "Unknown", 0, 0 }, | ||
42 | { "Unknown", 0, 0 }, | ||
43 | { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, | ||
44 | { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, | ||
45 | { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, | ||
46 | { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG }, | ||
47 | { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, | ||
48 | { "Unknown", 0, 0 } /* This entry MUST be the last */ | ||
49 | }; | ||
50 | |||
51 | int show_cpuinfo(struct seq_file *m, void *v) | ||
52 | { | ||
53 | unsigned long revision; | ||
54 | struct cpu_info *info; | ||
55 | |||
56 | /* read the version register in the CPU and print some stuff */ | ||
57 | |||
58 | revision = rdvr(); | ||
59 | |||
60 | if (revision >= sizeof cpu_info/sizeof *cpu_info) | ||
61 | info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1]; | ||
62 | else | ||
63 | info = &cpu_info[revision]; | ||
64 | |||
65 | return seq_printf(m, | ||
66 | "processor\t: 0\n" | ||
67 | "cpu\t\t: CRIS\n" | ||
68 | "cpu revision\t: %lu\n" | ||
69 | "cpu model\t: %s\n" | ||
70 | "cache size\t: %d kB\n" | ||
71 | "fpu\t\t: %s\n" | ||
72 | "mmu\t\t: %s\n" | ||
73 | "mmu DMA bug\t: %s\n" | ||
74 | "ethernet\t: %s Mbps\n" | ||
75 | "token ring\t: %s\n" | ||
76 | "scsi\t\t: %s\n" | ||
77 | "ata\t\t: %s\n" | ||
78 | "usb\t\t: %s\n" | ||
79 | "bogomips\t: %lu.%02lu\n", | ||
80 | |||
81 | revision, | ||
82 | info->model, | ||
83 | info->cache, | ||
84 | info->flags & HAS_FPU ? "yes" : "no", | ||
85 | info->flags & HAS_MMU ? "yes" : "no", | ||
86 | info->flags & HAS_MMU_BUG ? "yes" : "no", | ||
87 | info->flags & HAS_ETHERNET100 ? "10/100" : "10", | ||
88 | info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no", | ||
89 | info->flags & HAS_SCSI ? "yes" : "no", | ||
90 | info->flags & HAS_ATA ? "yes" : "no", | ||
91 | info->flags & HAS_USB ? "yes" : "no", | ||
92 | (loops_per_jiffy * HZ + 500) / 500000, | ||
93 | ((loops_per_jiffy * HZ + 500) / 5000) % 100); | ||
94 | } | ||
95 | |||
96 | #endif /* CONFIG_PROC_FS */ | ||
97 | |||
98 | void | ||
99 | show_etrax_copyright(void) | ||
100 | { | ||
101 | printk(KERN_INFO | ||
102 | "Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB\n"); | ||
103 | } | ||
diff --git a/arch/cris/arch-v10/kernel/shadows.c b/arch/cris/arch-v10/kernel/shadows.c new file mode 100644 index 000000000000..561a890a8e4c --- /dev/null +++ b/arch/cris/arch-v10/kernel/shadows.c | |||
@@ -0,0 +1,36 @@ | |||
1 | /* $Id: shadows.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $ | ||
2 | * | ||
3 | * Various shadow registers. Defines for these are in include/asm-etrax100/io.h | ||
4 | */ | ||
5 | |||
6 | /* Shadows for internal Etrax-registers */ | ||
7 | |||
8 | unsigned long genconfig_shadow; | ||
9 | unsigned long port_g_data_shadow; | ||
10 | unsigned char port_pa_dir_shadow; | ||
11 | unsigned char port_pa_data_shadow; | ||
12 | unsigned char port_pb_i2c_shadow; | ||
13 | unsigned char port_pb_config_shadow; | ||
14 | unsigned char port_pb_dir_shadow; | ||
15 | unsigned char port_pb_data_shadow; | ||
16 | unsigned long r_timer_ctrl_shadow; | ||
17 | |||
18 | /* Shadows for external I/O port registers. | ||
19 | * These are only usable if there actually IS a latch connected | ||
20 | * to the corresponding external chip-select pin. | ||
21 | * | ||
22 | * A common usage is that CSP0 controls LED's and CSP4 video chips. | ||
23 | */ | ||
24 | |||
25 | unsigned long port_cse1_shadow; | ||
26 | unsigned long port_csp0_shadow; | ||
27 | unsigned long port_csp4_shadow; | ||
28 | |||
29 | /* Corresponding addresses for the ports. | ||
30 | * These are initialized in arch/cris/mm/init.c using ioremap. | ||
31 | */ | ||
32 | |||
33 | volatile unsigned long *port_cse1_addr; | ||
34 | volatile unsigned long *port_csp0_addr; | ||
35 | volatile unsigned long *port_csp4_addr; | ||
36 | |||
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c new file mode 100644 index 000000000000..85e0032e664f --- /dev/null +++ b/arch/cris/arch-v10/kernel/signal.c | |||
@@ -0,0 +1,580 @@ | |||
1 | /* | ||
2 | * linux/arch/cris/kernel/signal.c | ||
3 | * | ||
4 | * Based on arch/i386/kernel/signal.c by | ||
5 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
6 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson * | ||
7 | * | ||
8 | * Ideas also taken from arch/arm. | ||
9 | * | ||
10 | * Copyright (C) 2000, 2001 Axis Communications AB | ||
11 | * | ||
12 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/sched.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/smp.h> | ||
19 | #include <linux/smp_lock.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/signal.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/wait.h> | ||
24 | #include <linux/ptrace.h> | ||
25 | #include <linux/unistd.h> | ||
26 | #include <linux/stddef.h> | ||
27 | |||
28 | #include <asm/processor.h> | ||
29 | #include <asm/ucontext.h> | ||
30 | #include <asm/uaccess.h> | ||
31 | |||
32 | #define DEBUG_SIG 0 | ||
33 | |||
34 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
35 | |||
36 | /* a syscall in Linux/CRIS is a break 13 instruction which is 2 bytes */ | ||
37 | /* manipulate regs so that upon return, it will be re-executed */ | ||
38 | |||
39 | /* We rely on that pc points to the instruction after "break 13", so the | ||
40 | * library must never do strange things like putting it in a delay slot. | ||
41 | */ | ||
42 | #define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2; | ||
43 | |||
44 | int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); | ||
45 | |||
46 | /* | ||
47 | * Atomically swap in the new signal mask, and wait for a signal. Define | ||
48 | * dummy arguments to be able to reach the regs argument. (Note that this | ||
49 | * arrangement relies on old_sigset_t occupying one register.) | ||
50 | */ | ||
51 | int | ||
52 | sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, | ||
53 | long srp, struct pt_regs *regs) | ||
54 | { | ||
55 | sigset_t saveset; | ||
56 | |||
57 | mask &= _BLOCKABLE; | ||
58 | spin_lock_irq(¤t->sighand->siglock); | ||
59 | saveset = current->blocked; | ||
60 | siginitset(¤t->blocked, mask); | ||
61 | recalc_sigpending(); | ||
62 | spin_unlock_irq(¤t->sighand->siglock); | ||
63 | |||
64 | regs->r10 = -EINTR; | ||
65 | while (1) { | ||
66 | current->state = TASK_INTERRUPTIBLE; | ||
67 | schedule(); | ||
68 | if (do_signal(0, &saveset, regs)) | ||
69 | /* We will get here twice: once to call the signal | ||
70 | handler, then again to return from the | ||
71 | sigsuspend system call. When calling the | ||
72 | signal handler, R10 holds the signal number as | ||
73 | set through do_signal. The sigsuspend call | ||
74 | will return with the restored value set above; | ||
75 | always -EINTR. */ | ||
76 | return regs->r10; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | /* Define dummy arguments to be able to reach the regs argument. (Note that | ||
81 | * this arrangement relies on size_t occupying one register.) | ||
82 | */ | ||
83 | int | ||
84 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, | ||
85 | long mof, long srp, struct pt_regs *regs) | ||
86 | { | ||
87 | sigset_t saveset, newset; | ||
88 | |||
89 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
90 | if (sigsetsize != sizeof(sigset_t)) | ||
91 | return -EINVAL; | ||
92 | |||
93 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
94 | return -EFAULT; | ||
95 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
96 | |||
97 | spin_lock_irq(¤t->sighand->siglock); | ||
98 | saveset = current->blocked; | ||
99 | current->blocked = newset; | ||
100 | recalc_sigpending(); | ||
101 | spin_unlock_irq(¤t->sighand->siglock); | ||
102 | |||
103 | regs->r10 = -EINTR; | ||
104 | while (1) { | ||
105 | current->state = TASK_INTERRUPTIBLE; | ||
106 | schedule(); | ||
107 | if (do_signal(0, &saveset, regs)) | ||
108 | /* We will get here twice: once to call the signal | ||
109 | handler, then again to return from the | ||
110 | sigsuspend system call. When calling the | ||
111 | signal handler, R10 holds the signal number as | ||
112 | set through do_signal. The sigsuspend call | ||
113 | will return with the restored value set above; | ||
114 | always -EINTR. */ | ||
115 | return regs->r10; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | int | ||
120 | sys_sigaction(int sig, const struct old_sigaction __user *act, | ||
121 | struct old_sigaction *oact) | ||
122 | { | ||
123 | struct k_sigaction new_ka, old_ka; | ||
124 | int ret; | ||
125 | |||
126 | if (act) { | ||
127 | old_sigset_t mask; | ||
128 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | ||
129 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | ||
130 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | ||
131 | return -EFAULT; | ||
132 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
133 | __get_user(mask, &act->sa_mask); | ||
134 | siginitset(&new_ka.sa.sa_mask, mask); | ||
135 | } | ||
136 | |||
137 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
138 | |||
139 | if (!ret && oact) { | ||
140 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | ||
141 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | ||
142 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | ||
143 | return -EFAULT; | ||
144 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
145 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
146 | } | ||
147 | |||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | int | ||
152 | sys_sigaltstack(const stack_t *uss, stack_t __user *uoss) | ||
153 | { | ||
154 | return do_sigaltstack(uss, uoss, rdusp()); | ||
155 | } | ||
156 | |||
157 | |||
158 | /* | ||
159 | * Do a signal return; undo the signal stack. | ||
160 | */ | ||
161 | |||
162 | struct sigframe { | ||
163 | struct sigcontext sc; | ||
164 | unsigned long extramask[_NSIG_WORDS-1]; | ||
165 | unsigned char retcode[8]; /* trampoline code */ | ||
166 | }; | ||
167 | |||
168 | struct rt_sigframe { | ||
169 | struct siginfo *pinfo; | ||
170 | void *puc; | ||
171 | struct siginfo info; | ||
172 | struct ucontext uc; | ||
173 | unsigned char retcode[8]; /* trampoline code */ | ||
174 | }; | ||
175 | |||
176 | |||
177 | static int | ||
178 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | ||
179 | { | ||
180 | unsigned int err = 0; | ||
181 | unsigned long old_usp; | ||
182 | |||
183 | /* Always make any pending restarted system calls return -EINTR */ | ||
184 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
185 | |||
186 | /* restore the regs from &sc->regs (same as sc, since regs is first) | ||
187 | * (sc is already checked for VERIFY_READ since the sigframe was | ||
188 | * checked in sys_sigreturn previously) | ||
189 | */ | ||
190 | |||
191 | if (__copy_from_user(regs, sc, sizeof(struct pt_regs))) | ||
192 | goto badframe; | ||
193 | |||
194 | /* make sure the U-flag is set so user-mode cannot fool us */ | ||
195 | |||
196 | regs->dccr |= 1 << 8; | ||
197 | |||
198 | /* restore the old USP as it was before we stacked the sc etc. | ||
199 | * (we cannot just pop the sigcontext since we aligned the sp and | ||
200 | * stuff after pushing it) | ||
201 | */ | ||
202 | |||
203 | err |= __get_user(old_usp, &sc->usp); | ||
204 | |||
205 | wrusp(old_usp); | ||
206 | |||
207 | /* TODO: the other ports use regs->orig_XX to disable syscall checks | ||
208 | * after this completes, but we don't use that mechanism. maybe we can | ||
209 | * use it now ? | ||
210 | */ | ||
211 | |||
212 | return err; | ||
213 | |||
214 | badframe: | ||
215 | return 1; | ||
216 | } | ||
217 | |||
218 | /* Define dummy arguments to be able to reach the regs argument. */ | ||
219 | |||
220 | asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, | ||
221 | long srp, struct pt_regs *regs) | ||
222 | { | ||
223 | struct sigframe __user *frame = (struct sigframe *)rdusp(); | ||
224 | sigset_t set; | ||
225 | |||
226 | /* | ||
227 | * Since we stacked the signal on a dword boundary, | ||
228 | * then frame should be dword aligned here. If it's | ||
229 | * not, then the user is trying to mess with us. | ||
230 | */ | ||
231 | if (((long)frame) & 3) | ||
232 | goto badframe; | ||
233 | |||
234 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
235 | goto badframe; | ||
236 | if (__get_user(set.sig[0], &frame->sc.oldmask) | ||
237 | || (_NSIG_WORDS > 1 | ||
238 | && __copy_from_user(&set.sig[1], frame->extramask, | ||
239 | sizeof(frame->extramask)))) | ||
240 | goto badframe; | ||
241 | |||
242 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
243 | spin_lock_irq(¤t->sighand->siglock); | ||
244 | current->blocked = set; | ||
245 | recalc_sigpending(); | ||
246 | spin_unlock_irq(¤t->sighand->siglock); | ||
247 | |||
248 | if (restore_sigcontext(regs, &frame->sc)) | ||
249 | goto badframe; | ||
250 | |||
251 | /* TODO: SIGTRAP when single-stepping as in arm ? */ | ||
252 | |||
253 | return regs->r10; | ||
254 | |||
255 | badframe: | ||
256 | force_sig(SIGSEGV, current); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /* Define dummy arguments to be able to reach the regs argument. */ | ||
261 | |||
262 | asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, | ||
263 | long mof, long srp, struct pt_regs *regs) | ||
264 | { | ||
265 | struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp(); | ||
266 | sigset_t set; | ||
267 | |||
268 | /* | ||
269 | * Since we stacked the signal on a dword boundary, | ||
270 | * then frame should be dword aligned here. If it's | ||
271 | * not, then the user is trying to mess with us. | ||
272 | */ | ||
273 | if (((long)frame) & 3) | ||
274 | goto badframe; | ||
275 | |||
276 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
277 | goto badframe; | ||
278 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
279 | goto badframe; | ||
280 | |||
281 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
282 | spin_lock_irq(¤t->sighand->siglock); | ||
283 | current->blocked = set; | ||
284 | recalc_sigpending(); | ||
285 | spin_unlock_irq(¤t->sighand->siglock); | ||
286 | |||
287 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) | ||
288 | goto badframe; | ||
289 | |||
290 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT) | ||
291 | goto badframe; | ||
292 | |||
293 | return regs->r10; | ||
294 | |||
295 | badframe: | ||
296 | force_sig(SIGSEGV, current); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | /* | ||
301 | * Set up a signal frame. | ||
302 | */ | ||
303 | |||
304 | static int | ||
305 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask) | ||
306 | { | ||
307 | int err = 0; | ||
308 | unsigned long usp = rdusp(); | ||
309 | |||
310 | /* copy the regs. they are first in sc so we can use sc directly */ | ||
311 | |||
312 | err |= __copy_to_user(sc, regs, sizeof(struct pt_regs)); | ||
313 | |||
314 | /* Set the frametype to CRIS_FRAME_NORMAL for the execution of | ||
315 | the signal handler. The frametype will be restored to its previous | ||
316 | value in restore_sigcontext. */ | ||
317 | regs->frametype = CRIS_FRAME_NORMAL; | ||
318 | |||
319 | /* then some other stuff */ | ||
320 | |||
321 | err |= __put_user(mask, &sc->oldmask); | ||
322 | |||
323 | err |= __put_user(usp, &sc->usp); | ||
324 | |||
325 | return err; | ||
326 | } | ||
327 | |||
328 | /* figure out where we want to put the new signal frame - usually on the stack */ | ||
329 | |||
330 | static inline void __user * | ||
331 | get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) | ||
332 | { | ||
333 | unsigned long sp = rdusp(); | ||
334 | |||
335 | /* This is the X/Open sanctioned signal stack switching. */ | ||
336 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
337 | if (! on_sig_stack(sp)) | ||
338 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
339 | } | ||
340 | |||
341 | /* make sure the frame is dword-aligned */ | ||
342 | |||
343 | sp &= ~3; | ||
344 | |||
345 | return (void __user*)(sp - frame_size); | ||
346 | } | ||
347 | |||
348 | /* grab and setup a signal frame. | ||
349 | * | ||
350 | * basically we stack a lot of state info, and arrange for the | ||
351 | * user-mode program to return to the kernel using either a | ||
352 | * trampoline which performs the syscall sigreturn, or a provided | ||
353 | * user-mode trampoline. | ||
354 | */ | ||
355 | |||
356 | static void setup_frame(int sig, struct k_sigaction *ka, | ||
357 | sigset_t *set, struct pt_regs * regs) | ||
358 | { | ||
359 | struct sigframe __user *frame; | ||
360 | unsigned long return_ip; | ||
361 | int err = 0; | ||
362 | |||
363 | frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
364 | |||
365 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
366 | goto give_sigsegv; | ||
367 | |||
368 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); | ||
369 | if (err) | ||
370 | goto give_sigsegv; | ||
371 | |||
372 | if (_NSIG_WORDS > 1) { | ||
373 | err |= __copy_to_user(frame->extramask, &set->sig[1], | ||
374 | sizeof(frame->extramask)); | ||
375 | } | ||
376 | if (err) | ||
377 | goto give_sigsegv; | ||
378 | |||
379 | /* Set up to return from userspace. If provided, use a stub | ||
380 | already in userspace. */ | ||
381 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
382 | return_ip = (unsigned long)ka->sa.sa_restorer; | ||
383 | } else { | ||
384 | /* trampoline - the desired return ip is the retcode itself */ | ||
385 | return_ip = (unsigned long)&frame->retcode; | ||
386 | /* This is movu.w __NR_sigreturn, r9; break 13; */ | ||
387 | err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0)); | ||
388 | err |= __put_user(__NR_sigreturn, (short __user*)(frame->retcode+2)); | ||
389 | err |= __put_user(0xe93d, (short __user*)(frame->retcode+4)); | ||
390 | } | ||
391 | |||
392 | if (err) | ||
393 | goto give_sigsegv; | ||
394 | |||
395 | /* Set up registers for signal handler */ | ||
396 | |||
397 | regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */ | ||
398 | regs->srp = return_ip; /* what we enter LATER */ | ||
399 | regs->r10 = sig; /* first argument is signo */ | ||
400 | |||
401 | /* actually move the usp to reflect the stacked frame */ | ||
402 | |||
403 | wrusp((unsigned long)frame); | ||
404 | |||
405 | return; | ||
406 | |||
407 | give_sigsegv: | ||
408 | force_sigsegv(sig, current); | ||
409 | } | ||
410 | |||
411 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
412 | sigset_t *set, struct pt_regs * regs) | ||
413 | { | ||
414 | struct rt_sigframe __user *frame; | ||
415 | unsigned long return_ip; | ||
416 | int err = 0; | ||
417 | |||
418 | frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
419 | |||
420 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
421 | goto give_sigsegv; | ||
422 | |||
423 | err |= __put_user(&frame->info, &frame->pinfo); | ||
424 | err |= __put_user(&frame->uc, &frame->puc); | ||
425 | err |= copy_siginfo_to_user(&frame->info, info); | ||
426 | if (err) | ||
427 | goto give_sigsegv; | ||
428 | |||
429 | /* Clear all the bits of the ucontext we don't use. */ | ||
430 | err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); | ||
431 | |||
432 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); | ||
433 | |||
434 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
435 | |||
436 | if (err) | ||
437 | goto give_sigsegv; | ||
438 | |||
439 | /* Set up to return from userspace. If provided, use a stub | ||
440 | already in userspace. */ | ||
441 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
442 | return_ip = (unsigned long)ka->sa.sa_restorer; | ||
443 | } else { | ||
444 | /* trampoline - the desired return ip is the retcode itself */ | ||
445 | return_ip = (unsigned long)&frame->retcode; | ||
446 | /* This is movu.w __NR_rt_sigreturn, r9; break 13; */ | ||
447 | err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0)); | ||
448 | err |= __put_user(__NR_rt_sigreturn, (short __user*)(frame->retcode+2)); | ||
449 | err |= __put_user(0xe93d, (short __user*)(frame->retcode+4)); | ||
450 | } | ||
451 | |||
452 | if (err) | ||
453 | goto give_sigsegv; | ||
454 | |||
455 | /* TODO what is the current->exec_domain stuff and invmap ? */ | ||
456 | |||
457 | /* Set up registers for signal handler */ | ||
458 | |||
459 | regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */ | ||
460 | regs->srp = return_ip; /* what we enter LATER */ | ||
461 | regs->r10 = sig; /* first argument is signo */ | ||
462 | regs->r11 = (unsigned long) &frame->info; /* second argument is (siginfo_t *) */ | ||
463 | regs->r12 = 0; /* third argument is unused */ | ||
464 | |||
465 | /* actually move the usp to reflect the stacked frame */ | ||
466 | |||
467 | wrusp((unsigned long)frame); | ||
468 | |||
469 | return; | ||
470 | |||
471 | give_sigsegv: | ||
472 | force_sigsegv(sig, current); | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * OK, we're invoking a handler | ||
477 | */ | ||
478 | |||
479 | extern inline void | ||
480 | handle_signal(int canrestart, unsigned long sig, | ||
481 | siginfo_t *info, struct k_sigaction *ka, | ||
482 | sigset_t *oldset, struct pt_regs * regs) | ||
483 | { | ||
484 | /* Are we from a system call? */ | ||
485 | if (canrestart) { | ||
486 | /* If so, check system call restarting.. */ | ||
487 | switch (regs->r10) { | ||
488 | case -ERESTART_RESTARTBLOCK: | ||
489 | case -ERESTARTNOHAND: | ||
490 | /* ERESTARTNOHAND means that the syscall should only be | ||
491 | restarted if there was no handler for the signal, and since | ||
492 | we only get here if there is a handler, we don't restart */ | ||
493 | regs->r10 = -EINTR; | ||
494 | break; | ||
495 | |||
496 | case -ERESTARTSYS: | ||
497 | /* ERESTARTSYS means to restart the syscall if there is no | ||
498 | handler or the handler was registered with SA_RESTART */ | ||
499 | if (!(ka->sa.sa_flags & SA_RESTART)) { | ||
500 | regs->r10 = -EINTR; | ||
501 | break; | ||
502 | } | ||
503 | /* fallthrough */ | ||
504 | case -ERESTARTNOINTR: | ||
505 | /* ERESTARTNOINTR means that the syscall should be called again | ||
506 | after the signal handler returns. */ | ||
507 | RESTART_CRIS_SYS(regs); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | /* Set up the stack frame */ | ||
512 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
513 | setup_rt_frame(sig, ka, info, oldset, regs); | ||
514 | else | ||
515 | setup_frame(sig, ka, oldset, regs); | ||
516 | |||
517 | if (ka->sa.sa_flags & SA_ONESHOT) | ||
518 | ka->sa.sa_handler = SIG_DFL; | ||
519 | |||
520 | if (!(ka->sa.sa_flags & SA_NODEFER)) { | ||
521 | spin_lock_irq(¤t->sighand->siglock); | ||
522 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | ||
523 | sigaddset(¤t->blocked,sig); | ||
524 | recalc_sigpending(); | ||
525 | spin_unlock_irq(¤t->sighand->siglock); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | /* | ||
530 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
531 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
532 | * mistake. | ||
533 | * | ||
534 | * Also note that the regs structure given here as an argument, is the latest | ||
535 | * pushed pt_regs. It may or may not be the same as the first pushed registers | ||
536 | * when the initial usermode->kernelmode transition took place. Therefore | ||
537 | * we can use user_mode(regs) to see if we came directly from kernel or user | ||
538 | * mode below. | ||
539 | */ | ||
540 | |||
541 | int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) | ||
542 | { | ||
543 | siginfo_t info; | ||
544 | int signr; | ||
545 | struct k_sigaction ka; | ||
546 | |||
547 | /* | ||
548 | * We want the common case to go fast, which | ||
549 | * is why we may in certain cases get here from | ||
550 | * kernel mode. Just return without doing anything | ||
551 | * if so. | ||
552 | */ | ||
553 | if (!user_mode(regs)) | ||
554 | return 1; | ||
555 | |||
556 | if (!oldset) | ||
557 | oldset = ¤t->blocked; | ||
558 | |||
559 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
560 | if (signr > 0) { | ||
561 | /* Whee! Actually deliver the signal. */ | ||
562 | handle_signal(canrestart, signr, &info, &ka, oldset, regs); | ||
563 | return 1; | ||
564 | } | ||
565 | |||
566 | /* Did we come from a system call? */ | ||
567 | if (canrestart) { | ||
568 | /* Restart the system call - no handlers present */ | ||
569 | if (regs->r10 == -ERESTARTNOHAND || | ||
570 | regs->r10 == -ERESTARTSYS || | ||
571 | regs->r10 == -ERESTARTNOINTR) { | ||
572 | RESTART_CRIS_SYS(regs); | ||
573 | } | ||
574 | if (regs->r10 == -ERESTART_RESTARTBLOCK){ | ||
575 | regs->r10 = __NR_restart_syscall; | ||
576 | regs->irp -= 2; | ||
577 | } | ||
578 | } | ||
579 | return 0; | ||
580 | } | ||
diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c new file mode 100644 index 000000000000..6b7b4e0802e3 --- /dev/null +++ b/arch/cris/arch-v10/kernel/time.c | |||
@@ -0,0 +1,369 @@ | |||
1 | /* $Id: time.c,v 1.5 2004/09/29 06:12:46 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/arch-v10/kernel/time.c | ||
4 | * | ||
5 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | ||
6 | * Copyright (C) 1999-2002 Axis Communications AB | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/timex.h> | ||
12 | #include <linux/time.h> | ||
13 | #include <linux/jiffies.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/swap.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <asm/arch/svinto.h> | ||
19 | #include <asm/types.h> | ||
20 | #include <asm/signal.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/delay.h> | ||
23 | #include <asm/rtc.h> | ||
24 | |||
25 | /* define this if you need to use print_timestamp */ | ||
26 | /* it will make jiffies at 96 hz instead of 100 hz though */ | ||
27 | #undef USE_CASCADE_TIMERS | ||
28 | |||
29 | extern void update_xtime_from_cmos(void); | ||
30 | extern int set_rtc_mmss(unsigned long nowtime); | ||
31 | extern int setup_irq(int, struct irqaction *); | ||
32 | extern int have_rtc; | ||
33 | |||
34 | unsigned long get_ns_in_jiffie(void) | ||
35 | { | ||
36 | unsigned char timer_count, t1; | ||
37 | unsigned short presc_count; | ||
38 | unsigned long ns; | ||
39 | unsigned long flags; | ||
40 | |||
41 | local_irq_save(flags); | ||
42 | local_irq_disable(); | ||
43 | timer_count = *R_TIMER0_DATA; | ||
44 | presc_count = *R_TIM_PRESC_STATUS; | ||
45 | /* presc_count might be wrapped */ | ||
46 | t1 = *R_TIMER0_DATA; | ||
47 | |||
48 | if (timer_count != t1){ | ||
49 | /* it wrapped, read prescaler again... */ | ||
50 | presc_count = *R_TIM_PRESC_STATUS; | ||
51 | timer_count = t1; | ||
52 | } | ||
53 | local_irq_restore(flags); | ||
54 | if (presc_count >= PRESCALE_VALUE/2 ){ | ||
55 | presc_count = PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2; | ||
56 | } else { | ||
57 | presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; | ||
58 | } | ||
59 | |||
60 | ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + | ||
61 | ( (presc_count) * (1000000000/PRESCALE_FREQ)); | ||
62 | return ns; | ||
63 | } | ||
64 | |||
65 | unsigned long do_slow_gettimeoffset(void) | ||
66 | { | ||
67 | unsigned long count, t1; | ||
68 | unsigned long usec_count = 0; | ||
69 | unsigned short presc_count; | ||
70 | |||
71 | static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */ | ||
72 | static unsigned long jiffies_p = 0; | ||
73 | |||
74 | /* | ||
75 | * cache volatile jiffies temporarily; we have IRQs turned off. | ||
76 | */ | ||
77 | unsigned long jiffies_t; | ||
78 | |||
79 | /* The timer interrupt comes from Etrax timer 0. In order to get | ||
80 | * better precision, we check the current value. It might have | ||
81 | * underflowed already though. | ||
82 | */ | ||
83 | |||
84 | #ifndef CONFIG_SVINTO_SIM | ||
85 | /* Not available in the xsim simulator. */ | ||
86 | count = *R_TIMER0_DATA; | ||
87 | presc_count = *R_TIM_PRESC_STATUS; | ||
88 | /* presc_count might be wrapped */ | ||
89 | t1 = *R_TIMER0_DATA; | ||
90 | if (count != t1){ | ||
91 | /* it wrapped, read prescaler again... */ | ||
92 | presc_count = *R_TIM_PRESC_STATUS; | ||
93 | count = t1; | ||
94 | } | ||
95 | #else | ||
96 | count = 0; | ||
97 | presc_count = 0; | ||
98 | #endif | ||
99 | |||
100 | jiffies_t = jiffies; | ||
101 | |||
102 | /* | ||
103 | * avoiding timer inconsistencies (they are rare, but they happen)... | ||
104 | * there are one problem that must be avoided here: | ||
105 | * 1. the timer counter underflows | ||
106 | */ | ||
107 | if( jiffies_t == jiffies_p ) { | ||
108 | if( count > count_p ) { | ||
109 | /* Timer wrapped, use new count and prescale | ||
110 | * increase the time corresponding to one jiffie | ||
111 | */ | ||
112 | usec_count = 1000000/HZ; | ||
113 | } | ||
114 | } else | ||
115 | jiffies_p = jiffies_t; | ||
116 | count_p = count; | ||
117 | if (presc_count >= PRESCALE_VALUE/2 ){ | ||
118 | presc_count = PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2; | ||
119 | } else { | ||
120 | presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; | ||
121 | } | ||
122 | /* Convert timer value to usec */ | ||
123 | usec_count += ( (TIMER0_DIV - count) * (1000000/HZ)/TIMER0_DIV ) + | ||
124 | (( (presc_count) * (1000000000/PRESCALE_FREQ))/1000); | ||
125 | |||
126 | return usec_count; | ||
127 | } | ||
128 | |||
129 | /* Excerpt from the Etrax100 HSDD about the built-in watchdog: | ||
130 | * | ||
131 | * 3.10.4 Watchdog timer | ||
132 | |||
133 | * When the watchdog timer is started, it generates an NMI if the watchdog | ||
134 | * isn't restarted or stopped within 0.1 s. If it still isn't restarted or | ||
135 | * stopped after an additional 3.3 ms, the watchdog resets the chip. | ||
136 | * The watchdog timer is stopped after reset. The watchdog timer is controlled | ||
137 | * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit | ||
138 | * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is | ||
139 | * described in the table below: | ||
140 | * | ||
141 | * Watchdog Value written: | ||
142 | * state: To enable: To key: Operation: | ||
143 | * -------- ---------- ------- ---------- | ||
144 | * stopped 0 X No effect. | ||
145 | * stopped 1 key_val Start watchdog with key = key_val. | ||
146 | * started 0 ~key Stop watchdog | ||
147 | * started 1 ~key Restart watchdog with key = ~key. | ||
148 | * started X new_key_val Change key to new_key_val. | ||
149 | * | ||
150 | * Note: '~' is the bitwise NOT operator. | ||
151 | * | ||
152 | */ | ||
153 | |||
154 | /* right now, starting the watchdog is the same as resetting it */ | ||
155 | #define start_watchdog reset_watchdog | ||
156 | |||
157 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
158 | static int watchdog_key = 0; /* arbitrary number */ | ||
159 | #endif | ||
160 | |||
161 | /* number of pages to consider "out of memory". it is normal that the memory | ||
162 | * is used though, so put this really low. | ||
163 | */ | ||
164 | |||
165 | #define WATCHDOG_MIN_FREE_PAGES 8 | ||
166 | |||
167 | void | ||
168 | reset_watchdog(void) | ||
169 | { | ||
170 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
171 | /* only keep watchdog happy as long as we have memory left! */ | ||
172 | if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { | ||
173 | /* reset the watchdog with the inverse of the old key */ | ||
174 | watchdog_key ^= 0x7; /* invert key, which is 3 bits */ | ||
175 | *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | | ||
176 | IO_STATE(R_WATCHDOG, enable, start); | ||
177 | } | ||
178 | #endif | ||
179 | } | ||
180 | |||
181 | /* stop the watchdog - we still need the correct key */ | ||
182 | |||
183 | void | ||
184 | stop_watchdog(void) | ||
185 | { | ||
186 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
187 | watchdog_key ^= 0x7; /* invert key, which is 3 bits */ | ||
188 | *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | | ||
189 | IO_STATE(R_WATCHDOG, enable, stop); | ||
190 | #endif | ||
191 | } | ||
192 | |||
193 | /* last time the cmos clock got updated */ | ||
194 | static long last_rtc_update = 0; | ||
195 | |||
196 | /* | ||
197 | * timer_interrupt() needs to keep up the real-time clock, | ||
198 | * as well as call the "do_timer()" routine every clocktick | ||
199 | */ | ||
200 | |||
201 | //static unsigned short myjiff; /* used by our debug routine print_timestamp */ | ||
202 | |||
203 | extern void cris_do_profile(struct pt_regs *regs); | ||
204 | |||
205 | static inline irqreturn_t | ||
206 | timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
207 | { | ||
208 | /* acknowledge the timer irq */ | ||
209 | |||
210 | #ifdef USE_CASCADE_TIMERS | ||
211 | *R_TIMER_CTRL = | ||
212 | IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | | ||
213 | IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | | ||
214 | IO_STATE( R_TIMER_CTRL, i1, clr) | | ||
215 | IO_STATE( R_TIMER_CTRL, tm1, run) | | ||
216 | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | | ||
217 | IO_STATE( R_TIMER_CTRL, i0, clr) | | ||
218 | IO_STATE( R_TIMER_CTRL, tm0, run) | | ||
219 | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); | ||
220 | #else | ||
221 | *R_TIMER_CTRL = r_timer_ctrl_shadow | | ||
222 | IO_STATE(R_TIMER_CTRL, i0, clr); | ||
223 | #endif | ||
224 | |||
225 | /* reset watchdog otherwise it resets us! */ | ||
226 | |||
227 | reset_watchdog(); | ||
228 | |||
229 | /* call the real timer interrupt handler */ | ||
230 | |||
231 | do_timer(regs); | ||
232 | |||
233 | cris_do_profile(regs); /* Save profiling information */ | ||
234 | |||
235 | /* | ||
236 | * If we have an externally synchronized Linux clock, then update | ||
237 | * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be | ||
238 | * called as close as possible to 500 ms before the new second starts. | ||
239 | * | ||
240 | * The division here is not time critical since it will run once in | ||
241 | * 11 minutes | ||
242 | */ | ||
243 | if ((time_status & STA_UNSYNC) == 0 && | ||
244 | xtime.tv_sec > last_rtc_update + 660 && | ||
245 | (xtime.tv_nsec / 1000) >= 500000 - (tick_nsec / 1000) / 2 && | ||
246 | (xtime.tv_nsec / 1000) <= 500000 + (tick_nsec / 1000) / 2) { | ||
247 | if (set_rtc_mmss(xtime.tv_sec) == 0) | ||
248 | last_rtc_update = xtime.tv_sec; | ||
249 | else | ||
250 | last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ | ||
251 | } | ||
252 | return IRQ_HANDLED; | ||
253 | } | ||
254 | |||
255 | /* timer is SA_SHIRQ so drivers can add stuff to the timer irq chain | ||
256 | * it needs to be SA_INTERRUPT to make the jiffies update work properly | ||
257 | */ | ||
258 | |||
259 | static struct irqaction irq2 = { timer_interrupt, SA_SHIRQ | SA_INTERRUPT, | ||
260 | CPU_MASK_NONE, "timer", NULL, NULL}; | ||
261 | |||
262 | void __init | ||
263 | time_init(void) | ||
264 | { | ||
265 | /* probe for the RTC and read it if it exists | ||
266 | * Before the RTC can be probed the loops_per_usec variable needs | ||
267 | * to be initialized to make usleep work. A better value for | ||
268 | * loops_per_usec is calculated by the kernel later once the | ||
269 | * clock has started. | ||
270 | */ | ||
271 | loops_per_usec = 50; | ||
272 | |||
273 | if(RTC_INIT() < 0) { | ||
274 | /* no RTC, start at 1980 */ | ||
275 | xtime.tv_sec = 0; | ||
276 | xtime.tv_nsec = 0; | ||
277 | have_rtc = 0; | ||
278 | } else { | ||
279 | /* get the current time */ | ||
280 | have_rtc = 1; | ||
281 | update_xtime_from_cmos(); | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * Initialize wall_to_monotonic such that adding it to xtime will yield zero, the | ||
286 | * tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC). | ||
287 | */ | ||
288 | set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); | ||
289 | |||
290 | /* Setup the etrax timers | ||
291 | * Base frequency is 25000 hz, divider 250 -> 100 HZ | ||
292 | * In normal mode, we use timer0, so timer1 is free. In cascade | ||
293 | * mode (which we sometimes use for debugging) both timers are used. | ||
294 | * Remember that linux/timex.h contains #defines that rely on the | ||
295 | * timer settings below (hz and divide factor) !!! | ||
296 | */ | ||
297 | |||
298 | #ifdef USE_CASCADE_TIMERS | ||
299 | *R_TIMER_CTRL = | ||
300 | IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | | ||
301 | IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | | ||
302 | IO_STATE( R_TIMER_CTRL, i1, nop) | | ||
303 | IO_STATE( R_TIMER_CTRL, tm1, stop_ld) | | ||
304 | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | | ||
305 | IO_STATE( R_TIMER_CTRL, i0, nop) | | ||
306 | IO_STATE( R_TIMER_CTRL, tm0, stop_ld) | | ||
307 | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); | ||
308 | |||
309 | *R_TIMER_CTRL = r_timer_ctrl_shadow = | ||
310 | IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | | ||
311 | IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | | ||
312 | IO_STATE( R_TIMER_CTRL, i1, nop) | | ||
313 | IO_STATE( R_TIMER_CTRL, tm1, run) | | ||
314 | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | | ||
315 | IO_STATE( R_TIMER_CTRL, i0, nop) | | ||
316 | IO_STATE( R_TIMER_CTRL, tm0, run) | | ||
317 | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); | ||
318 | #else | ||
319 | *R_TIMER_CTRL = | ||
320 | IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | | ||
321 | IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | | ||
322 | IO_STATE(R_TIMER_CTRL, i1, nop) | | ||
323 | IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | | ||
324 | IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | | ||
325 | IO_STATE(R_TIMER_CTRL, i0, nop) | | ||
326 | IO_STATE(R_TIMER_CTRL, tm0, stop_ld) | | ||
327 | IO_STATE(R_TIMER_CTRL, clksel0, flexible); | ||
328 | |||
329 | *R_TIMER_CTRL = r_timer_ctrl_shadow = | ||
330 | IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | | ||
331 | IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | | ||
332 | IO_STATE(R_TIMER_CTRL, i1, nop) | | ||
333 | IO_STATE(R_TIMER_CTRL, tm1, run) | | ||
334 | IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | | ||
335 | IO_STATE(R_TIMER_CTRL, i0, nop) | | ||
336 | IO_STATE(R_TIMER_CTRL, tm0, run) | | ||
337 | IO_STATE(R_TIMER_CTRL, clksel0, flexible); | ||
338 | |||
339 | *R_TIMER_PRESCALE = PRESCALE_VALUE; | ||
340 | #endif | ||
341 | |||
342 | *R_IRQ_MASK0_SET = | ||
343 | IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */ | ||
344 | |||
345 | /* now actually register the timer irq handler that calls timer_interrupt() */ | ||
346 | |||
347 | setup_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */ | ||
348 | |||
349 | /* enable watchdog if we should use one */ | ||
350 | |||
351 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
352 | printk("Enabling watchdog...\n"); | ||
353 | start_watchdog(); | ||
354 | |||
355 | /* If we use the hardware watchdog, we want to trap it as an NMI | ||
356 | and dump registers before it resets us. For this to happen, we | ||
357 | must set the "m" NMI enable flag (which once set, is unset only | ||
358 | when an NMI is taken). | ||
359 | |||
360 | The same goes for the external NMI, but that doesn't have any | ||
361 | driver or infrastructure support yet. */ | ||
362 | asm ("setf m"); | ||
363 | |||
364 | *R_IRQ_MASK0_SET = | ||
365 | IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set); | ||
366 | *R_VECT_MASK_SET = | ||
367 | IO_STATE(R_VECT_MASK_SET, nmi, set); | ||
368 | #endif | ||
369 | } | ||
diff --git a/arch/cris/arch-v10/kernel/traps.c b/arch/cris/arch-v10/kernel/traps.c new file mode 100644 index 000000000000..da491f438a6e --- /dev/null +++ b/arch/cris/arch-v10/kernel/traps.c | |||
@@ -0,0 +1,132 @@ | |||
1 | /* $Id: traps.c,v 1.2 2003/07/04 08:27:41 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/arch-v10/traps.c | ||
4 | * | ||
5 | * Heler functions for trap handlers | ||
6 | * | ||
7 | * Copyright (C) 2000-2002 Axis Communications AB | ||
8 | * | ||
9 | * Authors: Bjorn Wesen | ||
10 | * Hans-Peter Nilsson | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/ptrace.h> | ||
16 | #include <asm/uaccess.h> | ||
17 | #include <asm/arch/sv_addr_ag.h> | ||
18 | |||
19 | void | ||
20 | show_registers(struct pt_regs * regs) | ||
21 | { | ||
22 | /* We either use rdusp() - the USP register, which might not | ||
23 | correspond to the current process for all cases we're called, | ||
24 | or we use the current->thread.usp, which is not up to date for | ||
25 | the current process. Experience shows we want the USP | ||
26 | register. */ | ||
27 | unsigned long usp = rdusp(); | ||
28 | |||
29 | printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", | ||
30 | regs->irp, regs->srp, regs->dccr, usp, regs->mof ); | ||
31 | printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", | ||
32 | regs->r0, regs->r1, regs->r2, regs->r3); | ||
33 | printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", | ||
34 | regs->r4, regs->r5, regs->r6, regs->r7); | ||
35 | printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", | ||
36 | regs->r8, regs->r9, regs->r10, regs->r11); | ||
37 | printk("r12: %08lx r13: %08lx oR10: %08lx\n", | ||
38 | regs->r12, regs->r13, regs->orig_r10); | ||
39 | printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE); | ||
40 | printk("Process %s (pid: %d, stackpage=%08lx)\n", | ||
41 | current->comm, current->pid, (unsigned long)current); | ||
42 | |||
43 | /* | ||
44 | * When in-kernel, we also print out the stack and code at the | ||
45 | * time of the fault.. | ||
46 | */ | ||
47 | if (! user_mode(regs)) { | ||
48 | int i; | ||
49 | |||
50 | show_stack(NULL, (unsigned long*)usp); | ||
51 | |||
52 | /* Dump kernel stack if the previous dump wasn't one. */ | ||
53 | if (usp != 0) | ||
54 | show_stack (NULL, NULL); | ||
55 | |||
56 | printk("\nCode: "); | ||
57 | if(regs->irp < PAGE_OFFSET) | ||
58 | goto bad; | ||
59 | |||
60 | /* Often enough the value at regs->irp does not point to | ||
61 | the interesting instruction, which is most often the | ||
62 | _previous_ instruction. So we dump at an offset large | ||
63 | enough that instruction decoding should be in sync at | ||
64 | the interesting point, but small enough to fit on a row | ||
65 | (sort of). We point out the regs->irp location in a | ||
66 | ksymoops-friendly way by wrapping the byte for that | ||
67 | address in parentheses. */ | ||
68 | for(i = -12; i < 12; i++) | ||
69 | { | ||
70 | unsigned char c; | ||
71 | if(__get_user(c, &((unsigned char*)regs->irp)[i])) { | ||
72 | bad: | ||
73 | printk(" Bad IP value."); | ||
74 | break; | ||
75 | } | ||
76 | |||
77 | if (i == 0) | ||
78 | printk("(%02x) ", c); | ||
79 | else | ||
80 | printk("%02x ", c); | ||
81 | } | ||
82 | printk("\n"); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | /* Called from entry.S when the watchdog has bitten | ||
87 | * We print out something resembling an oops dump, and if | ||
88 | * we have the nice doggy development flag set, we halt here | ||
89 | * instead of rebooting. | ||
90 | */ | ||
91 | |||
92 | extern void reset_watchdog(void); | ||
93 | extern void stop_watchdog(void); | ||
94 | |||
95 | |||
96 | void | ||
97 | watchdog_bite_hook(struct pt_regs *regs) | ||
98 | { | ||
99 | #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY | ||
100 | local_irq_disable(); | ||
101 | stop_watchdog(); | ||
102 | show_registers(regs); | ||
103 | while(1) /* nothing */; | ||
104 | #else | ||
105 | show_registers(regs); | ||
106 | #endif | ||
107 | } | ||
108 | |||
109 | /* This is normally the 'Oops' routine */ | ||
110 | void | ||
111 | die_if_kernel(const char * str, struct pt_regs * regs, long err) | ||
112 | { | ||
113 | if(user_mode(regs)) | ||
114 | return; | ||
115 | |||
116 | #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY | ||
117 | /* This printout might take too long and trigger the | ||
118 | * watchdog normally. If we're in the nice doggy | ||
119 | * development mode, stop the watchdog during printout. | ||
120 | */ | ||
121 | stop_watchdog(); | ||
122 | #endif | ||
123 | |||
124 | printk("%s: %04lx\n", str, err & 0xffff); | ||
125 | |||
126 | show_registers(regs); | ||
127 | |||
128 | #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY | ||
129 | reset_watchdog(); | ||
130 | #endif | ||
131 | do_exit(SIGSEGV); | ||
132 | } | ||