xref: /netbsd/sys/arch/mips/mips/mips_emul.c (revision fddac2f3)
1 /*	$NetBSD: mips_emul.c,v 1.31 2021/11/16 06:15:48 simonb Exp $ */
2 
3 /*
4  * Copyright (c) 1999 Shuichiro URATA.  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. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: mips_emul.c,v 1.31 2021/11/16 06:15:48 simonb Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/cpu.h>
35 #include <sys/proc.h>
36 
37 #include <mips/locore.h>
38 #include <mips/mips_opcode.h>
39 
40 #include <mips/reg.h>
41 #include <mips/regnum.h>			/* symbolic register indices */
42 #include <mips/pcb.h>
43 #include <mips/vmparam.h>			/* for VM_MAX_ADDRESS */
44 #include <mips/trap.h>
45 
46 static inline void	send_sigsegv(intptr_t, uint32_t, struct trapframe *,
47 			    uint32_t);
48 static inline void	update_pc(struct trapframe *, uint32_t);
49 
50 static void	mips_emul_ll(uint32_t, struct trapframe *, uint32_t);
51 static void	mips_emul_sc(uint32_t, struct trapframe *, uint32_t);
52 
53 /*
54  * MIPS2 LL instruction emulation state
55  */
56 struct {
57 	struct lwp *lwp;
58 	vaddr_t addr;
59 	uint32_t value;
60 } llstate;
61 
62 /*
63  * Analyse 'next' PC address taking account of branch/jump instructions
64  */
65 vaddr_t
mips_emul_branch(struct trapframe * tf,vaddr_t instpc,uint32_t fpuCSR,bool allowNonBranch)66 mips_emul_branch(struct trapframe *tf, vaddr_t instpc, uint32_t fpuCSR,
67     bool allowNonBranch)
68 {
69 #define	BRANCHTARGET(pc, i) (4 + (pc) + ((short)(i).IType.imm << 2))
70 	InstFmt inst;
71 	vaddr_t nextpc;
72 
73 	if (instpc < MIPS_KSEG0_START) {
74 		inst.word = mips_ufetch32((void *)instpc);
75 	} else {
76 		inst.word = *(uint32_t *)instpc;
77 	}
78 
79 	switch ((int)inst.JType.op) {
80 	case OP_SPECIAL:
81 		if (inst.RType.func == OP_JR || inst.RType.func == OP_JALR)
82 			nextpc = tf->tf_regs[inst.RType.rs];
83 		else if (allowNonBranch)
84 			nextpc = instpc + 4;
85 		else
86 			panic("%s: %s instruction %08x at pc 0x%"PRIxVADDR,
87 			    __func__, "non-branch", inst.word, instpc);
88 		break;
89 
90 	case OP_REGIMM:
91 		switch ((int)inst.IType.rt) {
92 		case OP_BLTZ:
93 		case OP_BLTZAL:
94 		case OP_BLTZL:		/* squashed */
95 		case OP_BLTZALL:	/* squashed */
96 			if ((int)(tf->tf_regs[inst.RType.rs]) < 0)
97 				nextpc = BRANCHTARGET(instpc, inst);
98 			else
99 				nextpc = instpc + 8;
100 			break;
101 
102 		case OP_BGEZ:
103 		case OP_BGEZAL:
104 		case OP_BGEZL:		/* squashed */
105 		case OP_BGEZALL:	/* squashed */
106 			if ((int)(tf->tf_regs[inst.RType.rs]) >= 0)
107 				nextpc = BRANCHTARGET(instpc, inst);
108 			else
109 				nextpc = instpc + 8;
110 			break;
111 
112 		default:
113 			panic("%s: %s instruction 0x%08x at pc 0x%"PRIxVADDR,
114 			    __func__, "bad branch", inst.word, instpc);
115 		}
116 		break;
117 
118 	case OP_J:
119 	case OP_JAL:
120 		nextpc = (inst.JType.target << 2) |
121 			((intptr_t)instpc & 0xF0000000);
122 		break;
123 
124 	case OP_BEQ:
125 	case OP_BEQL:	/* squashed */
126 		if (tf->tf_regs[inst.RType.rs] == tf->tf_regs[inst.RType.rt])
127 			nextpc = BRANCHTARGET(instpc, inst);
128 		else
129 			nextpc = instpc + 8;
130 		break;
131 
132 	case OP_BNE:
133 	case OP_BNEL:	/* squashed */
134 		if (tf->tf_regs[inst.RType.rs] != tf->tf_regs[inst.RType.rt])
135 			nextpc = BRANCHTARGET(instpc, inst);
136 		else
137 			nextpc = instpc + 8;
138 		break;
139 
140 	case OP_BLEZ:
141 	case OP_BLEZL:	/* squashed */
142 		if ((int)(tf->tf_regs[inst.RType.rs]) <= 0)
143 			nextpc = BRANCHTARGET(instpc, inst);
144 		else
145 			nextpc = instpc + 8;
146 		break;
147 
148 	case OP_BGTZ:
149 	case OP_BGTZL:	/* squashed */
150 		if ((int)(tf->tf_regs[inst.RType.rs]) > 0)
151 			nextpc = BRANCHTARGET(instpc, inst);
152 		else
153 			nextpc = instpc + 8;
154 		break;
155 
156 	case OP_COP1:
157 		if (inst.RType.rs == OP_BCx || inst.RType.rs == OP_BCy) {
158 			int condition = (fpuCSR & MIPS_FCSR_FCC0) != 0;
159 			if ((inst.RType.rt & COPz_BC_TF_MASK) != COPz_BC_TRUE)
160 				condition = !condition;
161 			if (condition)
162 				nextpc = BRANCHTARGET(instpc, inst);
163 			else
164 				nextpc = instpc + 8;
165 		}
166 		else if (allowNonBranch)
167 			nextpc = instpc + 4;
168 		else
169 			panic("%s: %s instruction 0x%08x at pc 0x%"PRIxVADDR,
170 			    __func__, "bad COP1 branch", inst.word, instpc);
171 		break;
172 
173 	default:
174 		if (!allowNonBranch)
175 			panic("%s: %s instruction 0x%08x at pc 0x%"PRIxVADDR,
176 			    __func__, "non-branch", inst.word, instpc);
177 		nextpc = instpc + 4;
178 	}
179 	KASSERT((nextpc & 0x3) == 0);
180 	return nextpc;
181 #undef	BRANCHTARGET
182 }
183 
184 /*
185  * Emulate instructions (including floating-point instructions)
186  */
187 void
mips_emul_inst(uint32_t status,uint32_t cause,vaddr_t opc,struct trapframe * tf)188 mips_emul_inst(uint32_t status, uint32_t cause, vaddr_t opc,
189     struct trapframe *tf)
190 {
191 	uint32_t inst;
192 	ksiginfo_t ksi;
193 	int code = ILL_ILLOPC;
194 
195 	/*
196 	 *  Fetch the instruction.
197 	 */
198 	if (cause & MIPS_CR_BR_DELAY)
199 		inst = mips_ufetch32((uint32_t *)opc+1);
200 	else
201 		inst = mips_ufetch32((uint32_t *)opc);
202 
203 	switch (((InstFmt)inst).FRType.op) {
204 	case OP_LL:
205 		mips_emul_ll(inst, tf, cause);
206 		break;
207 	case OP_SC:
208 		mips_emul_sc(inst, tf, cause);
209 		break;
210 	case OP_SPECIAL:
211 		mips_emul_special(inst, tf, cause);
212 		break;
213 	case OP_SPECIAL3:
214 		mips_emul_special3(inst, tf, cause);
215 		break;
216 	case OP_COP1:
217 #if defined(FPEMUL)
218 		mips_emul_fp(inst, tf, cause);
219 		break;
220 #endif
221 	case OP_LWC1:
222 #if defined(FPEMUL)
223 		mips_emul_lwc1(inst, tf, cause);
224 		break;
225 #endif
226 	case OP_LDC1:
227 #if defined(FPEMUL)
228 		mips_emul_ldc1(inst, tf, cause);
229 		break;
230 #endif
231 	case OP_SWC1:
232 #if defined(FPEMUL)
233 		mips_emul_swc1(inst, tf, cause);
234 		break;
235 #endif
236 	case OP_SDC1:
237 #if defined(FPEMUL)
238 		mips_emul_sdc1(inst, tf, cause);
239 		break;
240 #else
241 		code = ILL_COPROC;
242 		/* FALLTHROUGH */
243 #endif
244 	default:
245 #ifdef DEBUG
246 		printf("pid %d (%s): trap: bad insn @ %#"PRIxVADDR
247 		    " cause %#x status %#"PRIxREGISTER" insn %#x code %d\n",
248 		    curproc->p_pid, curproc->p_comm, opc,
249 		    cause, tf->tf_regs[_R_SR], inst, code);
250 #endif
251 		tf->tf_regs[_R_CAUSE] = cause;
252 		tf->tf_regs[_R_BADVADDR] = opc;
253 		KSI_INIT_TRAP(&ksi);
254 		ksi.ksi_signo = SIGILL;
255 		ksi.ksi_trap = cause; /* XXX */
256 		ksi.ksi_code = code;
257 		ksi.ksi_addr = (void *)opc;
258 		(*curproc->p_emul->e_trapsignal)(curlwp, &ksi);
259 		break;
260 	}
261 }
262 
263 static inline void
send_sigsegv(intptr_t vaddr,uint32_t exccode,struct trapframe * tf,uint32_t cause)264 send_sigsegv(intptr_t vaddr, uint32_t exccode, struct trapframe *tf,
265     uint32_t cause)
266 {
267 	ksiginfo_t ksi;
268 	cause = (cause & ~0xFF) | (exccode << MIPS_CR_EXC_CODE_SHIFT);
269 	tf->tf_regs[_R_CAUSE] = cause;
270 	tf->tf_regs[_R_BADVADDR] = vaddr;
271 	KSI_INIT_TRAP(&ksi);
272 	ksi.ksi_signo = SIGSEGV;
273 	ksi.ksi_trap = cause;
274 	ksi.ksi_code = SEGV_MAPERR;
275 	ksi.ksi_addr = (void *)vaddr;
276 	(*curproc->p_emul->e_trapsignal)(curlwp, &ksi);
277 }
278 
279 static inline void
update_pc(struct trapframe * tf,uint32_t cause)280 update_pc(struct trapframe *tf, uint32_t cause)
281 {
282 
283 	if (cause & MIPS_CR_BR_DELAY)
284 		tf->tf_regs[_R_PC] =
285 		    mips_emul_branch(tf, tf->tf_regs[_R_PC],
286 			PCB_FSR(curpcb), 0);
287 	else
288 		tf->tf_regs[_R_PC] += 4;
289 }
290 
291 /*
292  * MIPS2 LL instruction
293  */
294 void
mips_emul_ll(uint32_t inst,struct trapframe * tf,uint32_t cause)295 mips_emul_ll(uint32_t inst, struct trapframe *tf, uint32_t cause)
296 {
297 	intptr_t	vaddr;
298 	int16_t		offset;
299 	void		*t;
300 
301 	offset = inst & 0xFFFF;
302 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
303 
304 	/* segment and alignment check */
305 	if (vaddr < 0 || (vaddr & 3)) {
306 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
307 		return;
308 	}
309 
310 	t = &(tf->tf_regs[(inst>>16)&0x1F]);
311 
312 	if (copyin((void *)vaddr, t, 4) != 0) {
313 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
314 		return;
315 	}
316 
317 	llstate.lwp = curlwp;
318 	llstate.addr = vaddr;
319 	llstate.value = *((uint32_t *)t);
320 
321 	update_pc(tf, cause);
322 }
323 
324 /*
325  * MIPS2 SC instruction
326  */
327 void
mips_emul_sc(uint32_t inst,struct trapframe * tf,uint32_t cause)328 mips_emul_sc(uint32_t inst, struct trapframe *tf, uint32_t cause)
329 {
330 	intptr_t	vaddr;
331 	uint32_t	value;
332 	int16_t		offset;
333 	mips_reg_t	*t;
334 
335 	offset = inst & 0xFFFF;
336 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
337 
338 	/* segment and alignment check */
339 	if (vaddr < 0 || (vaddr & 3)) {
340 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
341 		return;
342 	}
343 
344 	t = (mips_reg_t *)&(tf->tf_regs[(inst>>16)&0x1F]);
345 
346 	/*
347 	 * Check that the process and address match the last
348 	 * LL instruction.
349 	 */
350 	if (curlwp == llstate.lwp && vaddr == llstate.addr) {
351 		llstate.lwp = NULL;
352 		/*
353 		 * Check that the data at the address hasn't changed
354 		 * since the LL instruction.
355 		 */
356 		if (copyin((void *)vaddr, &value, 4) != 0) {
357 			send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
358 			return;
359 		}
360 		if (value == llstate.value) {
361 			/* SC successful */
362 			if (copyout(t, (void *)vaddr, 4) != 0) {
363 				send_sigsegv(vaddr, T_TLB_ST_MISS,
364 				    tf, cause);
365 				return;
366 			}
367 			*t = 1;
368 			update_pc(tf, cause);
369 			return;
370 		}
371 	}
372 
373 	/* SC failed */
374 	*t = 0;
375 	update_pc(tf, cause);
376 }
377 
378 void
mips_emul_special(uint32_t inst,struct trapframe * tf,uint32_t cause)379 mips_emul_special(uint32_t inst, struct trapframe *tf, uint32_t cause)
380 {
381 	ksiginfo_t ksi;
382 	const InstFmt instfmt = { .word = inst };
383 
384 	switch (instfmt.RType.func) {
385 	case OP_SYNC:
386 		/* nothing */
387 		break;
388 	default:
389 		tf->tf_regs[_R_CAUSE] = cause;
390 		tf->tf_regs[_R_BADVADDR] = tf->tf_regs[_R_PC];
391 		KSI_INIT_TRAP(&ksi);
392 		ksi.ksi_signo = SIGILL;
393 		ksi.ksi_trap = cause;
394 		ksi.ksi_code = ILL_ILLOPC;
395 		ksi.ksi_addr = (void *)(intptr_t)tf->tf_regs[_R_PC];
396 		(*curproc->p_emul->e_trapsignal)(curlwp, &ksi);
397 		break;
398 	}
399 
400 	update_pc(tf, cause);
401 }
402 
403 void
mips_emul_special3(uint32_t inst,struct trapframe * tf,uint32_t cause)404 mips_emul_special3(uint32_t inst, struct trapframe *tf, uint32_t cause)
405 {
406 	ksiginfo_t ksi;
407 	const InstFmt instfmt = { .word = inst };
408 	switch (instfmt.RType.func) {
409 	case OP_LX: {
410 		const intptr_t vaddr = tf->tf_regs[instfmt.RType.rs]
411 		    + tf->tf_regs[instfmt.RType.rt];
412 		mips_reg_t r;
413 		int error = EFAULT;
414 		if (vaddr < 0) {
415 		    addr_err:
416 			send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
417 			return;
418 		}
419 		switch (instfmt.RType.shamt) {
420 #if !defined(__mips_o32)
421 		case OP_LX_LDX: {
422 			uint64_t tmp64;
423 			if (vaddr & 7)
424 				goto addr_err;
425 			error = copyin((void *)vaddr, &tmp64, sizeof(tmp64));
426 			r = tmp64;
427 			break;
428 		}
429 #endif
430 		case OP_LX_LWX: {
431 			int32_t tmp32;
432 			if (vaddr & 3)
433 				goto addr_err;
434 			error = copyin((void *)vaddr, &tmp32, sizeof(tmp32));
435 			r = tmp32;
436 			break;
437 		}
438 		case OP_LX_LHX: {
439 			int16_t tmp16;
440 			if (vaddr & 1)
441 				goto addr_err;
442 			error = copyin((void *)vaddr, &tmp16, sizeof(tmp16));
443 			r = tmp16;
444 			break;
445 		}
446 		case OP_LX_LBUX: {
447 			uint8_t tmp8;
448 			error = copyin((void *)vaddr, &tmp8, sizeof(tmp8));
449 			r = tmp8;
450 			break;
451 		}
452 		default:
453 			goto illopc;
454 		}
455 		if (error) {
456 			send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
457 			return;
458 		}
459 		tf->tf_regs[instfmt.RType.rd] = r;
460 		break;
461 	}
462 	case OP_RDHWR:
463 		switch (instfmt.RType.rd) {
464 		case MIPS_HWR_ULR:
465 			tf->tf_regs[instfmt.RType.rt] =
466 			    (mips_reg_t)(intptr_t)curlwp->l_private;
467 			goto done;
468 		}
469 		/* FALLTHROUGH */
470 	illopc:
471 	default:
472 		tf->tf_regs[_R_CAUSE] = cause;
473 		tf->tf_regs[_R_BADVADDR] = tf->tf_regs[_R_PC];
474 		KSI_INIT_TRAP(&ksi);
475 		ksi.ksi_signo = SIGILL;
476 		ksi.ksi_trap = cause;
477 		ksi.ksi_code = ILL_ILLOPC;
478 		ksi.ksi_addr = (void *)(intptr_t)tf->tf_regs[_R_PC];
479 		(*curproc->p_emul->e_trapsignal)(curlwp, &ksi);
480 		return;
481 	}
482 done:
483 	update_pc(tf, cause);
484 }
485 
486 #if defined(FPEMUL)
487 
488 #define LWSWC1_MAXLOOP	12
489 
490 void
mips_emul_lwc1(uint32_t inst,struct trapframe * tf,uint32_t cause)491 mips_emul_lwc1(uint32_t inst, struct trapframe *tf, uint32_t cause)
492 {
493 	intptr_t	vaddr;
494 	int16_t		offset;
495 	void		*t;
496 	mips_reg_t	pc;
497 	int		i;
498 
499 	offset = inst & 0xFFFF;
500 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
501 
502 	/* segment and alignment check */
503 	if (vaddr < 0 || (vaddr & 3)) {
504 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
505 		return;
506 	}
507 
508 	/* NewABI FIXME */
509 	t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]);
510 
511 	if (copyin((void *)vaddr, t, 4) != 0) {
512 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
513 		return;
514 	}
515 
516 	pc = tf->tf_regs[_R_PC];
517 	update_pc(tf, cause);
518 
519 	if (cause & MIPS_CR_BR_DELAY)
520 		return;
521 
522 	for (i = 1; i < LWSWC1_MAXLOOP; i++) {
523 		if (mips_btop(tf->tf_regs[_R_PC]) != mips_btop(pc))
524 			return;
525 
526 		vaddr = tf->tf_regs[_R_PC];	/* XXX truncates to 32 bits */
527 		inst = mips_ufetch32((uint32_t *)vaddr);
528 		if (((InstFmt)inst).FRType.op != OP_LWC1)
529 			return;
530 
531 		offset = inst & 0xFFFF;
532 		vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
533 
534 		/* segment and alignment check */
535 		if (vaddr < 0 || (vaddr & 3)) {
536 			send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
537 			return;
538 		}
539 
540 		/* NewABI FIXME */
541 		t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]);
542 
543 		if (copyin((void *)vaddr, t, 4) != 0) {
544 			send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
545 			return;
546 		}
547 
548 		pc = tf->tf_regs[_R_PC];
549 		update_pc(tf, cause);
550 	}
551 }
552 
553 void
mips_emul_ldc1(uint32_t inst,struct trapframe * tf,uint32_t cause)554 mips_emul_ldc1(uint32_t inst, struct trapframe *tf, uint32_t cause)
555 {
556 	intptr_t	vaddr;
557 	int16_t		offset;
558 	void		*t;
559 
560 	offset = inst & 0xFFFF;
561 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
562 
563 	/* segment and alignment check */
564 	if (vaddr < 0  || (vaddr & 7)) {
565 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
566 		return;
567 	}
568 
569 	/* NewABI FIXME */
570 	t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1E]);
571 
572 	if (copyin((void *)vaddr, t, 8) != 0) {
573 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
574 		return;
575 	}
576 
577 	update_pc(tf, cause);
578 }
579 
580 void
mips_emul_swc1(uint32_t inst,struct trapframe * tf,uint32_t cause)581 mips_emul_swc1(uint32_t inst, struct trapframe *tf, uint32_t cause)
582 {
583 	intptr_t	vaddr;
584 	int16_t		offset;
585 	void		*t;
586 	mips_reg_t	pc;
587 	int		i;
588 
589 	offset = inst & 0xFFFF;
590 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
591 
592 	/* segment and alignment check */
593 	if (vaddr < 0 || (vaddr & 3)) {
594 		send_sigsegv(vaddr, T_ADDR_ERR_ST, tf, cause);
595 		return;
596 	}
597 
598 	/* NewABI FIXME */
599 	t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]);
600 
601 	if (copyout(t, (void *)vaddr, 4) != 0) {
602 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
603 		return;
604 	}
605 
606 	pc = tf->tf_regs[_R_PC];
607 	update_pc(tf, cause);
608 
609 	if (cause & MIPS_CR_BR_DELAY)
610 		return;
611 
612 	for (i = 1; i < LWSWC1_MAXLOOP; i++) {
613 		if (mips_btop(tf->tf_regs[_R_PC]) != mips_btop(pc))
614 			return;
615 
616 		vaddr = tf->tf_regs[_R_PC];	/* XXX truncates to 32 bits */
617 		inst = mips_ufetch32((uint32_t *)vaddr);
618 		if (((InstFmt)inst).FRType.op != OP_SWC1)
619 			return;
620 
621 		offset = inst & 0xFFFF;
622 		vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
623 
624 		/* segment and alignment check */
625 		if (vaddr < 0 || (vaddr & 3)) {
626 			send_sigsegv(vaddr, T_ADDR_ERR_ST, tf, cause);
627 			return;
628 		}
629 
630 		/* NewABI FIXME */
631 		t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]);
632 
633 		if (copyout(t, (void *)vaddr, 4) != 0) {
634 			send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
635 			return;
636 		}
637 
638 		pc = tf->tf_regs[_R_PC];
639 		update_pc(tf, cause);
640 	}
641 }
642 
643 void
mips_emul_sdc1(uint32_t inst,struct trapframe * tf,uint32_t cause)644 mips_emul_sdc1(uint32_t inst, struct trapframe *tf, uint32_t cause)
645 {
646 	intptr_t	vaddr;
647 	int16_t		offset;
648 	void		*t;
649 
650 	offset = inst & 0xFFFF;
651 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
652 
653 	/* segment and alignment check */
654 	if (vaddr < 0 || (vaddr & 7)) {
655 		send_sigsegv(vaddr, T_ADDR_ERR_ST, tf, cause);
656 		return;
657 	}
658 
659 	/* NewABI FIXME */
660 	t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1E]);
661 
662 	if (copyout(t, (void *)vaddr, 8) != 0) {
663 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
664 		return;
665 	}
666 
667 	update_pc(tf, cause);
668 }
669 
670 void
mips_emul_lb(uint32_t inst,struct trapframe * tf,uint32_t cause)671 mips_emul_lb(uint32_t inst, struct trapframe *tf, uint32_t cause)
672 {
673 	intptr_t	vaddr;
674 	int16_t		offset;
675 	int8_t		x;
676 
677 	offset = inst & 0xFFFF;
678 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
679 
680 	/* segment check */
681 	if (vaddr < 0) {
682 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
683 		return;
684 	}
685 
686 	if (copyin((void *)vaddr, &x, 1) != 0) {
687 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
688 		return;
689 	}
690 
691 	tf->tf_regs[(inst>>16)&0x1F] = x;
692 
693 	update_pc(tf, cause);
694 }
695 
696 void
mips_emul_lbu(uint32_t inst,struct trapframe * tf,uint32_t cause)697 mips_emul_lbu(uint32_t inst, struct trapframe *tf, uint32_t cause)
698 {
699 	intptr_t	vaddr;
700 	int16_t		offset;
701 	uint8_t		x;
702 
703 	offset = inst & 0xFFFF;
704 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
705 
706 	/* segment check */
707 	if (vaddr < 0) {
708 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
709 		return;
710 	}
711 
712 	if (copyin((void *)vaddr, &x, 1) != 0) {
713 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
714 		return;
715 	}
716 
717 	tf->tf_regs[(inst>>16)&0x1F] = x;
718 
719 	update_pc(tf, cause);
720 }
721 
722 void
mips_emul_lh(uint32_t inst,struct trapframe * tf,uint32_t cause)723 mips_emul_lh(uint32_t inst, struct trapframe *tf, uint32_t cause)
724 {
725 	intptr_t	vaddr;
726 	int16_t		offset;
727 	int16_t		x;
728 
729 	offset = inst & 0xFFFF;
730 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
731 
732 	/* segment and alignment check */
733 	if (vaddr < 0 || (vaddr & 1)) {
734 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
735 		return;
736 	}
737 
738 	if (copyin((void *)vaddr, &x, 2) != 0) {
739 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
740 		return;
741 	}
742 
743 	tf->tf_regs[(inst>>16)&0x1F] = x;
744 
745 	update_pc(tf, cause);
746 }
747 
748 void
mips_emul_lhu(uint32_t inst,struct trapframe * tf,uint32_t cause)749 mips_emul_lhu(uint32_t inst, struct trapframe *tf, uint32_t cause)
750 {
751 	intptr_t	vaddr;
752 	int16_t		offset;
753 	uint16_t	x;
754 
755 	offset = inst & 0xFFFF;
756 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
757 
758 	/* segment and alignment check */
759 	if (vaddr < 0 || (vaddr & 1)) {
760 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
761 		return;
762 	}
763 
764 	if (copyin((void *)vaddr, &x, 2) != 0) {
765 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
766 		return;
767 	}
768 
769 	tf->tf_regs[(inst>>16)&0x1F] = (mips_ureg_t)x;
770 
771 	update_pc(tf, cause);
772 }
773 
774 void
mips_emul_lw(uint32_t inst,struct trapframe * tf,uint32_t cause)775 mips_emul_lw(uint32_t inst, struct trapframe *tf, uint32_t cause)
776 {
777 	intptr_t	vaddr;
778 	int16_t		offset;
779 	int32_t		x;
780 
781 	offset = inst & 0xFFFF;
782 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
783 
784 	/* segment and alignment check */
785 	if (vaddr < 0 || (vaddr & 3)) {
786 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
787 		return;
788 	}
789 
790 	if (copyin((void *)vaddr, &x, 4) != 0) {
791 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
792 		return;
793 	}
794 
795 	tf->tf_regs[(inst>>16)&0x1F] = x;
796 
797 	update_pc(tf, cause);
798 }
799 
800 void
mips_emul_lwl(uint32_t inst,struct trapframe * tf,uint32_t cause)801 mips_emul_lwl(uint32_t inst, struct trapframe *tf, uint32_t cause)
802 {
803 	intptr_t	vaddr;
804 	uint32_t	a, x, shift;
805 	int16_t		offset;
806 
807 	offset = inst & 0xFFFF;
808 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
809 
810 	/* segment check */
811 	if (vaddr < 0) {
812 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
813 		return;
814 	}
815 
816 	if (copyin((void *)(vaddr & ~3), &a, 4) != 0) {
817 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
818 		return;
819 	}
820 
821 	x = tf->tf_regs[(inst>>16)&0x1F];
822 
823 	shift = (3 - (vaddr & 0x00000003)) * 8;
824 	a <<= shift;
825 	x &= ~(0xFFFFFFFFUL << shift);
826 	x |= a;
827 
828 	tf->tf_regs[(inst>>16)&0x1F] = x;
829 
830 	update_pc(tf, cause);
831 }
832 
833 void
mips_emul_lwr(uint32_t inst,struct trapframe * tf,uint32_t cause)834 mips_emul_lwr(uint32_t inst, struct trapframe *tf, uint32_t cause)
835 {
836 	intptr_t	vaddr;
837 	uint32_t	a, x, shift;
838 	int16_t		offset;
839 
840 	offset = inst & 0xFFFF;
841 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
842 
843 	/* segment check */
844 	if (vaddr & 0x80000000) {
845 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
846 		return;
847 	}
848 
849 	if (copyin((void *)(vaddr & ~3), &a, 4) != 0) {
850 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
851 		return;
852 	}
853 
854 	x = tf->tf_regs[(inst>>16)&0x1F];
855 
856 	shift = (vaddr & 0x00000003) * 8;
857 	a >>= shift;
858 	x &= ~(0xFFFFFFFFUL >> shift);
859 	x |= a;
860 
861 	tf->tf_regs[(inst>>16)&0x1F] = x;
862 
863 	update_pc(tf, cause);
864 }
865 
866 #if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64)
867 void
mips_emul_lwu(uint32_t inst,struct trapframe * tf,uint32_t cause)868 mips_emul_lwu(uint32_t inst, struct trapframe *tf, uint32_t cause)
869 {
870 	intptr_t	vaddr;
871 	int16_t		offset;
872 	uint32_t	x;
873 
874 	offset = inst & 0xFFFF;
875 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
876 
877 	/* segment and alignment check */
878 	if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
879 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
880 		return;
881 	}
882 
883 	if (copyin((void *)vaddr, &x, 4) != 0) {
884 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
885 		return;
886 	}
887 
888 	tf->tf_regs[(inst>>16)&0x1F] = x;
889 
890 	update_pc(tf, cause);
891 }
892 
893 void
mips_emul_ld(uint32_t inst,struct trapframe * tf,uint32_t cause)894 mips_emul_ld(uint32_t inst, struct trapframe *tf, uint32_t cause)
895 {
896 	intptr_t	vaddr;
897 	int16_t		offset;
898 
899 	offset = inst & 0xFFFF;
900 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
901 
902 	/* segment and alignment check */
903 	if (vaddr > VM_MAX_ADDRESS || vaddr & 0x7) {
904 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
905 		return;
906 	}
907 
908 	if (copyin((void *)vaddr, &(tf->tf_regs[(inst>>16)&0x1F]), 8) != 0) {
909 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
910 		return;
911 	}
912 
913 	update_pc(tf, cause);
914 }
915 
916 void
mips_emul_ldl(uint32_t inst,struct trapframe * tf,uint32_t cause)917 mips_emul_ldl(uint32_t inst, struct trapframe *tf, uint32_t cause)
918 {
919 	intptr_t	vaddr;
920 	uint64_t	a, x;
921 	uint32_t	shift;
922 	int16_t		offset;
923 
924 	offset = inst & 0xFFFF;
925 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
926 
927 	/* segment check */
928 	if (vaddr & 0x80000000) {
929 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
930 		return;
931 	}
932 
933 	if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) {
934 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
935 		return;
936 	}
937 
938 	x = tf->tf_regs[(inst>>16)&0x1F];
939 
940 	shift = (7 - (vaddr & 0x7)) * 8;
941 	a <<= shift;
942 	x &= ~(~(uint64_t)0UL << shift);
943 	x |= a;
944 
945 	tf->tf_regs[(inst>>16)&0x1F] = x;
946 
947 	update_pc(tf, cause);
948 }
949 
950 void
mips_emul_ldr(uint32_t inst,struct trapframe * tf,uint32_t cause)951 mips_emul_ldr(uint32_t inst, struct trapframe *tf, uint32_t cause)
952 {
953 	intptr_t	vaddr;
954 	uint64_t	a, x;
955 	uint32_t	shift;
956 	int16_t		offset;
957 
958 	offset = inst & 0xFFFF;
959 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
960 
961 	/* segment check */
962 	if (vaddr < 0) {
963 		send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause);
964 		return;
965 	}
966 
967 	if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) {
968 		send_sigsegv(vaddr, T_TLB_LD_MISS, tf, cause);
969 		return;
970 	}
971 
972 	x = tf->tf_regs[(inst>>16)&0x1F];
973 
974 	shift = (vaddr & 0x7) * 8;
975 	a >>= shift;
976 	x &= ~(~(uint64_t)0UL >> shift);
977 	x |= a;
978 
979 	tf->tf_regs[(inst>>16)&0x1F] = x;
980 
981 	update_pc(tf, cause);
982 }
983 #endif /* defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) */
984 
985 void
mips_emul_sb(uint32_t inst,struct trapframe * tf,uint32_t cause)986 mips_emul_sb(uint32_t inst, struct trapframe *tf, uint32_t cause)
987 {
988 	intptr_t	vaddr;
989 	int16_t		offset;
990 
991 	offset = inst & 0xFFFF;
992 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
993 
994 	/* segment check */
995 	if (vaddr < 0) {
996 		send_sigsegv(vaddr, T_ADDR_ERR_ST, tf, cause);
997 		return;
998 	}
999 
1000 	if (ustore_8((void *)vaddr, tf->tf_regs[(inst>>16)&0x1F]) != 0) {
1001 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
1002 		return;
1003 	}
1004 
1005 	update_pc(tf, cause);
1006 }
1007 
1008 void
mips_emul_sh(uint32_t inst,struct trapframe * tf,uint32_t cause)1009 mips_emul_sh(uint32_t inst, struct trapframe *tf, uint32_t cause)
1010 {
1011 	intptr_t	vaddr;
1012 	int16_t		offset;
1013 
1014 	offset = inst & 0xFFFF;
1015 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
1016 
1017 	/* segment and alignment check */
1018 	if (vaddr < 0 || vaddr & 1) {
1019 		send_sigsegv(vaddr, T_ADDR_ERR_ST, tf, cause);
1020 		return;
1021 	}
1022 
1023 	if (ustore_16((void *)vaddr, tf->tf_regs[(inst>>16)&0x1F]) != 0) {
1024 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
1025 		return;
1026 	}
1027 
1028 	update_pc(tf, cause);
1029 }
1030 
1031 void
mips_emul_sw(uint32_t inst,struct trapframe * tf,uint32_t cause)1032 mips_emul_sw(uint32_t inst, struct trapframe *tf, uint32_t cause)
1033 {
1034 	intptr_t	vaddr;
1035 	int16_t		offset;
1036 
1037 	offset = inst & 0xFFFF;
1038 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
1039 
1040 	/* segment and alignment check */
1041 	if (vaddr < 0 || (vaddr & 3)) {
1042 		send_sigsegv(vaddr, T_ADDR_ERR_ST, tf, cause);
1043 		return;
1044 	}
1045 
1046 	if (ustore_32((void *)vaddr, tf->tf_regs[(inst>>16)&0x1F]) != 0) {
1047 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
1048 		return;
1049 	}
1050 
1051 	update_pc(tf, cause);
1052 }
1053 
1054 void
mips_emul_swl(uint32_t inst,struct trapframe * tf,uint32_t cause)1055 mips_emul_swl(uint32_t inst, struct trapframe *tf, uint32_t cause)
1056 {
1057 	intptr_t	vaddr;
1058 	uint32_t	a, x, shift;
1059 	int16_t		offset;
1060 
1061 	offset = inst & 0xFFFF;
1062 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
1063 
1064 	/* segment check */
1065 	if (vaddr < 0) {
1066 		send_sigsegv(vaddr, T_ADDR_ERR_ST, tf, cause);
1067 		return;
1068 	}
1069 
1070 	if (copyin((void *)(vaddr & ~3), &a, 4) != 0) {
1071 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
1072 		return;
1073 	}
1074 
1075 	x = tf->tf_regs[(inst>>16)&0x1F];
1076 
1077 	shift = (3 - (vaddr & 3)) * 8;
1078 	x >>= shift;
1079 	a &= ~(0xFFFFFFFFUL >> shift);
1080 	a |= x;
1081 
1082 	if (ustore_32((void *)vaddr, a) != 0) {
1083 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
1084 		return;
1085 	}
1086 
1087 	update_pc(tf, cause);
1088 }
1089 
1090 void
mips_emul_swr(uint32_t inst,struct trapframe * tf,uint32_t cause)1091 mips_emul_swr(uint32_t inst, struct trapframe *tf, uint32_t cause)
1092 {
1093 	intptr_t	vaddr;
1094 	uint32_t	a, x, shift;
1095 	int16_t		offset;
1096 
1097 	offset = inst & 0xFFFF;
1098 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
1099 
1100 	/* segment check */
1101 	if (vaddr < 0) {
1102 		send_sigsegv(vaddr, T_ADDR_ERR_ST, tf, cause);
1103 		return;
1104 	}
1105 
1106 	if (copyin((void *)(vaddr & ~3), &a, 4) != 0) {
1107 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
1108 		return;
1109 	}
1110 
1111 	x = tf->tf_regs[(inst>>16)&0x1F];
1112 
1113 	shift = (vaddr & 3) * 8;
1114 	x <<= shift;
1115 	a &= ~(0xFFFFFFFFUL << shift);
1116 	a |= x;
1117 
1118 	if (ustore_32((void *)vaddr, a) != 0) {
1119 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
1120 		return;
1121 	}
1122 
1123 	update_pc(tf, cause);
1124 }
1125 
1126 #if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64)
1127 void
mips_emul_sd(uint32_t inst,struct trapframe * tf,uint32_t cause)1128 mips_emul_sd(uint32_t inst, struct trapframe *tf, uint32_t cause)
1129 {
1130 	intptr_t	vaddr;
1131 	int16_t		offset;
1132 
1133 	offset = inst & 0xFFFF;
1134 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
1135 
1136 	/* segment and alignment check */
1137 	if (vaddr < 0 || vaddr & 0x7) {
1138 		send_sigsegv(vaddr, T_ADDR_ERR_ST, tf, cause);
1139 		return;
1140 	}
1141 
1142 	if (copyout((void *)vaddr, &tf->tf_regs[(inst>>16)&0x1F], 8) < 0) {
1143 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
1144 		return;
1145 	}
1146 
1147 	update_pc(tf, cause);
1148 }
1149 
1150 void
mips_emul_sdl(uint32_t inst,struct trapframe * tf,uint32_t cause)1151 mips_emul_sdl(uint32_t inst, struct trapframe *tf, uint32_t cause)
1152 {
1153 	intptr_t	vaddr;
1154 	uint64_t	a, x;
1155 	uint32_t	shift;
1156 	int16_t		offset;
1157 
1158 	offset = inst & 0xFFFF;
1159 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
1160 
1161 	/* segment check */
1162 	if (vaddr < 0) {
1163 		send_sigsegv(vaddr, T_ADDR_ERR_ST, tf, cause);
1164 		return;
1165 	}
1166 
1167 	if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) {
1168 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
1169 		return;
1170 	}
1171 
1172 	x = tf->tf_regs[(inst>>16)&0x1F];
1173 
1174 	shift = (7 - (vaddr & 7)) * 8;
1175 	x >>= shift;
1176 	a &= ~(~(uint64_t)0U >> shift);
1177 	a |= x;
1178 
1179 	if (copyout((void *)(vaddr & ~0x7), &a, 8) != 0) {
1180 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
1181 		return;
1182 	}
1183 
1184 	update_pc(tf, cause);
1185 }
1186 
1187 void
mips_emul_sdr(uint32_t inst,struct trapframe * tf,uint32_t cause)1188 mips_emul_sdr(uint32_t inst, struct trapframe *tf, uint32_t cause)
1189 {
1190 	intptr_t	vaddr;
1191 	uint64_t	a, x;
1192 	uint32_t	shift;
1193 	int16_t		offset;
1194 
1195 	offset = inst & 0xFFFF;
1196 	vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset;
1197 
1198 	/* segment check */
1199 	if (vaddr < 0) {
1200 		send_sigsegv(vaddr, T_ADDR_ERR_ST, tf, cause);
1201 		return;
1202 	}
1203 
1204 	if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) {
1205 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
1206 		return;
1207 	}
1208 
1209 	x = tf->tf_regs[(inst>>16)&0x1F];
1210 
1211 	shift = (vaddr & 7) * 8;
1212 	x <<= shift;
1213 	a &= ~(~(uint64_t)0U << shift);
1214 	a |= x;
1215 
1216 	if (copyout((void *)(vaddr & ~0x7), &a, 8) != 0) {
1217 		send_sigsegv(vaddr, T_TLB_ST_MISS, tf, cause);
1218 		return;
1219 	}
1220 
1221 	update_pc(tf, cause);
1222 }
1223 #endif /* defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) */
1224 #endif /* defined(FPEMUL) */
1225