xref: /netbsd/sys/arch/mips/mips/mips_emul.c (revision 6550d01e)
1 /*	$NetBSD: mips_emul.c,v 1.21 2011/02/01 06:46:46 matt 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.21 2011/02/01 06:46:46 matt 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 void MachEmulateFP(uint32_t, struct frame *, uint32_t);
47 
48 static inline void	send_sigsegv(intptr_t, uint32_t, struct frame *,
49 			    uint32_t);
50 static inline void	update_pc(struct frame *, uint32_t);
51 
52 vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned, int);
53 void	MachEmulateInst(uint32_t, uint32_t, vaddr_t, struct frame *);
54 
55 void	MachEmulateLWC0(uint32_t, struct frame *, uint32_t);
56 void	MachEmulateSWC0(uint32_t, struct frame *, uint32_t);
57 void	MachEmulateSpecial(uint32_t, struct frame *, uint32_t);
58 void	MachEmulateSpecial3(uint32_t, struct frame *, uint32_t);
59 void	MachEmulateLWC1(uint32_t, struct frame *, uint32_t);
60 void	MachEmulateLDC1(uint32_t, struct frame *, uint32_t);
61 void	MachEmulateSWC1(uint32_t, struct frame *, uint32_t);
62 void	MachEmulateSDC1(uint32_t, struct frame *, uint32_t);
63 
64 void	bcemul_lb(uint32_t, struct frame *, uint32_t);
65 void	bcemul_lbu(uint32_t, struct frame *, uint32_t);
66 void	bcemul_lh(uint32_t, struct frame *, uint32_t);
67 void	bcemul_lhu(uint32_t, struct frame *, uint32_t);
68 void	bcemul_lw(uint32_t, struct frame *, uint32_t);
69 void	bcemul_lwl(uint32_t, struct frame *, uint32_t);
70 void	bcemul_lwr(uint32_t, struct frame *, uint32_t);
71 #if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64)
72 void	bcemul_ld(uint32_t, struct frame *, uint32_t);
73 void	bcemul_ldl(uint32_t, struct frame *, uint32_t);
74 void	bcemul_ldr(uint32_t, struct frame *, uint32_t);
75 #endif
76 void	bcemul_sb(uint32_t, struct frame *, uint32_t);
77 void	bcemul_sh(uint32_t, struct frame *, uint32_t);
78 void	bcemul_sw(uint32_t, struct frame *, uint32_t);
79 void	bcemul_swl(uint32_t, struct frame *, uint32_t);
80 void	bcemul_swr(uint32_t, struct frame *f, uint32_t);
81 #if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64)
82 void	bcemul_sd(uint32_t, struct frame *, uint32_t);
83 void	bcemul_sdl(uint32_t, struct frame *, uint32_t);
84 void	bcemul_sdr(uint32_t, struct frame *f, uint32_t);
85 #endif
86 
87 /*
88  * MIPS2 LL instruction emulation state
89  */
90 struct {
91 	struct lwp *lwp;
92 	vaddr_t addr;
93 	uint32_t value;
94 } llstate;
95 
96 /*
97  * Analyse 'next' PC address taking account of branch/jump instructions
98  */
99 vaddr_t
100 MachEmulateBranch(struct frame *f, vaddr_t instpc, unsigned fpuCSR,
101     int allowNonBranch)
102 {
103 #define	BRANCHTARGET(p, i) (4 + (p) + ((short)(i).IType.imm << 2))
104 	InstFmt inst;
105 	vaddr_t nextpc;
106 
107 	if (instpc < MIPS_KSEG0_START)
108 		inst.word = fuiword((void *)instpc);
109 	else
110 		inst.word = *(unsigned *)instpc;
111 
112 	switch ((int)inst.JType.op) {
113 	case OP_SPECIAL:
114 		if (inst.RType.func == OP_JR || inst.RType.func == OP_JALR)
115 			nextpc = f->f_regs[inst.RType.rs];
116 		else if (allowNonBranch)
117 			nextpc = instpc + 4;
118 		else
119 			panic("MachEmulateBranch: Non-branch instruction at "
120 			    "pc 0x%lx", (long)instpc);
121 		break;
122 
123 	case OP_BCOND:
124 		switch ((int)inst.IType.rt) {
125 		case OP_BLTZ:
126 		case OP_BLTZAL:
127 		case OP_BLTZL:		/* squashed */
128 		case OP_BLTZALL:	/* squashed */
129 			if ((int)(f->f_regs[inst.RType.rs]) < 0)
130 				nextpc = BRANCHTARGET(instpc, inst);
131 			else
132 				nextpc = instpc + 8;
133 			break;
134 
135 		case OP_BGEZ:
136 		case OP_BGEZAL:
137 		case OP_BGEZL:		/* squashed */
138 		case OP_BGEZALL:	/* squashed */
139 			if ((int)(f->f_regs[inst.RType.rs]) >= 0)
140 				nextpc = BRANCHTARGET(instpc, inst);
141 			else
142 				nextpc = instpc + 8;
143 			break;
144 
145 		default:
146 			panic("MachEmulateBranch: Bad branch cond");
147 		}
148 		break;
149 
150 	case OP_J:
151 	case OP_JAL:
152 		nextpc = (inst.JType.target << 2) |
153 			((unsigned)instpc & 0xF0000000);
154 		break;
155 
156 	case OP_BEQ:
157 	case OP_BEQL:	/* squashed */
158 		if (f->f_regs[inst.RType.rs] == f->f_regs[inst.RType.rt])
159 			nextpc = BRANCHTARGET(instpc, inst);
160 		else
161 			nextpc = instpc + 8;
162 		break;
163 
164 	case OP_BNE:
165 	case OP_BNEL:	/* squashed */
166 		if (f->f_regs[inst.RType.rs] != f->f_regs[inst.RType.rt])
167 			nextpc = BRANCHTARGET(instpc, inst);
168 		else
169 			nextpc = instpc + 8;
170 		break;
171 
172 	case OP_BLEZ:
173 	case OP_BLEZL:	/* squashed */
174 		if ((int)(f->f_regs[inst.RType.rs]) <= 0)
175 			nextpc = BRANCHTARGET(instpc, inst);
176 		else
177 			nextpc = instpc + 8;
178 		break;
179 
180 	case OP_BGTZ:
181 	case OP_BGTZL:	/* squashed */
182 		if ((int)(f->f_regs[inst.RType.rs]) > 0)
183 			nextpc = BRANCHTARGET(instpc, inst);
184 		else
185 			nextpc = instpc + 8;
186 		break;
187 
188 	case OP_COP1:
189 		if (inst.RType.rs == OP_BCx || inst.RType.rs == OP_BCy) {
190 			int condition = (fpuCSR & MIPS_FPU_COND_BIT) != 0;
191 			if ((inst.RType.rt & COPz_BC_TF_MASK) != COPz_BC_TRUE)
192 				condition = !condition;
193 			if (condition)
194 				nextpc = BRANCHTARGET(instpc, inst);
195 			else
196 				nextpc = instpc + 8;
197 		}
198 		else if (allowNonBranch)
199 			nextpc = instpc + 4;
200 		else
201 			panic("MachEmulateBranch: Bad COP1 branch instruction");
202 		break;
203 
204 	default:
205 		if (!allowNonBranch)
206 			panic("MachEmulateBranch: Non-branch instruction at "
207 			    "pc 0x%lx", (long)instpc);
208 		nextpc = instpc + 4;
209 	}
210 	return nextpc;
211 #undef	BRANCHTARGET
212 }
213 
214 /*
215  * Emulate instructions (including floating-point instructions)
216  */
217 void
218 MachEmulateInst(uint32_t status, uint32_t cause, vaddr_t opc,
219     struct frame *frame)
220 {
221 	uint32_t inst;
222 	ksiginfo_t ksi;
223 
224 	/*
225 	 *  Fetch the instruction.
226 	 */
227 	if (cause & MIPS_CR_BR_DELAY)
228 		inst = ufetch_uint32((uint32_t *)opc+1);
229 	else
230 		inst = ufetch_uint32((uint32_t *)opc);
231 
232 	switch (((InstFmt)inst).FRType.op) {
233 	case OP_LWC0:
234 		MachEmulateLWC0(inst, frame, cause);
235 		break;
236 	case OP_SWC0:
237 		MachEmulateSWC0(inst, frame, cause);
238 		break;
239 	case OP_SPECIAL:
240 		MachEmulateSpecial(inst, frame, cause);
241 		break;
242 	case OP_SPECIAL3:
243 		MachEmulateSpecial3(inst, frame, cause);
244 		break;
245 	case OP_COP1:
246 		MachEmulateFP(inst, frame, cause);
247 		break;
248 #if defined(SOFTFLOAT)
249 	case OP_LWC1:
250 		MachEmulateLWC1(inst, frame, cause);
251 		break;
252 	case OP_LDC1:
253 		MachEmulateLDC1(inst, frame, cause);
254 		break;
255 	case OP_SWC1:
256 		MachEmulateSWC1(inst, frame, cause);
257 		break;
258 	case OP_SDC1:
259 		MachEmulateSDC1(inst, frame, cause);
260 		break;
261 #endif
262 	default:
263 #ifdef DEBUG
264 		printf("pid %d(%s): trap: bad vaddr %#"PRIxVADDR" cause %#x insn %#x\n", curproc->p_pid, curproc->p_comm, opc, cause, inst);
265 #endif
266 		frame->f_regs[_R_CAUSE] = cause;
267 		frame->f_regs[_R_BADVADDR] = opc;
268 		KSI_INIT_TRAP(&ksi);
269 		ksi.ksi_signo = SIGSEGV;
270 		ksi.ksi_trap = cause; /* XXX */
271 		ksi.ksi_code = SEGV_MAPERR;
272 		ksi.ksi_addr = (void *)opc;
273 		(*curproc->p_emul->e_trapsignal)(curlwp, &ksi);
274 		break;
275 	}
276 }
277 
278 static inline void
279 send_sigsegv(intptr_t vaddr, uint32_t exccode, struct frame *frame,
280     uint32_t cause)
281 {
282 	ksiginfo_t ksi;
283 	cause = (cause & 0xFFFFFF00) | (exccode << MIPS_CR_EXC_CODE_SHIFT);
284 	frame->f_regs[_R_CAUSE] = cause;
285 	frame->f_regs[_R_BADVADDR] = vaddr;
286 	KSI_INIT_TRAP(&ksi);
287 	ksi.ksi_signo = SIGSEGV;
288 	ksi.ksi_trap = cause;
289 	ksi.ksi_code = SEGV_MAPERR;
290 	ksi.ksi_addr = (void *)vaddr;
291 	(*curproc->p_emul->e_trapsignal)(curlwp, &ksi);
292 }
293 
294 static inline void
295 update_pc(struct frame *frame, uint32_t cause)
296 {
297 
298 	if (cause & MIPS_CR_BR_DELAY)
299 		frame->f_regs[_R_PC] =
300 		    MachEmulateBranch(frame, frame->f_regs[_R_PC],
301 			PCB_FSR(curpcb), 0);
302 	else
303 		frame->f_regs[_R_PC] += 4;
304 }
305 
306 /*
307  * MIPS2 LL instruction
308  */
309 void
310 MachEmulateLWC0(uint32_t inst, struct frame *frame, uint32_t cause)
311 {
312 	intptr_t	vaddr;
313 	int16_t		offset;
314 	void		*t;
315 
316 	offset = inst & 0xFFFF;
317 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
318 
319 	/* segment and alignment check */
320 	if (vaddr < 0 || (vaddr & 3)) {
321 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
322 		return;
323 	}
324 
325 	t = &(frame->f_regs[(inst>>16)&0x1F]);
326 
327 	if (copyin((void *)vaddr, t, 4) != 0) {
328 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
329 		return;
330 	}
331 
332 	llstate.lwp = curlwp;
333 	llstate.addr = vaddr;
334 	llstate.value = *((uint32_t *)t);
335 
336 	update_pc(frame, cause);
337 }
338 
339 /*
340  * MIPS2 SC instruction
341  */
342 void
343 MachEmulateSWC0(uint32_t inst, struct frame *frame, uint32_t cause)
344 {
345 	intptr_t	vaddr;
346 	uint32_t	value;
347 	int16_t		offset;
348 	mips_reg_t	*t;
349 
350 	offset = inst & 0xFFFF;
351 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
352 
353 	/* segment and alignment check */
354 	if (vaddr < 0 || (vaddr & 3)) {
355 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
356 		return;
357 	}
358 
359 	t = (mips_reg_t *)&(frame->f_regs[(inst>>16)&0x1F]);
360 
361 	/*
362 	 * Check that the process and address match the last
363 	 * LL instruction.
364 	 */
365 	if (curlwp == llstate.lwp && vaddr == llstate.addr) {
366 		llstate.lwp = NULL;
367 		/*
368 		 * Check that the data at the address hasn't changed
369 		 * since the LL instruction.
370 		 */
371 		if (copyin((void *)vaddr, &value, 4) != 0) {
372 			send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
373 			return;
374 		}
375 		if (value == llstate.value) {
376 			/* SC successful */
377 			if (copyout(t, (void *)vaddr, 4) != 0) {
378 				send_sigsegv(vaddr, T_TLB_ST_MISS,
379 				    frame, cause);
380 				return;
381 			}
382 			*t = 1;
383 			update_pc(frame, cause);
384 			return;
385 		}
386 	}
387 
388 	/* SC failed */
389 	*t = 0;
390 	update_pc(frame, cause);
391 }
392 
393 void
394 MachEmulateSpecial(uint32_t inst, struct frame *frame, uint32_t cause)
395 {
396 	ksiginfo_t ksi;
397 
398 	switch (((InstFmt)inst).RType.func) {
399 	case OP_SYNC:
400 		/* nothing */
401 		break;
402 	default:
403 		frame->f_regs[_R_CAUSE] = cause;
404 		frame->f_regs[_R_BADVADDR] = frame->f_regs[_R_PC];
405 		KSI_INIT_TRAP(&ksi);
406 		ksi.ksi_signo = SIGSEGV;
407 		ksi.ksi_trap = cause;
408 		ksi.ksi_code = SEGV_MAPERR;
409 		ksi.ksi_addr = (void *)(intptr_t)frame->f_regs[_R_PC];
410 		(*curproc->p_emul->e_trapsignal)(curlwp, &ksi);
411 		break;
412 	}
413 
414 	update_pc(frame, cause);
415 }
416 
417 void
418 MachEmulateSpecial3(uint32_t inst, struct frame *frame, uint32_t cause)
419 {
420 	ksiginfo_t ksi;
421 	InstFmt instfmt = (InstFmt)inst;
422 
423 	switch (instfmt.RType.func) {
424 	case OP_RDHWR:
425 		switch (instfmt.RType.rd) {
426 		case 29:
427 			frame->f_regs[instfmt.RType.rt] =
428 				(mips_reg_t)(intptr_t)curlwp->l_private;
429 			goto out;
430 		}
431 		/* FALLTHROUGH */
432 	default:
433 		frame->f_regs[_R_CAUSE] = cause;
434 		frame->f_regs[_R_BADVADDR] = frame->f_regs[_R_PC];
435 		KSI_INIT_TRAP(&ksi);
436 		ksi.ksi_signo = SIGILL;
437 		ksi.ksi_trap = cause;
438 		ksi.ksi_code = ILL_ILLOPC;
439 		ksi.ksi_addr = (void *)(intptr_t)frame->f_regs[_R_PC];
440 		(*curproc->p_emul->e_trapsignal)(curlwp, &ksi);
441 		break;
442 	}
443 
444 out:
445 	update_pc(frame, cause);
446 }
447 
448 #if defined(SOFTFLOAT)
449 
450 #define LWSWC1_MAXLOOP	12
451 
452 void
453 MachEmulateLWC1(uint32_t inst, struct frame *frame, uint32_t cause)
454 {
455 	intptr_t	vaddr;
456 	int16_t		offset;
457 	void		*t;
458 	mips_reg_t	pc;
459 	int		i;
460 
461 	offset = inst & 0xFFFF;
462 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
463 
464 	/* segment and alignment check */
465 	if (vaddr < 0 || (vaddr & 3)) {
466 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
467 		return;
468 	}
469 
470 	/* NewABI FIXME */
471 	t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]);
472 
473 	if (copyin((void *)vaddr, t, 4) != 0) {
474 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
475 		return;
476 	}
477 
478 	pc = frame->f_regs[_R_PC];
479 	update_pc(frame, cause);
480 
481 	if (cause & MIPS_CR_BR_DELAY)
482 		return;
483 
484 	for (i = 1; i < LWSWC1_MAXLOOP; i++) {
485 		if (mips_btop(frame->f_regs[_R_PC]) != mips_btop(pc))
486 			return;
487 
488 		vaddr = frame->f_regs[_R_PC];	/* XXX truncates to 32 bits */
489 		inst = fuiword((uint32_t *)vaddr);
490 		if (((InstFmt)inst).FRType.op != OP_LWC1)
491 			return;
492 
493 		offset = inst & 0xFFFF;
494 		vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
495 
496 		/* segment and alignment check */
497 		if (vaddr < 0 || (vaddr & 3)) {
498 			send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
499 			return;
500 		}
501 
502 		/* NewABI FIXME */
503 		t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]);
504 
505 		if (copyin((void *)vaddr, t, 4) != 0) {
506 			send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
507 			return;
508 		}
509 
510 		pc = frame->f_regs[_R_PC];
511 		update_pc(frame, cause);
512 	}
513 }
514 
515 void
516 MachEmulateLDC1(uint32_t inst, struct frame *frame, uint32_t cause)
517 {
518 	intptr_t	vaddr;
519 	int16_t		offset;
520 	void		*t;
521 
522 	offset = inst & 0xFFFF;
523 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
524 
525 	/* segment and alignment check */
526 	if (vaddr < 0  || (vaddr & 7)) {
527 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
528 		return;
529 	}
530 
531 	/* NewABI FIXME */
532 	t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1E]);
533 
534 	if (copyin((void *)vaddr, t, 8) != 0) {
535 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
536 		return;
537 	}
538 
539 	update_pc(frame, cause);
540 }
541 
542 void
543 MachEmulateSWC1(uint32_t inst, struct frame *frame, uint32_t cause)
544 {
545 	intptr_t	vaddr;
546 	int16_t		offset;
547 	void		*t;
548 	mips_reg_t	pc;
549 	int		i;
550 
551 	offset = inst & 0xFFFF;
552 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
553 
554 	/* segment and alignment check */
555 	if (vaddr < 0 || (vaddr & 3)) {
556 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
557 		return;
558 	}
559 
560 	/* NewABI FIXME */
561 	t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]);
562 
563 	if (copyout(t, (void *)vaddr, 4) != 0) {
564 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
565 		return;
566 	}
567 
568 	pc = frame->f_regs[_R_PC];
569 	update_pc(frame, cause);
570 
571 	if (cause & MIPS_CR_BR_DELAY)
572 		return;
573 
574 	for (i = 1; i < LWSWC1_MAXLOOP; i++) {
575 		if (mips_btop(frame->f_regs[_R_PC]) != mips_btop(pc))
576 			return;
577 
578 		vaddr = frame->f_regs[_R_PC];	/* XXX truncates to 32 bits */
579 		inst = fuiword((uint32_t *)vaddr);
580 		if (((InstFmt)inst).FRType.op != OP_SWC1)
581 			return;
582 
583 		offset = inst & 0xFFFF;
584 		vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
585 
586 		/* segment and alignment check */
587 		if (vaddr < 0 || (vaddr & 3)) {
588 			send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
589 			return;
590 		}
591 
592 		/* NewABI FIXME */
593 		t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]);
594 
595 		if (copyout(t, (void *)vaddr, 4) != 0) {
596 			send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
597 			return;
598 		}
599 
600 		pc = frame->f_regs[_R_PC];
601 		update_pc(frame, cause);
602 	}
603 }
604 
605 void
606 MachEmulateSDC1(uint32_t inst, struct frame *frame, uint32_t cause)
607 {
608 	intptr_t	vaddr;
609 	int16_t		offset;
610 	void		*t;
611 
612 	offset = inst & 0xFFFF;
613 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
614 
615 	/* segment and alignment check */
616 	if (vaddr < 0 || (vaddr & 7)) {
617 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
618 		return;
619 	}
620 
621 	/* NewABI FIXME */
622 	t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1E]);
623 
624 	if (copyout(t, (void *)vaddr, 8) != 0) {
625 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
626 		return;
627 	}
628 
629 	update_pc(frame, cause);
630 }
631 
632 void
633 bcemul_lb(uint32_t inst, struct frame *frame, uint32_t cause)
634 {
635 	intptr_t	vaddr;
636 	int16_t		offset;
637 	int8_t		x;
638 
639 	offset = inst & 0xFFFF;
640 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
641 
642 	/* segment check */
643 	if (vaddr < 0) {
644 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
645 		return;
646 	}
647 
648 	if (copyin((void *)vaddr, &x, 1) != 0) {
649 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
650 		return;
651 	}
652 
653 	frame->f_regs[(inst>>16)&0x1F] = (int32_t)x;
654 
655 	update_pc(frame, cause);
656 }
657 
658 void
659 bcemul_lbu(uint32_t inst, struct frame *frame, uint32_t cause)
660 {
661 	intptr_t	vaddr;
662 	int16_t		offset;
663 	uint8_t	x;
664 
665 	offset = inst & 0xFFFF;
666 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
667 
668 	/* segment check */
669 	if (vaddr < 0) {
670 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
671 		return;
672 	}
673 
674 	if (copyin((void *)vaddr, &x, 1) != 0) {
675 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
676 		return;
677 	}
678 
679 	frame->f_regs[(inst>>16)&0x1F] = (mips_ureg_t)x;
680 
681 	update_pc(frame, cause);
682 }
683 
684 void
685 bcemul_lh(uint32_t inst, struct frame *frame, uint32_t cause)
686 {
687 	intptr_t	vaddr;
688 	int16_t		offset;
689 	int16_t		x;
690 
691 	offset = inst & 0xFFFF;
692 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
693 
694 	/* segment and alignment check */
695 	if (vaddr < 0 || (vaddr & 1)) {
696 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
697 		return;
698 	}
699 
700 	if (copyin((void *)vaddr, &x, 2) != 0) {
701 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
702 		return;
703 	}
704 
705 	frame->f_regs[(inst>>16)&0x1F] = x;
706 
707 	update_pc(frame, cause);
708 }
709 
710 void
711 bcemul_lhu(uint32_t inst, struct frame *frame, uint32_t cause)
712 {
713 	intptr_t	vaddr;
714 	int16_t		offset;
715 	u_int16_t	x;
716 
717 	offset = inst & 0xFFFF;
718 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
719 
720 	/* segment and alignment check */
721 	if (vaddr < 0 || (vaddr & 1)) {
722 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
723 		return;
724 	}
725 
726 	if (copyin((void *)vaddr, &x, 2) != 0) {
727 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
728 		return;
729 	}
730 
731 	frame->f_regs[(inst>>16)&0x1F] = (mips_ureg_t)x;
732 
733 	update_pc(frame, cause);
734 }
735 
736 void
737 bcemul_lw(uint32_t inst, struct frame *frame, uint32_t cause)
738 {
739 	intptr_t	vaddr;
740 	int16_t		offset;
741 
742 	offset = inst & 0xFFFF;
743 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
744 
745 	/* segment and alignment check */
746 	if (vaddr < 0 || (vaddr & 3)) {
747 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
748 		return;
749 	}
750 
751 	if (copyin((void *)vaddr, &(frame->f_regs[(inst>>16)&0x1F]), 4) != 0) {
752 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
753 		return;
754 	}
755 
756 	update_pc(frame, cause);
757 }
758 
759 void
760 bcemul_lwl(uint32_t inst, struct frame *frame, uint32_t cause)
761 {
762 	intptr_t	vaddr;
763 	uint32_t	a, x, shift;
764 	int16_t		offset;
765 
766 	offset = inst & 0xFFFF;
767 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
768 
769 	/* segment check */
770 	if (vaddr < 0) {
771 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
772 		return;
773 	}
774 
775 	if (copyin((void *)(vaddr & ~3), &a, 4) != 0) {
776 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
777 		return;
778 	}
779 
780 	x = frame->f_regs[(inst>>16)&0x1F];
781 
782 	shift = (3 - (vaddr & 0x00000003)) * 8;
783 	a <<= shift;
784 	x &= ~(0xFFFFFFFFUL << shift);
785 	x |= a;
786 
787 	frame->f_regs[(inst>>16)&0x1F] = x;
788 
789 	update_pc(frame, cause);
790 }
791 
792 void
793 bcemul_lwr(uint32_t inst, struct frame *frame, uint32_t cause)
794 {
795 	intptr_t		vaddr;
796 	uint32_t	a, x, shift;
797 	int16_t		offset;
798 
799 	offset = inst & 0xFFFF;
800 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
801 
802 	/* segment check */
803 	if (vaddr & 0x80000000) {
804 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
805 		return;
806 	}
807 
808 	if (copyin((void *)(vaddr & ~3), &a, 4) != 0) {
809 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
810 		return;
811 	}
812 
813 	x = frame->f_regs[(inst>>16)&0x1F];
814 
815 	shift = (vaddr & 0x00000003) * 8;
816 	a >>= shift;
817 	x &= ~(0xFFFFFFFFUL >> shift);
818 	x |= a;
819 
820 	frame->f_regs[(inst>>16)&0x1F] = x;
821 
822 	update_pc(frame, cause);
823 }
824 
825 #if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64)
826 void
827 bcemul_ld(uint32_t inst, struct frame *frame, uint32_t cause)
828 {
829 	intptr_t	vaddr;
830 	int16_t		offset;
831 
832 	offset = inst & 0xFFFF;
833 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
834 
835 	/* segment and alignment check */
836 	if (vaddr > VM_MAX_ADDRESS || vaddr & 0x7) {
837 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
838 		return;
839 	}
840 
841 	if (copyin((void *)vaddr, &(frame->f_regs[(inst>>16)&0x1F]), 8) != 0) {
842 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
843 		return;
844 	}
845 
846 	update_pc(frame, cause);
847 }
848 
849 void
850 bcemul_ldl(uint32_t inst, struct frame *frame, uint32_t cause)
851 {
852 	intptr_t	vaddr;
853 	uint64_t	a, x;
854 	uint32_t	shift;
855 	int16_t		offset;
856 
857 	offset = inst & 0xFFFF;
858 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
859 
860 	/* segment check */
861 	if (vaddr & 0x80000000) {
862 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
863 		return;
864 	}
865 
866 	if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) {
867 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
868 		return;
869 	}
870 
871 	x = frame->f_regs[(inst>>16)&0x1F];
872 
873 	shift = (7 - (vaddr & 0x7)) * 8;
874 	a <<= shift;
875 	x &= ~(~(uint64_t)0UL << shift);
876 	x |= a;
877 
878 	frame->f_regs[(inst>>16)&0x1F] = x;
879 
880 	update_pc(frame, cause);
881 }
882 
883 void
884 bcemul_ldr(uint32_t inst, struct frame *frame, uint32_t cause)
885 {
886 	intptr_t	vaddr;
887 	uint64_t	a, x;
888 	uint32_t	shift;
889 	int16_t		offset;
890 
891 	offset = inst & 0xFFFF;
892 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
893 
894 	/* segment check */
895 	if (vaddr < 0) {
896 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
897 		return;
898 	}
899 
900 	if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) {
901 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
902 		return;
903 	}
904 
905 	x = frame->f_regs[(inst>>16)&0x1F];
906 
907 	shift = (vaddr & 0x7) * 8;
908 	a >>= shift;
909 	x &= ~(~(uint64_t)0UL >> shift);
910 	x |= a;
911 
912 	frame->f_regs[(inst>>16)&0x1F] = x;
913 
914 	update_pc(frame, cause);
915 }
916 #endif /* defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) */
917 
918 void
919 bcemul_sb(uint32_t inst, struct frame *frame, uint32_t cause)
920 {
921 	intptr_t	vaddr;
922 	int16_t		offset;
923 
924 	offset = inst & 0xFFFF;
925 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
926 
927 	/* segment check */
928 	if (vaddr < 0) {
929 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
930 		return;
931 	}
932 
933 	if (subyte((void *)vaddr, frame->f_regs[(inst>>16)&0x1F]) < 0) {
934 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
935 		return;
936 	}
937 
938 	update_pc(frame, cause);
939 }
940 
941 void
942 bcemul_sh(uint32_t inst, struct frame *frame, uint32_t cause)
943 {
944 	intptr_t	vaddr;
945 	int16_t		offset;
946 
947 	offset = inst & 0xFFFF;
948 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
949 
950 	/* segment and alignment check */
951 	if (vaddr < 0 || vaddr & 1) {
952 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
953 		return;
954 	}
955 
956 	if (susword((void *)vaddr, frame->f_regs[(inst>>16)&0x1F]) < 0) {
957 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
958 		return;
959 	}
960 
961 	update_pc(frame, cause);
962 }
963 
964 void
965 bcemul_sw(uint32_t inst, struct frame *frame, uint32_t cause)
966 {
967 	intptr_t	vaddr;
968 	int16_t		offset;
969 
970 	offset = inst & 0xFFFF;
971 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
972 
973 	/* segment and alignment check */
974 	if (vaddr < 0 || (vaddr & 3)) {
975 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
976 		return;
977 	}
978 
979 	if (ustore_uint32((void *)vaddr, frame->f_regs[(inst>>16)&0x1F]) < 0) {
980 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
981 		return;
982 	}
983 
984 	update_pc(frame, cause);
985 }
986 
987 void
988 bcemul_swl(uint32_t inst, struct frame *frame, uint32_t cause)
989 {
990 	intptr_t	vaddr;
991 	uint32_t	a, x, shift;
992 	int16_t		offset;
993 
994 	offset = inst & 0xFFFF;
995 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
996 
997 	/* segment check */
998 	if (vaddr < 0) {
999 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
1000 		return;
1001 	}
1002 
1003 	if (copyin((void *)(vaddr & ~3), &a, 4) != 0) {
1004 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
1005 		return;
1006 	}
1007 
1008 	x = frame->f_regs[(inst>>16)&0x1F];
1009 
1010 	shift = (3 - (vaddr & 3)) * 8;
1011 	x >>= shift;
1012 	a &= ~(0xFFFFFFFFUL >> shift);
1013 	a |= x;
1014 
1015 	if (ustore_uint32((void *)vaddr, a) < 0) {
1016 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
1017 		return;
1018 	}
1019 
1020 	update_pc(frame, cause);
1021 }
1022 
1023 void
1024 bcemul_swr(uint32_t inst, struct frame *frame, uint32_t cause)
1025 {
1026 	intptr_t	vaddr;
1027 	uint32_t	a, x, shift;
1028 	int16_t		offset;
1029 
1030 	offset = inst & 0xFFFF;
1031 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
1032 
1033 	/* segment check */
1034 	if (vaddr < 0) {
1035 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
1036 		return;
1037 	}
1038 
1039 	if (copyin((void *)(vaddr & ~3), &a, 4) != 0) {
1040 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
1041 		return;
1042 	}
1043 
1044 	x = frame->f_regs[(inst>>16)&0x1F];
1045 
1046 	shift = (vaddr & 3) * 8;
1047 	x <<= shift;
1048 	a &= ~(0xFFFFFFFFUL << shift);
1049 	a |= x;
1050 
1051 	if (ustore_uint32((void *)vaddr, a) < 0) {
1052 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
1053 		return;
1054 	}
1055 
1056 	update_pc(frame, cause);
1057 }
1058 
1059 #if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64)
1060 void
1061 bcemul_sd(uint32_t inst, struct frame *frame, uint32_t cause)
1062 {
1063 	intptr_t	vaddr;
1064 	int16_t		offset;
1065 
1066 	offset = inst & 0xFFFF;
1067 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
1068 
1069 	/* segment and alignment check */
1070 	if (vaddr < 0 || vaddr & 0x7) {
1071 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
1072 		return;
1073 	}
1074 
1075 	if (copyout((void *)vaddr, &frame->f_regs[(inst>>16)&0x1F], 8) < 0) {
1076 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
1077 		return;
1078 	}
1079 
1080 	update_pc(frame, cause);
1081 }
1082 
1083 void
1084 bcemul_sdl(uint32_t inst, struct frame *frame, uint32_t cause)
1085 {
1086 	intptr_t	vaddr;
1087 	uint64_t	a, x;
1088 	uint32_t	shift;
1089 	int16_t		offset;
1090 
1091 	offset = inst & 0xFFFF;
1092 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
1093 
1094 	/* segment check */
1095 	if (vaddr < 0) {
1096 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
1097 		return;
1098 	}
1099 
1100 	if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) {
1101 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
1102 		return;
1103 	}
1104 
1105 	x = frame->f_regs[(inst>>16)&0x1F];
1106 
1107 	shift = (7 - (vaddr & 7)) * 8;
1108 	x >>= shift;
1109 	a &= ~(~(uint64_t)0U >> shift);
1110 	a |= x;
1111 
1112 	if (copyout((void *)(vaddr & ~0x7), &a, 8) != 0) {
1113 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
1114 		return;
1115 	}
1116 
1117 	update_pc(frame, cause);
1118 }
1119 
1120 void
1121 bcemul_sdr(uint32_t inst, struct frame *frame, uint32_t cause)
1122 {
1123 	intptr_t	vaddr;
1124 	uint64_t	a, x;
1125 	uint32_t	shift;
1126 	int16_t		offset;
1127 
1128 	offset = inst & 0xFFFF;
1129 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
1130 
1131 	/* segment check */
1132 	if (vaddr < 0) {
1133 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
1134 		return;
1135 	}
1136 
1137 	if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) {
1138 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
1139 		return;
1140 	}
1141 
1142 	x = frame->f_regs[(inst>>16)&0x1F];
1143 
1144 	shift = (vaddr & 7) * 8;
1145 	x <<= shift;
1146 	a &= ~(~(uint64_t)0U << shift);
1147 	a |= x;
1148 
1149 	if (copyout((void *)(vaddr & ~0x7), &a, 8) != 0) {
1150 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
1151 		return;
1152 	}
1153 
1154 	update_pc(frame, cause);
1155 }
1156 #endif /* defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) */
1157 #endif /* defined(SOFTFLOAT) */
1158