Added FPU emulation to SPARC port
[akaros.git] / kern / arch / sparc / trap.c
1 #include <arch/arch.h>
2 #include <assert.h>
3 #include <arch/trap.h>
4 #include <string.h>
5 #include <process.h>
6 #include <syscall.h>
7 #include <monitor.h>
8 #include <manager.h>
9 #include <stdio.h>
10 #include <smp.h>
11
12 #ifdef __SHARC__
13 #pragma nosharc
14 #endif
15
16 #ifdef __DEPUTY__
17 #pragma nodeputy
18 #endif
19
20 spinlock_t active_message_buf_busy[MAX_NUM_CPUS] = {0};
21 active_message_t active_message_buf[MAX_NUM_CPUS];
22
23 uint32_t send_active_message(uint32_t dst, amr_t pc,
24                              TV(a0t) arg0, TV(a1t) arg1, TV(a2t) arg2)
25 {
26         if(dst >= num_cpus || spin_trylock(&active_message_buf_busy[dst]))
27                 return -1;
28
29         active_message_buf[dst].srcid = core_id();
30         active_message_buf[dst].pc = pc;
31         active_message_buf[dst].arg0 = arg0;
32         active_message_buf[dst].arg1 = arg1;
33         active_message_buf[dst].arg2 = arg2;
34
35         if(send_ipi(dst))
36         {
37                 spin_unlock(&active_message_buf_busy[dst]);
38                 return -1;
39         }
40
41         return 0;
42 }
43
44 void
45 idt_init(void)
46 {
47 }
48
49 void
50 sysenter_init(void)
51 {
52 }
53
54 void
55 ( print_trapframe)(trapframe_t *tf)
56 {
57         int i, len;
58         char buf[1024];
59
60         len = snprintf(buf,sizeof(buf),"TRAP frame at %p on core %d\n",
61                        tf, core_id());
62
63         for(i = 0; i < 8; i++)
64         {
65                 len += snprintf(buf+len,sizeof(buf)-len,
66                                 "  g%d   0x%08x  o%d   0x%08x"
67                                 "  l%d   0x%08x  i%d 0x%08x\n",
68                                 i,tf->gpr[i],i,tf->gpr[i+8],
69                                 i,tf->gpr[i+16],i,tf->gpr[i+24]);
70         }
71
72         len += snprintf(buf+len,sizeof(buf)-len,
73                         "  psr  0x%08x  pc   0x%08x  npc  0x%08x  wim  0x%08x\n",
74                         tf->psr,tf->pc,tf->npc,tf->wim);
75         len += snprintf(buf+len,sizeof(buf)-len,
76                         "  tbr  0x%08x  y    0x%08x  fsr  0x%08x  far  0x%08x\n",
77                         tf->tbr,tf->y,tf->fault_status,tf->fault_addr);
78         len += snprintf(buf+len,sizeof(buf)-len,
79                         "  timestamp  %21lld\n",tf->timestamp);
80
81         cprintf("%s",buf);
82 }
83
84 #define TRAPNAME_MAX    32
85
86 static char*
87 get_trapname(uint8_t tt, char buf[TRAPNAME_MAX])
88 {
89         static const char* trapnames[] = {
90                 [0x00] "reset",
91                 [0x01] "instruction access exception",
92                 [0x02] "illegal instruction",
93                 [0x03] "privileged instruction",
94                 [0x04] "floating point disabled",
95                 [0x05] "window overflow",
96                 [0x06] "window underflow",
97                 [0x07] "memory address not aligned",
98                 [0x08] "floating point exception",
99                 [0x09] "data access exception",
100                 [0x20] "register access error",
101                 [0x21] "instruction access error",
102                 [0x24] "coprocessor disabled",
103                 [0x25] "unimplemented FLUSH",
104                 [0x28] "coprocessor exception",
105                 [0x29] "data access error",
106                 [0x2A] "division by zero",
107                 [0x2B] "data store error",
108                 [0x2C] "data MMU miss",
109                 [0x3C] "instruction MMU miss"
110         };
111
112         if(tt >= 0x80)
113                 snprintf(buf,TRAPNAME_MAX,"user trap 0x%02x",tt);
114         else if(tt >= 0x10 && tt < 0x20)
115                 snprintf(buf,TRAPNAME_MAX,"interrupt 0x%x",tt-0x10);
116         else if(tt >= sizeof(trapnames)/sizeof(trapnames[0]) || !trapnames[tt])
117                 snprintf(buf,TRAPNAME_MAX,"(unknown trap 0x%02x)",tt);
118         else
119                 strncpy(buf,trapnames[tt],sizeof(trapnames) + 1);
120
121         return buf;
122 }
123
124 void
125 trap(trapframe_t* state, void (*handler)(trapframe_t*))
126 {
127         // TODO: must save other cores' trap frames
128         // if we want them to migrate, block, etc.
129         if(current && current->vcoremap[0] == core_id())
130         {
131                 current->env_tf = *state;
132                 handler(&current->env_tf);
133         }
134         else
135                 handler(state);
136 }
137
138 void
139 handle_ipi(trapframe_t* state)
140 {
141         active_message_t m;
142         m = active_message_buf[core_id()];
143         spin_unlock(&active_message_buf_busy[core_id()]);
144
145         uint32_t src = m.srcid;
146         TV(a0t) a0 = m.arg0;
147         TV(a1t) a1 = m.arg1;
148         TV(a2t) a2 = m.arg2;
149         (m.pc)(state,src,a0,a1,a2);
150         env_pop_tf(state);
151 }
152
153 void
154 unhandled_trap(trapframe_t* state)
155 {
156         char buf[TRAPNAME_MAX];
157         uint32_t trap_type = (state->tbr >> 4) & 0xFF;
158         get_trapname(trap_type,buf);
159
160         if(state->psr & PSR_PS)
161         {
162                 print_trapframe(state);
163                 panic("Unhandled trap in kernel!\nTrap type: %s",buf);
164         }
165         else
166         {
167                 print_trapframe(state);
168                 warn("Unhandled trap in user!\nTrap type: %s",buf);
169                 assert(current);
170                 proc_destroy(current);
171                 panic("I shouldn't have gotten here!");
172         }
173 }
174
175 static void
176 stack_fucked(trapframe_t* state)
177 {
178         // see if the problem arose when flushing out
179         // windows during handle_trap
180         extern uint32_t tflush;
181         if(state->pc == (uint32_t)&tflush)
182         {
183                 // the trap happened while flushing out windows.
184                 // hope this happened in the user, or else we're hosed...
185                 extern char bootstacktop;
186                 state = (trapframe_t*)(&bootstacktop-SIZEOF_TRAPFRAME_T-core_id()*KSTKSIZE);
187         }
188
189         warn("You just got stack fucked!");
190         unhandled_trap(state);
191 }
192
193 void
194 stack_misaligned(trapframe_t* state)
195 {
196         state->tbr = (state->tbr & ~0xFFF) | 0x070;
197         stack_fucked(state);
198 }
199
200 void
201 stack_pagefault(trapframe_t* state)
202 {
203         state->tbr = (state->tbr & ~0xFFF) | 0x090;
204         stack_fucked(state);
205 }
206
207 void
208 address_unaligned(trapframe_t* state)
209 {
210         unhandled_trap(state);
211 }
212
213 void
214 access_exception(trapframe_t* state)
215 {
216         unhandled_trap(state);
217 }
218
219 void
220 illegal_instruction(trapframe_t* state)
221 {
222         unhandled_trap(state);
223 }
224
225 void
226 real_fp_exception(trapframe_t* state, ancillary_state_t* sillystate)
227 {
228         unhandled_trap(state);
229 }
230
231 void
232 fp_exception(trapframe_t* state)
233 {
234         ancillary_state_t sillystate;
235         save_fp_state(&sillystate);     
236
237         // since our FP HW exception behavior is sketchy, reexecute
238         // any faulting FP instruction in SW, which may call
239         // real_fp_exception above
240         emulate_fpu(state,&sillystate);
241
242         restore_fp_state(&sillystate);
243
244         env_pop_tf(state);
245 }
246
247 void
248 fp_disabled(trapframe_t* state)
249 {
250         if(state->psr & PSR_PS)
251                 panic("kernel executed an FP instruction!");
252
253         state->psr |= PSR_EF;
254         env_pop_tf(state);
255 }
256
257 void
258 handle_syscall(trapframe_t* state)
259 {
260         uint32_t num = state->gpr[1];
261         uint32_t a1 = state->gpr[8];
262         uint32_t a2 = state->gpr[9];
263         uint32_t a3 = state->gpr[10];
264         uint32_t a4 = state->gpr[11];
265         uint32_t a5 = state->gpr[12];
266
267         // advance pc (else we reexecute the syscall)
268         state->pc = state->npc;
269         state->npc += 4;
270
271         // TODO: must save other cores' ancillary state
272         // if we want them to migrate, block, etc.
273         if(current->vcoremap[0] == core_id())
274                 env_push_ancillary_state(current);
275
276         state->gpr[8] = syscall(current,state,num,a1,a2,a3,a4,a5);
277
278         proc_startcore(current,state);
279 }
280
281 void
282 flush_windows()
283 {
284         register int foo asm("g1");
285         register int nwin asm("g2");
286         extern int NWINDOWS;
287
288         nwin = NWINDOWS;
289         foo = nwin;
290
291         asm volatile ("1: deccc %0; bne,a 1b; save %%sp,-64,%%sp"
292                       : "=r"(foo) : "r"(foo));
293
294         foo = nwin;
295         asm volatile ("1: deccc %0; bne,a 1b; restore"
296                       : "=r"(foo) : "r"(foo));
297 }
298    
299 void
300 handle_flushw(trapframe_t* state)
301 {
302         flush_windows();
303         state->pc = state->npc;
304         state->npc += 4;
305         env_pop_tf(state);
306 }
307
308 void
309 handle_breakpoint(trapframe_t* state)
310 {
311         // advance the pc
312         state->pc = state->npc;
313         state->npc += 4;
314
315         // TODO: must save other cores' ancillary state
316         // if we want them to migrate, block, etc.
317         if(current->vcoremap[0] == core_id())
318                 env_push_ancillary_state(current);
319
320         // run the monitor
321         monitor(state);
322
323         assert(0);
324 }