trap.c revision 1.31.2.3 1 1.31.2.3 elad /* $NetBSD: trap.c,v 1.31.2.3 2006/04/19 02:33:32 elad Exp $ */
2 1.31.2.2 elad
3 1.31.2.2 elad /*
4 1.31.2.2 elad * Copyright 2001 Wasabi Systems, Inc.
5 1.31.2.2 elad * All rights reserved.
6 1.31.2.2 elad *
7 1.31.2.2 elad * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc.
8 1.31.2.2 elad *
9 1.31.2.2 elad * Redistribution and use in source and binary forms, with or without
10 1.31.2.2 elad * modification, are permitted provided that the following conditions
11 1.31.2.2 elad * are met:
12 1.31.2.2 elad * 1. Redistributions of source code must retain the above copyright
13 1.31.2.2 elad * notice, this list of conditions and the following disclaimer.
14 1.31.2.2 elad * 2. Redistributions in binary form must reproduce the above copyright
15 1.31.2.2 elad * notice, this list of conditions and the following disclaimer in the
16 1.31.2.2 elad * documentation and/or other materials provided with the distribution.
17 1.31.2.2 elad * 3. All advertising materials mentioning features or use of this software
18 1.31.2.2 elad * must display the following acknowledgement:
19 1.31.2.2 elad * This product includes software developed for the NetBSD Project by
20 1.31.2.2 elad * Wasabi Systems, Inc.
21 1.31.2.2 elad * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 1.31.2.2 elad * or promote products derived from this software without specific prior
23 1.31.2.2 elad * written permission.
24 1.31.2.2 elad *
25 1.31.2.2 elad * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 1.31.2.2 elad * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 1.31.2.2 elad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 1.31.2.2 elad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 1.31.2.2 elad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 1.31.2.2 elad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 1.31.2.2 elad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 1.31.2.2 elad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 1.31.2.2 elad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 1.31.2.2 elad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 1.31.2.2 elad * POSSIBILITY OF SUCH DAMAGE.
36 1.31.2.2 elad */
37 1.31.2.2 elad
38 1.31.2.2 elad /*
39 1.31.2.2 elad * Copyright (C) 1995, 1996 Wolfgang Solfrank.
40 1.31.2.2 elad * Copyright (C) 1995, 1996 TooLs GmbH.
41 1.31.2.2 elad * All rights reserved.
42 1.31.2.2 elad *
43 1.31.2.2 elad * Redistribution and use in source and binary forms, with or without
44 1.31.2.2 elad * modification, are permitted provided that the following conditions
45 1.31.2.2 elad * are met:
46 1.31.2.2 elad * 1. Redistributions of source code must retain the above copyright
47 1.31.2.2 elad * notice, this list of conditions and the following disclaimer.
48 1.31.2.2 elad * 2. Redistributions in binary form must reproduce the above copyright
49 1.31.2.2 elad * notice, this list of conditions and the following disclaimer in the
50 1.31.2.2 elad * documentation and/or other materials provided with the distribution.
51 1.31.2.2 elad * 3. All advertising materials mentioning features or use of this software
52 1.31.2.2 elad * must display the following acknowledgement:
53 1.31.2.2 elad * This product includes software developed by TooLs GmbH.
54 1.31.2.2 elad * 4. The name of TooLs GmbH may not be used to endorse or promote products
55 1.31.2.2 elad * derived from this software without specific prior written permission.
56 1.31.2.2 elad *
57 1.31.2.2 elad * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
58 1.31.2.2 elad * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59 1.31.2.2 elad * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60 1.31.2.2 elad * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
61 1.31.2.2 elad * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
62 1.31.2.2 elad * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
63 1.31.2.2 elad * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
64 1.31.2.2 elad * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
65 1.31.2.2 elad * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
66 1.31.2.2 elad * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 1.31.2.2 elad */
68 1.31.2.2 elad
69 1.31.2.2 elad #include <sys/cdefs.h>
70 1.31.2.3 elad __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.31.2.3 2006/04/19 02:33:32 elad Exp $");
71 1.31.2.2 elad
72 1.31.2.2 elad #include "opt_altivec.h"
73 1.31.2.2 elad #include "opt_ddb.h"
74 1.31.2.2 elad
75 1.31.2.2 elad #include <sys/param.h>
76 1.31.2.2 elad #include <sys/proc.h>
77 1.31.2.2 elad #include <sys/reboot.h>
78 1.31.2.2 elad #include <sys/syscall.h>
79 1.31.2.2 elad #include <sys/systm.h>
80 1.31.2.2 elad #include <sys/user.h>
81 1.31.2.2 elad #include <sys/pool.h>
82 1.31.2.2 elad #include <sys/sa.h>
83 1.31.2.2 elad #include <sys/savar.h>
84 1.31.2.2 elad #include <sys/userret.h>
85 1.31.2.2 elad
86 1.31.2.2 elad #include <uvm/uvm_extern.h>
87 1.31.2.2 elad
88 1.31.2.2 elad #include <dev/cons.h>
89 1.31.2.2 elad
90 1.31.2.2 elad #include <machine/cpu.h>
91 1.31.2.2 elad #include <machine/db_machdep.h>
92 1.31.2.2 elad #include <machine/fpu.h>
93 1.31.2.2 elad #include <machine/frame.h>
94 1.31.2.2 elad #include <machine/pcb.h>
95 1.31.2.2 elad #include <machine/psl.h>
96 1.31.2.2 elad #include <machine/trap.h>
97 1.31.2.2 elad
98 1.31.2.2 elad #include <powerpc/spr.h>
99 1.31.2.2 elad #include <powerpc/ibm4xx/pmap.h>
100 1.31.2.2 elad #include <powerpc/ibm4xx/tlb.h>
101 1.31.2.2 elad #include <powerpc/fpu/fpu_extern.h>
102 1.31.2.2 elad
103 1.31.2.2 elad /* These definitions should probably be somewhere else XXX */
104 1.31.2.2 elad #define FIRSTARG 3 /* first argument is in reg 3 */
105 1.31.2.2 elad #define NARGREG 8 /* 8 args are in registers */
106 1.31.2.2 elad #define MOREARGS(sp) ((caddr_t)((int)(sp) + 8)) /* more args go here */
107 1.31.2.2 elad
108 1.31.2.2 elad static int fix_unaligned __P((struct lwp *l, struct trapframe *frame));
109 1.31.2.2 elad
110 1.31.2.2 elad void trap __P((struct trapframe *)); /* Called from locore / trap_subr */
111 1.31.2.2 elad /* Why are these not defined in a header? */
112 1.31.2.2 elad int badaddr __P((void *, size_t));
113 1.31.2.2 elad int badaddr_read __P((void *, size_t, int *));
114 1.31.2.2 elad int ctx_setup __P((int, int));
115 1.31.2.2 elad
116 1.31.2.2 elad #ifdef DEBUG
117 1.31.2.2 elad #define TDB_ALL 0x1
118 1.31.2.2 elad int trapdebug = /* TDB_ALL */ 0;
119 1.31.2.2 elad #define DBPRINTF(x, y) if (trapdebug & (x)) printf y
120 1.31.2.2 elad #else
121 1.31.2.2 elad #define DBPRINTF(x, y)
122 1.31.2.2 elad #endif
123 1.31.2.2 elad
124 1.31.2.2 elad void
125 1.31.2.2 elad trap(struct trapframe *frame)
126 1.31.2.2 elad {
127 1.31.2.2 elad struct lwp *l = curlwp;
128 1.31.2.2 elad struct proc *p = l ? l->l_proc : NULL;
129 1.31.2.2 elad int type = frame->exc;
130 1.31.2.2 elad int ftype, rv;
131 1.31.2.2 elad ksiginfo_t ksi;
132 1.31.2.2 elad
133 1.31.2.2 elad KASSERT(l == 0 || (l->l_stat == LSONPROC));
134 1.31.2.2 elad
135 1.31.2.2 elad if (frame->srr1 & PSL_PR)
136 1.31.2.2 elad type |= EXC_USER;
137 1.31.2.2 elad
138 1.31.2.2 elad ftype = VM_PROT_READ;
139 1.31.2.2 elad
140 1.31.2.2 elad DBPRINTF(TDB_ALL, ("trap(%x) at %lx from frame %p &frame %p\n",
141 1.31.2.2 elad type, frame->srr0, frame, &frame));
142 1.31.2.2 elad
143 1.31.2.2 elad switch (type) {
144 1.31.2.2 elad case EXC_DEBUG|EXC_USER:
145 1.31.2.2 elad {
146 1.31.2.2 elad int srr2, srr3;
147 1.31.2.2 elad
148 1.31.2.2 elad __asm volatile("mfspr %0,0x3f0" :
149 1.31.2.2 elad "=r" (rv), "=r" (srr2), "=r" (srr3) :);
150 1.31.2.2 elad printf("debug reg is %x srr2 %x srr3 %x\n", rv, srr2,
151 1.31.2.2 elad srr3);
152 1.31.2.2 elad /* XXX fall through or break here?! */
153 1.31.2.2 elad }
154 1.31.2.2 elad /*
155 1.31.2.2 elad * DEBUG intr -- probably single-step.
156 1.31.2.2 elad */
157 1.31.2.2 elad case EXC_TRC|EXC_USER:
158 1.31.2.2 elad frame->srr1 &= ~PSL_SE;
159 1.31.2.2 elad KSI_INIT_TRAP(&ksi);
160 1.31.2.2 elad ksi.ksi_signo = SIGTRAP;
161 1.31.2.2 elad ksi.ksi_trap = EXC_TRC;
162 1.31.2.2 elad ksi.ksi_addr = (void *)frame->srr0;
163 1.31.2.2 elad KERNEL_PROC_LOCK(l);
164 1.31.2.2 elad trapsignal(l, &ksi);
165 1.31.2.2 elad KERNEL_PROC_UNLOCK(l);
166 1.31.2.2 elad break;
167 1.31.2.2 elad
168 1.31.2.2 elad /*
169 1.31.2.2 elad * If we could not find and install appropriate TLB entry, fall through.
170 1.31.2.2 elad */
171 1.31.2.2 elad
172 1.31.2.2 elad case EXC_DSI:
173 1.31.2.2 elad /* FALLTHROUGH */
174 1.31.2.2 elad case EXC_DTMISS:
175 1.31.2.2 elad {
176 1.31.2.2 elad struct vm_map *map;
177 1.31.2.2 elad vaddr_t va;
178 1.31.2.2 elad struct faultbuf *fb = NULL;
179 1.31.2.2 elad
180 1.31.2.2 elad KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
181 1.31.2.2 elad va = frame->dar;
182 1.31.2.2 elad if (frame->tf_xtra[TF_PID] == KERNEL_PID) {
183 1.31.2.2 elad map = kernel_map;
184 1.31.2.2 elad } else {
185 1.31.2.2 elad map = &p->p_vmspace->vm_map;
186 1.31.2.2 elad if (l->l_flag & L_SA) {
187 1.31.2.2 elad l->l_savp->savp_faultaddr = va;
188 1.31.2.2 elad l->l_flag |= L_SA_PAGEFAULT;
189 1.31.2.2 elad }
190 1.31.2.2 elad }
191 1.31.2.2 elad
192 1.31.2.2 elad if (frame->tf_xtra[TF_ESR] & (ESR_DST|ESR_DIZ))
193 1.31.2.2 elad ftype = VM_PROT_WRITE;
194 1.31.2.2 elad
195 1.31.2.2 elad DBPRINTF(TDB_ALL,
196 1.31.2.2 elad ("trap(EXC_DSI) at %lx %s fault on %p esr %x\n",
197 1.31.2.2 elad frame->srr0,
198 1.31.2.2 elad (ftype & VM_PROT_WRITE) ? "write" : "read",
199 1.31.2.2 elad (void *)va, frame->tf_xtra[TF_ESR]));
200 1.31.2.3 elad rv = uvm_fault(map, trunc_page(va), ftype);
201 1.31.2.2 elad KERNEL_UNLOCK();
202 1.31.2.2 elad if (map != kernel_map)
203 1.31.2.2 elad l->l_flag &= ~L_SA_PAGEFAULT;
204 1.31.2.2 elad if (rv == 0)
205 1.31.2.2 elad goto done;
206 1.31.2.2 elad if ((fb = l->l_addr->u_pcb.pcb_onfault) != NULL) {
207 1.31.2.2 elad frame->tf_xtra[TF_PID] = KERNEL_PID;
208 1.31.2.2 elad frame->srr0 = fb->fb_pc;
209 1.31.2.2 elad frame->srr1 |= PSL_IR; /* Re-enable IMMU */
210 1.31.2.2 elad frame->fixreg[1] = fb->fb_sp;
211 1.31.2.2 elad frame->fixreg[2] = fb->fb_r2;
212 1.31.2.2 elad frame->fixreg[3] = 1; /* Return TRUE */
213 1.31.2.2 elad frame->cr = fb->fb_cr;
214 1.31.2.2 elad memcpy(&frame->fixreg[13], fb->fb_fixreg,
215 1.31.2.2 elad sizeof(fb->fb_fixreg));
216 1.31.2.2 elad goto done;
217 1.31.2.2 elad }
218 1.31.2.2 elad }
219 1.31.2.2 elad goto brain_damage;
220 1.31.2.2 elad
221 1.31.2.2 elad case EXC_DSI|EXC_USER:
222 1.31.2.2 elad /* FALLTHROUGH */
223 1.31.2.2 elad case EXC_DTMISS|EXC_USER:
224 1.31.2.2 elad KERNEL_PROC_LOCK(l);
225 1.31.2.2 elad
226 1.31.2.2 elad if (frame->tf_xtra[TF_ESR] & (ESR_DST|ESR_DIZ))
227 1.31.2.2 elad ftype = VM_PROT_WRITE;
228 1.31.2.2 elad
229 1.31.2.2 elad DBPRINTF(TDB_ALL,
230 1.31.2.2 elad ("trap(EXC_DSI|EXC_USER) at %lx %s fault on %lx %x\n",
231 1.31.2.2 elad frame->srr0, (ftype & VM_PROT_WRITE) ? "write" : "read",
232 1.31.2.2 elad frame->dar, frame->tf_xtra[TF_ESR]));
233 1.31.2.2 elad KASSERT(l == curlwp && (l->l_stat == LSONPROC));
234 1.31.2.2 elad if (l->l_flag & L_SA) {
235 1.31.2.2 elad l->l_savp->savp_faultaddr = (vaddr_t)frame->dar;
236 1.31.2.2 elad l->l_flag |= L_SA_PAGEFAULT;
237 1.31.2.2 elad }
238 1.31.2.2 elad rv = uvm_fault(&p->p_vmspace->vm_map, trunc_page(frame->dar),
239 1.31.2.3 elad ftype);
240 1.31.2.2 elad if (rv == 0) {
241 1.31.2.2 elad l->l_flag &= ~L_SA_PAGEFAULT;
242 1.31.2.2 elad KERNEL_PROC_UNLOCK(l);
243 1.31.2.2 elad break;
244 1.31.2.2 elad }
245 1.31.2.2 elad KSI_INIT_TRAP(&ksi);
246 1.31.2.2 elad ksi.ksi_signo = SIGSEGV;
247 1.31.2.2 elad ksi.ksi_trap = EXC_DSI;
248 1.31.2.2 elad ksi.ksi_addr = (void *)frame->dar;
249 1.31.2.2 elad if (rv == ENOMEM) {
250 1.31.2.2 elad printf("UVM: pid %d (%s) lid %d, uid %d killed: "
251 1.31.2.2 elad "out of swap\n",
252 1.31.2.2 elad p->p_pid, p->p_comm, l->l_lid,
253 1.31.2.2 elad p->p_cred ?
254 1.31.2.2 elad kauth_cred_geteuid(p->p_cred) : -1);
255 1.31.2.2 elad ksi.ksi_signo = SIGKILL;
256 1.31.2.2 elad }
257 1.31.2.2 elad trapsignal(l, &ksi);
258 1.31.2.2 elad l->l_flag &= ~L_SA_PAGEFAULT;
259 1.31.2.2 elad KERNEL_PROC_UNLOCK(l);
260 1.31.2.2 elad break;
261 1.31.2.2 elad
262 1.31.2.2 elad case EXC_ITMISS|EXC_USER:
263 1.31.2.2 elad case EXC_ISI|EXC_USER:
264 1.31.2.2 elad KERNEL_PROC_LOCK(l);
265 1.31.2.2 elad if (l->l_flag & L_SA) {
266 1.31.2.2 elad l->l_savp->savp_faultaddr = (vaddr_t)frame->srr0;
267 1.31.2.2 elad l->l_flag |= L_SA_PAGEFAULT;
268 1.31.2.2 elad }
269 1.31.2.2 elad ftype = VM_PROT_EXECUTE;
270 1.31.2.2 elad DBPRINTF(TDB_ALL,
271 1.31.2.2 elad ("trap(EXC_ISI|EXC_USER) at %lx execute fault tf %p\n",
272 1.31.2.2 elad frame->srr0, frame));
273 1.31.2.2 elad rv = uvm_fault(&p->p_vmspace->vm_map, trunc_page(frame->srr0),
274 1.31.2.3 elad ftype);
275 1.31.2.2 elad if (rv == 0) {
276 1.31.2.2 elad l->l_flag &= ~L_SA_PAGEFAULT;
277 1.31.2.2 elad KERNEL_PROC_UNLOCK(l);
278 1.31.2.2 elad break;
279 1.31.2.2 elad }
280 1.31.2.2 elad KSI_INIT_TRAP(&ksi);
281 1.31.2.2 elad ksi.ksi_signo = SIGSEGV;
282 1.31.2.2 elad ksi.ksi_trap = EXC_ISI;
283 1.31.2.2 elad ksi.ksi_addr = (void *)frame->srr0;
284 1.31.2.2 elad ksi.ksi_code = (rv == EACCES ? SEGV_ACCERR : SEGV_MAPERR);
285 1.31.2.2 elad trapsignal(l, &ksi);
286 1.31.2.2 elad l->l_flag &= ~L_SA_PAGEFAULT;
287 1.31.2.2 elad KERNEL_PROC_UNLOCK(l);
288 1.31.2.2 elad break;
289 1.31.2.2 elad
290 1.31.2.2 elad case EXC_AST|EXC_USER:
291 1.31.2.2 elad curcpu()->ci_astpending = 0; /* we are about to do it */
292 1.31.2.2 elad KERNEL_PROC_LOCK(l);
293 1.31.2.2 elad uvmexp.softs++;
294 1.31.2.2 elad if (p->p_flag & P_OWEUPC) {
295 1.31.2.2 elad p->p_flag &= ~P_OWEUPC;
296 1.31.2.2 elad ADDUPROF(p);
297 1.31.2.2 elad }
298 1.31.2.2 elad /* Check whether we are being preempted. */
299 1.31.2.2 elad if (curcpu()->ci_want_resched)
300 1.31.2.2 elad preempt(0);
301 1.31.2.2 elad KERNEL_PROC_UNLOCK(l);
302 1.31.2.2 elad break;
303 1.31.2.2 elad
304 1.31.2.2 elad
305 1.31.2.2 elad case EXC_ALI|EXC_USER:
306 1.31.2.2 elad KERNEL_PROC_LOCK(l);
307 1.31.2.2 elad if (fix_unaligned(l, frame) != 0) {
308 1.31.2.2 elad KSI_INIT_TRAP(&ksi);
309 1.31.2.2 elad ksi.ksi_signo = SIGBUS;
310 1.31.2.2 elad ksi.ksi_trap = EXC_ALI;
311 1.31.2.2 elad ksi.ksi_addr = (void *)frame->dar;
312 1.31.2.2 elad trapsignal(l, &ksi);
313 1.31.2.2 elad } else
314 1.31.2.2 elad frame->srr0 += 4;
315 1.31.2.2 elad KERNEL_PROC_UNLOCK(l);
316 1.31.2.2 elad break;
317 1.31.2.2 elad
318 1.31.2.2 elad case EXC_PGM|EXC_USER:
319 1.31.2.2 elad /*
320 1.31.2.2 elad * Illegal insn:
321 1.31.2.2 elad *
322 1.31.2.2 elad * let's try to see if it's FPU and can be emulated.
323 1.31.2.2 elad */
324 1.31.2.2 elad uvmexp.traps++;
325 1.31.2.2 elad if (!(l->l_addr->u_pcb.pcb_flags & PCB_FPU)) {
326 1.31.2.2 elad memset(&l->l_addr->u_pcb.pcb_fpu, 0,
327 1.31.2.2 elad sizeof l->l_addr->u_pcb.pcb_fpu);
328 1.31.2.2 elad l->l_addr->u_pcb.pcb_flags |= PCB_FPU;
329 1.31.2.2 elad }
330 1.31.2.2 elad
331 1.31.2.2 elad if ((rv = fpu_emulate(frame,
332 1.31.2.2 elad (struct fpreg *)&l->l_addr->u_pcb.pcb_fpu))) {
333 1.31.2.2 elad KSI_INIT_TRAP(&ksi);
334 1.31.2.2 elad ksi.ksi_signo = rv;
335 1.31.2.2 elad ksi.ksi_trap = EXC_PGM;
336 1.31.2.2 elad ksi.ksi_addr = (void *)frame->srr0;
337 1.31.2.2 elad KERNEL_PROC_LOCK(l);
338 1.31.2.2 elad trapsignal(l, &ksi);
339 1.31.2.2 elad KERNEL_PROC_UNLOCK(l);
340 1.31.2.2 elad }
341 1.31.2.2 elad break;
342 1.31.2.2 elad
343 1.31.2.2 elad case EXC_MCHK:
344 1.31.2.2 elad {
345 1.31.2.2 elad struct faultbuf *fb;
346 1.31.2.2 elad
347 1.31.2.2 elad if ((fb = l->l_addr->u_pcb.pcb_onfault) != NULL) {
348 1.31.2.2 elad frame->tf_xtra[TF_PID] = KERNEL_PID;
349 1.31.2.2 elad frame->srr0 = fb->fb_pc;
350 1.31.2.2 elad frame->srr1 |= PSL_IR; /* Re-enable IMMU */
351 1.31.2.2 elad frame->fixreg[1] = fb->fb_sp;
352 1.31.2.2 elad frame->fixreg[2] = fb->fb_r2;
353 1.31.2.2 elad frame->fixreg[3] = 1; /* Return TRUE */
354 1.31.2.2 elad frame->cr = fb->fb_cr;
355 1.31.2.2 elad memcpy(&frame->fixreg[13], fb->fb_fixreg,
356 1.31.2.2 elad sizeof(fb->fb_fixreg));
357 1.31.2.2 elad goto done;
358 1.31.2.2 elad }
359 1.31.2.2 elad }
360 1.31.2.2 elad goto brain_damage;
361 1.31.2.2 elad default:
362 1.31.2.2 elad brain_damage:
363 1.31.2.2 elad printf("trap type 0x%x at 0x%lx\n", type, frame->srr0);
364 1.31.2.2 elad #ifdef DDB
365 1.31.2.2 elad if (kdb_trap(type, frame))
366 1.31.2.2 elad goto done;
367 1.31.2.2 elad #endif
368 1.31.2.2 elad #ifdef TRAP_PANICWAIT
369 1.31.2.2 elad printf("Press a key to panic.\n");
370 1.31.2.2 elad cngetc();
371 1.31.2.2 elad #endif
372 1.31.2.2 elad panic("trap");
373 1.31.2.2 elad }
374 1.31.2.2 elad
375 1.31.2.2 elad /* Invoke MI userret code */
376 1.31.2.2 elad mi_userret(l);
377 1.31.2.2 elad
378 1.31.2.2 elad curcpu()->ci_schedstate.spc_curpriority = l->l_priority = l->l_usrpri;
379 1.31.2.2 elad done:
380 1.31.2.2 elad return;
381 1.31.2.2 elad }
382 1.31.2.2 elad
383 1.31.2.2 elad int
384 1.31.2.2 elad ctx_setup(int ctx, int srr1)
385 1.31.2.2 elad {
386 1.31.2.2 elad volatile struct pmap *pm;
387 1.31.2.2 elad
388 1.31.2.2 elad /* Update PID if we're returning to user mode. */
389 1.31.2.2 elad if (srr1 & PSL_PR) {
390 1.31.2.2 elad pm = curproc->p_vmspace->vm_map.pmap;
391 1.31.2.2 elad if (!pm->pm_ctx) {
392 1.31.2.2 elad ctx_alloc(__UNVOLATILE(pm));
393 1.31.2.2 elad }
394 1.31.2.2 elad ctx = pm->pm_ctx;
395 1.31.2.2 elad if (srr1 & PSL_SE) {
396 1.31.2.2 elad int dbreg, mask = 0x48000000;
397 1.31.2.2 elad /*
398 1.31.2.2 elad * Set the Internal Debug and
399 1.31.2.2 elad * Instruction Completion bits of
400 1.31.2.2 elad * the DBCR0 register.
401 1.31.2.2 elad *
402 1.31.2.2 elad * XXX this is also used by jtag debuggers...
403 1.31.2.2 elad */
404 1.31.2.2 elad __asm volatile("mfspr %0,0x3f2;"
405 1.31.2.2 elad "or %0,%0,%1;"
406 1.31.2.2 elad "mtspr 0x3f2,%0;" :
407 1.31.2.2 elad "=&r" (dbreg) : "r" (mask));
408 1.31.2.2 elad }
409 1.31.2.2 elad }
410 1.31.2.2 elad else if (!ctx) {
411 1.31.2.2 elad ctx = KERNEL_PID;
412 1.31.2.2 elad }
413 1.31.2.2 elad return (ctx);
414 1.31.2.2 elad }
415 1.31.2.2 elad
416 1.31.2.2 elad /*
417 1.31.2.2 elad * Used by copyin()/copyout()
418 1.31.2.2 elad */
419 1.31.2.2 elad extern vaddr_t vmaprange __P((struct proc *, vaddr_t, vsize_t, int));
420 1.31.2.2 elad extern void vunmaprange __P((vaddr_t, vsize_t));
421 1.31.2.2 elad static int bigcopyin __P((const void *, void *, size_t ));
422 1.31.2.2 elad static int bigcopyout __P((const void *, void *, size_t ));
423 1.31.2.2 elad
424 1.31.2.2 elad int
425 1.31.2.2 elad copyin(const void *udaddr, void *kaddr, size_t len)
426 1.31.2.2 elad {
427 1.31.2.2 elad struct pmap *pm = curproc->p_vmspace->vm_map.pmap;
428 1.31.2.2 elad int msr, pid, tmp, ctx;
429 1.31.2.2 elad struct faultbuf env;
430 1.31.2.2 elad
431 1.31.2.2 elad /* For bigger buffers use the faster copy */
432 1.31.2.2 elad if (len > 256)
433 1.31.2.2 elad return (bigcopyin(udaddr, kaddr, len));
434 1.31.2.2 elad
435 1.31.2.2 elad if (setfault(&env)) {
436 1.31.2.2 elad curpcb->pcb_onfault = 0;
437 1.31.2.2 elad return EFAULT;
438 1.31.2.2 elad }
439 1.31.2.2 elad
440 1.31.2.2 elad if (!(ctx = pm->pm_ctx)) {
441 1.31.2.2 elad /* No context -- assign it one */
442 1.31.2.2 elad ctx_alloc(pm);
443 1.31.2.2 elad ctx = pm->pm_ctx;
444 1.31.2.2 elad }
445 1.31.2.2 elad
446 1.31.2.2 elad __asm volatile("addi %6,%6,1; mtctr %6;" /* Set up counter */
447 1.31.2.2 elad "mfmsr %0;" /* Save MSR */
448 1.31.2.2 elad "li %1,0x20; "
449 1.31.2.2 elad "andc %1,%0,%1; mtmsr %1;" /* Disable IMMU */
450 1.31.2.2 elad "mfpid %1;" /* Save old PID */
451 1.31.2.2 elad "sync; isync;"
452 1.31.2.2 elad
453 1.31.2.2 elad "1: bdz 2f;" /* while len */
454 1.31.2.2 elad "mtpid %3; sync;" /* Load user ctx */
455 1.31.2.2 elad "lbz %2,0(%4); addi %4,%4,1;" /* Load byte */
456 1.31.2.2 elad "sync; isync;"
457 1.31.2.2 elad "mtpid %1;sync;"
458 1.31.2.2 elad "stb %2,0(%5); dcbf 0,%5; addi %5,%5,1;" /* Store kernel byte */
459 1.31.2.2 elad "sync; isync;"
460 1.31.2.2 elad "b 1b;" /* repeat */
461 1.31.2.2 elad
462 1.31.2.2 elad "2: mtpid %1; mtmsr %0;" /* Restore PID and MSR */
463 1.31.2.2 elad "sync; isync;"
464 1.31.2.2 elad : "=&r" (msr), "=&r" (pid), "=&r" (tmp)
465 1.31.2.2 elad : "r" (ctx), "b" (udaddr), "b" (kaddr), "b" (len));
466 1.31.2.2 elad
467 1.31.2.2 elad curpcb->pcb_onfault = 0;
468 1.31.2.2 elad return 0;
469 1.31.2.2 elad }
470 1.31.2.2 elad
471 1.31.2.2 elad static int
472 1.31.2.2 elad bigcopyin(const void *udaddr, void *kaddr, size_t len)
473 1.31.2.2 elad {
474 1.31.2.2 elad const char *up;
475 1.31.2.2 elad char *kp = kaddr;
476 1.31.2.2 elad struct lwp *l = curlwp;
477 1.31.2.2 elad struct proc *p;
478 1.31.2.2 elad int error;
479 1.31.2.2 elad
480 1.31.2.2 elad if (!l) {
481 1.31.2.2 elad return EFAULT;
482 1.31.2.2 elad }
483 1.31.2.2 elad
484 1.31.2.2 elad p = l->l_proc;
485 1.31.2.2 elad
486 1.31.2.2 elad /*
487 1.31.2.2 elad * Stolen from physio():
488 1.31.2.2 elad */
489 1.31.2.2 elad PHOLD(l);
490 1.31.2.2 elad error = uvm_vslock(p, __UNCONST(udaddr), len, VM_PROT_READ);
491 1.31.2.2 elad if (error) {
492 1.31.2.2 elad PRELE(l);
493 1.31.2.2 elad return EFAULT;
494 1.31.2.2 elad }
495 1.31.2.2 elad up = (char *)vmaprange(p, (vaddr_t)udaddr, len, VM_PROT_READ);
496 1.31.2.2 elad
497 1.31.2.2 elad memcpy(kp, up, len);
498 1.31.2.2 elad vunmaprange((vaddr_t)up, len);
499 1.31.2.2 elad uvm_vsunlock(p, __UNCONST(udaddr), len);
500 1.31.2.2 elad PRELE(l);
501 1.31.2.2 elad
502 1.31.2.2 elad return 0;
503 1.31.2.2 elad }
504 1.31.2.2 elad
505 1.31.2.2 elad int
506 1.31.2.2 elad copyout(const void *kaddr, void *udaddr, size_t len)
507 1.31.2.2 elad {
508 1.31.2.2 elad struct pmap *pm = curproc->p_vmspace->vm_map.pmap;
509 1.31.2.2 elad int msr, pid, tmp, ctx;
510 1.31.2.2 elad struct faultbuf env;
511 1.31.2.2 elad
512 1.31.2.2 elad /* For big copies use more efficient routine */
513 1.31.2.2 elad if (len > 256)
514 1.31.2.2 elad return (bigcopyout(kaddr, udaddr, len));
515 1.31.2.2 elad
516 1.31.2.2 elad if (setfault(&env)) {
517 1.31.2.2 elad curpcb->pcb_onfault = 0;
518 1.31.2.2 elad return EFAULT;
519 1.31.2.2 elad }
520 1.31.2.2 elad
521 1.31.2.2 elad if (!(ctx = pm->pm_ctx)) {
522 1.31.2.2 elad /* No context -- assign it one */
523 1.31.2.2 elad ctx_alloc(pm);
524 1.31.2.2 elad ctx = pm->pm_ctx;
525 1.31.2.2 elad }
526 1.31.2.2 elad
527 1.31.2.2 elad __asm volatile("addi %6,%6,1; mtctr %6;" /* Set up counter */
528 1.31.2.2 elad "mfmsr %0;" /* Save MSR */
529 1.31.2.2 elad "li %1,0x20; "
530 1.31.2.2 elad "andc %1,%0,%1; mtmsr %1;" /* Disable IMMU */
531 1.31.2.2 elad "mfpid %1;" /* Save old PID */
532 1.31.2.2 elad "sync; isync;"
533 1.31.2.2 elad
534 1.31.2.2 elad "1: bdz 2f;" /* while len */
535 1.31.2.2 elad "mtpid %1;sync;"
536 1.31.2.2 elad "lbz %2,0(%5); addi %5,%5,1;" /* Load kernel byte */
537 1.31.2.2 elad "sync; isync;"
538 1.31.2.2 elad "mtpid %3; sync;" /* Load user ctx */
539 1.31.2.2 elad "stb %2,0(%4); dcbf 0,%4; addi %4,%4,1;" /* Store user byte */
540 1.31.2.2 elad "sync; isync;"
541 1.31.2.2 elad "b 1b;" /* repeat */
542 1.31.2.2 elad
543 1.31.2.2 elad "2: mtpid %1; mtmsr %0;" /* Restore PID and MSR */
544 1.31.2.2 elad "sync; isync;"
545 1.31.2.2 elad : "=&r" (msr), "=&r" (pid), "=&r" (tmp)
546 1.31.2.2 elad : "r" (ctx), "b" (udaddr), "b" (kaddr), "b" (len));
547 1.31.2.2 elad
548 1.31.2.2 elad curpcb->pcb_onfault = 0;
549 1.31.2.2 elad return 0;
550 1.31.2.2 elad }
551 1.31.2.2 elad
552 1.31.2.2 elad static int
553 1.31.2.2 elad bigcopyout(const void *kaddr, void *udaddr, size_t len)
554 1.31.2.2 elad {
555 1.31.2.2 elad char *up;
556 1.31.2.2 elad const char *kp = (const char *)kaddr;
557 1.31.2.2 elad struct lwp *l = curlwp;
558 1.31.2.2 elad struct proc *p;
559 1.31.2.2 elad int error;
560 1.31.2.2 elad
561 1.31.2.2 elad if (!l) {
562 1.31.2.2 elad return EFAULT;
563 1.31.2.2 elad }
564 1.31.2.2 elad
565 1.31.2.2 elad p = l->l_proc;
566 1.31.2.2 elad
567 1.31.2.2 elad /*
568 1.31.2.2 elad * Stolen from physio():
569 1.31.2.2 elad */
570 1.31.2.2 elad PHOLD(l);
571 1.31.2.2 elad error = uvm_vslock(p, udaddr, len, VM_PROT_WRITE);
572 1.31.2.2 elad if (error) {
573 1.31.2.2 elad PRELE(l);
574 1.31.2.2 elad return EFAULT;
575 1.31.2.2 elad }
576 1.31.2.2 elad up = (char *)vmaprange(p, (vaddr_t)udaddr, len,
577 1.31.2.2 elad VM_PROT_READ | VM_PROT_WRITE);
578 1.31.2.2 elad
579 1.31.2.2 elad memcpy(up, kp, len);
580 1.31.2.2 elad vunmaprange((vaddr_t)up, len);
581 1.31.2.2 elad uvm_vsunlock(p, udaddr, len);
582 1.31.2.2 elad PRELE(l);
583 1.31.2.2 elad
584 1.31.2.2 elad return 0;
585 1.31.2.2 elad }
586 1.31.2.2 elad
587 1.31.2.2 elad /*
588 1.31.2.2 elad * kcopy(const void *src, void *dst, size_t len);
589 1.31.2.2 elad *
590 1.31.2.2 elad * Copy len bytes from src to dst, aborting if we encounter a fatal
591 1.31.2.2 elad * page fault.
592 1.31.2.2 elad *
593 1.31.2.2 elad * kcopy() _must_ save and restore the old fault handler since it is
594 1.31.2.2 elad * called by uiomove(), which may be in the path of servicing a non-fatal
595 1.31.2.2 elad * page fault.
596 1.31.2.2 elad */
597 1.31.2.2 elad int
598 1.31.2.2 elad kcopy(const void *src, void *dst, size_t len)
599 1.31.2.2 elad {
600 1.31.2.2 elad struct faultbuf env, *oldfault;
601 1.31.2.2 elad
602 1.31.2.2 elad oldfault = curpcb->pcb_onfault;
603 1.31.2.2 elad if (setfault(&env)) {
604 1.31.2.2 elad curpcb->pcb_onfault = oldfault;
605 1.31.2.2 elad return EFAULT;
606 1.31.2.2 elad }
607 1.31.2.2 elad
608 1.31.2.2 elad memcpy(dst, src, len);
609 1.31.2.2 elad
610 1.31.2.2 elad curpcb->pcb_onfault = oldfault;
611 1.31.2.2 elad return 0;
612 1.31.2.2 elad }
613 1.31.2.2 elad
614 1.31.2.2 elad int
615 1.31.2.2 elad badaddr(void *addr, size_t size)
616 1.31.2.2 elad {
617 1.31.2.2 elad
618 1.31.2.2 elad return badaddr_read(addr, size, NULL);
619 1.31.2.2 elad }
620 1.31.2.2 elad
621 1.31.2.2 elad int
622 1.31.2.2 elad badaddr_read(void *addr, size_t size, int *rptr)
623 1.31.2.2 elad {
624 1.31.2.2 elad struct faultbuf env;
625 1.31.2.2 elad int x;
626 1.31.2.2 elad
627 1.31.2.2 elad /* Get rid of any stale machine checks that have been waiting. */
628 1.31.2.2 elad __asm volatile ("sync; isync");
629 1.31.2.2 elad
630 1.31.2.2 elad if (setfault(&env)) {
631 1.31.2.2 elad curpcb->pcb_onfault = 0;
632 1.31.2.2 elad __asm volatile ("sync");
633 1.31.2.2 elad return 1;
634 1.31.2.2 elad }
635 1.31.2.2 elad
636 1.31.2.2 elad __asm volatile ("sync");
637 1.31.2.2 elad
638 1.31.2.2 elad switch (size) {
639 1.31.2.2 elad case 1:
640 1.31.2.2 elad x = *(volatile int8_t *)addr;
641 1.31.2.2 elad break;
642 1.31.2.2 elad case 2:
643 1.31.2.2 elad x = *(volatile int16_t *)addr;
644 1.31.2.2 elad break;
645 1.31.2.2 elad case 4:
646 1.31.2.2 elad x = *(volatile int32_t *)addr;
647 1.31.2.2 elad break;
648 1.31.2.2 elad default:
649 1.31.2.2 elad panic("badaddr: invalid size (%d)", size);
650 1.31.2.2 elad }
651 1.31.2.2 elad
652 1.31.2.2 elad /* Make sure we took the machine check, if we caused one. */
653 1.31.2.2 elad __asm volatile ("sync; isync");
654 1.31.2.2 elad
655 1.31.2.2 elad curpcb->pcb_onfault = 0;
656 1.31.2.2 elad __asm volatile ("sync"); /* To be sure. */
657 1.31.2.2 elad
658 1.31.2.2 elad /* Use the value to avoid reorder. */
659 1.31.2.2 elad if (rptr)
660 1.31.2.2 elad *rptr = x;
661 1.31.2.2 elad
662 1.31.2.2 elad return 0;
663 1.31.2.2 elad }
664 1.31.2.2 elad
665 1.31.2.2 elad /*
666 1.31.2.2 elad * For now, this only deals with the particular unaligned access case
667 1.31.2.2 elad * that gcc tends to generate. Eventually it should handle all of the
668 1.31.2.2 elad * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
669 1.31.2.2 elad */
670 1.31.2.2 elad
671 1.31.2.2 elad static int
672 1.31.2.2 elad fix_unaligned(struct lwp *l, struct trapframe *frame)
673 1.31.2.2 elad {
674 1.31.2.2 elad
675 1.31.2.2 elad return -1;
676 1.31.2.2 elad }
677 1.31.2.2 elad
678 1.31.2.2 elad /*
679 1.31.2.2 elad * Start a new LWP
680 1.31.2.2 elad */
681 1.31.2.2 elad void
682 1.31.2.2 elad startlwp(arg)
683 1.31.2.2 elad void *arg;
684 1.31.2.2 elad {
685 1.31.2.2 elad int err;
686 1.31.2.2 elad ucontext_t *uc = arg;
687 1.31.2.2 elad struct lwp *l = curlwp;
688 1.31.2.2 elad
689 1.31.2.2 elad err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
690 1.31.2.2 elad #if DIAGNOSTIC
691 1.31.2.2 elad if (err) {
692 1.31.2.2 elad printf("Error %d from cpu_setmcontext.", err);
693 1.31.2.2 elad }
694 1.31.2.2 elad #endif
695 1.31.2.2 elad pool_put(&lwp_uc_pool, uc);
696 1.31.2.2 elad
697 1.31.2.2 elad upcallret(l);
698 1.31.2.2 elad }
699 1.31.2.2 elad
700 1.31.2.2 elad /*
701 1.31.2.2 elad * XXX This is a terrible name.
702 1.31.2.2 elad */
703 1.31.2.2 elad void
704 1.31.2.2 elad upcallret(l)
705 1.31.2.2 elad struct lwp *l;
706 1.31.2.2 elad {
707 1.31.2.2 elad
708 1.31.2.2 elad /* Invoke MI userret code */
709 1.31.2.2 elad mi_userret(l);
710 1.31.2.2 elad
711 1.31.2.2 elad curcpu()->ci_schedstate.spc_curpriority = l->l_priority = l->l_usrpri;
712 1.31.2.2 elad }
713