summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/arch/sparc32/wof.S
blob: 8d6bb73146228ce3e66ee50e726e8bae6378ff91 (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
/*
 * Proll takes this from Sparclinux kernel, ruthlessly truncated
 * because we have no user windows.
 *
 *   Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
 *
 *   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.
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License V2
 *   as published by the Free Software Foundation
 */

// #include <asm/winmacro.h>
// #include <asm/asmmacro.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

/* Store the register window onto the 8-byte aligned area starting
 * at %reg.  It might be %sp, it might not, we don't care.
 */
#define STORE_WINDOW(reg) \
	std	%l0, [%reg + RW_L0]; \
	std	%l2, [%reg + RW_L2]; \
	std	%l4, [%reg + RW_L4]; \
	std	%l6, [%reg + RW_L6]; \
	std	%i0, [%reg + RW_I0]; \
	std	%i2, [%reg + RW_I2]; \
	std	%i4, [%reg + RW_I4]; \
	std	%i6, [%reg + RW_I6];

/* We define macro's for registers which have a fixed
 * meaning throughout this entire routine.  The 'T' in
 * the comments mean that the register can only be
 * accessed when in the 'trap' window, 'G' means
 * accessible in any window.  Do not change these registers
 * after they have been set, until you are ready to return
 * from the trap.
 */
#define t_psr       l0 /* %psr at trap time                     T */
#define t_pc        l1 /* PC for trap return                    T */
#define t_npc       l2 /* NPC for trap return                   T */
#define t_wim       l3 /* %wim at trap time                     T */
#define saved_g5    l5 /* Global save register                  T */
#define saved_g6    l6 /* Global save register                  T */

/* Now registers whose values can change within the handler.      */
#define twin_tmp    l4 /* Temp reg, only usable in trap window  T */
#define glob_tmp    g5 /* Global temporary reg, usable anywhere G */

	.text
	.align	4

	/* BEGINNING OF PATCH INSTRUCTIONS */
	/* On a 7-window Sparc the boot code patches spnwin_*
	 * instructions with the following ones.
	 */
	.globl	spnwin_patch1_7win, spnwin_patch2_7win, spnwin_patch3_7win
spnwin_patch1_7win:	sll	%t_wim, 6, %glob_tmp
spnwin_patch2_7win:	and	%glob_tmp, 0x7f, %glob_tmp
spnwin_patch3_7win:	and	%twin_tmp, 0x7f, %twin_tmp
	/* END OF PATCH INSTRUCTIONS */

	/* The trap entry point has done the following:
	 *
	 * rd    %psr, %l0
	 * rd    %wim, %l3
	 * b     spill_window_entry
	 * nop
	 */

	.globl	spill_window_entry
	.globl	spnwin_patch1, spnwin_patch2
spill_window_entry:
	/* LOCATION: Trap Window */

	mov	%g5, %saved_g5		! save away global temp register
	mov	%g6, %saved_g6		! save away 'current' ptr register

	/* Compute what the new %wim will be if we save the
	 * window properly in this trap handler.
	 *
	 * newwim = ((%wim>>1) | (%wim<<(nwindows - 1)));
	 */
		srl	%t_wim, 0x1, %twin_tmp
spnwin_patch1:	sll	%t_wim, 7, %glob_tmp
		or	%glob_tmp, %twin_tmp, %glob_tmp
spnwin_patch2:	and	%glob_tmp, 0xff, %glob_tmp

	/* Save into the window which must be saved and do it.
	 */
	save	%g0, %g0, %g0		! save into the window to stash away
	wr	%glob_tmp, 0x0, %wim	! set new %wim, this is safe now

	/* LOCATION: Window to be saved */

	STORE_WINDOW(sp)		! stash the window
	restore	%g0, %g0, %g0		! go back into trap window

	/* LOCATION: Trap window */
	mov	%saved_g5, %g5		! restore %glob_tmp
	mov	%saved_g6, %g6		! restore %curptr
	wr	%t_psr, 0x0, %psr	! restore condition codes in %psr
	nop; nop; nop			! waste some time
	jmp	%t_pc			! Return from trap
	rett	%t_npc			! we are done