This source file includes following definitions.
- die_if_kernel
- do_entArith
- do_entIF
- do_entUna
- s_mem_to_reg
- s_reg_to_mem
- do_entUnaUser
- do_entSys
- trap_init
1
2
3
4
5
6
7
8
9
10
11 #include <linux/mm.h>
12 #include <linux/sched.h>
13 #include <linux/tty.h>
14
15 #include <asm/gentrap.h>
16 #include <asm/segment.h>
17 #include <asm/unaligned.h>
18
19 void die_if_kernel(char * str, struct pt_regs * regs, long err)
20 {
21 long i;
22 unsigned long sp;
23 unsigned int * pc;
24
25 if (regs->ps & 8)
26 return;
27 printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
28 sp = (unsigned long) (regs+1);
29 printk("pc = [<%lx>] ps = %04lx\n", regs->pc, regs->ps);
30 printk("rp = [<%lx>] sp = %lx\n", regs->r26, sp);
31 printk("r0=%lx r1=%lx r2=%lx r3=%lx\n",
32 regs->r0, regs->r1, regs->r2, regs->r3);
33 printk("r8=%lx\n", regs->r8);
34 printk("r16=%lx r17=%lx r18=%lx r19=%lx\n",
35 regs->r16, regs->r17, regs->r18, regs->r19);
36 printk("r20=%lx r21=%lx r22=%lx r23=%lx\n",
37 regs->r20, regs->r21, regs->r22, regs->r23);
38 printk("r24=%lx r25=%lx r26=%lx r27=%lx\n",
39 regs->r24, regs->r25, regs->r26, regs->r27);
40 printk("r28=%lx r29=%lx r30=%lx\n",
41 regs->r28, regs->gp, sp);
42 printk("Code:");
43 pc = (unsigned int *) regs->pc;
44 for (i = -3; i < 6; i++)
45 printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
46 printk("\n");
47 do_exit(SIGSEGV);
48 }
49
50 asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
51 unsigned long a2, unsigned long a3,
52 unsigned long a4, unsigned long a5,
53 struct pt_regs regs)
54 {
55 if ((summary & 1)) {
56 extern long alpha_fp_emul_imprecise (struct pt_regs * regs,
57 unsigned long write_mask);
58
59
60
61
62 if (alpha_fp_emul_imprecise(®s, write_mask)) {
63 return;
64 }
65 }
66 printk("Arithmetic trap at %016lx: %02lx %016lx\n",
67 regs.pc, summary, write_mask);
68 die_if_kernel("Arithmetic fault", ®s, 0);
69 send_sig(SIGFPE, current, 1);
70 }
71
72 asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
73 unsigned long a3, unsigned long a4, unsigned long a5,
74 struct pt_regs regs)
75 {
76 extern int ptrace_cancel_bpt (struct task_struct *who);
77
78 die_if_kernel("Instruction fault", ®s, type);
79 switch (type) {
80 case 0:
81 if (ptrace_cancel_bpt(current)) {
82 regs.pc -= 4;
83 }
84 send_sig(SIGTRAP, current, 1);
85 break;
86
87 case 2:
88
89
90
91
92
93
94
95 switch ((long) regs.r16) {
96 case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
97 case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
98 case GEN_FLTINE:
99 send_sig(SIGFPE, current, 1);
100 break;
101
102 case GEN_DECOVF:
103 case GEN_DECDIV:
104 case GEN_DECINV:
105 case GEN_ROPRAND:
106 case GEN_ASSERTERR:
107 case GEN_NULPTRERR:
108 case GEN_STKOVF:
109 case GEN_STRLENERR:
110 case GEN_SUBSTRERR:
111 case GEN_RANGERR:
112 case GEN_SUBRNG:
113 case GEN_SUBRNG1:
114 case GEN_SUBRNG2:
115 case GEN_SUBRNG3:
116 case GEN_SUBRNG4:
117 case GEN_SUBRNG5:
118 case GEN_SUBRNG6:
119 case GEN_SUBRNG7:
120 send_sig(SIGILL, current, 1);
121 break;
122 }
123 break;
124
125 case 1:
126 case 3:
127 send_sig(SIGILL, current, 1);
128 break;
129
130 case 4:
131 #ifdef CONFIG_ALPHA_NEED_ROUNDING_EMULATION
132 {
133 extern long alpha_fp_emul (unsigned long pc);
134 unsigned int opcode;
135
136
137 opcode = get_user((__u32*)(regs.pc - 4)) >> 26;
138 if (opcode == 0x16) {
139
140
141
142
143 if (!alpha_fp_emul(regs.pc - 4))
144 send_sig(SIGFPE, current, 1);
145 break;
146 }
147 }
148 #endif
149 send_sig(SIGILL, current, 1);
150 break;
151
152 default:
153 panic("do_entIF: unexpected instruction-fault type");
154 }
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 struct allregs {
171 unsigned long regs[32];
172 unsigned long ps, pc, gp, a0, a1, a2;
173 };
174
175 struct unaligned_stat {
176 unsigned long count, va, pc;
177 } unaligned[2];
178
179 asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
180 unsigned long a3, unsigned long a4, unsigned long a5,
181 struct allregs regs)
182 {
183 static int cnt = 0;
184 static long last_time = 0;
185
186 if (cnt >= 5 && jiffies - last_time > 5*HZ) {
187 cnt = 0;
188 }
189 if (++cnt < 5) {
190 printk("kernel: unaligned trap at %016lx: %p %lx %ld\n",
191 regs.pc - 4, va, opcode, reg);
192 }
193 last_time = jiffies;
194
195 ++unaligned[0].count;
196 unaligned[0].va = (unsigned long) va - 4;
197 unaligned[0].pc = regs.pc;
198
199
200 if (reg >= 16 && reg <= 18)
201 reg += 19;
202 switch (opcode) {
203 case 0x28:
204 *(reg+regs.regs) = (int) ldl_u(va);
205 return;
206 case 0x29:
207 *(reg+regs.regs) = ldq_u(va);
208 return;
209 case 0x2c:
210 stl_u(*(reg+regs.regs), va);
211 return;
212 case 0x2d:
213 stq_u(*(reg+regs.regs), va);
214 return;
215 }
216 printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
217 regs.pc, va, opcode, reg);
218 do_exit(SIGSEGV);
219 }
220
221
222
223
224
225
226
227 static inline unsigned long s_mem_to_reg (unsigned long s_mem)
228 {
229 unsigned long frac = (s_mem >> 0) & 0x7fffff;
230 unsigned long sign = (s_mem >> 31) & 0x1;
231 unsigned long exp_msb = (s_mem >> 30) & 0x1;
232 unsigned long exp_low = (s_mem >> 23) & 0x7f;
233 unsigned long exp;
234
235 exp = (exp_msb << 10) | exp_low;
236 if (exp_msb) {
237 if (exp_low == 0x7f) {
238 exp = 0x3ff;
239 }
240 } else {
241 if (exp_low == 0x00) {
242 exp = 0x000;
243 } else {
244 exp |= (0x7 << 8);
245 }
246 }
247 return (sign << 63) | (exp << 52) | (frac << 29);
248 }
249
250
251
252
253
254 static inline unsigned long s_reg_to_mem (unsigned long s_reg)
255 {
256 return ((s_reg >> 62) << 30) | ((s_reg << 5) >> 34);
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278 asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg,
279 unsigned long * frame)
280 {
281 long dir, size;
282 unsigned long *reg_addr, *pc_addr, usp, zero = 0;
283 static int cnt = 0;
284 static long last_time = 0;
285 extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
286 extern unsigned long alpha_read_fp_reg (unsigned long reg);
287
288 pc_addr = frame + 7 + 20 + 1;
289
290 if (cnt >= 5 && jiffies - last_time > 5*HZ) {
291 cnt = 0;
292 }
293 if (++cnt < 5) {
294 printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
295 current->comm, current->pid,
296 *pc_addr - 4, va, opcode, reg);
297 }
298 last_time = jiffies;
299
300 ++unaligned[1].count;
301 unaligned[1].va = (unsigned long) va - 4;
302 unaligned[1].pc = *pc_addr;
303
304 dir = VERIFY_READ;
305 if (opcode & 0x4) {
306
307 dir = VERIFY_WRITE;
308 }
309 size = 4;
310 if (opcode & 0x1) {
311
312 size = 8;
313 }
314 if (verify_area(dir, va, size)) {
315 *pc_addr -= 4;
316 send_sig(SIGSEGV, current, 1);
317 return;
318 }
319
320 reg_addr = frame;
321 if (opcode >= 0x28) {
322
323 if (reg < 9) {
324 reg_addr += 7 + reg;
325 } else if (reg < 16) {
326 reg_addr += (reg - 9);
327 } else if (reg < 19) {
328 reg_addr += 7 + 20 + 3 + (reg - 16);
329 } else if (reg < 29) {
330 reg_addr += 7 + 9 + (reg - 19);
331 } else {
332 switch (reg) {
333 case 29:
334 reg_addr += 7 + 20 + 2;
335 break;
336 case 30:
337 usp = rdusp();
338 reg_addr = &usp;
339 break;
340 case 31:
341 reg_addr = &zero;
342 break;
343 }
344 }
345 }
346
347 switch (opcode) {
348 case 0x22:
349 alpha_write_fp_reg(reg, s_mem_to_reg(ldl_u(va)));
350 break;
351 case 0x26:
352 alpha_write_fp_reg(reg, s_reg_to_mem(ldl_u(va)));
353 break;
354
355 case 0x23: alpha_write_fp_reg(reg, ldq_u(va)); break;
356 case 0x27: stq_u(alpha_read_fp_reg(reg), va); break;
357
358 case 0x28: *reg_addr = (int) ldl_u(va); break;
359 case 0x29: *reg_addr = ldq_u(va); break;
360 case 0x2c: stl_u(*reg_addr, va); break;
361 case 0x2d: stq_u(*reg_addr, va); break;
362 default:
363 *pc_addr -= 4;
364 send_sig(SIGBUS, current, 1);
365 return;
366 }
367
368 if (opcode >= 0x28 && reg == 30 && dir == VERIFY_WRITE) {
369 wrusp(usp);
370 }
371 }
372
373
374
375
376
377
378
379
380
381
382
383
384 asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2,
385 unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs)
386 {
387 if (regs.r0 != 112)
388 printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
389 return -1;
390 }
391
392 extern asmlinkage void entMM(void);
393 extern asmlinkage void entIF(void);
394 extern asmlinkage void entArith(void);
395 extern asmlinkage void entUna(void);
396 extern asmlinkage void entSys(void);
397
398 void trap_init(void)
399 {
400 unsigned long gptr;
401
402
403
404
405 __asm__("br %0,___tmp\n"
406 "___tmp:\tldgp %0,0(%0)"
407 : "=r" (gptr));
408 wrkgp(gptr);
409
410 wrent(entArith, 1);
411 wrent(entMM, 2);
412 wrent(entIF, 3);
413 wrent(entUna, 4);
414 wrent(entSys, 5);
415 }