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