From e7c2a72e2680827d6a733931273a93461c0d8d1b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 14 Nov 1995 08:00:00 +0000 Subject: Import of Linux/MIPS 1.3.0 --- arch/sparc/kernel/entry.S | 927 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 927 insertions(+) create mode 100644 arch/sparc/kernel/entry.S (limited to 'arch/sparc/kernel/entry.S') 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 +#include +#include +#include +#include + +/* 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 -- cgit v1.2.3