Fixed register clobbering in SPARC
[akaros.git] / kern / arch / sparc / trap_entry.S
1 #include <arch/sparc.h>
2 #include <arch/trap.h>
3 #include <arch/mmu.h>
4 #include <arch/trap_table.h>
5 #include <ros/memlayout.h>
6
7
8 // Macro to save a minimal part of the trap frame, i.e., what's necessary
9 // to safely return from interrupt.  Global registers, y, pc, npc.
10 #define SAVE_MINIMAL_TF(tf) \
11         std     %g0,[tf+  0] ;\
12         std     %g2,[tf+  8] ;\
13         std     %g4,[tf+ 16] ;\
14         std     %g6,[tf+ 24] ;\
15         st      %l7,[tf+128] ;\
16         st      %l5,[tf+132] ;\
17         st      %l6,[tf+136] ;\
18         mov     %y,%g1       ;\
19         st      %g1,[tf+148]
20
21 // Macro to restore same.
22 #define RESTORE_MINIMAL_TF(tf) \
23         ld      [tf+  4],%g1 ;\
24         ldd     [tf+  8],%g2 ;\
25         ldd     [tf+ 16],%g4 ;\
26         ldd     [tf+ 24],%g6 ;\
27         ld      [tf+148],%l0 ;\
28         mov     %l0,%y           ;\
29         ld      [tf+132],%l5 ;\
30         ld      [tf+136],%l6 ;\
31         jmp     %l5 ;\
32          rett   %l6
33
34
35         .section        ".text"!,#alloc,#execinstr,#progbits
36         .align          4
37
38         .global tflush1
39         .global tflush2
40         .global trap_patchme
41
42         .global handle_trap
43 handle_trap:
44
45         // First, make sure we have a valid register window.
46         // The restore won't trap, but the save might.
47         // The spill handler won't overwrite l0/l5/l6, so stash l1 (pc) and l2 (npc)
48         // in there, since the hardware will overwrite them if save traps
49         mov     %psr,%l7
50         wr      %l7,PSR_PIL,%psr
51         wr      %l7,PSR_PIL|PSR_ET,%psr
52
53         // Are we user or kernel?
54         btst    PSR_PS,%l7
55         mov     %l2,%l6
56         be      1f
57          mov    %l1,%l5
58
59         // Trap came from kernel.  Spill a window if necessary.
60         restore
61         save
62
63         // Set up stack, save state, call handler
64         sub     %fp,64+SIZEOF_TRAPFRAME_T,%sp
65         SAVE_MINIMAL_TF(%sp+64)
66         call    %l0
67          add    %sp,64,%o0
68
69         // Fill a window if necessary.
70         restore
71         save
72
73         // Restore PSR, then GTFO
74         ld      [%sp+64+128],%l7
75         mov     %l7,%psr
76         RESTORE_MINIMAL_TF(%sp+64)
77
78         // Trap came from user.  Spill a window if necessary.
79 1:      restore
80 tflush1:
81         save
82
83         // Set up stack.
84         mov     CORE_ID_REG,%l1
85         sll     %l1,KSTKSHIFT,%l1
86         set     bootstacktop-64-SIZEOF_TRAPFRAME_T,%sp
87         sub     %sp,%l1,%sp
88
89         // Save a full trap frame, since we might not return through this path
90         call    env_save_tf
91          add    %sp,64,%o0
92
93         // spill all trapper's windows out to the stack.
94         // the 'save' may trap (triggering the spill),
95         // and if the stack is corrupted, the process may die
96         mov     %l7,%g3
97         mov     %sp,%g4
98         mov %l0,%g5
99 trap_patchme:
100         mov     0,%g2                                           // 0 will become NWINDOWS-1
101 5:      deccc   %g2
102         bne,a   5b
103 tflush2:
104          save
105
106         // With windows flushed, now just set ourselves up as the first window
107         mov     %g0,%wim
108         andn    %g3,PSR_CWP,%g3
109         wr      %g3,PSR_PIL|PSR_ET,%psr
110         nop; nop; nop
111         mov     1<<1,%wim
112         mov     %g4,%sp
113
114         // Call the handler
115         call    %g5
116          add    %sp,64,%o0
117
118         // fallthrough to env_pop_tf, which is right below this function
119         add     %sp,64,%o0
120
121         // this routine only works for returning to userspace.
122         // right now, there's no mechanism to resume kernel operation after
123         // a fault
124         .global env_pop_tf
125 env_pop_tf:
126         mov     %psr,%o1
127         wr      %o1,PSR_ET,%psr
128
129         // CWP = 0 (therefore 1 after rett), so set window 2 invalid
130         mov     1<<2,%wim
131         ld      [%o0+128],%o1
132         mov     %o0,%g2
133         andn    %o1,PSR_CWP,%o1
134         mov     %o1,%psr
135         nop; nop; nop
136         mov     %g2,%o0
137
138 4:      // restore user context
139         restore
140         ldd     [%g2+32],%o0
141         ldd     [%g2+40],%o2
142         ldd     [%g2+48],%o4
143         ldd     [%g2+56],%o6
144         ldd     [%g2+64],%l0
145         ldd     [%g2+72],%l2
146         ldd     [%g2+80],%l4
147         ldd     [%g2+88],%l6
148         ldd     [%g2+96],%i0
149         ldd     [%g2+104],%i2
150         ldd     [%g2+112],%i4
151         ldd     [%g2+120],%i6
152         save
153
154         ld      [%o0+152],%l6
155         mov     %l6,%asr13
156
157         RESTORE_MINIMAL_TF(%o0)
158
159         // env_save_tf has a non-standard calling convention.
160         // o0: destination trapframe_t*
161         // l5: PC
162         // l6: nPC
163         // l7: PSR
164         .global env_save_tf
165 env_save_tf:
166
167         SAVE_MINIMAL_TF(%o0)
168
169         mov     %wim,%o4
170         st      %o4,[%o0+140]
171         mov     %tbr,%o4
172         st      %o4,[%o0+144]
173         mov     %asr13,%o5
174         st      %o5,[%o0+152]
175
176         set     0x300,%o4
177         set     0x400,%o5
178         lda     [%o4] 4,%o4
179         lda     [%o5] 4,%o5
180         std     %o4,[%o0+160]
181         lda     [%g0] 2,%o4
182         mov     4,%o5
183         lda     [%o5] 2,%o5
184         std     %o4,[%o0+168]
185
186         # try to read out the faulting insn (in no-fault mode)
187         andn    %l5,3,%o1
188         lda     [%g0] 4,%o2
189         or      %o2,2,%o3
190         sta     %o3,[%g0] 4
191         mov     -1,%o3
192         ld      [%o1],%o3
193         st      %o3,[%o0+156]
194         sta     %o2,[%g0] 4
195         mov     0x300,%o4
196         lda     [%o4] 4,%g0
197
198         mov     %o0,%g2
199
200         restore
201         std     %o0,[%g2+32]
202         std     %o2,[%g2+40]
203         std     %o4,[%g2+48]
204         std     %o6,[%g2+56]
205         std     %l0,[%g2+64]
206         std     %l2,[%g2+72]
207         std     %l4,[%g2+80]
208         std     %l6,[%g2+88]
209         std     %i0,[%g2+96]
210         std     %i2,[%g2+104]
211         std     %i4,[%g2+112]
212         std     %i6,[%g2+120]
213         save
214
215         retl
216          nop
217
218         .global handle_perfctr
219 handle_perfctr:
220         andn    %i0,7,%i1
221         lda     [%i1] 2,%i0
222         add     %i1,4,%i1
223         lda     [%i1] 2,%i1
224         jmp     %l2
225          rett   %l2+4
226
227         // we make cpu_halt a linker symbol so we know if we were halted.
228         // if we were halted, we should return to PC+4, not PC.
229         .global cpu_halt
230 cpu_halt:
231         ba,a cpu_halt
232         retl
233          nop