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