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