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