summaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/entry.S
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
committer <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
commite7c2a72e2680827d6a733931273a93461c0d8d1b (patch)
treec9abeda78ef7504062bb2e816bcf3e3c9d680112 /arch/sparc/kernel/entry.S
parentec6044459060a8c9ce7f64405c465d141898548c (diff)
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'arch/sparc/kernel/entry.S')
-rw-r--r--arch/sparc/kernel/entry.S927
1 files changed, 927 insertions, 0 deletions
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
new file mode 100644
index 000000000..21548015e
--- /dev/null
+++ b/arch/sparc/kernel/entry.S
@@ -0,0 +1,927 @@
+/* arch/sparc/kernel/entry.S: Sparc trap low-level entry points.
+ *
+ * Sparc traps are so ugly, this code is going to go through a lot
+ * of changes as I find out more interesting things. See head.S for
+ * the trap table and how it works, this will show you how we get
+ * to these routines.
+ *
+ * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/psr.h>
+#include <asm/cprefix.h>
+#include <asm/vaddrs.h>
+
+/* Here are macros for routines we do often, this allows me to inline this
+ * without making the code look real ugly. Well, the macro looks ugly too but
+ * makes the trap entry code easier to understand.
+ */
+
+/* I really don't like synthetic instructions. So I avoid them like the
+ * plague.
+ */
+
+/* Note that when I have to write a window out, and it is a user's window, I
+ * have to check that the pages of memory that I am going to throw the window(s)
+ * onto are valid and are writable by the user (this is %sp to %sp + 64) before
+ * I start dumping stuff there. We always assume that kernels stack is ok.
+ *
+ * If we have to save a kernel window, only one branch is taken. This should
+ * make trap handlers quicker in this scenario.
+ *
+ * Once 'current' is loaded into %g6, it stays there until we leave
+ * this macro.
+ *
+ * XXX must do some checking on the assumption that kernel stack is always ok
+ */
+
+/* I will document how this works real soon. TODO */
+
+#define TRAP_WIN_CLEAN \
+ or %g0, %g5, %l5; /* we need the globals to do our work */ \
+ or %g0, %g6, %l6; /* and %l0 to %l4 are loaded with important */ \
+ or %g0, %g7, %l7; /* information like the psr and pc's to return to */ \
+ sethi %hi( C_LABEL(current) ), %g6; \
+ ld [%g6 + %lo( C_LABEL(current) )], %g6; \
+ ld [%g6 + THREAD_UWINDOWS], %g7; /* how many user wins are active? */ \
+ subcc %g7, 0x0, %g0; \
+ bne 2f; /* If there are any, branch. */ \
+ save %g0, %g0, %g0; /* Save into that window either way. */ \
+ std %l0, [%sp]; /* If above shows only kernel windows */ \
+1: std %l2, [%sp + 0x8]; /* then we get here. */ \
+ std %l4, [%sp + 0x10]; \
+ std %l6, [%sp + 0x18]; \
+ std %i0, [%sp + 0x20]; \
+ std %i2, [%sp + 0x28]; \
+ std %i4, [%sp + 0x30]; \
+ std %i6, [%sp + 0x38]; \
+ or %g0, 0x1, %g5; \
+ rd %psr, %g7; \
+ sll %g5, %g7, %g5; \
+ wr %g5, 0x0, %wim; /* update %wim to 'now' invalid */ \
+ and %g7, 0x1f, %g7; \
+ st %g7, [%g6 + THREAD_WIM]; /* save 'this' threads mask */ \
+ restore %g0, %g0, %g0; \
+ or %g0, %l5, %g5; /* restore the globals we used */ \
+ or %g0, %l6, %g6; \
+ b 8f; /* we are done */ \
+ or %g0, %l7, %g7; \
+2: sub %g7, 0x1, %g7; \
+ st %g7, [%g6 + THREAD_UWINDOWS]; /* There are user windows if we */ \
+ andcc %sp, 0x7, %g0; /* get here. Check for stack alignment. */ \
+ bne 5f; /* Stack is unaligned, yuck. */ \
+ sra %sp, 0x1e, %g7; /* This stuff checks to see if top 3-bits */ \
+ subcc %g7, 0x0, %g0; /* of stack pointer address are ok. */ \
+ be,a 3f; \
+ andn %sp, 0xfff, %g7; \
+ subcc %g7, -1, %g0; \
+ bne 5f; /* bad stack pointer, ugh */ \
+ andn %sp, 0xfff, %g7; \
+3: lda [%g7] ASI_PTE, %g7; /* Ok, user stack is a valid address */ \
+ srl %g7, 0x1d, %g7; \
+ subcc %g7, 0x6, %g0; /* Can the user write to it? */ \
+ bne 5f; \
+ and %sp, 0xfff, %g7; \
+ subcc %g7, 0xfc1, %g0; /* Is our save area on one page? */ \
+ bl,a 1b; \
+ std %l0, [%sp]; \
+ add %sp, 0x38, %g5; /* Nope, have to check both pages */ \
+ sra %g5, 0x1e, %g7; \
+ subcc %g7, 0x0, %g0; \
+ be,a 4f; \
+ andn %g5, 0xfff, %g7; \
+ subcc %g7, -1, %g0; \
+ bne 5f; \
+ andn %g5, 0xfff, %g7; \
+4: lda [%g7] ASI_PTE, %g7; /* Stack space in 2nd page is valid */ \
+ srl %g7, 0x1d, %g7; \
+ subcc %g7, 0x6, %g0; /* Can user write here too? */ \
+ be,a 1b; \
+ std %l0, [%sp]; \
+5: ld [%g6 + THREAD_UWINDOWS], %g7; /* This is due to either bad page perms */ \
+ add %g6, THREAD_REG_WINDOW, %g5; /* for the users stack area, or the stack */ \
+6: std %l0, [%g5]; /* pointer is misaligned. See above. */ \
+ std %l2, [%g5 + 0x8]; \
+ std %l4, [%g5 + 0x10]; \
+ std %l6, [%g5 + 0x18]; \
+ std %i0, [%g5 + 0x20]; \
+ std %i2, [%g5 + 0x28]; \
+ std %i4, [%g5 + 0x30]; \
+ std %i6, [%g5 + 0x38]; \
+ subcc %g7, 0x1, %g7; \
+ bge,a 6b; /* while(uwindows>=0) { write_win(); */ \
+ save %g5, 0x40, %g5; /* uwindows--; } */ \
+ st %sp, [%g6 + THREAD_USP]; \
+ or %g0, 0x1, %g5; \
+ rd %psr, %g7; \
+ sll %g5, %g7, %g5; \
+ wr %g5, 0x0, %wim; \
+ and %g7, 0x1f, %g7; \
+ st %g7, [%g6 + THREAD_WIM]; /* Update thread_struct fields */ \
+ ld [%g6 + THREAD_UWINDOWS], %g7; \
+ add %g7, 0x1, %g5; \
+ st %g5, [%g6 + THREAD_W_SAVED]; \
+ st %g0, [%g6 + THREAD_UWINDOWS]; \
+7: subcc %g7, 0x1, %g7; /* Restore back to where we started. */ \
+ bge 7b; \
+ restore %g0, %g0, %g0; \
+ or %g0, %l5, %g5; /* Restore the globals. */ \
+ or %g0, %l6, %g6; \
+ or %g0, %l7, %g7; \
+8: nop; /* We are done when we get here. */ \
+
+/* As if the last macro wasn't enough, we have to go through a very similar routine
+ * upon entry to most traps and interrupts. This is save away the current window
+ * if it is the trap window, clean it, and adjust the stack for the handler c-code
+ * to work.
+ */
+
+#define ENTER_TRAP \
+ rd %wim, %l4; \
+ or %g0, 0x1, %l5; \
+ sll %l5, %l0, %l5; \
+ andcc %l0, 0x40, %g0; \
+ bz 1f; \
+ andcc %l4, %l5, %g0; \
+ bz,a 3f; \
+ sub %fp, 0xb0, %sp; \
+ TRAP_WIN_CLEAN \
+ b 3f; \
+ sub %fp, 0xb0, %sp; \
+1: sethi %hi( C_LABEL(current) ), %l6; \
+ ld [%l6 + %lo( C_LABEL(current) )], %l6; \
+ ld [%l6 + THREAD_WIM], %l5; \
+ and %l0, 0x1f, %l4; \
+ cmp %l5, %l3; \
+ ble,a 4f; \
+ sethi %hi( C_LABEL(nwindowsm1) ), %l4; \
+ sub %l5, %l3, %l3; \
+ b 5f; \
+ sub %l3, 0x1, %l5; \
+4: ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
+ sub %l4, %l3, %l4; \
+ add %l5, %l4, %l5; \
+5: st %l5, [%l6 + THREAD_UWINDOWS]; \
+ bz,a 2f; \
+ sethi %hi(TASK_SIZE-176), %l5; \
+ TRAP_WIN_CLEAN; \
+ sethi %hi( C_LABEL(current) ), %l6; \
+ ld [%l6 + %lo( C_LABEL(current) )], %l6; \
+ sethi %hi(TASK_SIZE-176), %l5; \
+2: or %l5, %lo(TASK_SIZE-176), %l5; \
+ add %l6, %l5, %sp; \
+3: \
+
+#define ENTER_IRQ \
+ rd %wim, %l4; \
+ or %g0, 0x1, %l5; \
+ sll %l5, %l0, %l5; \
+ andcc %l0, 0x40, %g0; \
+ bz 1f; \
+ andcc %l4, %l5, %g0; \
+ sethi %hi( C_LABEL(eintstack) ), %l7; \
+ or %l7, %lo( C_LABEL(eintstack) ), %l7; \
+ bz 0f; \
+ nop; \
+ TRAP_WIN_CLEAN \
+ sethi %hi( C_LABEL(eintstack) ), %l7; \
+ or %l7, %lo( C_LABEL(eintstack) ), %l7; \
+0: subcc %fp, %l7, %g0; \
+ bg,a 3f; \
+ sub %l7, 0xb0, %sp; \
+ b 3f; \
+ sub %fp, 0xb0, %sp; \
+1: sethi %hi( C_LABEL(current) ), %l6; \
+ ld [%l6 + %lo( C_LABEL(current) )], %l6; \
+ ld [%l6 + THREAD_WIM], %l5; \
+ and %l0, 0x1f, %l7; \
+ cmp %l5, %l7; \
+ ble,a 4f; \
+ sethi %hi( C_LABEL(nwindowsm1) ), %l4; \
+ sub %l5, %l7, %l7; \
+ b 5f; \
+ sub %l7, 0x1, %l5; \
+4: ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
+ sub %l4, %l7, %l4; \
+ add %l5, %l4, %l5; \
+5: st %l5, [%l6 + THREAD_UWINDOWS]; \
+ bz,a 2f; \
+ sethi %hi( C_LABEL(eintstack) ), %l7; \
+ TRAP_WIN_CLEAN \
+ sethi %hi( C_LABEL(eintstack) ), %l7; \
+2: \
+ sub %l7, 0xb0, %sp; \
+3:
+
+
+ .text
+ .align 4
+
+/* Default trap handler */
+ .globl my_trap_handler
+my_trap_handler:
+#if 1
+ jmp %l1
+ rett %l2
+ nop
+#else
+ rd %wim, %l4
+ or %g0, 0x1, %l5
+ sll %l5, %l0, %l5
+ cmp %l4, %l5 ! are we in the invalid window?
+
+ TRAP_WIN_CLEAN
+
+ nop
+ or %g0, %l3, %o0
+ call C_LABEL(do_hw_interrupt)
+ or %g0, %g0, %o1
+ wr %l0, 0x20, %psr ! re-enable traps and reset the condition codes
+ nop
+ nop
+ nop ! click our heels three times, "no place like home"
+ jmp %l1
+ rett %l2
+#endif /* bogon */
+
+ .align 4
+ .globl sparc_timer
+sparc_timer:
+ sethi %hi(TIMER_VADDR), %l4
+ or %l4, %lo(TIMER_VADDR), %l4 ! read the limit register
+ ld [%l4 + 0xc], %l4 ! to clear the interrupt
+ rd %wim, %l4
+ or %g0, 0x1, %l5
+ sll %l5, %l0, %l5
+ andcc %l0, 0x40, %g0
+ bz st1
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ andcc %l4, %l5, %g0
+ bz st0
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+ TRAP_WIN_CLEAN
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+st0: subcc %fp, %l7, %g0
+ bg,a st3
+ sub %l7, 0xb0, %sp
+ b st3
+ sub %fp, 0xb0, %sp
+st1: sethi %hi( C_LABEL(current) ), %l6
+ ld [%l6 + %lo( C_LABEL(current) )], %l6
+ ld [%l6 + THREAD_WIM], %l5
+ and %l0, 0x1f, %l7
+ cmp %l5, %l7
+ ble,a st4
+ sethi %hi( C_LABEL(nwindowsm1) ), %l4
+ sub %l5, %l7, %l7
+ b st5
+ sub %l7, 0x1, %l5
+st4: ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
+ sub %l4, %l7, %l4
+ add %l5, %l4, %l5
+st5: st %l5, [%l6 + THREAD_UWINDOWS]
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ bz,a st2
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+ TRAP_WIN_CLEAN
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+st2: sub %l7, 0xb0, %sp
+
+st3: std %g2, [%sp + 96 + 24]
+ or %g0, %g1, %l7
+ rd %y, %l6
+ std %g4, [%sp + 96 + 32]
+ andn %l0, PSR_PIL, %l4
+ sll %l3, 0x8, %l5
+ std %g6, [%sp + 96 + 40]
+ or %l5, %l4, %l4
+
+ wr %l4, 0x0, %psr
+ wr %l4, PSR_ET, %psr
+
+ std %l0, [%sp + 96 + 0]
+ std %l2, [%sp + 96 + 8]
+ st %fp, [%sp + 96 + 16]
+
+ or %g0, 14, %o0
+ or %g0, %g0, %o1
+ call C_LABEL(do_sparc_timer)
+ nop
+
+ or %g0, %l7, %g1
+ wr %l6, 0x0, %y
+ ldd [%sp + 96 + 24], %g2
+ ldd [%sp + 96 + 32], %g4
+ ldd [%sp + 96 + 40], %g6
+ wr %l0, 0x0, %psr
+ nop
+ nop
+ nop
+
+ and %l0, 31, %l5
+ sethi %hi(lnx_winmask), %l6
+ or %l6, %lo(lnx_winmask), %l6
+ ldub [%l6 + %l5], %l5
+ andcc %l0, PSR_PS, %g0
+ bnz 1f
+ rd %wim, %l4
+
+1: andcc %l5, %l4, %g0
+ bnz 2f
+ wr %l0, 0x0, %psr
+ nop
+ nop
+ nop
+
+ jmp %l1
+ rett %l2
+
+2: wr %g0, 0x0, %wim
+ nop
+ nop
+ nop
+
+ restore
+ restore %g0, 0x1, %l1
+ rd %psr, %l0
+ and %l0, 31, %l0
+ sll %l1, %l0, %l1
+ wr %l1, 0x0, %wim
+ sethi %hi( C_LABEL(current) ), %l1
+ ld [%l1 + %lo( C_LABEL(current) ) ], %l1
+ st %l0, [%l1 + THREAD_WIM]
+ save %g0, %g0, %g0
+
+ ldd [%sp], %l0
+ ldd [%sp + 0x8], %l2
+ ldd [%sp + 0x10], %l4
+ ldd [%sp + 0x18], %l6
+ ldd [%sp + 0x20], %i0
+ ldd [%sp + 0x28], %i2
+ ldd [%sp + 0x30], %i4
+ ldd [%sp + 0x38], %i6
+
+ save %g0, %g0, %g0
+
+ jmp %l1
+ rett %l2
+
+
+/* For now all IRQ's not registered get sent here so I can see
+ * what is poking the chip.
+ */
+
+ .align 4
+ .globl stray_irq_entry
+stray_irq_entry:
+ rd %wim, %l4
+ or %g0, 0x1, %l5
+ sll %l5, %l0, %l5
+ andcc %l0, 0x40, %g0
+ bz tt1
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ andcc %l4, %l5, %g0
+ bz tt0
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+ TRAP_WIN_CLEAN
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+tt0: subcc %fp, %l7, %g0
+ bg,a tt3
+ sub %l7, 0xb0, %sp
+ b tt3
+ sub %fp, 0xb0, %sp
+tt1: sethi %hi( C_LABEL(current) ), %l6
+ ld [%l6 + %lo( C_LABEL(current) )], %l6
+ ld [%l6 + THREAD_WIM], %l5
+ and %l0, 0x1f, %l7
+ cmp %l5, %l7
+ ble,a tt4
+ sethi %hi( C_LABEL(nwindowsm1) ), %l4
+ sub %l5, %l7, %l7
+ b tt5
+ sub %l7, 0x1, %l5
+tt4: ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
+ sub %l4, %l7, %l4
+ add %l5, %l4, %l5
+tt5: st %l5, [%l6 + THREAD_UWINDOWS]
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ bz,a tt2
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+ TRAP_WIN_CLEAN
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+tt2: sub %l7, 0xb0, %sp
+
+tt3: std %g2, [%sp + 96 + 24]
+ or %g0, %g1, %l7
+ rd %y, %l6
+ std %g4, [%sp + 96 + 32]
+ andn %l0, PSR_PIL, %l4
+ sll %l3, 0x8, %l5
+ std %g6, [%sp + 96 + 40]
+ or %l5, %l4, %l4
+
+ wr %l4, 0x0, %psr
+ wr %l4, PSR_ET, %psr
+
+ std %l0, [%sp + 96 + 0]
+ std %l2, [%sp + 96 + 8]
+ st %fp, [%sp + 96 + 16]
+
+ or %g0, %l3, %o0
+ or %g0, %g0, %o1
+ call C_LABEL(unexpected_irq)
+ nop
+
+ or %g0, %l7, %g1
+ wr %l6, 0x0, %y
+ ldd [%sp + 96 + 24], %g2
+ ldd [%sp + 96 + 32], %g4
+ ldd [%sp + 96 + 40], %g6
+ wr %l0, 0x0, %psr
+ nop
+ nop
+ nop
+
+ and %l0, 31, %l5
+ sethi %hi(lnx_winmask), %l6
+ or %l6, %lo(lnx_winmask), %l6
+ ldub [%l6 + %l5], %l5
+ andcc %l0, PSR_PS, %g0
+ bnz 1f
+ rd %wim, %l4
+
+1: andcc %l5, %l4, %g0
+ bnz 2f
+ wr %l0, 0x0, %psr
+ nop
+ nop
+ nop
+
+ jmp %l1
+ rett %l2
+
+2: wr %g0, 0x0, %wim
+ nop
+ nop
+ nop
+
+ restore
+ restore %g0, 0x1, %l1
+ rd %psr, %l0
+ and %l0, 31, %l0
+ sll %l1, %l0, %l1
+ wr %l1, 0x0, %wim
+ sethi %hi( C_LABEL(current) ), %l1
+ ld [%l1 + %lo( C_LABEL(current) ) ], %l1
+ st %l0, [%l1 + THREAD_WIM]
+ save %g0, %g0, %g0
+
+ ldd [%sp], %l0
+ ldd [%sp + 0x8], %l2
+ ldd [%sp + 0x10], %l4
+ ldd [%sp + 0x18], %l6
+ ldd [%sp + 0x20], %i0
+ ldd [%sp + 0x28], %i2
+ ldd [%sp + 0x30], %i4
+ ldd [%sp + 0x38], %i6
+
+ save %g0, %g0, %g0
+
+ jmp %l1
+ rett %l2
+
+
+
+/* This routine is optimized for kernel window fills. User fills take about two
+ * or three extra jumps on the average. We'll see how this works out.
+ */
+
+/* Don't use local labels, or if you do be REAL CAREFUL. TRAP_WIN_CLEAN is
+ * full of them! If you think this routine is hairy, window spills are worse,
+ * see below.
+ */
+
+ .align 4
+ .globl spill_window_entry
+spill_window_entry:
+ andcc %l0, 0x40, %g0 ! see if this is a user window fill
+ bz,a spill_from_user
+ nop
+
+ TRAP_WIN_CLEAN /* danger, danger... */
+ wr %l0, 0x0, %psr
+ nop
+ jmp %l1
+ rett %l2
+
+spill_from_user:
+ sethi %hi( C_LABEL(current) ), %l6
+ ld [%l6 + %lo( C_LABEL(current) )], %l6
+ ld [%l6 + THREAD_WIM], %l5
+ and %l0, 0x1f, %l3
+
+/* I don't know what's worse, the extra comparison here, or an extra load
+ * from a lookup table, we'll see.
+ */
+ cmp %l5, %l3
+ ble,a 1f
+ sethi %hi( C_LABEL(nwindowsm1) ), %l4
+ sub %l5, %l3, %l3
+ b 2f
+ sub %l3, 0x1, %l5
+1: ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
+ sub %l4, %l3, %l4
+ add %l5, %l4, %l5
+2: st %l5, [%l6 + THREAD_UWINDOWS]
+
+ TRAP_WIN_CLEAN /* danger, danger... */
+ sethi %hi( C_LABEL(current) ), %l6
+ ld [%l6 + %lo( C_LABEL(current) )], %l6
+ ld [%l6 + THREAD_KSP], %sp
+ and %l0, 0x1f, %l3
+ sethi %hi(lnx_winmask), %l6
+ or %l6, %lo(lnx_winmask), %l6
+ ldub [%l6 + %l3], %l5
+ rd %wim, %l4
+ jmp %l1
+ rett %l2
+
+/* A window spill has occurred. This presents a weird situation, a restore
+ * was attempted and a trap occurred. Therefore the restore attempt had no
+ * effect on window movement and the trap saved, which means it went in the
+ * other direction. :-( We are in a trap window which is two restores away
+ * from the window we want to un-invalidate so to speak and three away from
+ * the one which will become invalid after this routine. There are probably
+ * bugs already this routine. Bugs suck.
+ */
+
+/* This is a very complicated and hairy routine, don't expect to understand
+ * it the first time. :>
+ */
+
+ .align 4
+ .globl fill_window_entry
+fill_window_entry:
+ wr %g0, 0, %wim ! Can not enter invalid register without this.
+ andcc %l0, 0x40, %g0 ! From user?
+ restore ! restore to where trap occurred
+ bz fill_from_user
+ restore ! enter invalid register, whee...
+ restore %g0, 0x1, %l1 ! enter one-past invalid register
+ rd %psr, %l0 ! this is the window we need to save
+ and %l0, 0x1f, %l0
+ sll %l1, %l0, %l1
+ wr %l1, 0x0, %wim
+ sethi %hi( C_LABEL(current) ), %l1
+ ld [%l1 + %lo( C_LABEL(current) )], %l1
+ st %l0, [%l1 + THREAD_WIM]
+ save %g0, %g0, %g0 ! back to invalid register
+ ldd [%sp], %l0 ! load the window from stack
+ ldd [%sp + 8], %l2
+ ldd [%sp + 16], %l4
+ ldd [%sp + 24], %l6
+ ldd [%sp + 32], %i0
+ ldd [%sp + 40], %i2
+ ldd [%sp + 48], %i4
+ ldd [%sp + 56], %i6
+ save %g0, %g0, %g0 ! to window where trap happened
+ save %g0, %g0, %g0 ! back to trap window, so rett works
+ wr %l0, 0x0, %psr ! load condition codes
+ nop
+ jmp %l1
+ rett %l2 ! are you as confused as I am?
+
+fill_from_user:
+ andcc %sp, 0x7, %g0 ! check for alignment of user stack
+ bne fill_bad_stack
+ sra %sp, 0x1e, %l7
+ cmp %l7, 0x0
+ be,a 1f
+ andn %sp, 0xfff, %l7
+ cmp %l7, -1
+ bne fill_bad_stack
+ andn %sp, 0xfff, %l7
+1: lda [%l7] ASI_PTE, %l7
+ srl %l7, 0x1d, %l7
+ andn %l7, 0x2, %l7
+ cmp %l7, 0x4
+ bne fill_bad_stack
+ and %sp, 0xfff, %l7
+ cmp %l7, 0xfc1
+ bl,a fill_stack_ok
+ restore %g0, 1, %l1
+ add %sp, 0x38, %l5
+ sra %sp, 0x1e, %l7
+ cmp %l7, 0x0
+ be,a 1f
+ andn %sp, 0xfff, %l7
+ cmp %l7, -1
+ bne fill_bad_stack
+ andn %sp, 0xfff, %l7
+1: lda [%l7] ASI_PTE, %l7
+ srl %l7, 0x1d, %l7
+ andn %l7, 0x2, %l7
+ cmp %l7, 0x4
+ be,a fill_stack_ok
+ restore %g0, 0x1, %l1
+
+fill_bad_stack:
+ save %g0, %g0, %g0 ! save to where restore happened
+ save %g0, 0x1, %l4 ! save is an add remember? to trap window
+ sethi %hi( C_LABEL(current) ), %l6
+ ld [%l6 + %lo( C_LABEL(current) )], %l6
+ st %l4, [%l6 + THREAD_UWINDOWS] ! update current->tss values
+ ld [%l6 + THREAD_WIM], %l5
+ sll %l4, %l5, %l4
+ wr %l4, 0x0, %wim
+ ld [%l6 + THREAD_KSP], %sp ! set to kernel stack pointer
+ wr %l0, 0x20, %psr ! turn off traps
+ std %l0, [%sp + C_STACK] ! set up thread_frame on stack
+ rd %y, %l3
+ std %l2, [%sp + C_STACK + 0x8]
+ or %g0, 0x6, %o0 ! so _sparc_trap knows what to do
+ st %g1, [%sp + C_STACK + 0x14] ! no need to save %g0, always zero
+ or %g0, %l0, %o1
+ std %g2, [%sp + C_STACK + 0x18]
+ or %g0, %l1, %o2
+ std %g4, [%sp + C_STACK + 0x20]
+ add %sp, C_STACK, %o3
+ std %g6, [%sp + C_STACK + 0x28]
+ std %i0, [%sp + C_STACK + 0x30]
+ std %i2, [%sp + C_STACK + 0x38]
+ std %i4, [%sp + C_STACK + 0x40]
+ call sparc_trap
+ std %i6, [%sp + C_STACK + 0x48]
+
+ ldd [%sp + C_STACK], %l0
+ ldd [%sp + C_STACK + 0x8], %l2
+ wr %l3, 0, %y
+ ld [%sp + C_STACK + 0x14], %g1
+ ldd [%sp + C_STACK + 0x18], %g2
+ ldd [%sp + C_STACK + 0x20], %g4
+ ldd [%sp + C_STACK + 0x28], %g6
+ ldd [%sp + C_STACK + 0x30], %i0
+ ldd [%sp + C_STACK + 0x38], %i2
+ ldd [%sp + C_STACK + 0x40], %i4
+ wr %l0, 0, %psr ! disable traps again
+ ldd [%sp + C_STACK + 0x48], %i6
+ sethi %hi( C_LABEL(current) ), %l6
+ ld [%l6 + %lo( C_LABEL(current) )], %l6
+ ld [%l6 + THREAD_W_SAVED], %l7
+ cmp %l7, 0x0
+ bl,a 1f
+ wr %g0, 0x0, %wim
+ b,a leave_trap
+
+1: or %g0, %g6, %l3
+ or %g0, %l6, %g6
+ st %g0, [%g6 + THREAD_W_SAVED]
+ restore %g0, %g0, %g0
+ restore %g0, %g0, %g0
+ restore %g0, 0x1, %l1
+ rd %psr, %l0
+ sll %l1, %l0, %l1
+ wr %l1, 0x0, %wim
+ and %l0, 0x1f, %l0
+ st %l0, [%g6 + THREAD_WIM]
+ nop
+ save %g0, %g0, %g0
+ ldd [%sp], %l0 ! load number one
+ ldd [%sp + 0x8], %l2
+ ldd [%sp + 0x10], %l4
+ ldd [%sp + 0x18], %l6
+ ldd [%sp + 0x20], %i0
+ ldd [%sp + 0x28], %i2
+ ldd [%sp + 0x30], %i4
+ ldd [%sp + 0x38], %i6
+ save %g0, %g0, %g0
+ ldd [%sp], %l0 ! load number two
+ ldd [%sp + 0x8], %l2
+ ldd [%sp + 0x10], %l4
+ ldd [%sp + 0x18], %l6
+ ldd [%sp + 0x20], %i0
+ ldd [%sp + 0x28], %i2
+ ldd [%sp + 0x30], %i4
+ ldd [%sp + 0x38], %i6
+ save %g0, %g0, %g0 ! re-enter trap window
+ wr %l0, 0x0, %psr ! restore condition codes
+ or %g0, %l3, %g6 ! restore scratch register
+ jmp %l1
+ rett %l2
+
+fill_stack_ok:
+ rd %psr, %l0
+ sll %l1, %l0, %l1
+ wr %l1, 0x0, %wim
+ sethi %hi( C_LABEL(current) ), %l2
+ ld [%l2 + %lo( C_LABEL(current) )], %l2
+ and %l0, 0x1f, %l0
+ st %l0, [%l2 + THREAD_WIM]
+ save %g0, %g0, %g0
+ ldd [%sp], %l0 ! only one load necessary
+ ldd [%sp + 0x8], %l2
+ ldd [%sp + 0x10], %l4
+ ldd [%sp + 0x18], %l6
+ ldd [%sp + 0x20], %i0
+ ldd [%sp + 0x28], %i2
+ ldd [%sp + 0x30], %i4
+ ldd [%sp + 0x38], %i6
+ save %g0, %g0, %g0
+ save %g0, %g0, %g0 ! save into trap window
+ wr %l0, 0x0, %psr ! local number 0 here has cond codes
+ nop
+ jmp %l1
+ rett %l2
+
+ .align 4
+ .globl trap_entry
+trap_entry:
+ TRAP_WIN_CLEAN
+ jmp %l1
+ rett %l2
+
+ .align 4
+ .globl linux_trap_nmi
+linux_trap_nmi:
+ TRAP_WIN_CLEAN
+ jmp %l1
+ rett %l2
+
+ .align 4
+ .globl sparc_trap
+sparc_trap:
+ TRAP_WIN_CLEAN
+ jmp %l1
+ rett %l2
+
+ .align 4
+ .globl leave_trap
+leave_trap:
+ jmp %l1
+ rett %l2
+
+/* The following two things point to window management tables. The first
+ one is used to quickly look up how many user windows there are from
+ trap-land. The second is used in a trap handler to determine if a rett
+ instruction will land us smack inside the invalid window that possibly
+ the trap was called to fix-up.
+*/
+
+/* For now these are static tables geared for a 7 window sparc. */
+
+ .data
+ .align 4
+lnx_winmask: .byte 2, 4, 8, 16, 32, 64, 128, 1 ! lnx_winmask[0..7]
+
+
+ .align 4
+ .globl C_LABEL(sys_call_table)
+C_LABEL(sys_call_table):
+ .long C_LABEL(sys_setup) /* 0 */
+ .long C_LABEL(sys_exit)
+ .long C_LABEL(sys_fork)
+ .long C_LABEL(sys_read)
+ .long C_LABEL(sys_write)
+ .long C_LABEL(sys_open) /* 5 */
+ .long C_LABEL(sys_close)
+ .long C_LABEL(sys_waitpid)
+ .long C_LABEL(sys_creat)
+ .long C_LABEL(sys_link)
+ .long C_LABEL(sys_unlink) /* 10 */
+ .long C_LABEL(sys_execve)
+ .long C_LABEL(sys_chdir)
+ .long C_LABEL(sys_time)
+ .long C_LABEL(sys_mknod)
+ .long C_LABEL(sys_chmod) /* 15 */
+ .long C_LABEL(sys_chown)
+ .long C_LABEL(sys_break)
+ .long C_LABEL(sys_stat)
+ .long C_LABEL(sys_lseek)
+ .long C_LABEL(sys_getpid) /* 20 */
+ .long C_LABEL(sys_mount)
+ .long C_LABEL(sys_umount)
+ .long C_LABEL(sys_setuid)
+ .long C_LABEL(sys_getuid)
+ .long C_LABEL(sys_stime) /* 25 */
+ .long C_LABEL(sys_ni_syscall) /* this will be sys_ptrace() */
+ .long C_LABEL(sys_alarm)
+ .long C_LABEL(sys_fstat)
+ .long C_LABEL(sys_pause)
+ .long C_LABEL(sys_utime) /* 30 */
+ .long C_LABEL(sys_stty)
+ .long C_LABEL(sys_gtty)
+ .long C_LABEL(sys_access)
+ .long C_LABEL(sys_nice)
+ .long C_LABEL(sys_ftime) /* 35 */
+ .long C_LABEL(sys_sync)
+ .long C_LABEL(sys_kill)
+ .long C_LABEL(sys_rename)
+ .long C_LABEL(sys_mkdir)
+ .long C_LABEL(sys_rmdir) /* 40 */
+ .long C_LABEL(sys_dup)
+ .long C_LABEL(sys_pipe)
+ .long C_LABEL(sys_times)
+ .long C_LABEL(sys_prof)
+ .long C_LABEL(sys_brk) /* 45 */
+ .long C_LABEL(sys_setgid)
+ .long C_LABEL(sys_getgid)
+ .long C_LABEL(sys_signal)
+ .long C_LABEL(sys_geteuid)
+ .long C_LABEL(sys_getegid) /* 50 */
+ .long C_LABEL(sys_acct)
+ .long C_LABEL(sys_phys)
+ .long C_LABEL(sys_lock)
+ .long C_LABEL(sys_ioctl)
+ .long C_LABEL(sys_fcntl) /* 55 */
+ .long C_LABEL(sys_mpx)
+ .long C_LABEL(sys_setpgid)
+ .long C_LABEL(sys_ulimit)
+ .long C_LABEL(sys_olduname)
+ .long C_LABEL(sys_umask) /* 60 */
+ .long C_LABEL(sys_chroot)
+ .long C_LABEL(sys_ustat)
+ .long C_LABEL(sys_dup2)
+ .long C_LABEL(sys_getppid)
+ .long C_LABEL(sys_getpgrp) /* 65 */
+ .long C_LABEL(sys_setsid)
+ .long C_LABEL(sys_sigaction)
+ .long C_LABEL(sys_sgetmask)
+ .long C_LABEL(sys_ssetmask)
+ .long C_LABEL(sys_setreuid) /* 70 */
+ .long C_LABEL(sys_setregid)
+ .long C_LABEL(sys_sigsuspend)
+ .long C_LABEL(sys_sigpending)
+ .long C_LABEL(sys_sethostname)
+ .long C_LABEL(sys_setrlimit) /* 75 */
+ .long C_LABEL(sys_getrlimit)
+ .long C_LABEL(sys_getrusage)
+ .long C_LABEL(sys_gettimeofday)
+ .long C_LABEL(sys_settimeofday)
+ .long C_LABEL(sys_getgroups) /* 80 */
+ .long C_LABEL(sys_setgroups)
+ .long C_LABEL(sys_select)
+ .long C_LABEL(sys_symlink)
+ .long C_LABEL(sys_lstat)
+ .long C_LABEL(sys_readlink) /* 85 */
+ .long C_LABEL(sys_uselib)
+ .long C_LABEL(sys_swapon)
+ .long C_LABEL(sys_reboot)
+ .long C_LABEL(sys_readdir)
+ .long C_LABEL(sys_mmap) /* 90 */
+ .long C_LABEL(sys_munmap)
+ .long C_LABEL(sys_truncate)
+ .long C_LABEL(sys_ftruncate)
+ .long C_LABEL(sys_fchmod)
+ .long C_LABEL(sys_fchown) /* 95 */
+ .long C_LABEL(sys_getpriority)
+ .long C_LABEL(sys_setpriority)
+ .long C_LABEL(sys_profil)
+ .long C_LABEL(sys_statfs)
+ .long C_LABEL(sys_fstatfs) /* 100 */
+ .long C_LABEL(sys_ni_syscall)
+ .long C_LABEL(sys_socketcall)
+ .long C_LABEL(sys_syslog)
+ .long C_LABEL(sys_setitimer)
+ .long C_LABEL(sys_getitimer) /* 105 */
+ .long C_LABEL(sys_newstat)
+ .long C_LABEL(sys_newlstat)
+ .long C_LABEL(sys_newfstat)
+ .long C_LABEL(sys_uname)
+ .long C_LABEL(sys_ni_syscall) /* 110 */
+ .long C_LABEL(sys_vhangup)
+ .long C_LABEL(sys_idle)
+ .long C_LABEL(sys_ni_syscall) /* was vm86, meaningless on Sparc */
+ .long C_LABEL(sys_wait4)
+ .long C_LABEL(sys_swapoff) /* 115 */
+ .long C_LABEL(sys_sysinfo)
+ .long C_LABEL(sys_ipc)
+ .long C_LABEL(sys_fsync)
+ .long C_LABEL(sys_sigreturn)
+ .long C_LABEL(sys_ni_syscall) /* 120 */
+ .long C_LABEL(sys_setdomainname)
+ .long C_LABEL(sys_newuname)
+ .long C_LABEL(sys_ni_syscall)
+ .long C_LABEL(sys_adjtimex)
+ .long C_LABEL(sys_mprotect) /* 125 */
+ .long C_LABEL(sys_sigprocmask)
+ .long C_LABEL(sys_create_module)
+ .long C_LABEL(sys_init_module)
+ .long C_LABEL(sys_delete_module)
+ .long C_LABEL(sys_get_kernel_syms) /* 130 */
+ .long C_LABEL(sys_ni_syscall)
+ .long C_LABEL(sys_getpgid)
+ .long C_LABEL(sys_fchdir)
+ .long C_LABEL(sys_bdflush)
+ .long C_LABEL(sys_sysfs) /* 135 */
+ .long C_LABEL(sys_personality)
+ .long 0 /* for afs_syscall */
+ .long C_LABEL(sys_setfsuid)
+ .long C_LABEL(sys_setfsgid)
+ .long C_LABEL(sys_llseek) /* 140 */
+ .align 4