/* * 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 // #include /* 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