blob: 853fc732280a837aa8b69e7ab7be575d3e162078 [file] [log] [blame]
/*
* Window fill (underflow) trap, based on code from Sparclinux.
*
* Copyright (C) 1995 David S. Miller
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
// #include <psr.h>
// #include <asi.h>
/* Reg_window offsets */
#define RW_L0 0x00
#define RW_L1 0x04
#define RW_L2 0x08
#define RW_L3 0x0c
#define RW_L4 0x10
#define RW_L5 0x14
#define RW_L6 0x18
#define RW_L7 0x1c
#define RW_I0 0x20
#define RW_I1 0x24
#define RW_I2 0x28
#define RW_I3 0x2c
#define RW_I4 0x30
#define RW_I5 0x34
#define RW_I6 0x38
#define RW_I7 0x3c
/* Load a register window from the area beginning at %reg. */
#define LOAD_WINDOW(reg) \
ldd [%reg + RW_L0], %l0; \
ldd [%reg + RW_L2], %l2; \
ldd [%reg + RW_L4], %l4; \
ldd [%reg + RW_L6], %l6; \
ldd [%reg + RW_I0], %i0; \
ldd [%reg + RW_I2], %i2; \
ldd [%reg + RW_I4], %i4; \
ldd [%reg + RW_I6], %i6;
#define WRITE_PAUSE nop; nop; nop; /* Have to do this after %wim/%psr chg */
/* Just like the overflow handler we define macros for registers
* with fixed meanings in this routine.
*/
#define t_psr l0
#define t_pc l1
#define t_npc l2
#define t_wim l3
/* Don't touch the above registers or else you die horribly... */
/* Now macros for the available scratch registers in this routine. */
#define twin_tmp1 l4
#define twin_tmp2 l5
.text
.align 4
/* The trap entry point has executed the following:
*
* rd %psr, %l0
* rd %wim, %l3
* b fill_window_entry
* andcc %l0, PSR_PS, %g0
*/
/* To get an idea of what has just happened to cause this
* trap take a look at this diagram:
*
* 1 2 3 4 <-- Window number
* ----------
* T O W I <-- Symbolic name
*
* O == the window that execution was in when
* the restore was attempted
*
* T == the trap itself has save'd us into this
* window
*
* W == this window is the one which is now invalid
* and must be made valid plus loaded from the
* stack
*
* I == this window will be the invalid one when we
* are done and return from trap if successful
*/
/* BEGINNING OF PATCH INSTRUCTIONS */
/* On 7-window Sparc the boot code patches fnwin_patch1
* with the following instruction.
*/
.globl fnwin_patch1_7win, fnwin_patch2_7win
fnwin_patch1_7win: srl %t_wim, 6, %twin_tmp2
fnwin_patch2_7win: and %twin_tmp1, 0x7f, %twin_tmp1
/* END OF PATCH INSTRUCTIONS */
.globl fill_window_entry, fnwin_patch1, fnwin_patch2
fill_window_entry:
/* LOCATION: Window 'T' */
/* Compute what the new %wim is going to be if we retrieve
* the proper window off of the stack.
*/
sll %t_wim, 1, %twin_tmp1
fnwin_patch1: srl %t_wim, 7, %twin_tmp2
or %twin_tmp1, %twin_tmp2, %twin_tmp1
fnwin_patch2: and %twin_tmp1, 0xff, %twin_tmp1
wr %twin_tmp1, 0x0, %wim /* Make window 'I' invalid */
restore %g0, %g0, %g0 /* Restore to window 'O' */
/* Trapped from kernel, we trust that the kernel does not
* 'over restore' sorta speak and just grab the window
* from the stack and return. Easy enough.
*/
/* LOCATION: Window 'O' */
restore %g0, %g0, %g0
WRITE_PAUSE
/* LOCATION: Window 'W' */
LOAD_WINDOW(sp) /* Load it up */
/* Spin the wheel... */
save %g0, %g0, %g0
save %g0, %g0, %g0
/* I'd like to buy a vowel please... */
/* LOCATION: Window 'T' */
/* Now preserve the condition codes in %psr, pause, and
* return from trap. This is the simplest case of all.
*/
wr %t_psr, 0x0, %psr
WRITE_PAUSE
jmp %t_pc
rett %t_npc