summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/arch/sparc32/wuf.S
blob: 853fc732280a837aa8b69e7ab7be575d3e162078 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * 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