This source file includes following definitions.
- die_if_kernel
- do_entArith
- do_entIF
- do_entUna
- 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/unaligned.h>
16 #include <asm/gentrap.h>
17
18 void die_if_kernel(char * str, struct pt_regs * regs, long err)
19 {
20 long i;
21 unsigned long sp;
22 unsigned int * pc;
23
24 if (regs->ps & 8)
25 return;
26 printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
27 sp = (unsigned long) (regs+1);
28 printk("pc = [<%lx>] ps = %04lx\n", regs->pc, regs->ps);
29 printk("rp = [<%lx>] sp = %lx\n", regs->r26, sp);
30 printk("r0=%lx r1=%lx r2=%lx r3=%lx\n",
31 regs->r0, regs->r1, regs->r2, regs->r3);
32 printk("r8=%lx\n", regs->r8);
33 printk("r16=%lx r17=%lx r18=%lx r19=%lx\n",
34 regs->r16, regs->r17, regs->r18, regs->r19);
35 printk("r20=%lx r21=%lx r22=%lx r23=%lx\n",
36 regs->r20, regs->r21, regs->r22, regs->r23);
37 printk("r24=%lx r25=%lx r26=%lx r27=%lx\n",
38 regs->r24, regs->r25, regs->r26, regs->r27);
39 printk("r28=%lx r29=%lx r30=%lx\n",
40 regs->r28, regs->gp, sp);
41 printk("Code:");
42 pc = (unsigned int *) regs->pc;
43 for (i = -3; i < 6; i++)
44 printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
45 printk("\n");
46 do_exit(SIGSEGV);
47 }
48
49 asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
50 unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5,
51 struct pt_regs regs)
52 {
53 printk("Arithmetic trap: %02lx %016lx\n", summary, write_mask);
54 die_if_kernel("Arithmetic fault", ®s, 0);
55 send_sig(SIGFPE, current, 1);
56 }
57
58 asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
59 unsigned long a3, unsigned long a4, unsigned long a5,
60 struct pt_regs regs)
61 {
62 extern int ptrace_cancel_bpt (struct task_struct *who);
63
64 die_if_kernel("Instruction fault", ®s, type);
65 switch (type) {
66 case 0:
67 if (ptrace_cancel_bpt(current)) {
68 regs.pc -= 4;
69 }
70 send_sig(SIGTRAP, current, 1);
71 break;
72
73 case 2:
74
75
76
77
78
79
80
81 switch ((long) regs.r16) {
82 case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
83 case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
84 case GEN_FLTINE:
85 send_sig(SIGFPE, current, 1);
86 break;
87
88 case GEN_DECOVF:
89 case GEN_DECDIV:
90 case GEN_DECINV:
91 case GEN_ROPRAND:
92 case GEN_ASSERTERR:
93 case GEN_NULPTRERR:
94 case GEN_STKOVF:
95 case GEN_STRLENERR:
96 case GEN_SUBSTRERR:
97 case GEN_RANGERR:
98 case GEN_SUBRNG:
99 case GEN_SUBRNG1:
100 case GEN_SUBRNG2:
101 case GEN_SUBRNG3:
102 case GEN_SUBRNG4:
103 case GEN_SUBRNG5:
104 case GEN_SUBRNG6:
105 case GEN_SUBRNG7:
106 send_sig(SIGILL, current, 1);
107 break;
108 }
109 break;
110
111 case 1:
112 case 3:
113 case 4:
114 send_sig(SIGILL, current, 1);
115 break;
116
117 default:
118 panic("do_entIF: unexpected instruction-fault type");
119 }
120 }
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 struct allregs {
136 unsigned long regs[32];
137 unsigned long ps, pc, gp, a0, a1, a2;
138 };
139
140 struct unaligned_stat {
141 unsigned long count, va, pc;
142 } unaligned[2];
143
144 asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
145 unsigned long a3, unsigned long a4, unsigned long a5,
146 struct allregs regs)
147 {
148 static int cnt = 0;
149 static long last_time = 0;
150
151 if (cnt >= 5 && jiffies - last_time > 5*HZ) {
152 cnt = 0;
153 }
154 if (++cnt < 5) {
155 printk("kernel: unaligned trap at %016lx: %p %lx %ld\n",
156 regs.pc - 4, va, opcode, reg);
157 }
158 last_time = jiffies;
159
160 ++unaligned[0].count;
161 unaligned[0].va = (unsigned long) va - 4;
162 unaligned[0].pc = regs.pc;
163
164
165 if (reg >= 16 && reg <= 18)
166 reg += 19;
167 switch (opcode) {
168 case 0x28:
169 *(reg+regs.regs) = (int) ldl_u(va);
170 return;
171 case 0x29:
172 *(reg+regs.regs) = ldq_u(va);
173 return;
174 case 0x2c:
175 stl_u(*(reg+regs.regs), va);
176 return;
177 case 0x2d:
178 stq_u(*(reg+regs.regs), va);
179 return;
180 }
181 printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
182 regs.pc, va, opcode, reg);
183 do_exit(SIGSEGV);
184 }
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201 asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg,
202 unsigned long * frame)
203 {
204 long dir, size;
205 unsigned long *reg_addr, *pc_addr, usp, zero = 0;
206 static int cnt = 0;
207 static long last_time = 0;
208
209 pc_addr = frame + 7 + 20 + 1;
210
211 if (cnt >= 5 && jiffies - last_time > 5*HZ) {
212 cnt = 0;
213 }
214 if (++cnt < 5) {
215 printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
216 current->comm, current->pid,
217 *pc_addr - 4, va, opcode, reg);
218 }
219 last_time = jiffies;
220
221 ++unaligned[1].count;
222 unaligned[1].va = (unsigned long) va - 4;
223 unaligned[1].pc = *pc_addr;
224
225 dir = VERIFY_READ;
226 if (opcode > 0x29) {
227
228 dir = VERIFY_WRITE;
229 }
230 size = 4;
231 if (opcode & 1) {
232
233 size = 8;
234 }
235 if (verify_area(dir, va, size)) {
236 *pc_addr -= 4;
237 send_sig(SIGSEGV, current, 1);
238 return;
239 }
240
241 reg_addr = frame;
242 if (reg < 9) {
243 reg_addr += 7 + reg;
244 } else if (reg < 16) {
245 reg_addr += (reg - 9);
246 } else if (reg < 19) {
247 reg_addr += 7 + 20 + 3 + (reg - 16);
248 } else if (reg < 29) {
249 reg_addr += 7 + 9 + (reg - 19);
250 } else {
251 switch (reg) {
252 case 29:
253 reg_addr += 7 + 20 + 2;
254 break;
255 case 30:
256 usp = rdusp();
257 reg_addr = &usp;
258 break;
259 case 31:
260 reg_addr = &zero;
261 break;
262 }
263 }
264
265 switch (opcode) {
266 case 0x28: *reg_addr = (int) ldl_u(va); break;
267 case 0x29: *reg_addr = ldq_u(va); break;
268 case 0x2c: stl_u(*reg_addr, va); break;
269 case 0x2d: stq_u(*reg_addr, va); break;
270 default:
271 *pc_addr -= 4;
272 send_sig(SIGBUS, current, 1);
273 return;
274 }
275
276 if (reg == 30 && dir == VERIFY_WRITE) {
277 wrusp(usp);
278 }
279 }
280
281
282
283
284
285
286
287
288
289
290
291
292 asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2,
293 unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs)
294 {
295 if (regs.r0 != 112)
296 printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
297 return -1;
298 }
299
300 extern asmlinkage void entMM(void);
301 extern asmlinkage void entIF(void);
302 extern asmlinkage void entArith(void);
303 extern asmlinkage void entUna(void);
304 extern asmlinkage void entSys(void);
305
306 void trap_init(void)
307 {
308 unsigned long gptr;
309
310
311
312
313 __asm__("br %0,___tmp\n"
314 "___tmp:\tldgp %0,0(%0)"
315 : "=r" (gptr));
316 wrkgp(gptr);
317
318 wrent(entArith, 1);
319 wrent(entMM, 2);
320 wrent(entIF, 3);
321 wrent(entUna, 4);
322 wrent(entSys, 5);
323 }