Revision 83469015 target-sparc/helper.c
b/target-sparc/helper.c | ||
---|---|---|
1 | 1 |
/* |
2 | 2 |
* sparc helpers |
3 | 3 |
* |
4 |
* Copyright (c) 2003 Fabrice Bellard |
|
4 |
* Copyright (c) 2003-2005 Fabrice Bellard
|
|
5 | 5 |
* |
6 | 6 |
* This library is free software; you can redistribute it and/or |
7 | 7 |
* modify it under the terms of the GNU Lesser General Public |
... | ... | |
28 | 28 |
#include "cpu.h" |
29 | 29 |
#include "exec-all.h" |
30 | 30 |
|
31 |
//#define DEBUG_PCALL |
|
32 | 31 |
//#define DEBUG_MMU |
33 | 32 |
|
34 | 33 |
/* Sparc MMU emulation */ |
... | ... | |
62 | 61 |
#else |
63 | 62 |
|
64 | 63 |
#ifndef TARGET_SPARC64 |
64 |
/* |
|
65 |
* Sparc V8 Reference MMU (SRMMU) |
|
66 |
*/ |
|
65 | 67 |
static const int access_table[8][8] = { |
66 | 68 |
{ 0, 0, 0, 0, 2, 0, 3, 3 }, |
67 | 69 |
{ 0, 0, 0, 0, 2, 0, 0, 0 }, |
... | ... | |
229 | 231 |
} |
230 | 232 |
} |
231 | 233 |
#else |
234 |
/* |
|
235 |
* UltraSparc IIi I/DMMUs |
|
236 |
*/ |
|
232 | 237 |
static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot, |
233 | 238 |
int *access_index, target_ulong address, int rw, |
234 | 239 |
int is_user) |
... | ... | |
237 | 242 |
unsigned int i; |
238 | 243 |
|
239 | 244 |
if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */ |
240 |
*physical = address & 0xffffffff;
|
|
245 |
*physical = address; |
|
241 | 246 |
*prot = PAGE_READ | PAGE_WRITE; |
242 | 247 |
return 0; |
243 | 248 |
} |
244 | 249 |
|
245 | 250 |
for (i = 0; i < 64; i++) { |
246 |
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) { |
|
247 |
switch (env->dtlb_tte[i] >> 60) { |
|
248 |
default: |
|
249 |
case 0x4: // 8k |
|
250 |
mask = 0xffffffffffffe000ULL; |
|
251 |
break; |
|
252 |
case 0x5: // 64k |
|
253 |
mask = 0xffffffffffff0000ULL; |
|
254 |
break; |
|
255 |
case 0x6: // 512k |
|
256 |
mask = 0xfffffffffff80000ULL; |
|
257 |
break; |
|
258 |
case 0x7: // 4M |
|
259 |
mask = 0xffffffffffc00000ULL; |
|
260 |
break; |
|
261 |
} |
|
262 |
// ctx match, vaddr match? |
|
263 |
if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) && |
|
264 |
(address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) { |
|
265 |
// access ok? |
|
266 |
if (((env->dtlb_tte[i] & 0x4) && !(env->pstate & PS_PRIV)) || |
|
267 |
(!(env->dtlb_tte[i] & 0x2) && (rw == 1))) { |
|
268 |
env->exception_index = TT_DFAULT; |
|
269 |
return 1; |
|
270 |
} |
|
271 |
*physical = env->dtlb_tte[i] & 0xffffe000; |
|
272 |
*prot = PAGE_READ; |
|
273 |
if (env->dtlb_tte[i] & 0x2) |
|
274 |
*prot |= PAGE_WRITE; |
|
275 |
return 0; |
|
251 |
switch ((env->dtlb_tte[i] >> 61) & 3) { |
|
252 |
default: |
|
253 |
case 0x0: // 8k |
|
254 |
mask = 0xffffffffffffe000ULL; |
|
255 |
break; |
|
256 |
case 0x1: // 64k |
|
257 |
mask = 0xffffffffffff0000ULL; |
|
258 |
break; |
|
259 |
case 0x2: // 512k |
|
260 |
mask = 0xfffffffffff80000ULL; |
|
261 |
break; |
|
262 |
case 0x3: // 4M |
|
263 |
mask = 0xffffffffffc00000ULL; |
|
264 |
break; |
|
265 |
} |
|
266 |
// ctx match, vaddr match? |
|
267 |
if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) && |
|
268 |
(address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) { |
|
269 |
// valid, access ok? |
|
270 |
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 || |
|
271 |
((env->dtlb_tte[i] & 0x4) && is_user) || |
|
272 |
(!(env->dtlb_tte[i] & 0x2) && (rw == 1))) { |
|
273 |
if (env->dmmuregs[3]) /* Fault status register */ |
|
274 |
env->dmmuregs[3] = 2; /* overflow (not read before another fault) */ |
|
275 |
env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1; |
|
276 |
env->dmmuregs[4] = address; /* Fault address register */ |
|
277 |
env->exception_index = TT_DFAULT; |
|
278 |
#ifdef DEBUG_MMU |
|
279 |
printf("DFAULT at 0x%llx\n", address); |
|
280 |
#endif |
|
281 |
return 1; |
|
276 | 282 |
} |
283 |
*physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL); |
|
284 |
*prot = PAGE_READ; |
|
285 |
if (env->dtlb_tte[i] & 0x2) |
|
286 |
*prot |= PAGE_WRITE; |
|
287 |
return 0; |
|
277 | 288 |
} |
278 | 289 |
} |
279 |
env->exception_index = TT_DFAULT; |
|
290 |
#ifdef DEBUG_MMU |
|
291 |
printf("DMISS at 0x%llx\n", address); |
|
292 |
#endif |
|
293 |
env->exception_index = TT_DMISS; |
|
280 | 294 |
return 1; |
281 | 295 |
} |
282 | 296 |
|
... | ... | |
288 | 302 |
unsigned int i; |
289 | 303 |
|
290 | 304 |
if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */ |
291 |
*physical = address & 0xffffffff;
|
|
305 |
*physical = address; |
|
292 | 306 |
*prot = PAGE_READ; |
293 | 307 |
return 0; |
294 | 308 |
} |
309 |
|
|
295 | 310 |
for (i = 0; i < 64; i++) { |
296 |
if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) { |
|
297 |
switch (env->itlb_tte[i] >> 60) { |
|
298 |
default: |
|
299 |
case 0x4: // 8k |
|
300 |
mask = 0xffffffffffffe000ULL; |
|
301 |
break; |
|
302 |
case 0x5: // 64k |
|
303 |
mask = 0xffffffffffff0000ULL; |
|
304 |
break; |
|
305 |
case 0x6: // 512k |
|
306 |
mask = 0xfffffffffff80000ULL; |
|
307 |
break; |
|
308 |
case 0x7: // 4M |
|
309 |
mask = 0xffffffffffc00000ULL; |
|
311 |
switch ((env->itlb_tte[i] >> 61) & 3) { |
|
312 |
default: |
|
313 |
case 0x0: // 8k |
|
314 |
mask = 0xffffffffffffe000ULL; |
|
315 |
break; |
|
316 |
case 0x1: // 64k |
|
317 |
mask = 0xffffffffffff0000ULL; |
|
318 |
break; |
|
319 |
case 0x2: // 512k |
|
320 |
mask = 0xfffffffffff80000ULL; |
|
321 |
break; |
|
322 |
case 0x3: // 4M |
|
323 |
mask = 0xffffffffffc00000ULL; |
|
310 | 324 |
break; |
325 |
} |
|
326 |
// ctx match, vaddr match? |
|
327 |
if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) && |
|
328 |
(address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) { |
|
329 |
// valid, access ok? |
|
330 |
if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 || |
|
331 |
((env->itlb_tte[i] & 0x4) && is_user)) { |
|
332 |
if (env->immuregs[3]) /* Fault status register */ |
|
333 |
env->immuregs[3] = 2; /* overflow (not read before another fault) */ |
|
334 |
env->immuregs[3] |= (is_user << 3) | 1; |
|
335 |
env->exception_index = TT_TFAULT; |
|
336 |
#ifdef DEBUG_MMU |
|
337 |
printf("TFAULT at 0x%llx\n", address); |
|
338 |
#endif |
|
339 |
return 1; |
|
311 | 340 |
} |
312 |
// ctx match, vaddr match? |
|
313 |
if (env->immuregs[1] == (env->itlb_tag[i] & 0x1fff) && |
|
314 |
(address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) { |
|
315 |
// access ok? |
|
316 |
if ((env->itlb_tte[i] & 0x4) && !(env->pstate & PS_PRIV)) { |
|
317 |
env->exception_index = TT_TFAULT; |
|
318 |
return 1; |
|
319 |
} |
|
320 |
*physical = env->itlb_tte[i] & 0xffffe000; |
|
321 |
*prot = PAGE_READ; |
|
322 |
return 0; |
|
323 |
} |
|
341 |
*physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL); |
|
342 |
*prot = PAGE_READ; |
|
343 |
return 0; |
|
324 | 344 |
} |
325 | 345 |
} |
326 |
env->exception_index = TT_TFAULT; |
|
346 |
#ifdef DEBUG_MMU |
|
347 |
printf("TMISS at 0x%llx\n", address); |
|
348 |
#endif |
|
349 |
env->exception_index = TT_TMISS; |
|
327 | 350 |
return 1; |
328 | 351 |
} |
329 | 352 |
|
... | ... | |
341 | 364 |
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
342 | 365 |
int is_user, int is_softmmu) |
343 | 366 |
{ |
344 |
target_ulong virt_addr; |
|
367 |
target_ulong virt_addr, vaddr;
|
|
345 | 368 |
target_phys_addr_t paddr; |
346 |
unsigned long vaddr; |
|
347 | 369 |
int error_code = 0, prot, ret = 0, access_index; |
348 | 370 |
|
349 | 371 |
error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user); |
350 | 372 |
if (error_code == 0) { |
351 | 373 |
virt_addr = address & TARGET_PAGE_MASK; |
352 | 374 |
vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); |
375 |
#ifdef DEBUG_MMU |
|
376 |
printf("Translate at 0x%llx -> 0x%llx, vaddr 0x%llx\n", address, paddr, vaddr); |
|
377 |
#endif |
|
353 | 378 |
ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); |
354 | 379 |
return ret; |
355 | 380 |
} |
... | ... | |
471 | 496 |
printf("MMU dump ends\n"); |
472 | 497 |
} |
473 | 498 |
#endif |
499 |
#else |
|
500 |
#ifdef DEBUG_MMU |
|
501 |
void dump_mmu(CPUState *env) |
|
502 |
{ |
|
503 |
unsigned int i; |
|
504 |
const char *mask; |
|
505 |
|
|
506 |
printf("MMU contexts: Primary: %lld, Secondary: %lld\n", env->dmmuregs[1], env->dmmuregs[2]); |
|
507 |
if ((env->lsu & DMMU_E) == 0) { |
|
508 |
printf("DMMU disabled\n"); |
|
509 |
} else { |
|
510 |
printf("DMMU dump:\n"); |
|
511 |
for (i = 0; i < 64; i++) { |
|
512 |
switch ((env->dtlb_tte[i] >> 61) & 3) { |
|
513 |
default: |
|
514 |
case 0x0: |
|
515 |
mask = " 8k"; |
|
516 |
break; |
|
517 |
case 0x1: |
|
518 |
mask = " 64k"; |
|
519 |
break; |
|
520 |
case 0x2: |
|
521 |
mask = "512k"; |
|
522 |
break; |
|
523 |
case 0x3: |
|
524 |
mask = " 4M"; |
|
525 |
break; |
|
526 |
} |
|
527 |
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) { |
|
528 |
printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %lld\n", |
|
529 |
env->dtlb_tag[i] & ~0x1fffULL, |
|
530 |
env->dtlb_tte[i] & 0x1ffffffe000ULL, |
|
531 |
mask, |
|
532 |
env->dtlb_tte[i] & 0x4? "priv": "user", |
|
533 |
env->dtlb_tte[i] & 0x2? "RW": "RO", |
|
534 |
env->dtlb_tte[i] & 0x40? "locked": "unlocked", |
|
535 |
env->dtlb_tag[i] & 0x1fffULL); |
|
536 |
} |
|
537 |
} |
|
538 |
} |
|
539 |
if ((env->lsu & IMMU_E) == 0) { |
|
540 |
printf("IMMU disabled\n"); |
|
541 |
} else { |
|
542 |
printf("IMMU dump:\n"); |
|
543 |
for (i = 0; i < 64; i++) { |
|
544 |
switch ((env->itlb_tte[i] >> 61) & 3) { |
|
545 |
default: |
|
546 |
case 0x0: |
|
547 |
mask = " 8k"; |
|
548 |
break; |
|
549 |
case 0x1: |
|
550 |
mask = " 64k"; |
|
551 |
break; |
|
552 |
case 0x2: |
|
553 |
mask = "512k"; |
|
554 |
break; |
|
555 |
case 0x3: |
|
556 |
mask = " 4M"; |
|
557 |
break; |
|
558 |
} |
|
559 |
if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) { |
|
560 |
printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %lld\n", |
|
561 |
env->itlb_tag[i] & ~0x1fffULL, |
|
562 |
env->itlb_tte[i] & 0x1ffffffe000ULL, |
|
563 |
mask, |
|
564 |
env->itlb_tte[i] & 0x4? "priv": "user", |
|
565 |
env->itlb_tte[i] & 0x40? "locked": "unlocked", |
|
566 |
env->itlb_tag[i] & 0x1fffULL); |
|
567 |
} |
|
568 |
} |
|
569 |
} |
|
570 |
} |
|
571 |
#endif |
|
474 | 572 |
#endif |
Also available in: Unified diff