| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: mips_emul.c,v 1.28 2021/05/27 13:32:54 simonb Exp $ */ | | 1 | /* $NetBSD: mips_emul.c,v 1.29 2021/05/27 15:00:02 simonb Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1999 Shuichiro URATA. All rights reserved. | | 4 | * Copyright (c) 1999 Shuichiro URATA. All rights reserved. |
5 | * | | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions | | 7 | * modification, are permitted provided that the following conditions |
8 | * are met: | | 8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright | | 9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. | | 10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright | | 11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the | | 12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. | | 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 | | 14 | * 3. The name of the author may not be used to endorse or promote products |
| @@ -17,46 +17,49 @@ | | | @@ -17,46 +17,49 @@ |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 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 | | 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 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 | | 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 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 | | 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. | | 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include <sys/cdefs.h> | | 29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: mips_emul.c,v 1.28 2021/05/27 13:32:54 simonb Exp $"); | | 30 | __KERNEL_RCSID(0, "$NetBSD: mips_emul.c,v 1.29 2021/05/27 15:00:02 simonb Exp $"); |
31 | | | 31 | |
32 | #include <sys/param.h> | | 32 | #include <sys/param.h> |
33 | #include <sys/systm.h> | | 33 | #include <sys/systm.h> |
34 | #include <sys/cpu.h> | | 34 | #include <sys/cpu.h> |
35 | #include <sys/proc.h> | | 35 | #include <sys/proc.h> |
36 | | | 36 | |
37 | #include <mips/locore.h> | | 37 | #include <mips/locore.h> |
38 | #include <mips/mips_opcode.h> | | 38 | #include <mips/mips_opcode.h> |
39 | | | 39 | |
40 | #include <mips/reg.h> | | 40 | #include <mips/reg.h> |
41 | #include <mips/regnum.h> /* symbolic register indices */ | | 41 | #include <mips/regnum.h> /* symbolic register indices */ |
42 | #include <mips/pcb.h> | | 42 | #include <mips/pcb.h> |
43 | #include <mips/vmparam.h> /* for VM_MAX_ADDRESS */ | | 43 | #include <mips/vmparam.h> /* for VM_MAX_ADDRESS */ |
44 | #include <mips/trap.h> | | 44 | #include <mips/trap.h> |
45 | | | 45 | |
46 | static inline void send_sigsegv(intptr_t, uint32_t, struct trapframe *, | | 46 | static inline void send_sigsegv(intptr_t, uint32_t, struct trapframe *, |
47 | uint32_t); | | 47 | uint32_t); |
48 | static inline void update_pc(struct trapframe *, uint32_t); | | 48 | static inline void update_pc(struct trapframe *, uint32_t); |
49 | | | 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 | |
50 | /* | | 53 | /* |
51 | * MIPS2 LL instruction emulation state | | 54 | * MIPS2 LL instruction emulation state |
52 | */ | | 55 | */ |
53 | struct { | | 56 | struct { |
54 | struct lwp *lwp; | | 57 | struct lwp *lwp; |
55 | vaddr_t addr; | | 58 | vaddr_t addr; |
56 | uint32_t value; | | 59 | uint32_t value; |
57 | } llstate; | | 60 | } llstate; |
58 | | | 61 | |
59 | /* | | 62 | /* |
60 | * Analyse 'next' PC address taking account of branch/jump instructions | | 63 | * Analyse 'next' PC address taking account of branch/jump instructions |
61 | */ | | 64 | */ |
62 | vaddr_t | | 65 | vaddr_t |
| @@ -188,31 +191,31 @@ mips_emul_inst(uint32_t status, uint32_t | | | @@ -188,31 +191,31 @@ mips_emul_inst(uint32_t status, uint32_t |
188 | uint32_t inst; | | 191 | uint32_t inst; |
189 | ksiginfo_t ksi; | | 192 | ksiginfo_t ksi; |
190 | int code = ILL_ILLOPC; | | 193 | int code = ILL_ILLOPC; |
191 | | | 194 | |
192 | /* | | 195 | /* |
193 | * Fetch the instruction. | | 196 | * Fetch the instruction. |
194 | */ | | 197 | */ |
195 | if (cause & MIPS_CR_BR_DELAY) | | 198 | if (cause & MIPS_CR_BR_DELAY) |
196 | inst = mips_ufetch32((uint32_t *)opc+1); | | 199 | inst = mips_ufetch32((uint32_t *)opc+1); |
197 | else | | 200 | else |
198 | inst = mips_ufetch32((uint32_t *)opc); | | 201 | inst = mips_ufetch32((uint32_t *)opc); |
199 | | | 202 | |
200 | switch (((InstFmt)inst).FRType.op) { | | 203 | switch (((InstFmt)inst).FRType.op) { |
201 | case OP_LWC0: | | 204 | case OP_LL: |
202 | mips_emul_lwc0(inst, tf, cause); | | 205 | mips_emul_ll(inst, tf, cause); |
203 | break; | | 206 | break; |
204 | case OP_SWC0: | | 207 | case OP_SC: |
205 | mips_emul_swc0(inst, tf, cause); | | 208 | mips_emul_sc(inst, tf, cause); |
206 | break; | | 209 | break; |
207 | case OP_SPECIAL: | | 210 | case OP_SPECIAL: |
208 | mips_emul_special(inst, tf, cause); | | 211 | mips_emul_special(inst, tf, cause); |
209 | break; | | 212 | break; |
210 | case OP_SPECIAL3: | | 213 | case OP_SPECIAL3: |
211 | mips_emul_special3(inst, tf, cause); | | 214 | mips_emul_special3(inst, tf, cause); |
212 | break; | | 215 | break; |
213 | case OP_COP1: | | 216 | case OP_COP1: |
214 | #if defined(FPEMUL) | | 217 | #if defined(FPEMUL) |
215 | mips_emul_fp(inst, tf, cause); | | 218 | mips_emul_fp(inst, tf, cause); |
216 | break; | | 219 | break; |
217 | #endif | | 220 | #endif |
218 | case OP_LWC1: | | 221 | case OP_LWC1: |
| @@ -279,27 +282,27 @@ update_pc(struct trapframe *tf, uint32_t | | | @@ -279,27 +282,27 @@ update_pc(struct trapframe *tf, uint32_t |
279 | | | 282 | |
280 | if (cause & MIPS_CR_BR_DELAY) | | 283 | if (cause & MIPS_CR_BR_DELAY) |
281 | tf->tf_regs[_R_PC] = | | 284 | tf->tf_regs[_R_PC] = |
282 | mips_emul_branch(tf, tf->tf_regs[_R_PC], | | 285 | mips_emul_branch(tf, tf->tf_regs[_R_PC], |
283 | PCB_FSR(curpcb), 0); | | 286 | PCB_FSR(curpcb), 0); |
284 | else | | 287 | else |
285 | tf->tf_regs[_R_PC] += 4; | | 288 | tf->tf_regs[_R_PC] += 4; |
286 | } | | 289 | } |
287 | | | 290 | |
288 | /* | | 291 | /* |
289 | * MIPS2 LL instruction | | 292 | * MIPS2 LL instruction |
290 | */ | | 293 | */ |
291 | void | | 294 | void |
292 | mips_emul_lwc0(uint32_t inst, struct trapframe *tf, uint32_t cause) | | 295 | mips_emul_ll(uint32_t inst, struct trapframe *tf, uint32_t cause) |
293 | { | | 296 | { |
294 | intptr_t vaddr; | | 297 | intptr_t vaddr; |
295 | int16_t offset; | | 298 | int16_t offset; |
296 | void *t; | | 299 | void *t; |
297 | | | 300 | |
298 | offset = inst & 0xFFFF; | | 301 | offset = inst & 0xFFFF; |
299 | vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset; | | 302 | vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset; |
300 | | | 303 | |
301 | /* segment and alignment check */ | | 304 | /* segment and alignment check */ |
302 | if (vaddr < 0 || (vaddr & 3)) { | | 305 | if (vaddr < 0 || (vaddr & 3)) { |
303 | send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause); | | 306 | send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause); |
304 | return; | | 307 | return; |
305 | } | | 308 | } |
| @@ -312,27 +315,27 @@ mips_emul_lwc0(uint32_t inst, struct tra | | | @@ -312,27 +315,27 @@ mips_emul_lwc0(uint32_t inst, struct tra |
312 | } | | 315 | } |
313 | | | 316 | |
314 | llstate.lwp = curlwp; | | 317 | llstate.lwp = curlwp; |
315 | llstate.addr = vaddr; | | 318 | llstate.addr = vaddr; |
316 | llstate.value = *((uint32_t *)t); | | 319 | llstate.value = *((uint32_t *)t); |
317 | | | 320 | |
318 | update_pc(tf, cause); | | 321 | update_pc(tf, cause); |
319 | } | | 322 | } |
320 | | | 323 | |
321 | /* | | 324 | /* |
322 | * MIPS2 SC instruction | | 325 | * MIPS2 SC instruction |
323 | */ | | 326 | */ |
324 | void | | 327 | void |
325 | mips_emul_swc0(uint32_t inst, struct trapframe *tf, uint32_t cause) | | 328 | mips_emul_sc(uint32_t inst, struct trapframe *tf, uint32_t cause) |
326 | { | | 329 | { |
327 | intptr_t vaddr; | | 330 | intptr_t vaddr; |
328 | uint32_t value; | | 331 | uint32_t value; |
329 | int16_t offset; | | 332 | int16_t offset; |
330 | mips_reg_t *t; | | 333 | mips_reg_t *t; |
331 | | | 334 | |
332 | offset = inst & 0xFFFF; | | 335 | offset = inst & 0xFFFF; |
333 | vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset; | | 336 | vaddr = tf->tf_regs[(inst>>21)&0x1F] + offset; |
334 | | | 337 | |
335 | /* segment and alignment check */ | | 338 | /* segment and alignment check */ |
336 | if (vaddr < 0 || (vaddr & 3)) { | | 339 | if (vaddr < 0 || (vaddr & 3)) { |
337 | send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause); | | 340 | send_sigsegv(vaddr, T_ADDR_ERR_LD, tf, cause); |
338 | return; | | 341 | return; |