1/*
2 * Copyright (c) 2019-2020 Cobham Gaisler AB
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include <zephyr/toolchain.h>
8#include <zephyr/linker/sections.h>
9#include <offsets_short.h>
10#include <zephyr/arch/sparc/sparc.h>
11
12GTEXT(__sparc_trap_except_reason)
13GTEXT(__sparc_trap_fault)
14
15/*
16 * Fault trap handler
17 *
18 * - IU state is saved and restored
19 *
20 * On entry:
21 * %l0: psr (set by trap code)
22 * %l1: pc
23 * %l2: npc
24 * %l6: tbr (set by trap code)
25 * %fp: %sp of current register window at trap time
26 * %g1: reason
27 *
28 * This trap handler will trash some of the global registers, which is OK since
29 * we will not return to where we trapped.
30 */
31SECTION_FUNC(TEXT, __sparc_trap_except_reason)
32	mov	%g1, %l7
33.Ldoit:
34	/* %g2, %g3 are used at manual window overflow so save temporarily */
35	mov	%g2, %l4
36	mov	%g3, %l5
37
38	/* We may have trapped into the invalid window. If so, make it valid. */
39	rd	%wim, %g2
40	mov	%g2, %l3
41	srl	%g2, %l0, %g3
42	cmp	%g3, 1
43	bne	.Lwodone
44	 nop
45
46	/* Do the window overflow. */
47	sll	%g2, (CONFIG_SPARC_NWIN-1), %g3
48	srl	%g2, 1, %g2
49	or	%g2, %g3, %g2
50
51	/* Enter window to save. */
52	save
53	/* Install new wim calculated above. */
54	mov	%g2, %wim
55	nop
56	nop
57	nop
58	/* Put registers on the dedicated save area of the ABI stack frame. */
59	std	%l0, [%sp + 0x00]
60	std	%l2, [%sp + 0x08]
61	std	%l4, [%sp + 0x10]
62	std	%l6, [%sp + 0x18]
63	std	%i0, [%sp + 0x20]
64	std	%i2, [%sp + 0x28]
65	std	%i4, [%sp + 0x30]
66	std	%i6, [%sp + 0x38]
67	/* Leave saved window. */
68	restore
69
70.Lwodone:
71	mov	%l4, %g2
72	mov	%l5, %g3
73
74	/* Allocate an ABI stack frame and exception stack frame */
75	sub	%fp, 96 + __struct_arch_esf_SIZEOF, %sp
76	/*
77	 * %fp: %sp of interrupted task
78	 * %sp: %sp of interrupted task - ABI_frame - esf
79	 */
80
81	mov	%l7, %o0
82	/* Fill in the content of the exception stack frame */
83#if defined(CONFIG_EXTRA_EXCEPTION_INFO)
84	std	%i0, [%sp + 96 + __struct_arch_esf_out_OFFSET + 0x00]
85	std	%i2, [%sp + 96 + __struct_arch_esf_out_OFFSET + 0x08]
86	std	%i4, [%sp + 96 + __struct_arch_esf_out_OFFSET + 0x10]
87	std	%i6, [%sp + 96 + __struct_arch_esf_out_OFFSET + 0x18]
88	std	%g0, [%sp + 96 + __struct_arch_esf_global_OFFSET + 0x00]
89	std	%g2, [%sp + 96 + __struct_arch_esf_global_OFFSET + 0x08]
90	std	%g4, [%sp + 96 + __struct_arch_esf_global_OFFSET + 0x10]
91	std	%g6, [%sp + 96 + __struct_arch_esf_global_OFFSET + 0x18]
92#endif
93	std	%l0, [%sp + 96 + __struct_arch_esf_psr_OFFSET] /* psr pc */
94	std	%l2, [%sp + 96 + __struct_arch_esf_npc_OFFSET] /* npc wim */
95	rd	%y, %l7
96	std	%l6, [%sp + 96 + __struct_arch_esf_tbr_OFFSET] /* tbr y */
97
98	/* Enable traps, raise PIL to mask all maskable interrupts. */
99	or	%l0, PSR_PIL, %o2
100	wr	%o2, PSR_ET, %psr
101	nop
102	nop
103	nop
104
105#if defined(CONFIG_EXTRA_EXCEPTION_INFO)
106	/* Flush all register windows to the stack. */
107	.rept CONFIG_SPARC_NWIN-1
108	save	%sp, -64, %sp
109	.endr
110	.rept CONFIG_SPARC_NWIN-1
111	restore
112	.endr
113#endif
114
115	/*
116	 * reason is the first argument.
117	 * Exception stack frame prepared earlier is the second argument.
118	 */
119	call	z_sparc_fatal_error
120	 add	%sp, 96, %o1
121
122
123/*
124 * Entry for trap we don't handle explicitly
125 *
126 * Just drop into __sparc_trap_except_reason with reason set to
127 * K_ERR_CPU_EXCEPTION. Note that "reason" is transported in %l7 of the
128 * trapped-into window and global %g1 is preserved.
129 */
130SECTION_FUNC(TEXT, __sparc_trap_fault)
131	b	.Ldoit
132	/* K_ERR_CPU_EXCEPTION */
133	 mov	%g0, %l7
134