Made stuff work on SPARC HW
[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         wr      %l7,PSR_PIL,%psr
57         wr      %l7,PSR_PIL|PSR_ET,%psr
58
59         // Are we user or kernel?
60         btst    PSR_PS,%l7
61         mov     %l2,%l6
62         be      1f
63          mov    %l1,%l5
64
65         // Trap came from kernel.  Spill a window if necessary.
66         SAVE_MINIMAL_TF(%fp-SIZEOF_TRAPFRAME_T)
67         mov     %tbr,%g1
68         restore
69         save
70
71         // Set up stack, save state, call handler
72         sub     %fp,96+SIZEOF_TRAPFRAME_T,%sp
73
74         // Save full trap frame if this was a synchronous exception (=> bug!!)
75         and     %g1,0xF00,%g1
76         cmp     %g1,0x100
77         be      2f
78          nop
79
80         call    save_rest_of_tf
81          add    %sp,96,%o0
82
83 2:      call    %l0
84          add    %sp,96,%o0
85
86         // Fill a window if necessary.
87         restore
88         save
89
90         // Restore PSR, then GTFO
91         ld      [%sp+96+128],%l7
92         mov     %l7,%psr
93         RESTORE_MINIMAL_TF(%sp+96)
94
95         // Trap came from user.  Spill a window if necessary.
96 1:      mov     CORE_ID_REG,%l1
97         sll     %l1,KSTKSHIFT,%l1
98         set     bootstacktop-SIZEOF_TRAPFRAME_T,%l2
99         sub     %l2,%l1,%l1
100         SAVE_MINIMAL_TF(%l1)
101         sub     %l1,96,%g1
102         restore
103 tflush1:
104         save
105
106         // Set up stack.
107         // Save a full trap frame, since we might not return through this path
108         mov     %g1,%sp
109         call    save_rest_of_tf
110          add    %sp,96,%o0
111
112         // spill all trapper's windows out to the stack.
113         // the 'save' may trap (triggering the spill),
114         // and if the stack is corrupted, the process may die
115 trap_patchme:
116         mov     0,%g2                                           // 0 will become NWINDOWS-1
117         mov     %g2,%g3
118 5:      deccc   %g2
119         bne,a   5b
120 tflush2:
121          save
122
123         // get our old window back
124 5:      deccc   %g3
125         bne,a   5b
126          restore
127
128         // Call the handler
129         call    %l0
130          add    %sp,96,%o0
131
132         // fallthrough to env_pop_tf, which is right below this function
133         add     %sp,96,%o0
134
135         // this routine only works for returning to userspace.
136         // right now, there's no mechanism to resume kernel operation after
137         // a fault
138         .global env_pop_tf
139 env_pop_tf:
140         mov     %psr,%o1
141         wr      %o1,PSR_ET,%psr
142
143         // CWP = 0 (therefore 1 after rett), so set window 2 invalid
144         mov     1<<2,%wim
145         ld      [%o0+128],%o1
146         mov     %o0,%g2
147         andn    %o1,PSR_CWP,%o1
148         mov     %o1,%psr
149         nop; nop; nop
150         mov     %g2,%o0
151
152 4:      // restore user context
153         restore
154         ldd     [%g2+32],%o0
155         ldd     [%g2+40],%o2
156         ldd     [%g2+48],%o4
157         ldd     [%g2+56],%o6
158         ldd     [%g2+64],%l0
159         ldd     [%g2+72],%l2
160         ldd     [%g2+80],%l4
161         ldd     [%g2+88],%l6
162         ldd     [%g2+96],%i0
163         ldd     [%g2+104],%i2
164         ldd     [%g2+112],%i4
165         ldd     [%g2+120],%i6
166         save
167
168         RESTORE_MINIMAL_TF(%o0)
169
170         // save_rest_of_tf saves what SAVE_MINIMAL_TF doesn't.
171         // o0: destination trapframe_t*
172 save_rest_of_tf:
173
174         mov     %wim,%o4
175         st      %o4,[%o0+140]
176
177         lda     [%g0] 2,%o4
178         mov     4,%o5
179         lda     [%o5] 2,%o5
180         std     %o4,[%o0+160]
181
182         mov     %o0,%g2
183
184         restore
185         std     %o0,[%g2+32]
186         std     %o2,[%g2+40]
187         std     %o4,[%g2+48]
188         std     %o6,[%g2+56]
189         std     %l0,[%g2+64]
190         std     %l2,[%g2+72]
191         std     %l4,[%g2+80]
192         std     %l6,[%g2+88]
193         std     %i0,[%g2+96]
194         std     %i2,[%g2+104]
195         std     %i4,[%g2+112]
196         std     %i6,[%g2+120]
197         save
198
199         retl
200          nop
201
202         .global handle_perfctr
203 handle_perfctr:
204         andn    %i0,7,%i1
205         lda     [%i1] 2,%i0
206         add     %i1,4,%i1
207         lda     [%i1] 2,%i1
208         jmp     %l2
209          rett   %l2+4
210
211         // we make cpu_halt a linker symbol so we know if we were halted.
212         // if we were halted, we should return to PC+4, not PC.
213         .global cpu_halt
214 cpu_halt:
215         ba,a cpu_halt
216         retl
217          nop