1/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright © 2019 Keith Packard
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 *    copyright notice, this list of conditions and the following
15 *    disclaimer in the documentation and/or other materials provided
16 *    with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 *    contributors may be used to endorse or promote products derived
20 *    from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#define SPARC_NWIN	8
37
38#define PSR_VER_BIT                     24
39#define PSR_PIL_BIT                      8
40
41#define PSR_VER                         (0xf << PSR_VER_BIT)
42#define PSR_EF                          (1 << 12)
43#define PSR_S                           (1 <<  7)
44#define PSR_PS                          (1 <<  6)
45#define PSR_ET                          (1 <<  5)
46#define PSR_PIL                         (0xf << PSR_PIL_BIT)
47#define PSR_CWP                         0x1f
48
49#define TRAP(func) \
50	rd	%psr, %l0				; \
51	sethi	%hi(_sparc_ ## func ## _isr), %l4 	;\
52	jmp	%l4+%lo(_sparc_ ## func ## _isr) 	;\
53	rd	%tbr, %l6 				;
54
55#define TRAP_IN_TRAP \
56	ta	0x00		; \
57	nop			; \
58	nop			; \
59	nop			;
60
61#define TRAP_HALT(name) \
62	TRAP(name) 	      ; \
63	.weak	_sparc_ ## name ## _isr	      ; \
64	.equ	_sparc_ ## name ## _isr, _sparc_halt_isr ;
65
66	.section	.data.init.enter
67	.globl		__weak_interrupt_vector
68__weak_interrupt_vector:
69	TRAP(reset)
70	TRAP_HALT(instruction_access_exception)
71	TRAP_HALT(illegal_instruction)
72	TRAP_HALT(priveledged_instruction)
73	TRAP_HALT(fp_disabled)
74#ifdef _FLAT
75	TRAP_HALT(window_overflow)
76	TRAP_HALT(window_underflow)
77#else
78	TRAP(window_overflow)
79	TRAP(window_underflow)
80#endif
81	TRAP_HALT(mem_address_not_aligned)
82	TRAP_HALT(fp_exception)
83	TRAP_HALT(data_access_exception)
84	TRAP_HALT(tag_overflow)
85	TRAP_HALT(watchpoint_detected)
86	TRAP_HALT(trap_0c)
87	TRAP_HALT(trap_0d)
88	TRAP_HALT(trap_0e)
89	TRAP_HALT(trap_0f)
90	TRAP_HALT(trap_10)
91
92	. = __weak_interrupt_vector + 0x80 * 16
93
94	TRAP_HALT(syscall)
95	TRAP_HALT(breakpoint)
96	TRAP_HALT(divide_by_zero)
97#ifdef _FLAT
98	TRAP_HALT(window_flush)
99#else
100	TRAP(window_flush)
101#endif
102	TRAP_HALT(clean_windows)
103	.size	__weak_interrupt_vector, . - __weak_interrupt_vector
104	.weak	__interrupt_vector
105	.equ	__interrupt_vector, __weak_interrupt_vector
106
107	.text
108	.align 4
109
110	.global _sparc_reset_isr
111	.type 	_sparc_reset_isr, #function
112_sparc_reset_isr:
113	sethi	%hi(_start), %g4
114	jmp	%g4+%lo(_start)
115	nop
116	.size	_sparc_reset_isr, .-_sparc_reset_isr
117
118	.global	_sparc_halt_isr
119	.type	_sparc_halt_isr, #function
120_sparc_halt_isr:
121	ta	0x00
122	ba	_sparc_halt_isr
123	nop
124	.size	_sparc_halt_isr, .-_sparc_halt_isr
125
126	.global _sparc_window_overflow_isr
127	.type 	_sparc_window_overflow_isr, #function
128_sparc_window_overflow_isr:
129	/* Enter the window to be stored. */
130	save
131	/* Save local register set. */
132	std	%l0, [%sp + 0x00]
133	std	%l2, [%sp + 0x08]
134	std	%l4, [%sp + 0x10]
135	rd	%wim, %l3
136	std	%l6, [%sp + 0x18]
137	/* l2 := WIM << (NWIN-1) */
138	sll	%l3, (SPARC_NWIN-1), %l2
139	/* Save input register set. */
140	std	%i0, [%sp + 0x20]
141	/* l3 := WIM >> 1 */
142	srl	%l3, 1, %l3
143	std	%i2, [%sp + 0x28]
144	/* WIM := (WIM >> 1) ^ (WIM << (NWIN-1)) */
145	wr	%l3, %l2, %wim
146	/* NOTE: 3 instruction before restore (delayed write instruction) */
147	std	%i4, [%sp + 0x30]
148	nop
149	std	%i6, [%sp + 0x38]
150	/* Go back to trap window. */
151	restore
152	/* Re-execute save. */
153	jmp	%l1
154	rett	%l2
155	.size	_sparc_window_overflow_isr, .-_sparc_window_overflow_isr
156
157	.global _sparc_window_underflow_isr
158	.type 	_sparc_window_underflow_isr, #function
159_sparc_window_underflow_isr:
160	rd	%wim, %l3
161	/* l4 := WIM << 1 */
162	sll	%l3, 1, %l4
163	/* l5 := WIM >> (NWIN-1) */
164	srl	%l3, (SPARC_NWIN-1), %l5
165	/* WIM := (WIM << 1) ^ (WIM >> (NWIN-1)) */
166	wr	%l4, %l5, %wim
167	/* WIM is implicitly read so nops are needed. */
168	nop
169	nop
170	nop
171
172	/* Enter the window to restore requires two restore instructions. */
173	restore
174	restore
175	ldd	[%sp + 0x00], %l0
176	ldd	[%sp + 0x08], %l2
177	ldd	[%sp + 0x10], %l4
178	ldd	[%sp + 0x18], %l6
179	ldd	[%sp + 0x20], %i0
180	ldd	[%sp + 0x28], %i2
181	ldd	[%sp + 0x30], %i4
182	ldd	[%sp + 0x38], %i6
183	/* Go back to the trap window. */
184	save
185	save
186	/* Re-execute restore. */
187	jmp	%l1
188	rett	%l2
189	.size	_sparc_window_underflow_isr, .-_sparc_window_underflow_isr
190
191	.global _sparc_window_flush_isr
192	.type 	_sparc_window_flush_isr, #function
193_sparc_window_flush_isr:
194	/*
195	 * push a few registers which are needed later to the stack using
196	 * sp from the window we trapped from (which is fp in this window)
197	 */
198	sub	%fp, 0x10, %fp
199	std	%l0, [%fp + 0x40 + 0x00]
200	st	%l2, [%fp + 0x40 + 0x08]
201	st	%g1, [%fp + 0x40 + 0x0c]
202
203	restore
204	/* In window where we trapped from. This window will not be flushed. */
205
206	/* Set highest processor interrupt level and enable traps. */
207	rd	%psr, %g1
208	or	%g1, PSR_PIL, %g1
209	wr	%g1, PSR_ET, %psr
210	nop
211	nop
212
213	/* Execute "save" NWINDOWS-1 times. */
214	set     SPARC_NWIN-2, %g1
2151:
216	save
217	cmp	%g1, %g0
218	bne	1b
219	sub	%g1, 1, %g1
220
221	/* Execute "restore" NWINDOWS-1 times. */
222	set     SPARC_NWIN-2, %g1
2232:
224	restore
225	cmp	%g1, %g0
226	bne	2b
227	sub	%g1, 1, %g1
228
229	save
230
231	/* pop registers from stack which are used for the trap return */
232	ldd	[%fp + 0x40 + 0x00], %l0
233	ld	[%fp + 0x40 + 0x08], %l2
234	ld	[%fp + 0x40 + 0x0c], %g1
235	add	%fp, 0x10, %fp
236
237	/* Restore %psr as it was on trap entry. */
238	wr	%l0, %psr
239	nop
240	nop
241	nop
242
243	jmp	%l2
244	rett	%l2 + 4
245	.size	_sparc_window_flush_isr, .-_sparc_window_flush_isr
246