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