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