1 /*-
2  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
3  * Copyright (C) 1995, 1996 TooLs GmbH.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by TooLs GmbH.
17  * 4. The name of TooLs GmbH may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $NetBSD: trap.c,v 1.58 2002/03/04 04:07:35 dbj Exp $
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD: stable/10/sys/powerpc/aim/trap.c 333205 2018-05-03 07:57:08Z avg $");
36 
37 #include "opt_kdtrace.h"
38 
39 #include <sys/param.h>
40 #include <sys/kdb.h>
41 #include <sys/proc.h>
42 #include <sys/ktr.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/pioctl.h>
46 #include <sys/ptrace.h>
47 #include <sys/reboot.h>
48 #include <sys/syscall.h>
49 #include <sys/sysent.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/uio.h>
53 #include <sys/signalvar.h>
54 #include <sys/vmmeter.h>
55 
56 #include <security/audit/audit.h>
57 
58 #include <vm/vm.h>
59 #include <vm/pmap.h>
60 #include <vm/vm_extern.h>
61 #include <vm/vm_param.h>
62 #include <vm/vm_kern.h>
63 #include <vm/vm_map.h>
64 #include <vm/vm_page.h>
65 
66 #include <machine/_inttypes.h>
67 #include <machine/altivec.h>
68 #include <machine/cpu.h>
69 #include <machine/db_machdep.h>
70 #include <machine/fpu.h>
71 #include <machine/frame.h>
72 #include <machine/pcb.h>
73 #include <machine/pmap.h>
74 #include <machine/psl.h>
75 #include <machine/trap.h>
76 #include <machine/spr.h>
77 #include <machine/sr.h>
78 
79 static void	trap_fatal(struct trapframe *frame);
80 static void	printtrap(u_int vector, struct trapframe *frame, int isfatal,
81 		    int user);
82 static int	trap_pfault(struct trapframe *frame, int user);
83 static int	fix_unaligned(struct thread *td, struct trapframe *frame);
84 static int	handle_onfault(struct trapframe *frame);
85 static void	syscall(struct trapframe *frame);
86 
87 #ifdef __powerpc64__
88        void	handle_kernel_slb_spill(int, register_t, register_t);
89 static int	handle_user_slb_spill(pmap_t pm, vm_offset_t addr);
90 extern int	n_slbs;
91 #endif
92 
93 struct powerpc_exception {
94 	u_int	vector;
95 	char	*name;
96 };
97 
98 #ifdef KDTRACE_HOOKS
99 #include <sys/dtrace_bsd.h>
100 
101 int (*dtrace_invop_jump_addr)(struct trapframe *);
102 #endif
103 
104 static struct powerpc_exception powerpc_exceptions[] = {
105 	{ 0x0100, "system reset" },
106 	{ 0x0200, "machine check" },
107 	{ 0x0300, "data storage interrupt" },
108 	{ 0x0380, "data segment exception" },
109 	{ 0x0400, "instruction storage interrupt" },
110 	{ 0x0480, "instruction segment exception" },
111 	{ 0x0500, "external interrupt" },
112 	{ 0x0600, "alignment" },
113 	{ 0x0700, "program" },
114 	{ 0x0800, "floating-point unavailable" },
115 	{ 0x0900, "decrementer" },
116 	{ 0x0c00, "system call" },
117 	{ 0x0d00, "trace" },
118 	{ 0x0e00, "floating-point assist" },
119 	{ 0x0f00, "performance monitoring" },
120 	{ 0x0f20, "altivec unavailable" },
121 	{ 0x1000, "instruction tlb miss" },
122 	{ 0x1100, "data load tlb miss" },
123 	{ 0x1200, "data store tlb miss" },
124 	{ 0x1300, "instruction breakpoint" },
125 	{ 0x1400, "system management" },
126 	{ 0x1600, "altivec assist" },
127 	{ 0x1700, "thermal management" },
128 	{ 0x2000, "run mode/trace" },
129 	{ 0x3000, NULL }
130 };
131 
132 static const char *
trapname(u_int vector)133 trapname(u_int vector)
134 {
135 	struct	powerpc_exception *pe;
136 
137 	for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) {
138 		if (pe->vector == vector)
139 			return (pe->name);
140 	}
141 
142 	return ("unknown");
143 }
144 
145 void
trap(struct trapframe * frame)146 trap(struct trapframe *frame)
147 {
148 	struct thread	*td;
149 	struct proc	*p;
150 #ifdef KDTRACE_HOOKS
151 	uint32_t inst;
152 #endif
153 	int		sig, type, user;
154 	u_int		ucode;
155 	ksiginfo_t	ksi;
156 
157 	PCPU_INC(cnt.v_trap);
158 
159 	td = curthread;
160 	p = td->td_proc;
161 
162 	type = ucode = frame->exc;
163 	sig = 0;
164 	user = frame->srr1 & PSL_PR;
165 
166 	CTR3(KTR_TRAP, "trap: %s type=%s (%s)", td->td_name,
167 	    trapname(type), user ? "user" : "kernel");
168 
169 #ifdef KDTRACE_HOOKS
170 	/*
171 	 * A trap can occur while DTrace executes a probe. Before
172 	 * executing the probe, DTrace blocks re-scheduling and sets
173 	 * a flag in it's per-cpu flags to indicate that it doesn't
174 	 * want to fault. On returning from the probe, the no-fault
175 	 * flag is cleared and finally re-scheduling is enabled.
176 	 *
177 	 * If the DTrace kernel module has registered a trap handler,
178 	 * call it and if it returns non-zero, assume that it has
179 	 * handled the trap and modified the trap frame so that this
180 	 * function can return normally.
181 	 */
182 	/*
183 	 * XXXDTRACE: add pid probe handler here (if ever)
184 	 */
185 	if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, type))
186 		return;
187 #endif
188 
189 	if (user) {
190 		td->td_pticks = 0;
191 		td->td_frame = frame;
192 		if (td->td_ucred != p->p_ucred)
193 			cred_update_thread(td);
194 
195 		/* User Mode Traps */
196 		switch (type) {
197 		case EXC_RUNMODETRC:
198 		case EXC_TRC:
199 			frame->srr1 &= ~PSL_SE;
200 			sig = SIGTRAP;
201 			ucode = TRAP_TRACE;
202 			break;
203 
204 #ifdef __powerpc64__
205 		case EXC_ISE:
206 		case EXC_DSE:
207 			if (handle_user_slb_spill(&p->p_vmspace->vm_pmap,
208 			    (type == EXC_ISE) ? frame->srr0 :
209 			    frame->cpu.aim.dar) != 0) {
210 				sig = SIGSEGV;
211 				ucode = SEGV_MAPERR;
212 			}
213 			break;
214 #endif
215 		case EXC_DSI:
216 		case EXC_ISI:
217 			sig = trap_pfault(frame, 1);
218 			if (sig == SIGSEGV)
219 				ucode = SEGV_MAPERR;
220 			break;
221 
222 		case EXC_SC:
223 			syscall(frame);
224 			break;
225 
226 		case EXC_FPU:
227 			KASSERT((td->td_pcb->pcb_flags & PCB_FPU) != PCB_FPU,
228 			    ("FPU already enabled for thread"));
229 			enable_fpu(td);
230 			break;
231 
232 		case EXC_VEC:
233 			KASSERT((td->td_pcb->pcb_flags & PCB_VEC) != PCB_VEC,
234 			    ("Altivec already enabled for thread"));
235 			enable_vec(td);
236 			break;
237 
238 		case EXC_VECAST_G4:
239 		case EXC_VECAST_G5:
240 			/*
241 			 * We get a VPU assist exception for IEEE mode
242 			 * vector operations on denormalized floats.
243 			 * Emulating this is a giant pain, so for now,
244 			 * just switch off IEEE mode and treat them as
245 			 * zero.
246 			 */
247 
248 			save_vec(td);
249 			td->td_pcb->pcb_vec.vscr |= ALTIVEC_VSCR_NJ;
250 			enable_vec(td);
251 			break;
252 
253 		case EXC_ALI:
254 			if (fix_unaligned(td, frame) != 0) {
255 				sig = SIGBUS;
256 				ucode = BUS_ADRALN;
257 			}
258 			else
259 				frame->srr0 += 4;
260 			break;
261 
262 		case EXC_PGM:
263 			/* Identify the trap reason */
264 			if (frame->srr1 & EXC_PGM_TRAP) {
265 #ifdef KDTRACE_HOOKS
266 				inst = fuword32((const void *)frame->srr0);
267 				if (inst == 0x0FFFDDDD && dtrace_pid_probe_ptr != NULL) {
268 					struct reg regs;
269 					fill_regs(td, &regs);
270 					(*dtrace_pid_probe_ptr)(&regs);
271 					break;
272 				}
273 #endif
274  				sig = SIGTRAP;
275 				ucode = TRAP_BRKPT;
276 			} else {
277 				sig = ppc_instr_emulate(frame, td->td_pcb);
278 				if (sig == SIGILL) {
279 					if (frame->srr1 & EXC_PGM_PRIV)
280 						ucode = ILL_PRVOPC;
281 					else if (frame->srr1 & EXC_PGM_ILLEGAL)
282 						ucode = ILL_ILLOPC;
283 				} else if (sig == SIGFPE)
284 					ucode = FPE_FLTINV;	/* Punt for now, invalid operation. */
285 			}
286 			break;
287 
288 		case EXC_MCHK:
289 			/*
290 			 * Note that this may not be recoverable for the user
291 			 * process, depending on the type of machine check,
292 			 * but it at least prevents the kernel from dying.
293 			 */
294 			sig = SIGBUS;
295 			ucode = BUS_OBJERR;
296 			break;
297 
298 		default:
299 			trap_fatal(frame);
300 		}
301 	} else {
302 		/* Kernel Mode Traps */
303 
304 		KASSERT(cold || td->td_ucred != NULL,
305 		    ("kernel trap doesn't have ucred"));
306 		switch (type) {
307 #ifdef KDTRACE_HOOKS
308 		case EXC_PGM:
309 			if (frame->srr1 & EXC_PGM_TRAP) {
310 				if (*(uint32_t *)frame->srr0 == 0x7c810808) {
311 					if (dtrace_invop_jump_addr != NULL) {
312 						dtrace_invop_jump_addr(frame);
313 						return;
314 					}
315 				}
316 			}
317 			break;
318 #endif
319 #ifdef __powerpc64__
320 		case EXC_DSE:
321 			if ((frame->cpu.aim.dar & SEGMENT_MASK) == USER_ADDR) {
322 				__asm __volatile ("slbmte %0, %1" ::
323 					"r"(td->td_pcb->pcb_cpu.aim.usr_vsid),
324 					"r"(USER_SLB_SLBE));
325 				return;
326 			}
327 			break;
328 #endif
329 		case EXC_DSI:
330 			if (trap_pfault(frame, 0) == 0)
331  				return;
332 			break;
333 		case EXC_MCHK:
334 			if (handle_onfault(frame))
335  				return;
336 			break;
337 		default:
338 			break;
339 		}
340 		trap_fatal(frame);
341 	}
342 
343 	if (sig != 0) {
344 		if (p->p_sysent->sv_transtrap != NULL)
345 			sig = (p->p_sysent->sv_transtrap)(sig, type);
346 		ksiginfo_init_trap(&ksi);
347 		ksi.ksi_signo = sig;
348 		ksi.ksi_code = (int) ucode; /* XXX, not POSIX */
349 		/* ksi.ksi_addr = ? */
350 		ksi.ksi_trapno = type;
351 		trapsignal(td, &ksi);
352 	}
353 
354 	userret(td, frame);
355 }
356 
357 static void
trap_fatal(struct trapframe * frame)358 trap_fatal(struct trapframe *frame)
359 {
360 #ifdef KDB
361 	bool handled;
362 #endif
363 
364 	printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR));
365 #ifdef KDB
366 	if (debugger_on_panic) {
367 		kdb_why = KDB_WHY_TRAP;
368 		handled = kdb_trap(frame->exc, 0, frame);
369 		kdb_why = KDB_WHY_UNSET;
370 		if (handled)
371 			return;
372 	}
373 #endif
374 	panic("%s trap", trapname(frame->exc));
375 }
376 
377 static void
printtrap(u_int vector,struct trapframe * frame,int isfatal,int user)378 printtrap(u_int vector, struct trapframe *frame, int isfatal, int user)
379 {
380 
381 	printf("\n");
382 	printf("%s %s trap:\n", isfatal ? "fatal" : "handled",
383 	    user ? "user" : "kernel");
384 	printf("\n");
385 	printf("   exception       = 0x%x (%s)\n", vector, trapname(vector));
386 	switch (vector) {
387 	case EXC_DSE:
388 	case EXC_DSI:
389 		printf("   virtual address = 0x%" PRIxPTR "\n",
390 		    frame->cpu.aim.dar);
391 		printf("   dsisr           = 0x%" PRIxPTR "\n",
392 		    frame->cpu.aim.dsisr);
393 		break;
394 	case EXC_ISE:
395 	case EXC_ISI:
396 		printf("   virtual address = 0x%" PRIxPTR "\n", frame->srr0);
397 		break;
398 	}
399 	printf("   srr0            = 0x%" PRIxPTR "\n", frame->srr0);
400 	printf("   srr1            = 0x%" PRIxPTR "\n", frame->srr1);
401 	printf("   lr              = 0x%" PRIxPTR "\n", frame->lr);
402 	printf("   curthread       = %p\n", curthread);
403 	if (curthread != NULL)
404 		printf("          pid = %d, comm = %s\n",
405 		    curthread->td_proc->p_pid, curthread->td_name);
406 	printf("\n");
407 }
408 
409 /*
410  * Handles a fatal fault when we have onfault state to recover.  Returns
411  * non-zero if there was onfault recovery state available.
412  */
413 static int
handle_onfault(struct trapframe * frame)414 handle_onfault(struct trapframe *frame)
415 {
416 	struct		thread *td;
417 	faultbuf	*fb;
418 
419 	td = curthread;
420 	fb = td->td_pcb->pcb_onfault;
421 	if (fb != NULL) {
422 		frame->srr0 = (*fb)[0];
423 		frame->fixreg[1] = (*fb)[1];
424 		frame->fixreg[2] = (*fb)[2];
425 		frame->fixreg[3] = 1;
426 		frame->cr = (*fb)[3];
427 		bcopy(&(*fb)[4], &frame->fixreg[13],
428 		    19 * sizeof(register_t));
429 		return (1);
430 	}
431 	return (0);
432 }
433 
434 int
cpu_fetch_syscall_args(struct thread * td,struct syscall_args * sa)435 cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
436 {
437 	struct proc *p;
438 	struct trapframe *frame;
439 	caddr_t	params;
440 	size_t argsz;
441 	int error, n, i;
442 
443 	p = td->td_proc;
444 	frame = td->td_frame;
445 
446 	sa->code = frame->fixreg[0];
447 	params = (caddr_t)(frame->fixreg + FIRSTARG);
448 	n = NARGREG;
449 
450 	if (sa->code == SYS_syscall) {
451 		/*
452 		 * code is first argument,
453 		 * followed by actual args.
454 		 */
455 		sa->code = *(register_t *) params;
456 		params += sizeof(register_t);
457 		n -= 1;
458 	} else if (sa->code == SYS___syscall) {
459 		/*
460 		 * Like syscall, but code is a quad,
461 		 * so as to maintain quad alignment
462 		 * for the rest of the args.
463 		 */
464 		if (SV_PROC_FLAG(p, SV_ILP32)) {
465 			params += sizeof(register_t);
466 			sa->code = *(register_t *) params;
467 			params += sizeof(register_t);
468 			n -= 2;
469 		} else {
470 			sa->code = *(register_t *) params;
471 			params += sizeof(register_t);
472 			n -= 1;
473 		}
474 	}
475 
476  	if (p->p_sysent->sv_mask)
477 		sa->code &= p->p_sysent->sv_mask;
478 	if (sa->code >= p->p_sysent->sv_size)
479 		sa->callp = &p->p_sysent->sv_table[0];
480 	else
481 		sa->callp = &p->p_sysent->sv_table[sa->code];
482 
483 	sa->narg = sa->callp->sy_narg;
484 
485 	if (SV_PROC_FLAG(p, SV_ILP32)) {
486 		argsz = sizeof(uint32_t);
487 
488 		for (i = 0; i < n; i++)
489 			sa->args[i] = ((u_register_t *)(params))[i] &
490 			    0xffffffff;
491 	} else {
492 		argsz = sizeof(uint64_t);
493 
494 		for (i = 0; i < n; i++)
495 			sa->args[i] = ((u_register_t *)(params))[i];
496 	}
497 
498 	if (sa->narg > n)
499 		error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n,
500 			       (sa->narg - n) * argsz);
501 	else
502 		error = 0;
503 
504 #ifdef __powerpc64__
505 	if (SV_PROC_FLAG(p, SV_ILP32) && sa->narg > n) {
506 		/* Expand the size of arguments copied from the stack */
507 
508 		for (i = sa->narg; i >= n; i--)
509 			sa->args[i] = ((uint32_t *)(&sa->args[n]))[i-n];
510 	}
511 #endif
512 
513 	if (error == 0) {
514 		td->td_retval[0] = 0;
515 		td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
516 	}
517 	return (error);
518 }
519 
520 #include "../../kern/subr_syscall.c"
521 
522 void
syscall(struct trapframe * frame)523 syscall(struct trapframe *frame)
524 {
525 	struct thread *td;
526 	struct syscall_args sa;
527 	int error;
528 
529 	td = curthread;
530 	td->td_frame = frame;
531 
532 #ifdef __powerpc64__
533 	/*
534 	 * Speculatively restore last user SLB segment, which we know is
535 	 * invalid already, since we are likely to do copyin()/copyout().
536 	 */
537 	__asm __volatile ("slbmte %0, %1; isync" ::
538             "r"(td->td_pcb->pcb_cpu.aim.usr_vsid), "r"(USER_SLB_SLBE));
539 #endif
540 
541 	error = syscallenter(td, &sa);
542 	syscallret(td, error, &sa);
543 }
544 
545 #ifdef __powerpc64__
546 /* Handle kernel SLB faults -- runs in real mode, all seat belts off */
547 void
handle_kernel_slb_spill(int type,register_t dar,register_t srr0)548 handle_kernel_slb_spill(int type, register_t dar, register_t srr0)
549 {
550 	struct slb *slbcache;
551 	uint64_t slbe, slbv;
552 	uint64_t esid, addr;
553 	int i;
554 
555 	addr = (type == EXC_ISE) ? srr0 : dar;
556 	slbcache = PCPU_GET(slb);
557 	esid = (uintptr_t)addr >> ADDR_SR_SHFT;
558 	slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID;
559 
560 	/* See if the hardware flushed this somehow (can happen in LPARs) */
561 	for (i = 0; i < n_slbs; i++)
562 		if (slbcache[i].slbe == (slbe | (uint64_t)i))
563 			return;
564 
565 	/* Not in the map, needs to actually be added */
566 	slbv = kernel_va_to_slbv(addr);
567 	if (slbcache[USER_SLB_SLOT].slbe == 0) {
568 		for (i = 0; i < n_slbs; i++) {
569 			if (i == USER_SLB_SLOT)
570 				continue;
571 			if (!(slbcache[i].slbe & SLBE_VALID))
572 				goto fillkernslb;
573 		}
574 
575 		if (i == n_slbs)
576 			slbcache[USER_SLB_SLOT].slbe = 1;
577 	}
578 
579 	/* Sacrifice a random SLB entry that is not the user entry */
580 	i = mftb() % n_slbs;
581 	if (i == USER_SLB_SLOT)
582 		i = (i+1) % n_slbs;
583 
584 fillkernslb:
585 	/* Write new entry */
586 	slbcache[i].slbv = slbv;
587 	slbcache[i].slbe = slbe | (uint64_t)i;
588 
589 	/* Trap handler will restore from cache on exit */
590 }
591 
592 static int
handle_user_slb_spill(pmap_t pm,vm_offset_t addr)593 handle_user_slb_spill(pmap_t pm, vm_offset_t addr)
594 {
595 	struct slb *user_entry;
596 	uint64_t esid;
597 	int i;
598 
599 	esid = (uintptr_t)addr >> ADDR_SR_SHFT;
600 
601 	PMAP_LOCK(pm);
602 	user_entry = user_va_to_slb_entry(pm, addr);
603 
604 	if (user_entry == NULL) {
605 		/* allocate_vsid auto-spills it */
606 		(void)allocate_user_vsid(pm, esid, 0);
607 	} else {
608 		/*
609 		 * Check that another CPU has not already mapped this.
610 		 * XXX: Per-thread SLB caches would be better.
611 		 */
612 		for (i = 0; i < pm->pm_slb_len; i++)
613 			if (pm->pm_slb[i] == user_entry)
614 				break;
615 
616 		if (i == pm->pm_slb_len)
617 			slb_insert_user(pm, user_entry);
618 	}
619 	PMAP_UNLOCK(pm);
620 
621 	return (0);
622 }
623 #endif
624 
625 static int
trap_pfault(struct trapframe * frame,int user)626 trap_pfault(struct trapframe *frame, int user)
627 {
628 	vm_offset_t	eva, va;
629 	struct		thread *td;
630 	struct		proc *p;
631 	vm_map_t	map;
632 	vm_prot_t	ftype;
633 	int		rv;
634 	register_t	user_sr;
635 
636 	td = curthread;
637 	p = td->td_proc;
638 	if (frame->exc == EXC_ISI) {
639 		eva = frame->srr0;
640 		ftype = VM_PROT_EXECUTE;
641 		if (frame->srr1 & SRR1_ISI_PFAULT)
642 			ftype |= VM_PROT_READ;
643 	} else {
644 		eva = frame->cpu.aim.dar;
645 		if (frame->cpu.aim.dsisr & DSISR_STORE)
646 			ftype = VM_PROT_WRITE;
647 		else
648 			ftype = VM_PROT_READ;
649 	}
650 
651 	if (user) {
652 		map = &p->p_vmspace->vm_map;
653 	} else {
654 		if ((eva >> ADDR_SR_SHFT) == (USER_ADDR >> ADDR_SR_SHFT)) {
655 			if (p->p_vmspace == NULL)
656 				return (SIGSEGV);
657 
658 			map = &p->p_vmspace->vm_map;
659 
660 			user_sr = td->td_pcb->pcb_cpu.aim.usr_segm;
661 			eva &= ADDR_PIDX | ADDR_POFF;
662 			eva |= user_sr << ADDR_SR_SHFT;
663 		} else {
664 			map = kernel_map;
665 		}
666 	}
667 	va = trunc_page(eva);
668 
669 	if (map != kernel_map) {
670 		/*
671 		 * Keep swapout from messing with us during this
672 		 *	critical time.
673 		 */
674 		PROC_LOCK(p);
675 		++p->p_lock;
676 		PROC_UNLOCK(p);
677 
678 		/* Fault in the user page: */
679 		rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
680 
681 		PROC_LOCK(p);
682 		--p->p_lock;
683 		PROC_UNLOCK(p);
684 		/*
685 		 * XXXDTRACE: add dtrace_doubletrap_func here?
686 		 */
687 	} else {
688 		/*
689 		 * Don't have to worry about process locking or stacks in the
690 		 * kernel.
691 		 */
692 		rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
693 	}
694 
695 	if (rv == KERN_SUCCESS)
696 		return (0);
697 
698 	if (!user && handle_onfault(frame))
699 		return (0);
700 
701 	return (SIGSEGV);
702 }
703 
704 /*
705  * For now, this only deals with the particular unaligned access case
706  * that gcc tends to generate.  Eventually it should handle all of the
707  * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
708  */
709 
710 static int
fix_unaligned(struct thread * td,struct trapframe * frame)711 fix_unaligned(struct thread *td, struct trapframe *frame)
712 {
713 	struct thread	*fputhread;
714 	int		indicator, reg;
715 	double		*fpr;
716 
717 	indicator = EXC_ALI_OPCODE_INDICATOR(frame->cpu.aim.dsisr);
718 
719 	switch (indicator) {
720 	case EXC_ALI_LFD:
721 	case EXC_ALI_STFD:
722 		reg = EXC_ALI_RST(frame->cpu.aim.dsisr);
723 		fpr = &td->td_pcb->pcb_fpu.fpr[reg];
724 		fputhread = PCPU_GET(fputhread);
725 
726 		/* Juggle the FPU to ensure that we've initialized
727 		 * the FPRs, and that their current state is in
728 		 * the PCB.
729 		 */
730 		if (fputhread != td) {
731 			if (fputhread)
732 				save_fpu(fputhread);
733 			enable_fpu(td);
734 		}
735 		save_fpu(td);
736 
737 		if (indicator == EXC_ALI_LFD) {
738 			if (copyin((void *)frame->cpu.aim.dar, fpr,
739 			    sizeof(double)) != 0)
740 				return -1;
741 			enable_fpu(td);
742 		} else {
743 			if (copyout(fpr, (void *)frame->cpu.aim.dar,
744 			    sizeof(double)) != 0)
745 				return -1;
746 		}
747 		return 0;
748 		break;
749 	}
750 
751 	return -1;
752 }
753 
754