diff options
Diffstat (limited to 'arch/sparc/kernel/entry.S')
-rw-r--r-- | arch/sparc/kernel/entry.S | 1956 |
1 files changed, 1956 insertions, 0 deletions
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S new file mode 100644 index 000000000000..b448166f5da9 --- /dev/null +++ b/arch/sparc/kernel/entry.S | |||
@@ -0,0 +1,1956 @@ | |||
1 | /* $Id: entry.S,v 1.170 2001/11/13 00:57:05 davem Exp $ | ||
2 | * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. | ||
3 | * | ||
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) | ||
6 | * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) | ||
7 | * Copyright (C) 1996-1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
8 | * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au) | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/errno.h> | ||
13 | |||
14 | #include <asm/head.h> | ||
15 | #include <asm/asi.h> | ||
16 | #include <asm/smp.h> | ||
17 | #include <asm/kgdb.h> | ||
18 | #include <asm/contregs.h> | ||
19 | #include <asm/ptrace.h> | ||
20 | #include <asm/asm_offsets.h> | ||
21 | #include <asm/psr.h> | ||
22 | #include <asm/vaddrs.h> | ||
23 | #include <asm/memreg.h> | ||
24 | #include <asm/page.h> | ||
25 | #ifdef CONFIG_SUN4 | ||
26 | #include <asm/pgtsun4.h> | ||
27 | #else | ||
28 | #include <asm/pgtsun4c.h> | ||
29 | #endif | ||
30 | #include <asm/winmacro.h> | ||
31 | #include <asm/signal.h> | ||
32 | #include <asm/obio.h> | ||
33 | #include <asm/mxcc.h> | ||
34 | #include <asm/thread_info.h> | ||
35 | #include <asm/param.h> | ||
36 | |||
37 | #include <asm/asmmacro.h> | ||
38 | |||
39 | #define curptr g6 | ||
40 | |||
41 | #define NR_SYSCALLS 284 /* Each OS is different... */ | ||
42 | |||
43 | /* These are just handy. */ | ||
44 | #define _SV save %sp, -STACKFRAME_SZ, %sp | ||
45 | #define _RS restore | ||
46 | |||
47 | #define FLUSH_ALL_KERNEL_WINDOWS \ | ||
48 | _SV; _SV; _SV; _SV; _SV; _SV; _SV; \ | ||
49 | _RS; _RS; _RS; _RS; _RS; _RS; _RS; | ||
50 | |||
51 | /* First, KGDB low level things. This is a rewrite | ||
52 | * of the routines found in the sparc-stub.c asm() statement | ||
53 | * from the gdb distribution. This is also dual-purpose | ||
54 | * as a software trap for userlevel programs. | ||
55 | */ | ||
56 | .data | ||
57 | .align 4 | ||
58 | |||
59 | in_trap_handler: | ||
60 | .word 0 | ||
61 | |||
62 | .text | ||
63 | .align 4 | ||
64 | |||
65 | #if 0 /* kgdb is dropped from 2.5.33 */ | ||
66 | ! This function is called when any SPARC trap (except window overflow or | ||
67 | ! underflow) occurs. It makes sure that the invalid register window is still | ||
68 | ! available before jumping into C code. It will also restore the world if you | ||
69 | ! return from handle_exception. | ||
70 | |||
71 | .globl trap_low | ||
72 | trap_low: | ||
73 | rd %wim, %l3 | ||
74 | SAVE_ALL | ||
75 | |||
76 | sethi %hi(in_trap_handler), %l4 | ||
77 | ld [%lo(in_trap_handler) + %l4], %l5 | ||
78 | inc %l5 | ||
79 | st %l5, [%lo(in_trap_handler) + %l4] | ||
80 | |||
81 | /* Make sure kgdb sees the same state we just saved. */ | ||
82 | LOAD_PT_GLOBALS(sp) | ||
83 | LOAD_PT_INS(sp) | ||
84 | ld [%sp + STACKFRAME_SZ + PT_Y], %l4 | ||
85 | ld [%sp + STACKFRAME_SZ + PT_WIM], %l3 | ||
86 | ld [%sp + STACKFRAME_SZ + PT_PSR], %l0 | ||
87 | ld [%sp + STACKFRAME_SZ + PT_PC], %l1 | ||
88 | ld [%sp + STACKFRAME_SZ + PT_NPC], %l2 | ||
89 | rd %tbr, %l5 /* Never changes... */ | ||
90 | |||
91 | /* Make kgdb exception frame. */ | ||
92 | sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals | ||
93 | ! + hidden arg + arg spill | ||
94 | ! + doubleword alignment | ||
95 | ! + registers[72] local var | ||
96 | SAVE_KGDB_GLOBALS(sp) | ||
97 | SAVE_KGDB_INS(sp) | ||
98 | SAVE_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2) | ||
99 | |||
100 | /* We are increasing PIL, so two writes. */ | ||
101 | or %l0, PSR_PIL, %l0 | ||
102 | wr %l0, 0, %psr | ||
103 | WRITE_PAUSE | ||
104 | wr %l0, PSR_ET, %psr | ||
105 | WRITE_PAUSE | ||
106 | |||
107 | call handle_exception | ||
108 | add %sp, STACKFRAME_SZ, %o0 ! Pass address of registers | ||
109 | |||
110 | /* Load new kgdb register set. */ | ||
111 | LOAD_KGDB_GLOBALS(sp) | ||
112 | LOAD_KGDB_INS(sp) | ||
113 | LOAD_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2) | ||
114 | wr %l4, 0x0, %y | ||
115 | |||
116 | sethi %hi(in_trap_handler), %l4 | ||
117 | ld [%lo(in_trap_handler) + %l4], %l5 | ||
118 | dec %l5 | ||
119 | st %l5, [%lo(in_trap_handler) + %l4] | ||
120 | |||
121 | add %sp,(16+1+6+1+72)*4,%sp ! Undo the kgdb trap frame. | ||
122 | |||
123 | /* Now take what kgdb did and place it into the pt_regs | ||
124 | * frame which SparcLinux RESTORE_ALL understands., | ||
125 | */ | ||
126 | STORE_PT_INS(sp) | ||
127 | STORE_PT_GLOBALS(sp) | ||
128 | STORE_PT_YREG(sp, g2) | ||
129 | STORE_PT_PRIV(sp, l0, l1, l2) | ||
130 | |||
131 | RESTORE_ALL | ||
132 | #endif | ||
133 | |||
134 | #ifdef CONFIG_BLK_DEV_FD | ||
135 | .text | ||
136 | .align 4 | ||
137 | .globl floppy_hardint | ||
138 | floppy_hardint: | ||
139 | /* | ||
140 | * This code cannot touch registers %l0 %l1 and %l2 | ||
141 | * because SAVE_ALL depends on their values. It depends | ||
142 | * on %l3 also, but we regenerate it before a call. | ||
143 | * Other registers are: | ||
144 | * %l3 -- base address of fdc registers | ||
145 | * %l4 -- pdma_vaddr | ||
146 | * %l5 -- scratch for ld/st address | ||
147 | * %l6 -- pdma_size | ||
148 | * %l7 -- scratch [floppy byte, ld/st address, aux. data] | ||
149 | */ | ||
150 | |||
151 | /* Do we have work to do? */ | ||
152 | sethi %hi(doing_pdma), %l7 | ||
153 | ld [%l7 + %lo(doing_pdma)], %l7 | ||
154 | cmp %l7, 0 | ||
155 | be floppy_dosoftint | ||
156 | nop | ||
157 | |||
158 | /* Load fdc register base */ | ||
159 | sethi %hi(fdc_status), %l3 | ||
160 | ld [%l3 + %lo(fdc_status)], %l3 | ||
161 | |||
162 | /* Setup register addresses */ | ||
163 | sethi %hi(pdma_vaddr), %l5 ! transfer buffer | ||
164 | ld [%l5 + %lo(pdma_vaddr)], %l4 | ||
165 | sethi %hi(pdma_size), %l5 ! bytes to go | ||
166 | ld [%l5 + %lo(pdma_size)], %l6 | ||
167 | next_byte: | ||
168 | ldub [%l3], %l7 | ||
169 | |||
170 | andcc %l7, 0x80, %g0 ! Does fifo still have data | ||
171 | bz floppy_fifo_emptied ! fifo has been emptied... | ||
172 | andcc %l7, 0x20, %g0 ! in non-dma mode still? | ||
173 | bz floppy_overrun ! nope, overrun | ||
174 | andcc %l7, 0x40, %g0 ! 0=write 1=read | ||
175 | bz floppy_write | ||
176 | sub %l6, 0x1, %l6 | ||
177 | |||
178 | /* Ok, actually read this byte */ | ||
179 | ldub [%l3 + 1], %l7 | ||
180 | orcc %g0, %l6, %g0 | ||
181 | stb %l7, [%l4] | ||
182 | bne next_byte | ||
183 | add %l4, 0x1, %l4 | ||
184 | |||
185 | b floppy_tdone | ||
186 | nop | ||
187 | |||
188 | floppy_write: | ||
189 | /* Ok, actually write this byte */ | ||
190 | ldub [%l4], %l7 | ||
191 | orcc %g0, %l6, %g0 | ||
192 | stb %l7, [%l3 + 1] | ||
193 | bne next_byte | ||
194 | add %l4, 0x1, %l4 | ||
195 | |||
196 | /* fall through... */ | ||
197 | floppy_tdone: | ||
198 | sethi %hi(pdma_vaddr), %l5 | ||
199 | st %l4, [%l5 + %lo(pdma_vaddr)] | ||
200 | sethi %hi(pdma_size), %l5 | ||
201 | st %l6, [%l5 + %lo(pdma_size)] | ||
202 | /* Flip terminal count pin */ | ||
203 | set auxio_register, %l7 | ||
204 | ld [%l7], %l7 | ||
205 | |||
206 | set sparc_cpu_model, %l5 | ||
207 | ld [%l5], %l5 | ||
208 | subcc %l5, 1, %g0 /* enum { sun4c = 1 }; */ | ||
209 | be 1f | ||
210 | ldub [%l7], %l5 | ||
211 | |||
212 | or %l5, 0xc2, %l5 | ||
213 | stb %l5, [%l7] | ||
214 | andn %l5, 0x02, %l5 | ||
215 | b 2f | ||
216 | nop | ||
217 | |||
218 | 1: | ||
219 | or %l5, 0xf4, %l5 | ||
220 | stb %l5, [%l7] | ||
221 | andn %l5, 0x04, %l5 | ||
222 | |||
223 | 2: | ||
224 | /* Kill some time so the bits set */ | ||
225 | WRITE_PAUSE | ||
226 | WRITE_PAUSE | ||
227 | |||
228 | stb %l5, [%l7] | ||
229 | |||
230 | /* Prevent recursion */ | ||
231 | sethi %hi(doing_pdma), %l7 | ||
232 | b floppy_dosoftint | ||
233 | st %g0, [%l7 + %lo(doing_pdma)] | ||
234 | |||
235 | /* We emptied the FIFO, but we haven't read everything | ||
236 | * as of yet. Store the current transfer address and | ||
237 | * bytes left to read so we can continue when the next | ||
238 | * fast IRQ comes in. | ||
239 | */ | ||
240 | floppy_fifo_emptied: | ||
241 | sethi %hi(pdma_vaddr), %l5 | ||
242 | st %l4, [%l5 + %lo(pdma_vaddr)] | ||
243 | sethi %hi(pdma_size), %l7 | ||
244 | st %l6, [%l7 + %lo(pdma_size)] | ||
245 | |||
246 | /* Restore condition codes */ | ||
247 | wr %l0, 0x0, %psr | ||
248 | WRITE_PAUSE | ||
249 | |||
250 | jmp %l1 | ||
251 | rett %l2 | ||
252 | |||
253 | floppy_overrun: | ||
254 | sethi %hi(pdma_vaddr), %l5 | ||
255 | st %l4, [%l5 + %lo(pdma_vaddr)] | ||
256 | sethi %hi(pdma_size), %l5 | ||
257 | st %l6, [%l5 + %lo(pdma_size)] | ||
258 | /* Prevent recursion */ | ||
259 | sethi %hi(doing_pdma), %l7 | ||
260 | st %g0, [%l7 + %lo(doing_pdma)] | ||
261 | |||
262 | /* fall through... */ | ||
263 | floppy_dosoftint: | ||
264 | rd %wim, %l3 | ||
265 | SAVE_ALL | ||
266 | |||
267 | /* Set all IRQs off. */ | ||
268 | or %l0, PSR_PIL, %l4 | ||
269 | wr %l4, 0x0, %psr | ||
270 | WRITE_PAUSE | ||
271 | wr %l4, PSR_ET, %psr | ||
272 | WRITE_PAUSE | ||
273 | |||
274 | mov 11, %o0 ! floppy irq level (unused anyway) | ||
275 | mov %g0, %o1 ! devid is not used in fast interrupts | ||
276 | call sparc_floppy_irq | ||
277 | add %sp, STACKFRAME_SZ, %o2 ! struct pt_regs *regs | ||
278 | |||
279 | RESTORE_ALL | ||
280 | |||
281 | #endif /* (CONFIG_BLK_DEV_FD) */ | ||
282 | |||
283 | /* Bad trap handler */ | ||
284 | .globl bad_trap_handler | ||
285 | bad_trap_handler: | ||
286 | SAVE_ALL | ||
287 | |||
288 | wr %l0, PSR_ET, %psr | ||
289 | WRITE_PAUSE | ||
290 | |||
291 | add %sp, STACKFRAME_SZ, %o0 ! pt_regs | ||
292 | call do_hw_interrupt | ||
293 | mov %l7, %o1 ! trap number | ||
294 | |||
295 | RESTORE_ALL | ||
296 | |||
297 | /* For now all IRQ's not registered get sent here. handler_irq() will | ||
298 | * see if a routine is registered to handle this interrupt and if not | ||
299 | * it will say so on the console. | ||
300 | */ | ||
301 | |||
302 | .align 4 | ||
303 | .globl real_irq_entry, patch_handler_irq | ||
304 | real_irq_entry: | ||
305 | SAVE_ALL | ||
306 | |||
307 | #ifdef CONFIG_SMP | ||
308 | .globl patchme_maybe_smp_msg | ||
309 | |||
310 | cmp %l7, 12 | ||
311 | patchme_maybe_smp_msg: | ||
312 | bgu maybe_smp4m_msg | ||
313 | nop | ||
314 | #endif | ||
315 | |||
316 | real_irq_continue: | ||
317 | or %l0, PSR_PIL, %g2 | ||
318 | wr %g2, 0x0, %psr | ||
319 | WRITE_PAUSE | ||
320 | wr %g2, PSR_ET, %psr | ||
321 | WRITE_PAUSE | ||
322 | mov %l7, %o0 ! irq level | ||
323 | patch_handler_irq: | ||
324 | call handler_irq | ||
325 | add %sp, STACKFRAME_SZ, %o1 ! pt_regs ptr | ||
326 | or %l0, PSR_PIL, %g2 ! restore PIL after handler_irq | ||
327 | wr %g2, PSR_ET, %psr ! keep ET up | ||
328 | WRITE_PAUSE | ||
329 | |||
330 | RESTORE_ALL | ||
331 | |||
332 | #ifdef CONFIG_SMP | ||
333 | /* SMP per-cpu ticker interrupts are handled specially. */ | ||
334 | smp4m_ticker: | ||
335 | bne real_irq_continue+4 | ||
336 | or %l0, PSR_PIL, %g2 | ||
337 | wr %g2, 0x0, %psr | ||
338 | WRITE_PAUSE | ||
339 | wr %g2, PSR_ET, %psr | ||
340 | WRITE_PAUSE | ||
341 | call smp4m_percpu_timer_interrupt | ||
342 | add %sp, STACKFRAME_SZ, %o0 | ||
343 | wr %l0, PSR_ET, %psr | ||
344 | WRITE_PAUSE | ||
345 | RESTORE_ALL | ||
346 | |||
347 | /* Here is where we check for possible SMP IPI passed to us | ||
348 | * on some level other than 15 which is the NMI and only used | ||
349 | * for cross calls. That has a separate entry point below. | ||
350 | */ | ||
351 | maybe_smp4m_msg: | ||
352 | GET_PROCESSOR4M_ID(o3) | ||
353 | set sun4m_interrupts, %l5 | ||
354 | ld [%l5], %o5 | ||
355 | sethi %hi(0x40000000), %o2 | ||
356 | sll %o3, 12, %o3 | ||
357 | ld [%o5 + %o3], %o1 | ||
358 | andcc %o1, %o2, %g0 | ||
359 | be,a smp4m_ticker | ||
360 | cmp %l7, 14 | ||
361 | st %o2, [%o5 + 0x4] | ||
362 | WRITE_PAUSE | ||
363 | ld [%o5], %g0 | ||
364 | WRITE_PAUSE | ||
365 | or %l0, PSR_PIL, %l4 | ||
366 | wr %l4, 0x0, %psr | ||
367 | WRITE_PAUSE | ||
368 | wr %l4, PSR_ET, %psr | ||
369 | WRITE_PAUSE | ||
370 | call smp_reschedule_irq | ||
371 | nop | ||
372 | |||
373 | RESTORE_ALL | ||
374 | |||
375 | .align 4 | ||
376 | .globl linux_trap_ipi15_sun4m | ||
377 | linux_trap_ipi15_sun4m: | ||
378 | SAVE_ALL | ||
379 | sethi %hi(0x80000000), %o2 | ||
380 | GET_PROCESSOR4M_ID(o0) | ||
381 | set sun4m_interrupts, %l5 | ||
382 | ld [%l5], %o5 | ||
383 | sll %o0, 12, %o0 | ||
384 | add %o5, %o0, %o5 | ||
385 | ld [%o5], %o3 | ||
386 | andcc %o3, %o2, %g0 | ||
387 | be 1f ! Must be an NMI async memory error | ||
388 | st %o2, [%o5 + 4] | ||
389 | WRITE_PAUSE | ||
390 | ld [%o5], %g0 | ||
391 | WRITE_PAUSE | ||
392 | or %l0, PSR_PIL, %l4 | ||
393 | wr %l4, 0x0, %psr | ||
394 | WRITE_PAUSE | ||
395 | wr %l4, PSR_ET, %psr | ||
396 | WRITE_PAUSE | ||
397 | call smp4m_cross_call_irq | ||
398 | nop | ||
399 | b ret_trap_lockless_ipi | ||
400 | clr %l6 | ||
401 | 1: | ||
402 | /* NMI async memory error handling. */ | ||
403 | sethi %hi(0x80000000), %l4 | ||
404 | sethi %hi(0x4000), %o3 | ||
405 | sub %o5, %o0, %o5 | ||
406 | add %o5, %o3, %l5 | ||
407 | st %l4, [%l5 + 0xc] | ||
408 | WRITE_PAUSE | ||
409 | ld [%l5], %g0 | ||
410 | WRITE_PAUSE | ||
411 | or %l0, PSR_PIL, %l4 | ||
412 | wr %l4, 0x0, %psr | ||
413 | WRITE_PAUSE | ||
414 | wr %l4, PSR_ET, %psr | ||
415 | WRITE_PAUSE | ||
416 | call sun4m_nmi | ||
417 | nop | ||
418 | st %l4, [%l5 + 0x8] | ||
419 | WRITE_PAUSE | ||
420 | ld [%l5], %g0 | ||
421 | WRITE_PAUSE | ||
422 | RESTORE_ALL | ||
423 | |||
424 | .globl smp4d_ticker | ||
425 | /* SMP per-cpu ticker interrupts are handled specially. */ | ||
426 | smp4d_ticker: | ||
427 | SAVE_ALL | ||
428 | or %l0, PSR_PIL, %g2 | ||
429 | sethi %hi(CC_ICLR), %o0 | ||
430 | sethi %hi(1 << 14), %o1 | ||
431 | or %o0, %lo(CC_ICLR), %o0 | ||
432 | stha %o1, [%o0] ASI_M_MXCC /* Clear PIL 14 in MXCC's ICLR */ | ||
433 | wr %g2, 0x0, %psr | ||
434 | WRITE_PAUSE | ||
435 | wr %g2, PSR_ET, %psr | ||
436 | WRITE_PAUSE | ||
437 | call smp4d_percpu_timer_interrupt | ||
438 | add %sp, STACKFRAME_SZ, %o0 | ||
439 | wr %l0, PSR_ET, %psr | ||
440 | WRITE_PAUSE | ||
441 | RESTORE_ALL | ||
442 | |||
443 | .align 4 | ||
444 | .globl linux_trap_ipi15_sun4d | ||
445 | linux_trap_ipi15_sun4d: | ||
446 | SAVE_ALL | ||
447 | sethi %hi(CC_BASE), %o4 | ||
448 | sethi %hi(MXCC_ERR_ME|MXCC_ERR_PEW|MXCC_ERR_ASE|MXCC_ERR_PEE), %o2 | ||
449 | or %o4, (CC_EREG - CC_BASE), %o0 | ||
450 | ldda [%o0] ASI_M_MXCC, %o0 | ||
451 | andcc %o0, %o2, %g0 | ||
452 | bne 1f | ||
453 | sethi %hi(BB_STAT2), %o2 | ||
454 | lduba [%o2] ASI_M_CTL, %o2 | ||
455 | andcc %o2, BB_STAT2_MASK, %g0 | ||
456 | bne 2f | ||
457 | or %o4, (CC_ICLR - CC_BASE), %o0 | ||
458 | sethi %hi(1 << 15), %o1 | ||
459 | stha %o1, [%o0] ASI_M_MXCC /* Clear PIL 15 in MXCC's ICLR */ | ||
460 | or %l0, PSR_PIL, %l4 | ||
461 | wr %l4, 0x0, %psr | ||
462 | WRITE_PAUSE | ||
463 | wr %l4, PSR_ET, %psr | ||
464 | WRITE_PAUSE | ||
465 | call smp4d_cross_call_irq | ||
466 | nop | ||
467 | b ret_trap_lockless_ipi | ||
468 | clr %l6 | ||
469 | |||
470 | 1: /* MXCC error */ | ||
471 | 2: /* BB error */ | ||
472 | /* Disable PIL 15 */ | ||
473 | set CC_IMSK, %l4 | ||
474 | lduha [%l4] ASI_M_MXCC, %l5 | ||
475 | sethi %hi(1 << 15), %l7 | ||
476 | or %l5, %l7, %l5 | ||
477 | stha %l5, [%l4] ASI_M_MXCC | ||
478 | /* FIXME */ | ||
479 | 1: b,a 1b | ||
480 | |||
481 | #endif /* CONFIG_SMP */ | ||
482 | |||
483 | /* This routine handles illegal instructions and privileged | ||
484 | * instruction attempts from user code. | ||
485 | */ | ||
486 | .align 4 | ||
487 | .globl bad_instruction | ||
488 | bad_instruction: | ||
489 | sethi %hi(0xc1f80000), %l4 | ||
490 | ld [%l1], %l5 | ||
491 | sethi %hi(0x81d80000), %l7 | ||
492 | and %l5, %l4, %l5 | ||
493 | cmp %l5, %l7 | ||
494 | be 1f | ||
495 | SAVE_ALL | ||
496 | |||
497 | wr %l0, PSR_ET, %psr ! re-enable traps | ||
498 | WRITE_PAUSE | ||
499 | |||
500 | add %sp, STACKFRAME_SZ, %o0 | ||
501 | mov %l1, %o1 | ||
502 | mov %l2, %o2 | ||
503 | call do_illegal_instruction | ||
504 | mov %l0, %o3 | ||
505 | |||
506 | RESTORE_ALL | ||
507 | |||
508 | 1: /* unimplemented flush - just skip */ | ||
509 | jmpl %l2, %g0 | ||
510 | rett %l2 + 4 | ||
511 | |||
512 | .align 4 | ||
513 | .globl priv_instruction | ||
514 | priv_instruction: | ||
515 | SAVE_ALL | ||
516 | |||
517 | wr %l0, PSR_ET, %psr | ||
518 | WRITE_PAUSE | ||
519 | |||
520 | add %sp, STACKFRAME_SZ, %o0 | ||
521 | mov %l1, %o1 | ||
522 | mov %l2, %o2 | ||
523 | call do_priv_instruction | ||
524 | mov %l0, %o3 | ||
525 | |||
526 | RESTORE_ALL | ||
527 | |||
528 | /* This routine handles unaligned data accesses. */ | ||
529 | .align 4 | ||
530 | .globl mna_handler | ||
531 | mna_handler: | ||
532 | andcc %l0, PSR_PS, %g0 | ||
533 | be mna_fromuser | ||
534 | nop | ||
535 | |||
536 | SAVE_ALL | ||
537 | |||
538 | wr %l0, PSR_ET, %psr | ||
539 | WRITE_PAUSE | ||
540 | |||
541 | ld [%l1], %o1 | ||
542 | call kernel_unaligned_trap | ||
543 | add %sp, STACKFRAME_SZ, %o0 | ||
544 | |||
545 | RESTORE_ALL | ||
546 | |||
547 | mna_fromuser: | ||
548 | SAVE_ALL | ||
549 | |||
550 | wr %l0, PSR_ET, %psr ! re-enable traps | ||
551 | WRITE_PAUSE | ||
552 | |||
553 | ld [%l1], %o1 | ||
554 | call user_unaligned_trap | ||
555 | add %sp, STACKFRAME_SZ, %o0 | ||
556 | |||
557 | RESTORE_ALL | ||
558 | |||
559 | /* This routine handles floating point disabled traps. */ | ||
560 | .align 4 | ||
561 | .globl fpd_trap_handler | ||
562 | fpd_trap_handler: | ||
563 | SAVE_ALL | ||
564 | |||
565 | wr %l0, PSR_ET, %psr ! re-enable traps | ||
566 | WRITE_PAUSE | ||
567 | |||
568 | add %sp, STACKFRAME_SZ, %o0 | ||
569 | mov %l1, %o1 | ||
570 | mov %l2, %o2 | ||
571 | call do_fpd_trap | ||
572 | mov %l0, %o3 | ||
573 | |||
574 | RESTORE_ALL | ||
575 | |||
576 | /* This routine handles Floating Point Exceptions. */ | ||
577 | .align 4 | ||
578 | .globl fpe_trap_handler | ||
579 | fpe_trap_handler: | ||
580 | set fpsave_magic, %l5 | ||
581 | cmp %l1, %l5 | ||
582 | be 1f | ||
583 | sethi %hi(fpsave), %l5 | ||
584 | or %l5, %lo(fpsave), %l5 | ||
585 | cmp %l1, %l5 | ||
586 | bne 2f | ||
587 | sethi %hi(fpsave_catch2), %l5 | ||
588 | or %l5, %lo(fpsave_catch2), %l5 | ||
589 | wr %l0, 0x0, %psr | ||
590 | WRITE_PAUSE | ||
591 | jmp %l5 | ||
592 | rett %l5 + 4 | ||
593 | 1: | ||
594 | sethi %hi(fpsave_catch), %l5 | ||
595 | or %l5, %lo(fpsave_catch), %l5 | ||
596 | wr %l0, 0x0, %psr | ||
597 | WRITE_PAUSE | ||
598 | jmp %l5 | ||
599 | rett %l5 + 4 | ||
600 | |||
601 | 2: | ||
602 | SAVE_ALL | ||
603 | |||
604 | wr %l0, PSR_ET, %psr ! re-enable traps | ||
605 | WRITE_PAUSE | ||
606 | |||
607 | add %sp, STACKFRAME_SZ, %o0 | ||
608 | mov %l1, %o1 | ||
609 | mov %l2, %o2 | ||
610 | call do_fpe_trap | ||
611 | mov %l0, %o3 | ||
612 | |||
613 | RESTORE_ALL | ||
614 | |||
615 | /* This routine handles Tag Overflow Exceptions. */ | ||
616 | .align 4 | ||
617 | .globl do_tag_overflow | ||
618 | do_tag_overflow: | ||
619 | SAVE_ALL | ||
620 | |||
621 | wr %l0, PSR_ET, %psr ! re-enable traps | ||
622 | WRITE_PAUSE | ||
623 | |||
624 | add %sp, STACKFRAME_SZ, %o0 | ||
625 | mov %l1, %o1 | ||
626 | mov %l2, %o2 | ||
627 | call handle_tag_overflow | ||
628 | mov %l0, %o3 | ||
629 | |||
630 | RESTORE_ALL | ||
631 | |||
632 | /* This routine handles Watchpoint Exceptions. */ | ||
633 | .align 4 | ||
634 | .globl do_watchpoint | ||
635 | do_watchpoint: | ||
636 | SAVE_ALL | ||
637 | |||
638 | wr %l0, PSR_ET, %psr ! re-enable traps | ||
639 | WRITE_PAUSE | ||
640 | |||
641 | add %sp, STACKFRAME_SZ, %o0 | ||
642 | mov %l1, %o1 | ||
643 | mov %l2, %o2 | ||
644 | call handle_watchpoint | ||
645 | mov %l0, %o3 | ||
646 | |||
647 | RESTORE_ALL | ||
648 | |||
649 | /* This routine handles Register Access Exceptions. */ | ||
650 | .align 4 | ||
651 | .globl do_reg_access | ||
652 | do_reg_access: | ||
653 | SAVE_ALL | ||
654 | |||
655 | wr %l0, PSR_ET, %psr ! re-enable traps | ||
656 | WRITE_PAUSE | ||
657 | |||
658 | add %sp, STACKFRAME_SZ, %o0 | ||
659 | mov %l1, %o1 | ||
660 | mov %l2, %o2 | ||
661 | call handle_reg_access | ||
662 | mov %l0, %o3 | ||
663 | |||
664 | RESTORE_ALL | ||
665 | |||
666 | /* This routine handles Co-Processor Disabled Exceptions. */ | ||
667 | .align 4 | ||
668 | .globl do_cp_disabled | ||
669 | do_cp_disabled: | ||
670 | SAVE_ALL | ||
671 | |||
672 | wr %l0, PSR_ET, %psr ! re-enable traps | ||
673 | WRITE_PAUSE | ||
674 | |||
675 | add %sp, STACKFRAME_SZ, %o0 | ||
676 | mov %l1, %o1 | ||
677 | mov %l2, %o2 | ||
678 | call handle_cp_disabled | ||
679 | mov %l0, %o3 | ||
680 | |||
681 | RESTORE_ALL | ||
682 | |||
683 | /* This routine handles Co-Processor Exceptions. */ | ||
684 | .align 4 | ||
685 | .globl do_cp_exception | ||
686 | do_cp_exception: | ||
687 | SAVE_ALL | ||
688 | |||
689 | wr %l0, PSR_ET, %psr ! re-enable traps | ||
690 | WRITE_PAUSE | ||
691 | |||
692 | add %sp, STACKFRAME_SZ, %o0 | ||
693 | mov %l1, %o1 | ||
694 | mov %l2, %o2 | ||
695 | call handle_cp_exception | ||
696 | mov %l0, %o3 | ||
697 | |||
698 | RESTORE_ALL | ||
699 | |||
700 | /* This routine handles Hardware Divide By Zero Exceptions. */ | ||
701 | .align 4 | ||
702 | .globl do_hw_divzero | ||
703 | do_hw_divzero: | ||
704 | SAVE_ALL | ||
705 | |||
706 | wr %l0, PSR_ET, %psr ! re-enable traps | ||
707 | WRITE_PAUSE | ||
708 | |||
709 | add %sp, STACKFRAME_SZ, %o0 | ||
710 | mov %l1, %o1 | ||
711 | mov %l2, %o2 | ||
712 | call handle_hw_divzero | ||
713 | mov %l0, %o3 | ||
714 | |||
715 | RESTORE_ALL | ||
716 | |||
717 | .align 4 | ||
718 | .globl do_flush_windows | ||
719 | do_flush_windows: | ||
720 | SAVE_ALL | ||
721 | |||
722 | wr %l0, PSR_ET, %psr | ||
723 | WRITE_PAUSE | ||
724 | |||
725 | andcc %l0, PSR_PS, %g0 | ||
726 | bne dfw_kernel | ||
727 | nop | ||
728 | |||
729 | call flush_user_windows | ||
730 | nop | ||
731 | |||
732 | /* Advance over the trap instruction. */ | ||
733 | ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 | ||
734 | add %l1, 0x4, %l2 | ||
735 | st %l1, [%sp + STACKFRAME_SZ + PT_PC] | ||
736 | st %l2, [%sp + STACKFRAME_SZ + PT_NPC] | ||
737 | |||
738 | RESTORE_ALL | ||
739 | |||
740 | .globl flush_patch_one | ||
741 | |||
742 | /* We get these for debugging routines using __builtin_return_address() */ | ||
743 | dfw_kernel: | ||
744 | flush_patch_one: | ||
745 | FLUSH_ALL_KERNEL_WINDOWS | ||
746 | |||
747 | /* Advance over the trap instruction. */ | ||
748 | ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 | ||
749 | add %l1, 0x4, %l2 | ||
750 | st %l1, [%sp + STACKFRAME_SZ + PT_PC] | ||
751 | st %l2, [%sp + STACKFRAME_SZ + PT_NPC] | ||
752 | |||
753 | RESTORE_ALL | ||
754 | |||
755 | /* The getcc software trap. The user wants the condition codes from | ||
756 | * the %psr in register %g1. | ||
757 | */ | ||
758 | |||
759 | .align 4 | ||
760 | .globl getcc_trap_handler | ||
761 | getcc_trap_handler: | ||
762 | srl %l0, 20, %g1 ! give user | ||
763 | and %g1, 0xf, %g1 ! only ICC bits in %psr | ||
764 | jmp %l2 ! advance over trap instruction | ||
765 | rett %l2 + 0x4 ! like this... | ||
766 | |||
767 | /* The setcc software trap. The user has condition codes in %g1 | ||
768 | * that it would like placed in the %psr. Be careful not to flip | ||
769 | * any unintentional bits! | ||
770 | */ | ||
771 | |||
772 | .align 4 | ||
773 | .globl setcc_trap_handler | ||
774 | setcc_trap_handler: | ||
775 | sll %g1, 0x14, %l4 | ||
776 | set PSR_ICC, %l5 | ||
777 | andn %l0, %l5, %l0 ! clear ICC bits in %psr | ||
778 | and %l4, %l5, %l4 ! clear non-ICC bits in user value | ||
779 | or %l4, %l0, %l4 ! or them in... mix mix mix | ||
780 | |||
781 | wr %l4, 0x0, %psr ! set new %psr | ||
782 | WRITE_PAUSE ! TI scumbags... | ||
783 | |||
784 | jmp %l2 ! advance over trap instruction | ||
785 | rett %l2 + 0x4 ! like this... | ||
786 | |||
787 | .align 4 | ||
788 | .globl linux_trap_nmi_sun4c | ||
789 | linux_trap_nmi_sun4c: | ||
790 | SAVE_ALL | ||
791 | |||
792 | /* Ugh, we need to clear the IRQ line. This is now | ||
793 | * a very sun4c specific trap handler... | ||
794 | */ | ||
795 | sethi %hi(interrupt_enable), %l5 | ||
796 | ld [%l5 + %lo(interrupt_enable)], %l5 | ||
797 | ldub [%l5], %l6 | ||
798 | andn %l6, INTS_ENAB, %l6 | ||
799 | stb %l6, [%l5] | ||
800 | |||
801 | /* Now it is safe to re-enable traps without recursion. */ | ||
802 | or %l0, PSR_PIL, %l0 | ||
803 | wr %l0, PSR_ET, %psr | ||
804 | WRITE_PAUSE | ||
805 | |||
806 | /* Now call the c-code with the pt_regs frame ptr and the | ||
807 | * memory error registers as arguments. The ordering chosen | ||
808 | * here is due to unlatching semantics. | ||
809 | */ | ||
810 | sethi %hi(AC_SYNC_ERR), %o0 | ||
811 | add %o0, 0x4, %o0 | ||
812 | lda [%o0] ASI_CONTROL, %o2 ! sync vaddr | ||
813 | sub %o0, 0x4, %o0 | ||
814 | lda [%o0] ASI_CONTROL, %o1 ! sync error | ||
815 | add %o0, 0xc, %o0 | ||
816 | lda [%o0] ASI_CONTROL, %o4 ! async vaddr | ||
817 | sub %o0, 0x4, %o0 | ||
818 | lda [%o0] ASI_CONTROL, %o3 ! async error | ||
819 | call sparc_lvl15_nmi | ||
820 | add %sp, STACKFRAME_SZ, %o0 | ||
821 | |||
822 | RESTORE_ALL | ||
823 | |||
824 | .align 4 | ||
825 | .globl invalid_segment_patch1_ff | ||
826 | .globl invalid_segment_patch2_ff | ||
827 | invalid_segment_patch1_ff: cmp %l4, 0xff | ||
828 | invalid_segment_patch2_ff: mov 0xff, %l3 | ||
829 | |||
830 | .align 4 | ||
831 | .globl invalid_segment_patch1_1ff | ||
832 | .globl invalid_segment_patch2_1ff | ||
833 | invalid_segment_patch1_1ff: cmp %l4, 0x1ff | ||
834 | invalid_segment_patch2_1ff: mov 0x1ff, %l3 | ||
835 | |||
836 | .align 4 | ||
837 | .globl num_context_patch1_16, num_context_patch2_16 | ||
838 | num_context_patch1_16: mov 0x10, %l7 | ||
839 | num_context_patch2_16: mov 0x10, %l7 | ||
840 | |||
841 | .align 4 | ||
842 | .globl vac_linesize_patch_32 | ||
843 | vac_linesize_patch_32: subcc %l7, 32, %l7 | ||
844 | |||
845 | .align 4 | ||
846 | .globl vac_hwflush_patch1_on, vac_hwflush_patch2_on | ||
847 | |||
848 | /* | ||
849 | * Ugly, but we cant use hardware flushing on the sun4 and we'd require | ||
850 | * two instructions (Anton) | ||
851 | */ | ||
852 | #ifdef CONFIG_SUN4 | ||
853 | vac_hwflush_patch1_on: nop | ||
854 | #else | ||
855 | vac_hwflush_patch1_on: addcc %l7, -PAGE_SIZE, %l7 | ||
856 | #endif | ||
857 | |||
858 | vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG | ||
859 | |||
860 | .globl invalid_segment_patch1, invalid_segment_patch2 | ||
861 | .globl num_context_patch1 | ||
862 | .globl vac_linesize_patch, vac_hwflush_patch1 | ||
863 | .globl vac_hwflush_patch2 | ||
864 | |||
865 | .align 4 | ||
866 | .globl sun4c_fault | ||
867 | |||
868 | ! %l0 = %psr | ||
869 | ! %l1 = %pc | ||
870 | ! %l2 = %npc | ||
871 | ! %l3 = %wim | ||
872 | ! %l7 = 1 for textfault | ||
873 | ! We want error in %l5, vaddr in %l6 | ||
874 | sun4c_fault: | ||
875 | #ifdef CONFIG_SUN4 | ||
876 | sethi %hi(sun4c_memerr_reg), %l4 | ||
877 | ld [%l4+%lo(sun4c_memerr_reg)], %l4 ! memerr ctrl reg addr | ||
878 | ld [%l4], %l6 ! memerr ctrl reg | ||
879 | ld [%l4 + 4], %l5 ! memerr vaddr reg | ||
880 | andcc %l6, 0x80, %g0 ! check for error type | ||
881 | st %g0, [%l4 + 4] ! clear the error | ||
882 | be 0f ! normal error | ||
883 | sethi %hi(AC_BUS_ERROR), %l4 ! bus err reg addr | ||
884 | |||
885 | call prom_halt ! something weird happened | ||
886 | ! what exactly did happen? | ||
887 | ! what should we do here? | ||
888 | |||
889 | 0: or %l4, %lo(AC_BUS_ERROR), %l4 ! bus err reg addr | ||
890 | lduba [%l4] ASI_CONTROL, %l6 ! bus err reg | ||
891 | |||
892 | cmp %l7, 1 ! text fault? | ||
893 | be 1f ! yes | ||
894 | nop | ||
895 | |||
896 | ld [%l1], %l4 ! load instruction that caused fault | ||
897 | srl %l4, 21, %l4 | ||
898 | andcc %l4, 1, %g0 ! store instruction? | ||
899 | |||
900 | be 1f ! no | ||
901 | sethi %hi(SUN4C_SYNC_BADWRITE), %l4 ! yep | ||
902 | ! %lo(SUN4C_SYNC_BADWRITE) = 0 | ||
903 | or %l4, %l6, %l6 ! set write bit to emulate sun4c | ||
904 | 1: | ||
905 | #else | ||
906 | sethi %hi(AC_SYNC_ERR), %l4 | ||
907 | add %l4, 0x4, %l6 ! AC_SYNC_VA in %l6 | ||
908 | lda [%l6] ASI_CONTROL, %l5 ! Address | ||
909 | lda [%l4] ASI_CONTROL, %l6 ! Error, retained for a bit | ||
910 | #endif | ||
911 | |||
912 | andn %l5, 0xfff, %l5 ! Encode all info into l7 | ||
913 | srl %l6, 14, %l4 | ||
914 | |||
915 | and %l4, 2, %l4 | ||
916 | or %l5, %l4, %l4 | ||
917 | |||
918 | or %l4, %l7, %l7 ! l7 = [addr,write,txtfault] | ||
919 | |||
920 | andcc %l0, PSR_PS, %g0 | ||
921 | be sun4c_fault_fromuser | ||
922 | andcc %l7, 1, %g0 ! Text fault? | ||
923 | |||
924 | be 1f | ||
925 | sethi %hi(KERNBASE), %l4 | ||
926 | |||
927 | mov %l1, %l5 ! PC | ||
928 | |||
929 | 1: | ||
930 | cmp %l5, %l4 | ||
931 | blu sun4c_fault_fromuser | ||
932 | sethi %hi(~((1 << SUN4C_REAL_PGDIR_SHIFT) - 1)), %l4 | ||
933 | |||
934 | /* If the kernel references a bum kernel pointer, or a pte which | ||
935 | * points to a non existant page in ram, we will run this code | ||
936 | * _forever_ and lock up the machine!!!!! So we must check for | ||
937 | * this condition, the AC_SYNC_ERR bits are what we must examine. | ||
938 | * Also a parity error would make this happen as well. So we just | ||
939 | * check that we are in fact servicing a tlb miss and not some | ||
940 | * other type of fault for the kernel. | ||
941 | */ | ||
942 | andcc %l6, 0x80, %g0 | ||
943 | be sun4c_fault_fromuser | ||
944 | and %l5, %l4, %l5 | ||
945 | |||
946 | /* Test for NULL pte_t * in vmalloc area. */ | ||
947 | sethi %hi(VMALLOC_START), %l4 | ||
948 | cmp %l5, %l4 | ||
949 | blu,a invalid_segment_patch1 | ||
950 | lduXa [%l5] ASI_SEGMAP, %l4 | ||
951 | |||
952 | sethi %hi(swapper_pg_dir), %l4 | ||
953 | srl %l5, SUN4C_PGDIR_SHIFT, %l6 | ||
954 | or %l4, %lo(swapper_pg_dir), %l4 | ||
955 | sll %l6, 2, %l6 | ||
956 | ld [%l4 + %l6], %l4 | ||
957 | #ifdef CONFIG_SUN4 | ||
958 | sethi %hi(PAGE_MASK), %l6 | ||
959 | andcc %l4, %l6, %g0 | ||
960 | #else | ||
961 | andcc %l4, PAGE_MASK, %g0 | ||
962 | #endif | ||
963 | be sun4c_fault_fromuser | ||
964 | lduXa [%l5] ASI_SEGMAP, %l4 | ||
965 | |||
966 | invalid_segment_patch1: | ||
967 | cmp %l4, 0x7f | ||
968 | bne 1f | ||
969 | sethi %hi(sun4c_kfree_ring), %l4 | ||
970 | or %l4, %lo(sun4c_kfree_ring), %l4 | ||
971 | ld [%l4 + 0x18], %l3 | ||
972 | deccc %l3 ! do we have a free entry? | ||
973 | bcs,a 2f ! no, unmap one. | ||
974 | sethi %hi(sun4c_kernel_ring), %l4 | ||
975 | |||
976 | st %l3, [%l4 + 0x18] ! sun4c_kfree_ring.num_entries-- | ||
977 | |||
978 | ld [%l4 + 0x00], %l6 ! entry = sun4c_kfree_ring.ringhd.next | ||
979 | st %l5, [%l6 + 0x08] ! entry->vaddr = address | ||
980 | |||
981 | ld [%l6 + 0x00], %l3 ! next = entry->next | ||
982 | ld [%l6 + 0x04], %l7 ! entry->prev | ||
983 | |||
984 | st %l7, [%l3 + 0x04] ! next->prev = entry->prev | ||
985 | st %l3, [%l7 + 0x00] ! entry->prev->next = next | ||
986 | |||
987 | sethi %hi(sun4c_kernel_ring), %l4 | ||
988 | or %l4, %lo(sun4c_kernel_ring), %l4 | ||
989 | ! head = &sun4c_kernel_ring.ringhd | ||
990 | |||
991 | ld [%l4 + 0x00], %l7 ! head->next | ||
992 | |||
993 | st %l4, [%l6 + 0x04] ! entry->prev = head | ||
994 | st %l7, [%l6 + 0x00] ! entry->next = head->next | ||
995 | st %l6, [%l7 + 0x04] ! head->next->prev = entry | ||
996 | |||
997 | st %l6, [%l4 + 0x00] ! head->next = entry | ||
998 | |||
999 | ld [%l4 + 0x18], %l3 | ||
1000 | inc %l3 ! sun4c_kernel_ring.num_entries++ | ||
1001 | st %l3, [%l4 + 0x18] | ||
1002 | b 4f | ||
1003 | ld [%l6 + 0x08], %l5 | ||
1004 | |||
1005 | 2: | ||
1006 | or %l4, %lo(sun4c_kernel_ring), %l4 | ||
1007 | ! head = &sun4c_kernel_ring.ringhd | ||
1008 | |||
1009 | ld [%l4 + 0x04], %l6 ! entry = head->prev | ||
1010 | |||
1011 | ld [%l6 + 0x08], %l3 ! tmp = entry->vaddr | ||
1012 | |||
1013 | ! Flush segment from the cache. | ||
1014 | #ifdef CONFIG_SUN4 | ||
1015 | sethi %hi((128 * 1024)), %l7 | ||
1016 | #else | ||
1017 | sethi %hi((64 * 1024)), %l7 | ||
1018 | #endif | ||
1019 | 9: | ||
1020 | vac_hwflush_patch1: | ||
1021 | vac_linesize_patch: | ||
1022 | subcc %l7, 16, %l7 | ||
1023 | bne 9b | ||
1024 | vac_hwflush_patch2: | ||
1025 | sta %g0, [%l3 + %l7] ASI_FLUSHSEG | ||
1026 | |||
1027 | st %l5, [%l6 + 0x08] ! entry->vaddr = address | ||
1028 | |||
1029 | ld [%l6 + 0x00], %l5 ! next = entry->next | ||
1030 | ld [%l6 + 0x04], %l7 ! entry->prev | ||
1031 | |||
1032 | st %l7, [%l5 + 0x04] ! next->prev = entry->prev | ||
1033 | st %l5, [%l7 + 0x00] ! entry->prev->next = next | ||
1034 | st %l4, [%l6 + 0x04] ! entry->prev = head | ||
1035 | |||
1036 | ld [%l4 + 0x00], %l7 ! head->next | ||
1037 | |||
1038 | st %l7, [%l6 + 0x00] ! entry->next = head->next | ||
1039 | st %l6, [%l7 + 0x04] ! head->next->prev = entry | ||
1040 | st %l6, [%l4 + 0x00] ! head->next = entry | ||
1041 | |||
1042 | mov %l3, %l5 ! address = tmp | ||
1043 | |||
1044 | 4: | ||
1045 | num_context_patch1: | ||
1046 | mov 0x08, %l7 | ||
1047 | |||
1048 | ld [%l6 + 0x08], %l4 | ||
1049 | ldub [%l6 + 0x0c], %l3 | ||
1050 | or %l4, %l3, %l4 ! encode new vaddr/pseg into l4 | ||
1051 | |||
1052 | sethi %hi(AC_CONTEXT), %l3 | ||
1053 | lduba [%l3] ASI_CONTROL, %l6 | ||
1054 | |||
1055 | /* Invalidate old mapping, instantiate new mapping, | ||
1056 | * for each context. Registers l6/l7 are live across | ||
1057 | * this loop. | ||
1058 | */ | ||
1059 | 3: deccc %l7 | ||
1060 | sethi %hi(AC_CONTEXT), %l3 | ||
1061 | stba %l7, [%l3] ASI_CONTROL | ||
1062 | invalid_segment_patch2: | ||
1063 | mov 0x7f, %l3 | ||
1064 | stXa %l3, [%l5] ASI_SEGMAP | ||
1065 | andn %l4, 0x1ff, %l3 | ||
1066 | bne 3b | ||
1067 | stXa %l4, [%l3] ASI_SEGMAP | ||
1068 | |||
1069 | sethi %hi(AC_CONTEXT), %l3 | ||
1070 | stba %l6, [%l3] ASI_CONTROL | ||
1071 | |||
1072 | andn %l4, 0x1ff, %l5 | ||
1073 | |||
1074 | 1: | ||
1075 | sethi %hi(VMALLOC_START), %l4 | ||
1076 | cmp %l5, %l4 | ||
1077 | |||
1078 | bgeu 1f | ||
1079 | mov 1 << (SUN4C_REAL_PGDIR_SHIFT - PAGE_SHIFT), %l7 | ||
1080 | |||
1081 | sethi %hi(KERNBASE), %l6 | ||
1082 | |||
1083 | sub %l5, %l6, %l4 | ||
1084 | srl %l4, PAGE_SHIFT, %l4 | ||
1085 | sethi %hi((SUN4C_PAGE_KERNEL & 0xf4000000)), %l3 | ||
1086 | or %l3, %l4, %l3 | ||
1087 | |||
1088 | sethi %hi(PAGE_SIZE), %l4 | ||
1089 | |||
1090 | 2: | ||
1091 | sta %l3, [%l5] ASI_PTE | ||
1092 | deccc %l7 | ||
1093 | inc %l3 | ||
1094 | bne 2b | ||
1095 | add %l5, %l4, %l5 | ||
1096 | |||
1097 | b 7f | ||
1098 | sethi %hi(sun4c_kernel_faults), %l4 | ||
1099 | |||
1100 | 1: | ||
1101 | srl %l5, SUN4C_PGDIR_SHIFT, %l3 | ||
1102 | sethi %hi(swapper_pg_dir), %l4 | ||
1103 | or %l4, %lo(swapper_pg_dir), %l4 | ||
1104 | sll %l3, 2, %l3 | ||
1105 | ld [%l4 + %l3], %l4 | ||
1106 | #ifndef CONFIG_SUN4 | ||
1107 | and %l4, PAGE_MASK, %l4 | ||
1108 | #else | ||
1109 | sethi %hi(PAGE_MASK), %l6 | ||
1110 | and %l4, %l6, %l4 | ||
1111 | #endif | ||
1112 | |||
1113 | srl %l5, (PAGE_SHIFT - 2), %l6 | ||
1114 | and %l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6 | ||
1115 | add %l6, %l4, %l6 | ||
1116 | |||
1117 | sethi %hi(PAGE_SIZE), %l4 | ||
1118 | |||
1119 | 2: | ||
1120 | ld [%l6], %l3 | ||
1121 | deccc %l7 | ||
1122 | sta %l3, [%l5] ASI_PTE | ||
1123 | add %l6, 0x4, %l6 | ||
1124 | bne 2b | ||
1125 | add %l5, %l4, %l5 | ||
1126 | |||
1127 | sethi %hi(sun4c_kernel_faults), %l4 | ||
1128 | 7: | ||
1129 | ld [%l4 + %lo(sun4c_kernel_faults)], %l3 | ||
1130 | inc %l3 | ||
1131 | st %l3, [%l4 + %lo(sun4c_kernel_faults)] | ||
1132 | |||
1133 | /* Restore condition codes */ | ||
1134 | wr %l0, 0x0, %psr | ||
1135 | WRITE_PAUSE | ||
1136 | jmp %l1 | ||
1137 | rett %l2 | ||
1138 | |||
1139 | sun4c_fault_fromuser: | ||
1140 | SAVE_ALL | ||
1141 | nop | ||
1142 | |||
1143 | mov %l7, %o1 ! Decode the info from %l7 | ||
1144 | mov %l7, %o2 | ||
1145 | and %o1, 1, %o1 ! arg2 = text_faultp | ||
1146 | mov %l7, %o3 | ||
1147 | and %o2, 2, %o2 ! arg3 = writep | ||
1148 | andn %o3, 0xfff, %o3 ! arg4 = faulting address | ||
1149 | |||
1150 | wr %l0, PSR_ET, %psr | ||
1151 | WRITE_PAUSE | ||
1152 | |||
1153 | call do_sun4c_fault | ||
1154 | add %sp, STACKFRAME_SZ, %o0 ! arg1 = pt_regs ptr | ||
1155 | |||
1156 | RESTORE_ALL | ||
1157 | |||
1158 | .align 4 | ||
1159 | .globl srmmu_fault | ||
1160 | srmmu_fault: | ||
1161 | mov 0x400, %l5 | ||
1162 | mov 0x300, %l4 | ||
1163 | |||
1164 | lda [%l5] ASI_M_MMUREGS, %l6 ! read sfar first | ||
1165 | lda [%l4] ASI_M_MMUREGS, %l5 ! read sfsr last | ||
1166 | |||
1167 | andn %l6, 0xfff, %l6 | ||
1168 | srl %l5, 6, %l5 ! and encode all info into l7 | ||
1169 | |||
1170 | and %l5, 2, %l5 | ||
1171 | or %l5, %l6, %l6 | ||
1172 | |||
1173 | or %l6, %l7, %l7 ! l7 = [addr,write,txtfault] | ||
1174 | |||
1175 | SAVE_ALL | ||
1176 | |||
1177 | mov %l7, %o1 | ||
1178 | mov %l7, %o2 | ||
1179 | and %o1, 1, %o1 ! arg2 = text_faultp | ||
1180 | mov %l7, %o3 | ||
1181 | and %o2, 2, %o2 ! arg3 = writep | ||
1182 | andn %o3, 0xfff, %o3 ! arg4 = faulting address | ||
1183 | |||
1184 | wr %l0, PSR_ET, %psr | ||
1185 | WRITE_PAUSE | ||
1186 | |||
1187 | call do_sparc_fault | ||
1188 | add %sp, STACKFRAME_SZ, %o0 ! arg1 = pt_regs ptr | ||
1189 | |||
1190 | RESTORE_ALL | ||
1191 | |||
1192 | #ifdef CONFIG_SUNOS_EMUL | ||
1193 | /* SunOS uses syscall zero as the 'indirect syscall' it looks | ||
1194 | * like indir_syscall(scall_num, arg0, arg1, arg2...); etc. | ||
1195 | * This is complete brain damage. | ||
1196 | */ | ||
1197 | .globl sunos_indir | ||
1198 | sunos_indir: | ||
1199 | mov %o7, %l4 | ||
1200 | cmp %o0, NR_SYSCALLS | ||
1201 | blu,a 1f | ||
1202 | sll %o0, 0x2, %o0 | ||
1203 | |||
1204 | sethi %hi(sunos_nosys), %l6 | ||
1205 | b 2f | ||
1206 | or %l6, %lo(sunos_nosys), %l6 | ||
1207 | |||
1208 | 1: | ||
1209 | set sunos_sys_table, %l7 | ||
1210 | ld [%l7 + %o0], %l6 | ||
1211 | |||
1212 | 2: | ||
1213 | mov %o1, %o0 | ||
1214 | mov %o2, %o1 | ||
1215 | mov %o3, %o2 | ||
1216 | mov %o4, %o3 | ||
1217 | mov %o5, %o4 | ||
1218 | call %l6 | ||
1219 | mov %l4, %o7 | ||
1220 | #endif | ||
1221 | |||
1222 | .align 4 | ||
1223 | .globl sys_nis_syscall | ||
1224 | sys_nis_syscall: | ||
1225 | mov %o7, %l5 | ||
1226 | add %sp, STACKFRAME_SZ, %o0 ! pt_regs *regs arg | ||
1227 | call c_sys_nis_syscall | ||
1228 | mov %l5, %o7 | ||
1229 | |||
1230 | .align 4 | ||
1231 | .globl sys_ptrace | ||
1232 | sys_ptrace: | ||
1233 | call do_ptrace | ||
1234 | add %sp, STACKFRAME_SZ, %o0 | ||
1235 | |||
1236 | ld [%curptr + TI_FLAGS], %l5 | ||
1237 | andcc %l5, _TIF_SYSCALL_TRACE, %g0 | ||
1238 | be 1f | ||
1239 | nop | ||
1240 | |||
1241 | call syscall_trace | ||
1242 | nop | ||
1243 | |||
1244 | 1: | ||
1245 | RESTORE_ALL | ||
1246 | |||
1247 | .align 4 | ||
1248 | .globl sys_execve | ||
1249 | sys_execve: | ||
1250 | mov %o7, %l5 | ||
1251 | add %sp, STACKFRAME_SZ, %o0 ! pt_regs *regs arg | ||
1252 | call sparc_execve | ||
1253 | mov %l5, %o7 | ||
1254 | |||
1255 | .align 4 | ||
1256 | .globl sys_pipe | ||
1257 | sys_pipe: | ||
1258 | mov %o7, %l5 | ||
1259 | add %sp, STACKFRAME_SZ, %o0 ! pt_regs *regs arg | ||
1260 | call sparc_pipe | ||
1261 | mov %l5, %o7 | ||
1262 | |||
1263 | .align 4 | ||
1264 | .globl sys_sigaltstack | ||
1265 | sys_sigaltstack: | ||
1266 | mov %o7, %l5 | ||
1267 | mov %fp, %o2 | ||
1268 | call do_sigaltstack | ||
1269 | mov %l5, %o7 | ||
1270 | |||
1271 | .align 4 | ||
1272 | .globl sys_sigstack | ||
1273 | sys_sigstack: | ||
1274 | mov %o7, %l5 | ||
1275 | mov %fp, %o2 | ||
1276 | call do_sys_sigstack | ||
1277 | mov %l5, %o7 | ||
1278 | |||
1279 | .align 4 | ||
1280 | .globl sys_sigpause | ||
1281 | sys_sigpause: | ||
1282 | /* Note: %o0 already has correct value... */ | ||
1283 | call do_sigpause | ||
1284 | add %sp, STACKFRAME_SZ, %o1 | ||
1285 | |||
1286 | ld [%curptr + TI_FLAGS], %l5 | ||
1287 | andcc %l5, _TIF_SYSCALL_TRACE, %g0 | ||
1288 | be 1f | ||
1289 | nop | ||
1290 | |||
1291 | call syscall_trace | ||
1292 | nop | ||
1293 | |||
1294 | 1: | ||
1295 | /* We are returning to a signal handler. */ | ||
1296 | RESTORE_ALL | ||
1297 | |||
1298 | .align 4 | ||
1299 | .globl sys_sigsuspend | ||
1300 | sys_sigsuspend: | ||
1301 | call do_sigsuspend | ||
1302 | add %sp, STACKFRAME_SZ, %o0 | ||
1303 | |||
1304 | ld [%curptr + TI_FLAGS], %l5 | ||
1305 | andcc %l5, _TIF_SYSCALL_TRACE, %g0 | ||
1306 | be 1f | ||
1307 | nop | ||
1308 | |||
1309 | call syscall_trace | ||
1310 | nop | ||
1311 | |||
1312 | 1: | ||
1313 | /* We are returning to a signal handler. */ | ||
1314 | RESTORE_ALL | ||
1315 | |||
1316 | .align 4 | ||
1317 | .globl sys_rt_sigsuspend | ||
1318 | sys_rt_sigsuspend: | ||
1319 | /* Note: %o0, %o1 already have correct value... */ | ||
1320 | call do_rt_sigsuspend | ||
1321 | add %sp, STACKFRAME_SZ, %o2 | ||
1322 | |||
1323 | ld [%curptr + TI_FLAGS], %l5 | ||
1324 | andcc %l5, _TIF_SYSCALL_TRACE, %g0 | ||
1325 | be 1f | ||
1326 | nop | ||
1327 | |||
1328 | call syscall_trace | ||
1329 | nop | ||
1330 | |||
1331 | 1: | ||
1332 | /* We are returning to a signal handler. */ | ||
1333 | RESTORE_ALL | ||
1334 | |||
1335 | .align 4 | ||
1336 | .globl sys_sigreturn | ||
1337 | sys_sigreturn: | ||
1338 | call do_sigreturn | ||
1339 | add %sp, STACKFRAME_SZ, %o0 | ||
1340 | |||
1341 | ld [%curptr + TI_FLAGS], %l5 | ||
1342 | andcc %l5, _TIF_SYSCALL_TRACE, %g0 | ||
1343 | be 1f | ||
1344 | nop | ||
1345 | |||
1346 | call syscall_trace | ||
1347 | nop | ||
1348 | |||
1349 | 1: | ||
1350 | /* We don't want to muck with user registers like a | ||
1351 | * normal syscall, just return. | ||
1352 | */ | ||
1353 | RESTORE_ALL | ||
1354 | |||
1355 | .align 4 | ||
1356 | .globl sys_rt_sigreturn | ||
1357 | sys_rt_sigreturn: | ||
1358 | call do_rt_sigreturn | ||
1359 | add %sp, STACKFRAME_SZ, %o0 | ||
1360 | |||
1361 | ld [%curptr + TI_FLAGS], %l5 | ||
1362 | andcc %l5, _TIF_SYSCALL_TRACE, %g0 | ||
1363 | be 1f | ||
1364 | nop | ||
1365 | |||
1366 | call syscall_trace | ||
1367 | nop | ||
1368 | |||
1369 | 1: | ||
1370 | /* We are returning to a signal handler. */ | ||
1371 | RESTORE_ALL | ||
1372 | |||
1373 | /* Now that we have a real sys_clone, sys_fork() is | ||
1374 | * implemented in terms of it. Our _real_ implementation | ||
1375 | * of SunOS vfork() will use sys_vfork(). | ||
1376 | * | ||
1377 | * XXX These three should be consolidated into mostly shared | ||
1378 | * XXX code just like on sparc64... -DaveM | ||
1379 | */ | ||
1380 | .align 4 | ||
1381 | .globl sys_fork, flush_patch_two | ||
1382 | sys_fork: | ||
1383 | mov %o7, %l5 | ||
1384 | flush_patch_two: | ||
1385 | FLUSH_ALL_KERNEL_WINDOWS; | ||
1386 | ld [%curptr + TI_TASK], %o4 | ||
1387 | rd %psr, %g4 | ||
1388 | WRITE_PAUSE | ||
1389 | mov SIGCHLD, %o0 ! arg0: clone flags | ||
1390 | rd %wim, %g5 | ||
1391 | WRITE_PAUSE | ||
1392 | mov %fp, %o1 ! arg1: usp | ||
1393 | std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr] | ||
1394 | add %sp, STACKFRAME_SZ, %o2 ! arg2: pt_regs ptr | ||
1395 | mov 0, %o3 | ||
1396 | call sparc_do_fork | ||
1397 | mov %l5, %o7 | ||
1398 | |||
1399 | /* Whee, kernel threads! */ | ||
1400 | .globl sys_clone, flush_patch_three | ||
1401 | sys_clone: | ||
1402 | mov %o7, %l5 | ||
1403 | flush_patch_three: | ||
1404 | FLUSH_ALL_KERNEL_WINDOWS; | ||
1405 | ld [%curptr + TI_TASK], %o4 | ||
1406 | rd %psr, %g4 | ||
1407 | WRITE_PAUSE | ||
1408 | |||
1409 | /* arg0,1: flags,usp -- loaded already */ | ||
1410 | cmp %o1, 0x0 ! Is new_usp NULL? | ||
1411 | rd %wim, %g5 | ||
1412 | WRITE_PAUSE | ||
1413 | be,a 1f | ||
1414 | mov %fp, %o1 ! yes, use callers usp | ||
1415 | andn %o1, 7, %o1 ! no, align to 8 bytes | ||
1416 | 1: | ||
1417 | std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr] | ||
1418 | add %sp, STACKFRAME_SZ, %o2 ! arg2: pt_regs ptr | ||
1419 | mov 0, %o3 | ||
1420 | call sparc_do_fork | ||
1421 | mov %l5, %o7 | ||
1422 | |||
1423 | /* Whee, real vfork! */ | ||
1424 | .globl sys_vfork, flush_patch_four | ||
1425 | sys_vfork: | ||
1426 | flush_patch_four: | ||
1427 | FLUSH_ALL_KERNEL_WINDOWS; | ||
1428 | ld [%curptr + TI_TASK], %o4 | ||
1429 | rd %psr, %g4 | ||
1430 | WRITE_PAUSE | ||
1431 | rd %wim, %g5 | ||
1432 | WRITE_PAUSE | ||
1433 | std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr] | ||
1434 | sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0 | ||
1435 | mov %fp, %o1 | ||
1436 | or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 | ||
1437 | sethi %hi(sparc_do_fork), %l1 | ||
1438 | mov 0, %o3 | ||
1439 | jmpl %l1 + %lo(sparc_do_fork), %g0 | ||
1440 | add %sp, STACKFRAME_SZ, %o2 | ||
1441 | |||
1442 | .align 4 | ||
1443 | linux_sparc_ni_syscall: | ||
1444 | sethi %hi(sys_ni_syscall), %l7 | ||
1445 | b syscall_is_too_hard | ||
1446 | or %l7, %lo(sys_ni_syscall), %l7 | ||
1447 | |||
1448 | linux_fast_syscall: | ||
1449 | andn %l7, 3, %l7 | ||
1450 | mov %i0, %o0 | ||
1451 | mov %i1, %o1 | ||
1452 | mov %i2, %o2 | ||
1453 | jmpl %l7 + %g0, %g0 | ||
1454 | mov %i3, %o3 | ||
1455 | |||
1456 | linux_syscall_trace: | ||
1457 | call syscall_trace | ||
1458 | nop | ||
1459 | mov %i0, %o0 | ||
1460 | mov %i1, %o1 | ||
1461 | mov %i2, %o2 | ||
1462 | mov %i3, %o3 | ||
1463 | b 2f | ||
1464 | mov %i4, %o4 | ||
1465 | |||
1466 | .globl ret_from_fork | ||
1467 | ret_from_fork: | ||
1468 | call schedule_tail | ||
1469 | mov %g3, %o0 | ||
1470 | b ret_sys_call | ||
1471 | ld [%sp + STACKFRAME_SZ + PT_I0], %o0 | ||
1472 | |||
1473 | /* Linux native and SunOS system calls enter here... */ | ||
1474 | .align 4 | ||
1475 | .globl linux_sparc_syscall | ||
1476 | linux_sparc_syscall: | ||
1477 | /* Direct access to user regs, must faster. */ | ||
1478 | cmp %g1, NR_SYSCALLS | ||
1479 | bgeu linux_sparc_ni_syscall | ||
1480 | sll %g1, 2, %l4 | ||
1481 | ld [%l7 + %l4], %l7 | ||
1482 | andcc %l7, 1, %g0 | ||
1483 | bne linux_fast_syscall | ||
1484 | /* Just do first insn from SAVE_ALL in the delay slot */ | ||
1485 | |||
1486 | .globl syscall_is_too_hard | ||
1487 | syscall_is_too_hard: | ||
1488 | SAVE_ALL_HEAD | ||
1489 | rd %wim, %l3 | ||
1490 | |||
1491 | wr %l0, PSR_ET, %psr | ||
1492 | mov %i0, %o0 | ||
1493 | mov %i1, %o1 | ||
1494 | mov %i2, %o2 | ||
1495 | |||
1496 | ld [%curptr + TI_FLAGS], %l5 | ||
1497 | mov %i3, %o3 | ||
1498 | andcc %l5, _TIF_SYSCALL_TRACE, %g0 | ||
1499 | mov %i4, %o4 | ||
1500 | bne linux_syscall_trace | ||
1501 | mov %i0, %l5 | ||
1502 | 2: | ||
1503 | call %l7 | ||
1504 | mov %i5, %o5 | ||
1505 | |||
1506 | st %o0, [%sp + STACKFRAME_SZ + PT_I0] | ||
1507 | |||
1508 | .globl ret_sys_call | ||
1509 | ret_sys_call: | ||
1510 | ld [%curptr + TI_FLAGS], %l6 | ||
1511 | cmp %o0, -ERESTART_RESTARTBLOCK | ||
1512 | ld [%sp + STACKFRAME_SZ + PT_PSR], %g3 | ||
1513 | set PSR_C, %g2 | ||
1514 | bgeu 1f | ||
1515 | andcc %l6, _TIF_SYSCALL_TRACE, %g0 | ||
1516 | |||
1517 | /* System call success, clear Carry condition code. */ | ||
1518 | andn %g3, %g2, %g3 | ||
1519 | clr %l6 | ||
1520 | st %g3, [%sp + STACKFRAME_SZ + PT_PSR] | ||
1521 | bne linux_syscall_trace2 | ||
1522 | ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */ | ||
1523 | add %l1, 0x4, %l2 /* npc = npc+4 */ | ||
1524 | st %l1, [%sp + STACKFRAME_SZ + PT_PC] | ||
1525 | b ret_trap_entry | ||
1526 | st %l2, [%sp + STACKFRAME_SZ + PT_NPC] | ||
1527 | 1: | ||
1528 | /* System call failure, set Carry condition code. | ||
1529 | * Also, get abs(errno) to return to the process. | ||
1530 | */ | ||
1531 | sub %g0, %o0, %o0 | ||
1532 | or %g3, %g2, %g3 | ||
1533 | st %o0, [%sp + STACKFRAME_SZ + PT_I0] | ||
1534 | mov 1, %l6 | ||
1535 | st %g3, [%sp + STACKFRAME_SZ + PT_PSR] | ||
1536 | bne linux_syscall_trace2 | ||
1537 | ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */ | ||
1538 | add %l1, 0x4, %l2 /* npc = npc+4 */ | ||
1539 | st %l1, [%sp + STACKFRAME_SZ + PT_PC] | ||
1540 | b ret_trap_entry | ||
1541 | st %l2, [%sp + STACKFRAME_SZ + PT_NPC] | ||
1542 | |||
1543 | linux_syscall_trace2: | ||
1544 | call syscall_trace | ||
1545 | add %l1, 0x4, %l2 /* npc = npc+4 */ | ||
1546 | st %l1, [%sp + STACKFRAME_SZ + PT_PC] | ||
1547 | b ret_trap_entry | ||
1548 | st %l2, [%sp + STACKFRAME_SZ + PT_NPC] | ||
1549 | |||
1550 | |||
1551 | /* | ||
1552 | * Solaris system calls and indirect system calls enter here. | ||
1553 | * | ||
1554 | * I have named the solaris indirect syscalls like that because | ||
1555 | * it seems like Solaris has some fast path syscalls that can | ||
1556 | * be handled as indirect system calls. - mig | ||
1557 | */ | ||
1558 | |||
1559 | linux_syscall_for_solaris: | ||
1560 | sethi %hi(sys_call_table), %l7 | ||
1561 | b linux_sparc_syscall | ||
1562 | or %l7, %lo(sys_call_table), %l7 | ||
1563 | |||
1564 | .align 4 | ||
1565 | .globl solaris_syscall | ||
1566 | solaris_syscall: | ||
1567 | cmp %g1,59 | ||
1568 | be linux_syscall_for_solaris | ||
1569 | cmp %g1,2 | ||
1570 | be linux_syscall_for_solaris | ||
1571 | cmp %g1,42 | ||
1572 | be linux_syscall_for_solaris | ||
1573 | cmp %g1,119 | ||
1574 | be,a linux_syscall_for_solaris | ||
1575 | mov 2, %g1 | ||
1576 | 1: | ||
1577 | SAVE_ALL_HEAD | ||
1578 | rd %wim, %l3 | ||
1579 | |||
1580 | wr %l0, PSR_ET, %psr | ||
1581 | nop | ||
1582 | nop | ||
1583 | mov %i0, %l5 | ||
1584 | |||
1585 | call do_solaris_syscall | ||
1586 | add %sp, STACKFRAME_SZ, %o0 | ||
1587 | |||
1588 | st %o0, [%sp + STACKFRAME_SZ + PT_I0] | ||
1589 | set PSR_C, %g2 | ||
1590 | cmp %o0, -ERESTART_RESTARTBLOCK | ||
1591 | bgeu 1f | ||
1592 | ld [%sp + STACKFRAME_SZ + PT_PSR], %g3 | ||
1593 | |||
1594 | /* System call success, clear Carry condition code. */ | ||
1595 | andn %g3, %g2, %g3 | ||
1596 | clr %l6 | ||
1597 | b 2f | ||
1598 | st %g3, [%sp + STACKFRAME_SZ + PT_PSR] | ||
1599 | |||
1600 | 1: | ||
1601 | /* System call failure, set Carry condition code. | ||
1602 | * Also, get abs(errno) to return to the process. | ||
1603 | */ | ||
1604 | sub %g0, %o0, %o0 | ||
1605 | mov 1, %l6 | ||
1606 | st %o0, [%sp + STACKFRAME_SZ + PT_I0] | ||
1607 | or %g3, %g2, %g3 | ||
1608 | st %g3, [%sp + STACKFRAME_SZ + PT_PSR] | ||
1609 | |||
1610 | /* Advance the pc and npc over the trap instruction. | ||
1611 | * If the npc is unaligned (has a 1 in the lower byte), it means | ||
1612 | * the kernel does not want us to play magic (ie, skipping over | ||
1613 | * traps). Mainly when the Solaris code wants to set some PC and | ||
1614 | * nPC (setcontext). | ||
1615 | */ | ||
1616 | 2: | ||
1617 | ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */ | ||
1618 | andcc %l1, 1, %g0 | ||
1619 | bne 1f | ||
1620 | add %l1, 0x4, %l2 /* npc = npc+4 */ | ||
1621 | st %l1, [%sp + STACKFRAME_SZ + PT_PC] | ||
1622 | b ret_trap_entry | ||
1623 | st %l2, [%sp + STACKFRAME_SZ + PT_NPC] | ||
1624 | |||
1625 | /* kernel knows what it is doing, fixup npc and continue */ | ||
1626 | 1: | ||
1627 | sub %l1, 1, %l1 | ||
1628 | b ret_trap_entry | ||
1629 | st %l1, [%sp + STACKFRAME_SZ + PT_NPC] | ||
1630 | |||
1631 | #ifndef CONFIG_SUNOS_EMUL | ||
1632 | .align 4 | ||
1633 | .globl sunos_syscall | ||
1634 | sunos_syscall: | ||
1635 | SAVE_ALL_HEAD | ||
1636 | rd %wim, %l3 | ||
1637 | wr %l0, PSR_ET, %psr | ||
1638 | nop | ||
1639 | nop | ||
1640 | mov %i0, %l5 | ||
1641 | call do_sunos_syscall | ||
1642 | add %sp, STACKFRAME_SZ, %o0 | ||
1643 | #endif | ||
1644 | |||
1645 | /* {net, open}bsd system calls enter here... */ | ||
1646 | .align 4 | ||
1647 | .globl bsd_syscall | ||
1648 | bsd_syscall: | ||
1649 | /* Direct access to user regs, must faster. */ | ||
1650 | cmp %g1, NR_SYSCALLS | ||
1651 | blu,a 1f | ||
1652 | sll %g1, 2, %l4 | ||
1653 | |||
1654 | set sys_ni_syscall, %l7 | ||
1655 | b bsd_is_too_hard | ||
1656 | nop | ||
1657 | |||
1658 | 1: | ||
1659 | ld [%l7 + %l4], %l7 | ||
1660 | |||
1661 | .globl bsd_is_too_hard | ||
1662 | bsd_is_too_hard: | ||
1663 | rd %wim, %l3 | ||
1664 | SAVE_ALL | ||
1665 | |||
1666 | wr %l0, PSR_ET, %psr | ||
1667 | WRITE_PAUSE | ||
1668 | |||
1669 | 2: | ||
1670 | mov %i0, %o0 | ||
1671 | mov %i1, %o1 | ||
1672 | mov %i2, %o2 | ||
1673 | mov %i0, %l5 | ||
1674 | mov %i3, %o3 | ||
1675 | mov %i4, %o4 | ||
1676 | call %l7 | ||
1677 | mov %i5, %o5 | ||
1678 | |||
1679 | st %o0, [%sp + STACKFRAME_SZ + PT_I0] | ||
1680 | set PSR_C, %g2 | ||
1681 | cmp %o0, -ERESTART_RESTARTBLOCK | ||
1682 | bgeu 1f | ||
1683 | ld [%sp + STACKFRAME_SZ + PT_PSR], %g3 | ||
1684 | |||
1685 | /* System call success, clear Carry condition code. */ | ||
1686 | andn %g3, %g2, %g3 | ||
1687 | clr %l6 | ||
1688 | b 2f | ||
1689 | st %g3, [%sp + STACKFRAME_SZ + PT_PSR] | ||
1690 | |||
1691 | 1: | ||
1692 | /* System call failure, set Carry condition code. | ||
1693 | * Also, get abs(errno) to return to the process. | ||
1694 | */ | ||
1695 | sub %g0, %o0, %o0 | ||
1696 | #if 0 /* XXX todo XXX */ | ||
1697 | sethi %hi(bsd_xlatb_rorl), %o3 | ||
1698 | or %o3, %lo(bsd_xlatb_rorl), %o3 | ||
1699 | sll %o0, 2, %o0 | ||
1700 | ld [%o3 + %o0], %o0 | ||
1701 | #endif | ||
1702 | mov 1, %l6 | ||
1703 | st %o0, [%sp + STACKFRAME_SZ + PT_I0] | ||
1704 | or %g3, %g2, %g3 | ||
1705 | st %g3, [%sp + STACKFRAME_SZ + PT_PSR] | ||
1706 | |||
1707 | /* Advance the pc and npc over the trap instruction. */ | ||
1708 | 2: | ||
1709 | ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */ | ||
1710 | add %l1, 0x4, %l2 /* npc = npc+4 */ | ||
1711 | st %l1, [%sp + STACKFRAME_SZ + PT_PC] | ||
1712 | b ret_trap_entry | ||
1713 | st %l2, [%sp + STACKFRAME_SZ + PT_NPC] | ||
1714 | |||
1715 | /* Saving and restoring the FPU state is best done from lowlevel code. | ||
1716 | * | ||
1717 | * void fpsave(unsigned long *fpregs, unsigned long *fsr, | ||
1718 | * void *fpqueue, unsigned long *fpqdepth) | ||
1719 | */ | ||
1720 | |||
1721 | .globl fpsave | ||
1722 | fpsave: | ||
1723 | st %fsr, [%o1] ! this can trap on us if fpu is in bogon state | ||
1724 | ld [%o1], %g1 | ||
1725 | set 0x2000, %g4 | ||
1726 | andcc %g1, %g4, %g0 | ||
1727 | be 2f | ||
1728 | mov 0, %g2 | ||
1729 | |||
1730 | /* We have an fpqueue to save. */ | ||
1731 | 1: | ||
1732 | std %fq, [%o2] | ||
1733 | fpsave_magic: | ||
1734 | st %fsr, [%o1] | ||
1735 | ld [%o1], %g3 | ||
1736 | andcc %g3, %g4, %g0 | ||
1737 | add %g2, 1, %g2 | ||
1738 | bne 1b | ||
1739 | add %o2, 8, %o2 | ||
1740 | |||
1741 | 2: | ||
1742 | st %g2, [%o3] | ||
1743 | |||
1744 | std %f0, [%o0 + 0x00] | ||
1745 | std %f2, [%o0 + 0x08] | ||
1746 | std %f4, [%o0 + 0x10] | ||
1747 | std %f6, [%o0 + 0x18] | ||
1748 | std %f8, [%o0 + 0x20] | ||
1749 | std %f10, [%o0 + 0x28] | ||
1750 | std %f12, [%o0 + 0x30] | ||
1751 | std %f14, [%o0 + 0x38] | ||
1752 | std %f16, [%o0 + 0x40] | ||
1753 | std %f18, [%o0 + 0x48] | ||
1754 | std %f20, [%o0 + 0x50] | ||
1755 | std %f22, [%o0 + 0x58] | ||
1756 | std %f24, [%o0 + 0x60] | ||
1757 | std %f26, [%o0 + 0x68] | ||
1758 | std %f28, [%o0 + 0x70] | ||
1759 | retl | ||
1760 | std %f30, [%o0 + 0x78] | ||
1761 | |||
1762 | /* Thanks for Theo Deraadt and the authors of the Sprite/netbsd/openbsd | ||
1763 | * code for pointing out this possible deadlock, while we save state | ||
1764 | * above we could trap on the fsr store so our low level fpu trap | ||
1765 | * code has to know how to deal with this. | ||
1766 | */ | ||
1767 | fpsave_catch: | ||
1768 | b fpsave_magic + 4 | ||
1769 | st %fsr, [%o1] | ||
1770 | |||
1771 | fpsave_catch2: | ||
1772 | b fpsave + 4 | ||
1773 | st %fsr, [%o1] | ||
1774 | |||
1775 | /* void fpload(unsigned long *fpregs, unsigned long *fsr); */ | ||
1776 | |||
1777 | .globl fpload | ||
1778 | fpload: | ||
1779 | ldd [%o0 + 0x00], %f0 | ||
1780 | ldd [%o0 + 0x08], %f2 | ||
1781 | ldd [%o0 + 0x10], %f4 | ||
1782 | ldd [%o0 + 0x18], %f6 | ||
1783 | ldd [%o0 + 0x20], %f8 | ||
1784 | ldd [%o0 + 0x28], %f10 | ||
1785 | ldd [%o0 + 0x30], %f12 | ||
1786 | ldd [%o0 + 0x38], %f14 | ||
1787 | ldd [%o0 + 0x40], %f16 | ||
1788 | ldd [%o0 + 0x48], %f18 | ||
1789 | ldd [%o0 + 0x50], %f20 | ||
1790 | ldd [%o0 + 0x58], %f22 | ||
1791 | ldd [%o0 + 0x60], %f24 | ||
1792 | ldd [%o0 + 0x68], %f26 | ||
1793 | ldd [%o0 + 0x70], %f28 | ||
1794 | ldd [%o0 + 0x78], %f30 | ||
1795 | ld [%o1], %fsr | ||
1796 | retl | ||
1797 | nop | ||
1798 | |||
1799 | /* __ndelay and __udelay take two arguments: | ||
1800 | * 0 - nsecs or usecs to delay | ||
1801 | * 1 - per_cpu udelay_val (loops per jiffy) | ||
1802 | * | ||
1803 | * Note that ndelay gives HZ times higher resolution but has a 10ms | ||
1804 | * limit. udelay can handle up to 1s. | ||
1805 | */ | ||
1806 | .globl __ndelay | ||
1807 | __ndelay: | ||
1808 | save %sp, -STACKFRAME_SZ, %sp | ||
1809 | mov %i0, %o0 | ||
1810 | call .umul | ||
1811 | mov 0x1ad, %o1 ! 2**32 / (1 000 000 000 / HZ) | ||
1812 | call .umul | ||
1813 | mov %i1, %o1 ! udelay_val | ||
1814 | ba delay_continue | ||
1815 | mov %o1, %o0 ! >>32 later for better resolution | ||
1816 | |||
1817 | .globl __udelay | ||
1818 | __udelay: | ||
1819 | save %sp, -STACKFRAME_SZ, %sp | ||
1820 | mov %i0, %o0 | ||
1821 | sethi %hi(0x10c6), %o1 | ||
1822 | call .umul | ||
1823 | or %o1, %lo(0x10c6), %o1 ! 2**32 / 1 000 000 | ||
1824 | call .umul | ||
1825 | mov %i1, %o1 ! udelay_val | ||
1826 | call .umul | ||
1827 | mov HZ, %o0 ! >>32 earlier for wider range | ||
1828 | |||
1829 | delay_continue: | ||
1830 | cmp %o0, 0x0 | ||
1831 | 1: | ||
1832 | bne 1b | ||
1833 | subcc %o0, 1, %o0 | ||
1834 | |||
1835 | ret | ||
1836 | restore | ||
1837 | |||
1838 | /* Handle a software breakpoint */ | ||
1839 | /* We have to inform parent that child has stopped */ | ||
1840 | .align 4 | ||
1841 | .globl breakpoint_trap | ||
1842 | breakpoint_trap: | ||
1843 | rd %wim,%l3 | ||
1844 | SAVE_ALL | ||
1845 | wr %l0, PSR_ET, %psr | ||
1846 | WRITE_PAUSE | ||
1847 | |||
1848 | st %i0, [%sp + STACKFRAME_SZ + PT_G0] ! for restarting syscalls | ||
1849 | call sparc_breakpoint | ||
1850 | add %sp, STACKFRAME_SZ, %o0 | ||
1851 | |||
1852 | RESTORE_ALL | ||
1853 | |||
1854 | .align 4 | ||
1855 | .globl __handle_exception, flush_patch_exception | ||
1856 | __handle_exception: | ||
1857 | flush_patch_exception: | ||
1858 | FLUSH_ALL_KERNEL_WINDOWS; | ||
1859 | ldd [%o0], %o6 | ||
1860 | jmpl %o7 + 0xc, %g0 ! see asm-sparc/processor.h | ||
1861 | mov 1, %g1 ! signal EFAULT condition | ||
1862 | |||
1863 | .align 4 | ||
1864 | .globl kill_user_windows, kuw_patch1_7win | ||
1865 | .globl kuw_patch1 | ||
1866 | kuw_patch1_7win: sll %o3, 6, %o3 | ||
1867 | |||
1868 | /* No matter how much overhead this routine has in the worst | ||
1869 | * case scenerio, it is several times better than taking the | ||
1870 | * traps with the old method of just doing flush_user_windows(). | ||
1871 | */ | ||
1872 | kill_user_windows: | ||
1873 | ld [%g6 + TI_UWINMASK], %o0 ! get current umask | ||
1874 | orcc %g0, %o0, %g0 ! if no bits set, we are done | ||
1875 | be 3f ! nothing to do | ||
1876 | rd %psr, %o5 ! must clear interrupts | ||
1877 | or %o5, PSR_PIL, %o4 ! or else that could change | ||
1878 | wr %o4, 0x0, %psr ! the uwinmask state | ||
1879 | WRITE_PAUSE ! burn them cycles | ||
1880 | 1: | ||
1881 | ld [%g6 + TI_UWINMASK], %o0 ! get consistent state | ||
1882 | orcc %g0, %o0, %g0 ! did an interrupt come in? | ||
1883 | be 4f ! yep, we are done | ||
1884 | rd %wim, %o3 ! get current wim | ||
1885 | srl %o3, 1, %o4 ! simulate a save | ||
1886 | kuw_patch1: | ||
1887 | sll %o3, 7, %o3 ! compute next wim | ||
1888 | or %o4, %o3, %o3 ! result | ||
1889 | andncc %o0, %o3, %o0 ! clean this bit in umask | ||
1890 | bne kuw_patch1 ! not done yet | ||
1891 | srl %o3, 1, %o4 ! begin another save simulation | ||
1892 | wr %o3, 0x0, %wim ! set the new wim | ||
1893 | st %g0, [%g6 + TI_UWINMASK] ! clear uwinmask | ||
1894 | 4: | ||
1895 | wr %o5, 0x0, %psr ! re-enable interrupts | ||
1896 | WRITE_PAUSE ! burn baby burn | ||
1897 | 3: | ||
1898 | retl ! return | ||
1899 | st %g0, [%g6 + TI_W_SAVED] ! no windows saved | ||
1900 | |||
1901 | .align 4 | ||
1902 | .globl restore_current | ||
1903 | restore_current: | ||
1904 | LOAD_CURRENT(g6, o0) | ||
1905 | retl | ||
1906 | nop | ||
1907 | |||
1908 | #ifdef CONFIG_PCI | ||
1909 | #include <asm/pcic.h> | ||
1910 | |||
1911 | .align 4 | ||
1912 | .globl linux_trap_ipi15_pcic | ||
1913 | linux_trap_ipi15_pcic: | ||
1914 | rd %wim, %l3 | ||
1915 | SAVE_ALL | ||
1916 | |||
1917 | /* | ||
1918 | * First deactivate NMI | ||
1919 | * or we cannot drop ET, cannot get window spill traps. | ||
1920 | * The busy loop is necessary because the PIO error | ||
1921 | * sometimes does not go away quickly and we trap again. | ||
1922 | */ | ||
1923 | sethi %hi(pcic_regs), %o1 | ||
1924 | ld [%o1 + %lo(pcic_regs)], %o2 | ||
1925 | |||
1926 | ! Get pending status for printouts later. | ||
1927 | ld [%o2 + PCI_SYS_INT_PENDING], %o0 | ||
1928 | |||
1929 | mov PCI_SYS_INT_PENDING_CLEAR_ALL, %o1 | ||
1930 | stb %o1, [%o2 + PCI_SYS_INT_PENDING_CLEAR] | ||
1931 | 1: | ||
1932 | ld [%o2 + PCI_SYS_INT_PENDING], %o1 | ||
1933 | andcc %o1, ((PCI_SYS_INT_PENDING_PIO|PCI_SYS_INT_PENDING_PCI)>>24), %g0 | ||
1934 | bne 1b | ||
1935 | nop | ||
1936 | |||
1937 | or %l0, PSR_PIL, %l4 | ||
1938 | wr %l4, 0x0, %psr | ||
1939 | WRITE_PAUSE | ||
1940 | wr %l4, PSR_ET, %psr | ||
1941 | WRITE_PAUSE | ||
1942 | |||
1943 | call pcic_nmi | ||
1944 | add %sp, STACKFRAME_SZ, %o1 ! struct pt_regs *regs | ||
1945 | RESTORE_ALL | ||
1946 | |||
1947 | .globl pcic_nmi_trap_patch | ||
1948 | pcic_nmi_trap_patch: | ||
1949 | sethi %hi(linux_trap_ipi15_pcic), %l3 | ||
1950 | jmpl %l3 + %lo(linux_trap_ipi15_pcic), %g0 | ||
1951 | rd %psr, %l0 | ||
1952 | .word 0 | ||
1953 | |||
1954 | #endif /* CONFIG_PCI */ | ||
1955 | |||
1956 | /* End of entry.S */ | ||