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