Revision 1147e189
b/target-mips/helper.c | ||
---|---|---|
201 | 201 |
} |
202 | 202 |
#endif |
203 | 203 |
|
204 |
static void raise_mmu_exception(CPUState *env, target_ulong address, |
|
205 |
int rw, int tlb_error) |
|
206 |
{ |
|
207 |
int exception = 0, error_code = 0; |
|
208 |
|
|
209 |
switch (tlb_error) { |
|
210 |
default: |
|
211 |
case TLBRET_BADADDR: |
|
212 |
/* Reference to kernel address from user mode or supervisor mode */ |
|
213 |
/* Reference to supervisor address from user mode */ |
|
214 |
if (rw) |
|
215 |
exception = EXCP_AdES; |
|
216 |
else |
|
217 |
exception = EXCP_AdEL; |
|
218 |
break; |
|
219 |
case TLBRET_NOMATCH: |
|
220 |
/* No TLB match for a mapped address */ |
|
221 |
if (rw) |
|
222 |
exception = EXCP_TLBS; |
|
223 |
else |
|
224 |
exception = EXCP_TLBL; |
|
225 |
error_code = 1; |
|
226 |
break; |
|
227 |
case TLBRET_INVALID: |
|
228 |
/* TLB match with no valid bit */ |
|
229 |
if (rw) |
|
230 |
exception = EXCP_TLBS; |
|
231 |
else |
|
232 |
exception = EXCP_TLBL; |
|
233 |
break; |
|
234 |
case TLBRET_DIRTY: |
|
235 |
/* TLB match but 'D' bit is cleared */ |
|
236 |
exception = EXCP_LTLBL; |
|
237 |
break; |
|
238 |
|
|
239 |
} |
|
240 |
/* Raise exception */ |
|
241 |
env->CP0_BadVAddr = address; |
|
242 |
env->CP0_Context = (env->CP0_Context & ~0x007fffff) | |
|
243 |
((address >> 9) & 0x007ffff0); |
|
244 |
env->CP0_EntryHi = |
|
245 |
(env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1)); |
|
246 |
#if defined(TARGET_MIPS64) |
|
247 |
env->CP0_EntryHi &= env->SEGMask; |
|
248 |
env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) | |
|
249 |
((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) | |
|
250 |
((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9); |
|
251 |
#endif |
|
252 |
env->exception_index = exception; |
|
253 |
env->error_code = error_code; |
|
254 |
} |
|
255 |
|
|
204 | 256 |
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
205 | 257 |
{ |
206 | 258 |
#if defined(CONFIG_USER_ONLY) |
... | ... | |
222 | 274 |
target_phys_addr_t physical; |
223 | 275 |
int prot; |
224 | 276 |
#endif |
225 |
int exception = 0, error_code = 0; |
|
226 | 277 |
int access_type; |
227 | 278 |
int ret = 0; |
228 | 279 |
|
... | ... | |
252 | 303 |
} else if (ret < 0) |
253 | 304 |
#endif |
254 | 305 |
{ |
255 |
switch (ret) { |
|
256 |
default: |
|
257 |
case TLBRET_BADADDR: |
|
258 |
/* Reference to kernel address from user mode or supervisor mode */ |
|
259 |
/* Reference to supervisor address from user mode */ |
|
260 |
if (rw) |
|
261 |
exception = EXCP_AdES; |
|
262 |
else |
|
263 |
exception = EXCP_AdEL; |
|
264 |
break; |
|
265 |
case TLBRET_NOMATCH: |
|
266 |
/* No TLB match for a mapped address */ |
|
267 |
if (rw) |
|
268 |
exception = EXCP_TLBS; |
|
269 |
else |
|
270 |
exception = EXCP_TLBL; |
|
271 |
error_code = 1; |
|
272 |
break; |
|
273 |
case TLBRET_INVALID: |
|
274 |
/* TLB match with no valid bit */ |
|
275 |
if (rw) |
|
276 |
exception = EXCP_TLBS; |
|
277 |
else |
|
278 |
exception = EXCP_TLBL; |
|
279 |
break; |
|
280 |
case TLBRET_DIRTY: |
|
281 |
/* TLB match but 'D' bit is cleared */ |
|
282 |
exception = EXCP_LTLBL; |
|
283 |
break; |
|
284 |
|
|
285 |
} |
|
286 |
/* Raise exception */ |
|
287 |
env->CP0_BadVAddr = address; |
|
288 |
env->CP0_Context = (env->CP0_Context & ~0x007fffff) | |
|
289 |
((address >> 9) & 0x007ffff0); |
|
290 |
env->CP0_EntryHi = |
|
291 |
(env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1)); |
|
292 |
#if defined(TARGET_MIPS64) |
|
293 |
env->CP0_EntryHi &= env->SEGMask; |
|
294 |
env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) | |
|
295 |
((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) | |
|
296 |
((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9); |
|
297 |
#endif |
|
298 |
env->exception_index = exception; |
|
299 |
env->error_code = error_code; |
|
306 |
raise_mmu_exception(env, address, rw, ret); |
|
300 | 307 |
ret = 1; |
301 | 308 |
} |
302 | 309 |
|
Also available in: Unified diff