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