xref: /openbsd/sys/arch/hppa/hppa/trap.c (revision 36dba039)
1 /*	$OpenBSD: trap.c,v 1.166 2024/04/14 03:26:25 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 1998-2004 Michael Shalayeff
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /* #define TRAPDEBUG */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/syscall.h>
34 #include <sys/proc.h>
35 #include <sys/signalvar.h>
36 #include <sys/user.h>
37 #include <sys/syscall_mi.h>
38 
39 #include <uvm/uvm_extern.h>
40 
41 #include <machine/autoconf.h>
42 
43 #ifdef DDB
44 #ifdef TRAPDEBUG
45 #include <ddb/db_output.h>
46 #else
47 #include <machine/db_machdep.h>
48 #endif
49 #endif
50 
inst_store(u_int ins)51 static __inline int inst_store(u_int ins) {
52 	return (ins & 0xf0000000) == 0x60000000 ||	/* st */
53 	       (ins & 0xf4000200) == 0x24000200 ||	/* fst/cst */
54 	       (ins & 0xfc000200) == 0x0c000200 ||	/* stby */
55 	       (ins & 0xfc0003c0) == 0x0c0001c0;	/* ldcw */
56 }
57 
58 int	pcxs_unaligned(u_int opcode, vaddr_t va);
59 #ifdef PTRACE
60 void	ss_clear_breakpoints(struct proc *p);
61 #endif
62 
63 void	ast(struct proc *);
64 
65 /* single-step breakpoint */
66 #define SSBREAKPOINT	(HPPA_BREAK_KERNEL | (HPPA_BREAK_SS << 13))
67 
68 const char *trap_type[] = {
69 	"invalid",
70 	"HPMC",
71 	"power failure",
72 	"recovery counter",
73 	"external interrupt",
74 	"LPMC",
75 	"ITLB miss fault",
76 	"instruction protection",
77 	"Illegal instruction",
78 	"break instruction",
79 	"privileged operation",
80 	"privileged register",
81 	"overflow",
82 	"conditional",
83 	"assist exception",
84 	"DTLB miss",
85 	"ITLB non-access miss",
86 	"DTLB non-access miss",
87 	"data protection/rights/alignment",
88 	"data break",
89 	"TLB dirty",
90 	"page reference",
91 	"assist emulation",
92 	"higher-priv transfer",
93 	"lower-priv transfer",
94 	"taken branch",
95 	"data access rights",
96 	"data protection",
97 	"unaligned data ref",
98 };
99 int trap_types = sizeof(trap_type)/sizeof(trap_type[0]);
100 
101 #define	frame_regmap(tf,r)	(((u_int *)(tf))[hppa_regmap[(r)]])
102 u_char hppa_regmap[32] = {
103 	offsetof(struct trapframe, tf_pad[0]) / 4,	/* r0 XXX */
104 	offsetof(struct trapframe, tf_r1) / 4,
105 	offsetof(struct trapframe, tf_rp) / 4,
106 	offsetof(struct trapframe, tf_r3) / 4,
107 	offsetof(struct trapframe, tf_r4) / 4,
108 	offsetof(struct trapframe, tf_r5) / 4,
109 	offsetof(struct trapframe, tf_r6) / 4,
110 	offsetof(struct trapframe, tf_r7) / 4,
111 	offsetof(struct trapframe, tf_r8) / 4,
112 	offsetof(struct trapframe, tf_r9) / 4,
113 	offsetof(struct trapframe, tf_r10) / 4,
114 	offsetof(struct trapframe, tf_r11) / 4,
115 	offsetof(struct trapframe, tf_r12) / 4,
116 	offsetof(struct trapframe, tf_r13) / 4,
117 	offsetof(struct trapframe, tf_r14) / 4,
118 	offsetof(struct trapframe, tf_r15) / 4,
119 	offsetof(struct trapframe, tf_r16) / 4,
120 	offsetof(struct trapframe, tf_r17) / 4,
121 	offsetof(struct trapframe, tf_r18) / 4,
122 	offsetof(struct trapframe, tf_t4) / 4,
123 	offsetof(struct trapframe, tf_t3) / 4,
124 	offsetof(struct trapframe, tf_t2) / 4,
125 	offsetof(struct trapframe, tf_t1) / 4,
126 	offsetof(struct trapframe, tf_arg3) / 4,
127 	offsetof(struct trapframe, tf_arg2) / 4,
128 	offsetof(struct trapframe, tf_arg1) / 4,
129 	offsetof(struct trapframe, tf_arg0) / 4,
130 	offsetof(struct trapframe, tf_dp) / 4,
131 	offsetof(struct trapframe, tf_ret0) / 4,
132 	offsetof(struct trapframe, tf_ret1) / 4,
133 	offsetof(struct trapframe, tf_sp) / 4,
134 	offsetof(struct trapframe, tf_r31) / 4,
135 };
136 
137 void
ast(struct proc * p)138 ast(struct proc *p)
139 {
140 	if (p->p_md.md_astpending) {
141 		p->p_md.md_astpending = 0;
142 		uvmexp.softs++;
143 		mi_ast(p, curcpu()->ci_want_resched);
144 	}
145 
146 }
147 
148 void
trap(int type,struct trapframe * frame)149 trap(int type, struct trapframe *frame)
150 {
151 	struct proc *p = curproc;
152 	vaddr_t va;
153 	struct vm_map *map;
154 	struct vmspace *vm;
155 	register vm_prot_t access_type;
156 	register pa_space_t space;
157 	union sigval sv;
158 	u_int opcode;
159 	int ret, trapnum;
160 	const char *tts;
161 #ifdef DIAGNOSTIC
162 	int oldcpl = curcpu()->ci_cpl;
163 #endif
164 
165 	trapnum = type & ~T_USER;
166 	opcode = frame->tf_iir;
167 	if (trapnum <= T_EXCEPTION || trapnum == T_HIGHERPL ||
168 	    trapnum == T_LOWERPL || trapnum == T_TAKENBR ||
169 	    trapnum == T_IDEBUG || trapnum == T_PERFMON) {
170 		va = frame->tf_iioq_head;
171 		space = frame->tf_iisq_head;
172 		access_type = PROT_EXEC;
173 	} else {
174 		va = frame->tf_ior;
175 		space = frame->tf_isr;
176 		if (va == frame->tf_iioq_head)
177 			access_type = PROT_EXEC;
178 		else if (inst_store(opcode))
179 			access_type = PROT_WRITE;
180 		else
181 			access_type = PROT_READ;
182 	}
183 
184 	if (frame->tf_flags & TFF_LAST)
185 		p->p_md.md_regs = frame;
186 
187 	if (trapnum > trap_types)
188 		tts = "reserved";
189 	else
190 		tts = trap_type[trapnum];
191 
192 #ifdef TRAPDEBUG
193 	if (trapnum != T_INTERRUPT && trapnum != T_IBREAK)
194 		db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n",
195 		    type, tts, space, va, frame->tf_iisq_head,
196 		    frame->tf_iioq_head, frame->tf_flags, frame);
197 	else if (trapnum  == T_IBREAK)
198 		db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n",
199 		    break5(opcode), break13(opcode),
200 		    frame->tf_iisq_head, frame->tf_iioq_head, frame);
201 
202 	{
203 		extern int etext;
204 		if (frame < (struct trapframe *)&etext) {
205 			printf("trap: bogus frame ptr %p\n", frame);
206 			goto dead_end;
207 		}
208 	}
209 #endif
210 	if (trapnum != T_INTERRUPT) {
211 		uvmexp.traps++;
212 		mtctl(frame->tf_eiem, CR_EIEM);
213 	}
214 
215 	if (type & T_USER)
216 		refreshcreds(p);
217 
218 	switch (type) {
219 	case T_NONEXIST:
220 	case T_NONEXIST | T_USER:
221 		/* we've got screwed up by the central scrutinizer */
222 		printf("trap: elvis has just left the building!\n");
223 		goto dead_end;
224 
225 	case T_RECOVERY:
226 	case T_RECOVERY | T_USER:
227 		/* XXX will implement later */
228 		printf("trap: handicapped");
229 		goto dead_end;
230 
231 #ifdef DIAGNOSTIC
232 	case T_EXCEPTION:
233 		panic("FPU/SFU emulation botch");
234 
235 		/* these just can't happen ever */
236 	case T_PRIV_OP:
237 	case T_PRIV_REG:
238 		/* these just can't make it to the trap() ever */
239 	case T_HPMC:
240 	case T_HPMC | T_USER:
241 #endif
242 	case T_IBREAK:
243 	case T_DATALIGN:
244 	case T_DBREAK:
245 	dead_end:
246 #ifdef DDB
247 		if (db_ktrap(type, va, frame)) {
248 			if (type == T_IBREAK) {
249 				/* skip break instruction */
250 				frame->tf_iioq_head = frame->tf_iioq_tail;
251 				frame->tf_iioq_tail += 4;
252 			}
253 			return;
254 		}
255 #else
256 		if (type == T_DATALIGN || type == T_DPROT)
257 			panic ("trap: %s at 0x%lx", tts, va);
258 		else
259 			panic ("trap: no debugger for \"%s\" (%d)", tts, type);
260 #endif
261 		break;
262 
263 	case T_IBREAK | T_USER:
264 	case T_DBREAK | T_USER: {
265 		int code = TRAP_BRKPT;
266 
267 #ifdef PTRACE
268 		KERNEL_LOCK();
269 		ss_clear_breakpoints(p);
270 		if (opcode == SSBREAKPOINT)
271 			code = TRAP_TRACE;
272 		KERNEL_UNLOCK();
273 #endif
274 		/* pass to user debugger */
275 		sv.sival_int = va;
276 		trapsignal(p, SIGTRAP, type & ~T_USER, code, sv);
277 		}
278 		break;
279 
280 #ifdef PTRACE
281 	case T_TAKENBR | T_USER:
282 		KERNEL_LOCK();
283 		ss_clear_breakpoints(p);
284 		KERNEL_UNLOCK();
285 		/* pass to user debugger */
286 		sv.sival_int = va;
287 		trapsignal(p, SIGTRAP, type & ~T_USER, TRAP_TRACE, sv);
288 		break;
289 #endif
290 
291 	case T_EXCEPTION | T_USER: {
292 		struct hppa_fpstate *hfp;
293 		u_int64_t *fpp;
294 		u_int32_t *pex;
295 		int i, flt;
296 
297 		hfp = (struct hppa_fpstate *)frame->tf_cr30;
298 		fpp = (u_int64_t *)&hfp->hfp_regs;
299 
300 		pex = (u_int32_t *)&fpp[0];
301 		for (i = 0, pex++; i < 7 && !*pex; i++, pex++)
302 			;
303 		flt = 0;
304 		if (i < 7) {
305 			u_int32_t stat = HPPA_FPU_OP(*pex);
306 			if (stat & HPPA_FPU_UNMPL)
307 				flt = FPE_FLTINV;
308 			else if (stat & (HPPA_FPU_V << 1))
309 				flt = FPE_FLTINV;
310 			else if (stat & (HPPA_FPU_Z << 1))
311 				flt = FPE_FLTDIV;
312 			else if (stat & (HPPA_FPU_I << 1))
313 				flt = FPE_FLTRES;
314 			else if (stat & (HPPA_FPU_O << 1))
315 				flt = FPE_FLTOVF;
316 			else if (stat & (HPPA_FPU_U << 1))
317 				flt = FPE_FLTUND;
318 			/* still left: under/over-flow w/ inexact */
319 
320 			/* cleanup exceptions (XXX deliver all ?) */
321 			while (i++ < 7)
322 				*pex++ = 0;
323 		}
324 		/* reset the trap flag, as if there was none */
325 		fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32);
326 
327 		sv.sival_int = va;
328 		trapsignal(p, SIGFPE, type & ~T_USER, flt, sv);
329 		}
330 		break;
331 
332 	case T_EMULATION:
333 		panic("trap: emulation trap in the kernel");
334 		break;
335 
336 	case T_EMULATION | T_USER:
337 		sv.sival_int = va;
338 		trapsignal(p, SIGILL, type & ~T_USER, ILL_COPROC, sv);
339 		break;
340 
341 	case T_OVERFLOW | T_USER:
342 		sv.sival_int = va;
343 		trapsignal(p, SIGFPE, type & ~T_USER, FPE_INTOVF, sv);
344 		break;
345 
346 	case T_CONDITION | T_USER:
347 		sv.sival_int = va;
348 		trapsignal(p, SIGFPE, type & ~T_USER, FPE_INTDIV, sv);
349 		break;
350 
351 	case T_PRIV_OP | T_USER:
352 		sv.sival_int = va;
353 		trapsignal(p, SIGILL, type & ~T_USER, ILL_PRVOPC, sv);
354 		break;
355 
356 	case T_PRIV_REG | T_USER:
357 		/*
358 		 * On PCXS processors, attempting to read control registers
359 		 * cr26 and cr27 from userland causes a ``privileged register''
360 		 * trap.  Later processors do not restrict read accesses to
361 		 * these registers.
362 		 */
363 		if (cpu_type == hpcxs &&
364 		    (opcode & (0xfc1fffe0 | (0x1e << 21))) ==
365 		     (0x000008a0 | (0x1a << 21))) { /* mfctl %cr{26,27}, %r# */
366 			register_t cr;
367 
368 			if (((opcode >> 21) & 0x1f) == 27)
369 				cr = frame->tf_cr27;	/* cr27 */
370 			else
371 				cr = 0;			/* cr26 */
372 			frame_regmap(frame, opcode & 0x1f) = cr;
373 			frame->tf_ipsw |= PSL_N;
374 		} else {
375 			sv.sival_int = va;
376 			trapsignal(p, SIGILL, type & ~T_USER, ILL_PRVREG, sv);
377 		}
378 		break;
379 
380 		/* these should never got here */
381 	case T_HIGHERPL | T_USER:
382 	case T_LOWERPL | T_USER:
383 	case T_DATAPID | T_USER:
384 		sv.sival_int = va;
385 		trapsignal(p, SIGSEGV, access_type, SEGV_ACCERR, sv);
386 		break;
387 
388 	/*
389 	 * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN
390 	 * are shared.  We need to sort out the unaligned access situation
391 	 * first, before handling this trap as T_DATACC.
392 	 */
393 	case T_DPROT | T_USER:
394 		if (cpu_type == hpcxs) {
395 			if (pcxs_unaligned(opcode, va))
396 				goto datalign_user;
397 			else
398 				goto datacc;
399 		}
400 
401 		sv.sival_int = va;
402 		trapsignal(p, SIGSEGV, access_type, SEGV_ACCERR, sv);
403 		break;
404 
405 	case T_ITLBMISSNA:
406 	case T_ITLBMISSNA | T_USER:
407 	case T_DTLBMISSNA:
408 	case T_DTLBMISSNA | T_USER:
409 		if (space == HPPA_SID_KERNEL)
410 			map = kernel_map;
411 		else {
412 			vm = p->p_vmspace;
413 			map = &vm->vm_map;
414 		}
415 
416 		if ((opcode & 0xfc003fc0) == 0x04001340) {
417 			/* lpa failure case */
418 			frame_regmap(frame, opcode & 0x1f) = 0;
419 			frame->tf_ipsw |= PSL_N;
420 		} else if ((opcode & 0xfc001f80) == 0x04001180) {
421 			int pl;
422 
423 			/* dig probe[rw]i? insns */
424 			if (opcode & 0x2000)
425 				pl = (opcode >> 16) & 3;
426 			else
427 				pl = frame_regmap(frame,
428 				    (opcode >> 16) & 0x1f) & 3;
429 
430 			KERNEL_LOCK();
431 
432 			if ((type & T_USER && space == HPPA_SID_KERNEL) ||
433 			    (frame->tf_iioq_head & 3) != pl ||
434 			    (type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
435 			    uvm_fault(map, trunc_page(va), 0,
436 			     opcode & 0x40? PROT_WRITE : PROT_READ)) {
437 				frame_regmap(frame, opcode & 0x1f) = 0;
438 				frame->tf_ipsw |= PSL_N;
439 			}
440 
441 			KERNEL_UNLOCK();
442 		} else if (type & T_USER) {
443 			sv.sival_int = va;
444 			trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLTRP, sv);
445 		} else
446 			panic("trap: %s @ 0x%lx:0x%lx for 0x%x:0x%lx irr 0x%08x",
447 			    tts, frame->tf_iisq_head, frame->tf_iioq_head,
448 			    space, va, opcode);
449 		break;
450 
451 	case T_IPROT | T_USER:
452 	case T_TLB_DIRTY:
453 	case T_TLB_DIRTY | T_USER:
454 	case T_DATACC:
455 	case T_DATACC | T_USER:
456 datacc:
457 	case T_ITLBMISS:
458 	case T_ITLBMISS | T_USER:
459 	case T_DTLBMISS:
460 	case T_DTLBMISS | T_USER:
461 		if (type & T_USER) {
462 			if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
463 			    "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
464 			    uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
465 				goto out;
466 		}
467 
468 		/*
469 		 * it could be a kernel map for exec_map faults
470 		 */
471 		if (space == HPPA_SID_KERNEL)
472 			map = kernel_map;
473 		else {
474 			vm = p->p_vmspace;
475 			map = &vm->vm_map;
476 		}
477 
478 		/*
479 		 * user faults out of user addr space are always a fail,
480 		 * this happens on va >= VM_MAXUSER_ADDRESS, where
481 		 * space id will be zero and therefore cause
482 		 * a misbehave lower in the code.
483 		 *
484 		 * also check that faulted space id matches the curproc.
485 		 */
486 		if ((type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
487 		   (type & T_USER && map->pmap->pm_space != space)) {
488 			sv.sival_int = va;
489 			trapsignal(p, SIGSEGV, access_type, SEGV_MAPERR, sv);
490 			break;
491 		}
492 
493 		KERNEL_LOCK();
494 		ret = uvm_fault(map, trunc_page(va), 0, access_type);
495 		KERNEL_UNLOCK();
496 
497 		/*
498 		 * If this was a stack access we keep track of the maximum
499 		 * accessed stack size.  Also, if uvm_fault gets a protection
500 		 * failure it is due to accessing the stack region outside
501 		 * the current limit and we need to reflect that as an access
502 		 * error.
503 		 */
504 		if (ret == 0 && space != HPPA_SID_KERNEL)
505 			uvm_grow(p, va);
506 
507 		if (ret != 0) {
508 			if (type & T_USER) {
509 				int signal, sicode;
510 
511 				signal = SIGSEGV;
512 				sicode = SEGV_MAPERR;
513 				if (ret == EACCES)
514 					sicode = SEGV_ACCERR;
515 				if (ret == EIO) {
516 					signal = SIGBUS;
517 					sicode = BUS_OBJERR;
518 				}
519 				sv.sival_int = va;
520 				trapsignal(p, signal, access_type, sicode, sv);
521 			} else {
522 				if (p && p->p_addr->u_pcb.pcb_onfault) {
523 					frame->tf_iioq_tail = 4 +
524 					    (frame->tf_iioq_head =
525 						p->p_addr->u_pcb.pcb_onfault);
526 #ifdef DDB
527 					frame->tf_iir = 0;
528 #endif
529 				} else {
530 					panic("trap: "
531 					    "uvm_fault(%p, %lx, 0, %d): %d",
532 					    map, va, access_type, ret);
533 				}
534 			}
535 		}
536 		break;
537 
538 	case T_DATAPID:
539 		/* This should never happen, unless within spcopy() */
540 		if (p && p->p_addr->u_pcb.pcb_onfault) {
541 			frame->tf_iioq_tail = 4 +
542 			    (frame->tf_iioq_head =
543 				p->p_addr->u_pcb.pcb_onfault);
544 #ifdef DDB
545 			frame->tf_iir = 0;
546 #endif
547 		} else
548 			goto dead_end;
549 		break;
550 
551 	case T_DATALIGN | T_USER:
552 datalign_user:
553 		sv.sival_int = va;
554 		trapsignal(p, SIGBUS, access_type, BUS_ADRALN, sv);
555 		break;
556 
557 	case T_INTERRUPT:
558 	case T_INTERRUPT | T_USER:
559 		cpu_intr(frame);
560 		break;
561 
562 	case T_CONDITION:
563 		panic("trap: divide by zero in the kernel");
564 		break;
565 
566 	case T_ILLEGAL:
567 	case T_ILLEGAL | T_USER:
568 		/* see if it's a SPOP1,,0 */
569 		if ((opcode & 0xfffffe00) == 0x10000200) {
570 			frame_regmap(frame, opcode & 0x1f) = 0;
571 			frame->tf_ipsw |= PSL_N;
572 			break;
573 		}
574 		if (type & T_USER) {
575 			sv.sival_int = va;
576 			trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLOPC, sv);
577 			break;
578 		}
579 		/* FALLTHROUGH */
580 
581 	/*
582 	 * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN
583 	 * are shared.  We need to sort out the unaligned access situation
584 	 * first, before handling this trap as T_DATACC.
585 	 */
586 	case T_DPROT:
587 		if (cpu_type == hpcxs) {
588 			if (pcxs_unaligned(opcode, va))
589 				goto dead_end;
590 			else
591 				goto datacc;
592 		}
593 		/* FALLTHROUGH to unimplemented */
594 
595 	case T_LOWERPL:
596 	case T_IPROT:
597 	case T_OVERFLOW:
598 	case T_HIGHERPL:
599 	case T_TAKENBR:
600 	case T_POWERFAIL:
601 	case T_LPMC:
602 	case T_PAGEREF:
603 		/* FALLTHROUGH to unimplemented */
604 	default:
605 #ifdef TRAPDEBUG
606 		if (db_ktrap(type, va, frame))
607 			return;
608 #endif
609 		panic("trap: unimplemented \'%s\' (%d)", tts, trapnum);
610 	}
611 
612 #ifdef DIAGNOSTIC
613 	if (curcpu()->ci_cpl != oldcpl)
614 		printf("WARNING: SPL (%d) NOT LOWERED ON "
615 		    "TRAP (%d) EXIT\n", curcpu()->ci_cpl, trapnum);
616 #endif
617 
618 	if (trapnum != T_INTERRUPT)
619 		splx(curcpu()->ci_cpl);	/* process softints */
620 
621 	/*
622 	 * in case we were interrupted from the syscall gate page
623 	 * treat this as we were not really running user code no more
624 	 * for weird things start to happen on return to the userland
625 	 * and also see a note in locore.S:TLABEL(all)
626 	 */
627 	if ((type & T_USER) && !(frame->tf_iisq_head == HPPA_SID_KERNEL &&
628 	    (frame->tf_iioq_head & ~PAGE_MASK) == SYSCALLGATE)) {
629 		ast(p);
630 out:
631 		userret(p);
632 	}
633 }
634 
635 void
child_return(void * arg)636 child_return(void *arg)
637 {
638 	struct proc *p = (struct proc *)arg;
639 	struct trapframe *tf = p->p_md.md_regs;
640 
641 	/*
642 	 * Set up return value registers as libc:fork() expects
643 	 */
644 	tf->tf_ret0 = 0;
645 	tf->tf_t1 = 0;		/* errno */
646 
647 	KERNEL_UNLOCK();
648 
649 	ast(p);
650 
651 	mi_child_return(p);
652 }
653 
654 #ifdef PTRACE
655 
656 #include <sys/ptrace.h>
657 
658 int	ss_get_value(struct proc *p, vaddr_t addr, u_int *value);
659 int	ss_put_value(struct proc *p, vaddr_t addr, u_int value);
660 
661 int
ss_get_value(struct proc * p,vaddr_t addr,u_int * value)662 ss_get_value(struct proc *p, vaddr_t addr, u_int *value)
663 {
664 	struct uio uio;
665 	struct iovec iov;
666 
667 	iov.iov_base = (caddr_t)value;
668 	iov.iov_len = sizeof(u_int);
669 	uio.uio_iov = &iov;
670 	uio.uio_iovcnt = 1;
671 	uio.uio_offset = (off_t)addr;
672 	uio.uio_resid = sizeof(u_int);
673 	uio.uio_segflg = UIO_SYSSPACE;
674 	uio.uio_rw = UIO_READ;
675 	uio.uio_procp = curproc;
676 	return (process_domem(curproc, p->p_p, &uio, PT_READ_I));
677 }
678 
679 int
ss_put_value(struct proc * p,vaddr_t addr,u_int value)680 ss_put_value(struct proc *p, vaddr_t addr, u_int value)
681 {
682 	struct uio uio;
683 	struct iovec iov;
684 
685 	iov.iov_base = (caddr_t)&value;
686 	iov.iov_len = sizeof(u_int);
687 	uio.uio_iov = &iov;
688 	uio.uio_iovcnt = 1;
689 	uio.uio_offset = (off_t)addr;
690 	uio.uio_resid = sizeof(u_int);
691 	uio.uio_segflg = UIO_SYSSPACE;
692 	uio.uio_rw = UIO_WRITE;
693 	uio.uio_procp = curproc;
694 	return (process_domem(curproc, p->p_p, &uio, PT_WRITE_I));
695 }
696 
697 void
ss_clear_breakpoints(struct proc * p)698 ss_clear_breakpoints(struct proc *p)
699 {
700 	/* Restore original instructions. */
701 	if (p->p_md.md_bpva != 0) {
702 		ss_put_value(p, p->p_md.md_bpva, p->p_md.md_bpsave[0]);
703 		ss_put_value(p, p->p_md.md_bpva + 4, p->p_md.md_bpsave[1]);
704 		p->p_md.md_bpva = 0;
705 	}
706 }
707 
708 int
process_sstep(struct proc * p,int sstep)709 process_sstep(struct proc *p, int sstep)
710 {
711 	int error;
712 
713 	ss_clear_breakpoints(p);
714 
715 	if (sstep == 0) {
716 		p->p_md.md_regs->tf_ipsw &= ~PSL_T;
717 		return (0);
718 	}
719 
720 	/*
721 	 * Don't touch the syscall gateway page.  Instead, insert a
722 	 * breakpoint where we're supposed to return.
723 	 */
724 	if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) == SYSCALLGATE)
725 		p->p_md.md_bpva = p->p_md.md_regs->tf_r31 & ~HPPA_PC_PRIV_MASK;
726 	else
727 		p->p_md.md_bpva = p->p_md.md_regs->tf_iioq_tail & ~HPPA_PC_PRIV_MASK;
728 
729 	/*
730 	 * Insert two breakpoint instructions; the first one might be
731 	 * nullified.  Of course we need to save two instruction
732 	 * first.
733 	 */
734 
735 	error = ss_get_value(p, p->p_md.md_bpva, &p->p_md.md_bpsave[0]);
736 	if (error)
737 		return (error);
738 	error = ss_get_value(p, p->p_md.md_bpva + 4, &p->p_md.md_bpsave[1]);
739 	if (error)
740 		return (error);
741 
742 	error = ss_put_value(p, p->p_md.md_bpva, SSBREAKPOINT);
743 	if (error)
744 		return (error);
745 	error = ss_put_value(p, p->p_md.md_bpva + 4, SSBREAKPOINT);
746 	if (error)
747 		return (error);
748 
749 	if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) != SYSCALLGATE)
750 		p->p_md.md_regs->tf_ipsw |= PSL_T;
751 	else
752 		p->p_md.md_regs->tf_ipsw &= ~PSL_T;
753 
754 	return (0);
755 }
756 
757 #endif	/* PTRACE */
758 
759 void	syscall(struct trapframe *frame);
760 
761 /*
762  * call actual syscall routine
763  */
764 void
syscall(struct trapframe * frame)765 syscall(struct trapframe *frame)
766 {
767 	struct proc *p = curproc;
768 	const struct sysent *callp = sysent;
769 	int code, argsize, argoff, error;
770 	register_t args[8], rval[2];
771 #ifdef DIAGNOSTIC
772 	int oldcpl = curcpu()->ci_cpl;
773 #endif
774 
775 	uvmexp.syscalls++;
776 
777 	if (!USERMODE(frame->tf_iioq_head))
778 		panic("syscall");
779 
780 	p->p_md.md_regs = frame;
781 
782 	argoff = 4;
783 	code = frame->tf_t1;
784 	args[0] = frame->tf_arg0;
785 	args[1] = frame->tf_arg1;
786 	args[2] = frame->tf_arg2;
787 	args[3] = frame->tf_arg3;
788 
789 	// XXX out of range stays on syscall0, which we assume is enosys
790 	if (code > 0 && code < SYS_MAXSYSCALL)
791 		callp += code;
792 
793 	if ((argsize = callp->sy_argsize)) {
794 		register_t *s, *e, t;
795 		int i;
796 
797 		argsize -= argoff * 4;
798 		if (argsize > 0) {
799 			i = argsize / 4;
800 			if ((error = copyin((void *)(frame->tf_sp +
801 			    HPPA_FRAME_ARG(4 + i - 1)), args + argoff,
802 			    argsize)))
803 				goto bad;
804 			/* reverse the args[] entries */
805 			s = args + argoff;
806 			e = s + i - 1;
807 			while (s < e) {
808 				t = *s;
809 				*s = *e;
810 				*e = t;
811 				s++, e--;
812 			}
813 		}
814 
815 		/*
816 		 * System calls with 64-bit arguments need a word swap
817 		 * due to the order of the arguments on the stack.
818 		 */
819 		i = 0;
820 		switch (code) {
821 		case SYS_lseek:
822 		case SYS_truncate:
823 		case SYS_ftruncate:	i = 2;	break;
824 		case SYS_preadv:
825 		case SYS_pwritev:
826 		case SYS_pread:
827 		case SYS_pwrite:	i = 4;	break;
828 		case SYS_mquery:
829 		case SYS_mmap:		i = 6;	break;
830 		}
831 
832 		if (i) {
833 			t = args[i];
834 			args[i] = args[i + 1];
835 			args[i + 1] = t;
836 		}
837 	}
838 
839 	rval[0] = 0;
840 	rval[1] = frame->tf_ret1;
841 
842 	error = mi_syscall(p, code, callp, args, rval);
843 
844 	switch (error) {
845 	case 0:
846 		frame->tf_ret0 = rval[0];
847 		frame->tf_ret1 = rval[1];
848 		frame->tf_t1 = 0;
849 		break;
850 	case ERESTART:
851 		frame->tf_iioq_head -= 12;
852 		frame->tf_iioq_tail -= 12;
853 	case EJUSTRETURN:
854 		break;
855 	default:
856 	bad:
857 		frame->tf_t1 = error;
858 		frame->tf_ret0 = error;
859 		frame->tf_ret1 = 0;
860 		break;
861 	}
862 
863 	ast(p);		// XXX why?
864 
865 	mi_syscall_return(p, code, error, rval);
866 
867 #ifdef DIAGNOSTIC
868 	if (curcpu()->ci_cpl != oldcpl) {
869 		printf("WARNING: SPL (0x%x) NOT LOWERED ON "
870 		    "syscall(0x%x, 0x%lx, 0x%lx, 0x%lx...) EXIT, PID %d\n",
871 		    curcpu()->ci_cpl, code, args[0], args[1], args[2],
872 		    p->p_p->ps_pid);
873 		curcpu()->ci_cpl = oldcpl;
874 	}
875 #endif
876 	splx(curcpu()->ci_cpl);	/* process softints */
877 }
878 
879 /*
880  * Decide if opcode `opcode' accessing virtual address `va' caused an
881  * unaligned trap. Returns zero if the access is correctly aligned.
882  * Used on PCXS processors to sort out exception causes.
883  */
884 int
pcxs_unaligned(u_int opcode,vaddr_t va)885 pcxs_unaligned(u_int opcode, vaddr_t va)
886 {
887 	u_int mbz_bits;
888 
889 	/*
890 	 * Exit early if the va is obviously aligned enough.
891 	 */
892 	if ((va & 0x0f) == 0)
893 		return 0;
894 
895 	mbz_bits = 0;
896 
897 	/*
898 	 * Only load and store instructions can cause unaligned access.
899 	 * There are three opcode patterns to look for:
900 	 * - canonical load/store
901 	 * - load/store short or indexed
902 	 * - coprocessor load/store
903 	 */
904 
905 	if ((opcode & 0xd0000000) == 0x40000000) {
906 		switch ((opcode >> 26) & 0x03) {
907 		case 0x00:	/* ldb, stb */
908 			mbz_bits = 0x00;
909 			break;
910 		case 0x01:	/* ldh, sth */
911 			mbz_bits = 0x01;
912 			break;
913 		case 0x02:	/* ldw, stw */
914 		case 0x03:	/* ldwm, stwm */
915 			mbz_bits = 0x03;
916 			break;
917 		}
918 	} else
919 
920 	if ((opcode & 0xfc000000) == 0x0c000000) {
921 		switch ((opcode >> 6) & 0x0f) {
922 		case 0x01:	/* ldhx, ldhs */
923 			mbz_bits = 0x01;
924 			break;
925 		case 0x02:	/* ldwx, ldws */
926 			mbz_bits = 0x03;
927 			break;
928 		case 0x07:	/* ldcwx, ldcws */
929 			mbz_bits = 0x0f;
930 			break;
931 		case 0x09:
932 			if ((opcode & (1 << 12)) != 0)	/* sths */
933 				mbz_bits = 0x01;
934 			break;
935 		case 0x0a:
936 			if ((opcode & (1 << 12)) != 0)	/* stws */
937 				mbz_bits = 0x03;
938 			break;
939 		}
940 	} else
941 
942 	if ((opcode & 0xf4000000) == 0x24000000) {
943 		if ((opcode & (1 << 27)) != 0) {
944 			/* cldwx, cstwx, cldws, cstws */
945 			mbz_bits = 0x03;
946 		} else {
947 			/* clddx, cstdx, cldds, cstds */
948 			mbz_bits = 0x07;
949 		}
950 	}
951 
952 	return (va & mbz_bits);
953 }
954