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