1/*
2 * Window fill (underflow) trap, based on code from Sparclinux.
3 *
4 * Copyright (C) 1995 David S. Miller
5 *
6 *   This program is free software; you can redistribute it and/or
7 *   modify it under the terms of the GNU General Public License
8 *   version 2 as published by the Free Software Foundation.
9 *
10 *   This program is distributed in the hope that it will be useful,
11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *   GNU General Public License for more details.
14 *
15 *   You should have received a copy of the GNU General Public License
16 *   along with this program; if not, write to the Free Software
17 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 *   MA  02110-1301, USA.
19 */
20
21// #include <psr.h>
22// #include <asi.h>
23
24/* Reg_window offsets */
25#define RW_L0     0x00
26#define RW_L1     0x04
27#define RW_L2     0x08
28#define RW_L3     0x0c
29#define RW_L4     0x10
30#define RW_L5     0x14
31#define RW_L6     0x18
32#define RW_L7     0x1c
33#define RW_I0     0x20
34#define RW_I1     0x24
35#define RW_I2     0x28
36#define RW_I3     0x2c
37#define RW_I4     0x30
38#define RW_I5     0x34
39#define RW_I6     0x38
40#define RW_I7     0x3c
41
42/* Load a register window from the area beginning at %reg. */
43#define LOAD_WINDOW(reg) \
44	ldd	[%reg + RW_L0], %l0; \
45	ldd	[%reg + RW_L2], %l2; \
46	ldd	[%reg + RW_L4], %l4; \
47	ldd	[%reg + RW_L6], %l6; \
48	ldd	[%reg + RW_I0], %i0; \
49	ldd	[%reg + RW_I2], %i2; \
50	ldd	[%reg + RW_I4], %i4; \
51	ldd	[%reg + RW_I6], %i6;
52
53#define WRITE_PAUSE	nop; nop; nop; /* Have to do this after %wim/%psr chg */
54
55/* Just like the overflow handler we define macros for registers
56 * with fixed meanings in this routine.
57 */
58#define t_psr       l0
59#define t_pc        l1
60#define t_npc       l2
61#define t_wim       l3
62/* Don't touch the above registers or else you die horribly... */
63
64/* Now macros for the available scratch registers in this routine. */
65#define twin_tmp1    l4
66#define twin_tmp2    l5
67
68	.text
69	.align	4
70
71	/* The trap entry point has executed the following:
72	 *
73	 * rd    %psr, %l0
74	 * rd    %wim, %l3
75	 * b     fill_window_entry
76	 * andcc %l0, PSR_PS, %g0
77	 */
78
79	/* To get an idea of what has just happened to cause this
80	 * trap take a look at this diagram:
81	 *
82	 *      1  2  3  4     <--  Window number
83	 *      ----------
84	 *      T  O  W  I     <--  Symbolic name
85	 *
86	 *      O == the window that execution was in when
87	 *           the restore was attempted
88	 *
89	 *      T == the trap itself has save'd us into this
90	 *           window
91	 *
92	 *      W == this window is the one which is now invalid
93	 *           and must be made valid plus loaded from the
94	 *           stack
95	 *
96	 *      I == this window will be the invalid one when we
97	 *           are done and return from trap if successful
98	 */
99
100	/* BEGINNING OF PATCH INSTRUCTIONS */
101
102	/* On 7-window Sparc the boot code patches fnwin_patch1
103	 * with the following instruction.
104	 */
105	.globl	fnwin_patch1_7win, fnwin_patch2_7win
106fnwin_patch1_7win:	srl	%t_wim, 6, %twin_tmp2
107fnwin_patch2_7win:	and	%twin_tmp1, 0x7f, %twin_tmp1
108	/* END OF PATCH INSTRUCTIONS */
109
110
111	.globl	fill_window_entry, fnwin_patch1, fnwin_patch2
112fill_window_entry:
113	/* LOCATION: Window 'T' */
114
115	/* Compute what the new %wim is going to be if we retrieve
116	 * the proper window off of the stack.
117	 */
118		sll	%t_wim, 1, %twin_tmp1
119fnwin_patch1:	srl	%t_wim, 7, %twin_tmp2
120		or	%twin_tmp1, %twin_tmp2, %twin_tmp1
121fnwin_patch2:	and	%twin_tmp1, 0xff, %twin_tmp1
122
123	wr	%twin_tmp1, 0x0, %wim	/* Make window 'I' invalid */
124
125	restore	%g0, %g0, %g0		/* Restore to window 'O' */
126
127	/* Trapped from kernel, we trust that the kernel does not
128	 * 'over restore' sorta speak and just grab the window
129	 * from the stack and return.  Easy enough.
130	 */
131	/* LOCATION: Window 'O' */
132
133	restore %g0, %g0, %g0
134        WRITE_PAUSE
135
136	/* LOCATION: Window 'W' */
137
138	LOAD_WINDOW(sp)	                /* Load it up */
139
140	/* Spin the wheel... */
141	save	%g0, %g0, %g0
142	save	%g0, %g0, %g0
143	/* I'd like to buy a vowel please... */
144
145	/* LOCATION: Window 'T' */
146
147	/* Now preserve the condition codes in %psr, pause, and
148	 * return from trap.  This is the simplest case of all.
149	 */
150	wr	%t_psr, 0x0, %psr
151	WRITE_PAUSE
152
153	jmp	%t_pc
154	rett	%t_npc
155