Added arch framework for handling page faults
[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 #include <mm.h>
13 #include <ros/mman.h>
14
15 #ifdef __SHARC__
16 #pragma nosharc
17 #endif
18
19 #ifdef __DEPUTY__
20 #pragma nodeputy
21 #endif
22
23 spinlock_t active_message_buf_busy[MAX_NUM_CPUS] = {SPINLOCK_INITIALIZER};
24 active_message_t active_message_buf[MAX_NUM_CPUS];
25
26 uint32_t send_active_message(uint32_t dst, amr_t pc,
27                              TV(a0t) arg0, TV(a1t) arg1, TV(a2t) arg2)
28 {
29         if(dst >= num_cpus || spin_trylock(&active_message_buf_busy[dst]))
30                 return -1;
31
32         active_message_buf[dst].srcid = core_id();
33         active_message_buf[dst].pc = pc;
34         active_message_buf[dst].arg0 = arg0;
35         active_message_buf[dst].arg1 = arg1;
36         active_message_buf[dst].arg2 = arg2;
37
38         if(send_ipi(dst))
39         {
40                 spin_unlock(&active_message_buf_busy[dst]);
41                 return -1;
42         }
43
44         return 0;
45 }
46
47 void
48 advance_pc(trapframe_t* state)
49 {
50         state->pc = state->npc;
51         state->npc += 4;
52 }
53
54 void
55 idt_init(void)
56 {
57 }
58
59 void
60 sysenter_init(void)
61 {
62 }
63
64 void
65 ( print_trapframe)(trapframe_t *tf)
66 {
67         int i, len;
68         char buf[1024];
69
70         len = snprintf(buf,sizeof(buf),"TRAP frame at %p on core %d\n",
71                        tf, core_id());
72
73         for(i = 0; i < 8; i++)
74         {
75                 len += snprintf(buf+len,sizeof(buf)-len,
76                                 "  g%d   0x%08x  o%d   0x%08x"
77                                 "  l%d   0x%08x  i%d 0x%08x\n",
78                                 i,tf->gpr[i],i,tf->gpr[i+8],
79                                 i,tf->gpr[i+16],i,tf->gpr[i+24]);
80         }
81
82         len += snprintf(buf+len,sizeof(buf)-len,
83                         "  psr  0x%08x  pc   0x%08x  npc  0x%08x  wim  0x%08x\n",
84                         tf->psr,tf->pc,tf->npc,tf->wim);
85         len += snprintf(buf+len,sizeof(buf)-len,
86                         "  y    0x%08x  fsr  0x%08x  far  0x%08x\n",
87                         tf->y,tf->fault_status,tf->fault_addr);
88         len += snprintf(buf+len,sizeof(buf)-len,
89                         "  timestamp  %21lld\n",tf->timestamp);
90
91         cprintf("%s",buf);
92 }
93
94 #define TRAPNAME_MAX    32
95
96 static char*
97 get_trapname(uint8_t tt, char buf[TRAPNAME_MAX])
98 {
99         static const char* trapnames[] = {
100                 [0x00] "reset",
101                 [0x01] "instruction access exception",
102                 [0x02] "illegal instruction",
103                 [0x03] "privileged instruction",
104                 [0x04] "floating point disabled",
105                 [0x05] "window overflow",
106                 [0x06] "window underflow",
107                 [0x07] "memory address not aligned",
108                 [0x08] "floating point exception",
109                 [0x09] "data access exception",
110                 [0x20] "register access error",
111                 [0x21] "instruction access error",
112                 [0x24] "coprocessor disabled",
113                 [0x25] "unimplemented FLUSH",
114                 [0x28] "coprocessor exception",
115                 [0x29] "data access error",
116                 [0x2A] "division by zero",
117                 [0x2B] "data store error",
118                 [0x2C] "data MMU miss",
119                 [0x3C] "instruction MMU miss"
120         };
121
122         if(tt >= 0x80)
123                 snprintf(buf,TRAPNAME_MAX,"user trap 0x%02x",tt);
124         else if(tt >= 0x10 && tt < 0x20)
125                 snprintf(buf,TRAPNAME_MAX,"interrupt 0x%x",tt-0x10);
126         else if(tt >= sizeof(trapnames)/sizeof(trapnames[0]) || !trapnames[tt])
127                 snprintf(buf,TRAPNAME_MAX,"(unknown trap 0x%02x)",tt);
128         else
129                 strncpy(buf,trapnames[tt],sizeof(trapnames) + 1);
130
131         return buf;
132 }
133
134 void
135 handle_ipi(trapframe_t* state)
136 {
137         active_message_t m;
138         m = active_message_buf[core_id()];
139         spin_unlock(&active_message_buf_busy[core_id()]);
140
141         uint32_t src = m.srcid;
142         TV(a0t) a0 = m.arg0;
143         TV(a1t) a1 = m.arg1;
144         TV(a2t) a2 = m.arg2;
145         (m.pc)(state,src,a0,a1,a2);
146         env_pop_tf(state);
147 }
148
149 void
150 unhandled_trap(trapframe_t* state)
151 {
152         char buf[TRAPNAME_MAX];
153         uint32_t trap_type = (state->tbr >> 4) & 0xFF;
154         get_trapname(trap_type,buf);
155
156         if(state->psr & PSR_PS)
157         {
158                 print_trapframe(state);
159                 panic("Unhandled trap in kernel!\nTrap type: %s",buf);
160         }
161         else
162         {
163                 warn("Unhandled trap in user!\nTrap type: %s",buf);
164                 print_trapframe(state);
165                 backtrace();
166
167                 assert(current);
168                 proc_incref(current, 1);
169                 proc_destroy(current);
170
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 instruction_access_exception(trapframe_t* state)
215 {
216         if(handle_page_fault(current,state->fault_addr,PROT_EXEC))
217                 unhandled_trap(state);
218         else
219                 env_pop_tf(state);
220 }
221
222 void
223 data_access_exception(trapframe_t* state)
224 {
225         int store = ((state->fault_status >> 5) & 7) > 4;
226         int prot = store ? PROT_WRITE : PROT_READ;
227
228         if(handle_page_fault(current,state->fault_addr,prot))
229                 unhandled_trap(state);
230         else
231                 env_pop_tf(state);
232 }
233
234 void
235 illegal_instruction(trapframe_t* state)
236 {
237         unhandled_trap(state);
238 }
239
240 void
241 real_fp_exception(trapframe_t* state, ancillary_state_t* sillystate)
242 {
243         unhandled_trap(state);
244 }
245
246 void
247 fp_exception(trapframe_t* state)
248 {
249         ancillary_state_t sillystate;
250         save_fp_state(&sillystate);     
251
252         // since our FP HW exception behavior is sketchy, reexecute
253         // any faulting FP instruction in SW, which may call
254         // real_fp_exception above
255         emulate_fpu(state,&sillystate);
256
257         restore_fp_state(&sillystate);
258
259         env_pop_tf(state);
260 }
261
262 void
263 fp_disabled(trapframe_t* state)
264 {
265         if(state->psr & PSR_PS)
266                 panic("kernel executed an FP instruction!");
267
268         state->psr |= PSR_EF;
269         env_pop_tf(state);
270 }
271
272 void
273 handle_syscall(trapframe_t* state)
274 {
275         uint32_t num = state->gpr[1];
276         uint32_t a1 = state->gpr[8];
277         uint32_t a2 = state->gpr[9];
278         uint32_t a3 = state->gpr[10];
279         uint32_t a4 = state->gpr[11];
280         uint32_t a5 = state->gpr[12];
281
282         advance_pc(state);
283
284         /* Note we are not preemptively saving the TF in the env_tf.  We do maintain
285          * a reference to it in current_tf (a per-cpu pointer).
286          * In general, only save the tf and any silly state once you know it
287          * is necessary (blocking).  And only save it in env_tf when you know you
288          * are single core (PROC_RUNNING_S) */
289         set_current_tf(state);
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         env_pop_tf(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         // don't actually need to do anything here.
321         // trap_entry flushes user windows to the stack.
322         advance_pc(state);
323         env_pop_tf(state);
324 }
325
326 void
327 handle_breakpoint(trapframe_t* state)
328 {
329         advance_pc(state);
330         monitor(state);
331         env_pop_tf(state);
332 }
333
334 struct kmem_cache *active_msg_cache;
335 void active_msg_init(void)
336 {
337         active_msg_cache = kmem_cache_create("active_msgs",
338                            sizeof(struct active_message), HW_CACHE_ALIGN, 0, 0, 0);
339 }