154 lines
4.2 KiB
ArmAsm
154 lines
4.2 KiB
ArmAsm
/*
|
|
* 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
|