Revision a8dea12f
b/target-ppc/helper.c | ||
---|---|---|
549 | 549 |
if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { |
550 | 550 |
/* Software TLB search */ |
551 | 551 |
ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); |
552 |
} else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { |
|
553 |
/* XXX: TODO */ |
|
554 | 552 |
} else { |
555 | 553 |
#if defined (DEBUG_MMU) |
556 | 554 |
if (loglevel > 0) { |
... | ... | |
632 | 630 |
return ret; |
633 | 631 |
} |
634 | 632 |
|
633 |
int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
|
634 |
uint32_t address, int rw, int access_type) |
|
635 |
{ |
|
636 |
ppcemb_tlb_t *tlb; |
|
637 |
target_phys_addr_t raddr; |
|
638 |
target_ulong mask; |
|
639 |
int i, ret, zsel, zpr; |
|
640 |
|
|
641 |
ret = -6; |
|
642 |
for (i = 0; i < env->nb_tlb; i++) { |
|
643 |
tlb = &env->tlb[i].tlbe; |
|
644 |
/* Check valid flag */ |
|
645 |
if (!(tlb->prot & PAGE_VALID)) { |
|
646 |
if (loglevel) |
|
647 |
fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); |
|
648 |
continue; |
|
649 |
} |
|
650 |
mask = ~(tlb->size - 1); |
|
651 |
if (loglevel) { |
|
652 |
fprintf(logfile, "%s: TLB %d address %08x PID %04x <=> " |
|
653 |
"%08x %08x %04x\n", |
|
654 |
__func__, i, address, env->spr[SPR_40x_PID], |
|
655 |
tlb->EPN, mask, tlb->PID); |
|
656 |
} |
|
657 |
/* Check PID */ |
|
658 |
if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) |
|
659 |
continue; |
|
660 |
/* Check effective address */ |
|
661 |
if ((address & mask) != tlb->EPN) |
|
662 |
continue; |
|
663 |
raddr = (tlb->RPN & mask) | (address & ~mask); |
|
664 |
zsel = (tlb->attr >> 4) & 0xF; |
|
665 |
zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3; |
|
666 |
if (loglevel) { |
|
667 |
fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n", |
|
668 |
__func__, i, zsel, zpr, rw, tlb->attr); |
|
669 |
} |
|
670 |
if (access_type == ACCESS_CODE) { |
|
671 |
/* Check execute enable bit */ |
|
672 |
switch (zpr) { |
|
673 |
case 0x0: |
|
674 |
if (msr_pr) { |
|
675 |
ret = -3; |
|
676 |
ctx->prot = 0; |
|
677 |
break; |
|
678 |
} |
|
679 |
/* No break here */ |
|
680 |
case 0x1: |
|
681 |
case 0x2: |
|
682 |
/* Check from TLB entry */ |
|
683 |
if (!(tlb->prot & PAGE_EXEC)) { |
|
684 |
ret = -3; |
|
685 |
} else { |
|
686 |
if (tlb->prot & PAGE_WRITE) |
|
687 |
ctx->prot = PAGE_READ | PAGE_WRITE; |
|
688 |
else |
|
689 |
ctx->prot = PAGE_READ; |
|
690 |
ret = 0; |
|
691 |
} |
|
692 |
break; |
|
693 |
case 0x3: |
|
694 |
/* All accesses granted */ |
|
695 |
ret = 0; |
|
696 |
ctx->prot = PAGE_READ | PAGE_WRITE; |
|
697 |
break; |
|
698 |
} |
|
699 |
} else { |
|
700 |
switch (zpr) { |
|
701 |
case 0x0: |
|
702 |
if (msr_pr) { |
|
703 |
ret = -2; |
|
704 |
ctx->prot = 0; |
|
705 |
break; |
|
706 |
} |
|
707 |
/* No break here */ |
|
708 |
case 0x1: |
|
709 |
case 0x2: |
|
710 |
/* Check from TLB entry */ |
|
711 |
/* Check write protection bit */ |
|
712 |
if (rw && !(tlb->prot & PAGE_WRITE)) { |
|
713 |
ret = -2; |
|
714 |
} else { |
|
715 |
ret = 2; |
|
716 |
if (tlb->prot & PAGE_WRITE) |
|
717 |
ctx->prot = PAGE_READ | PAGE_WRITE; |
|
718 |
else |
|
719 |
ctx->prot = PAGE_READ; |
|
720 |
} |
|
721 |
break; |
|
722 |
case 0x3: |
|
723 |
/* All accesses granted */ |
|
724 |
ret = 2; |
|
725 |
ctx->prot = PAGE_READ | PAGE_WRITE; |
|
726 |
break; |
|
727 |
} |
|
728 |
} |
|
729 |
if (ret >= 0) { |
|
730 |
ctx->raddr = raddr; |
|
731 |
if (loglevel) { |
|
732 |
fprintf(logfile, "%s: access granted " ADDRX " => " REGX |
|
733 |
" %d\n", __func__, address, ctx->raddr, ctx->prot); |
|
734 |
} |
|
735 |
return i; |
|
736 |
} |
|
737 |
} |
|
738 |
|
|
739 |
return ret; |
|
740 |
} |
|
741 |
|
|
635 | 742 |
static int check_physical (CPUState *env, mmu_ctx_t *ctx, |
636 | 743 |
target_ulong eaddr, int rw) |
637 | 744 |
{ |
... | ... | |
682 | 789 |
/* No address translation */ |
683 | 790 |
ret = check_physical(env, ctx, eaddr, rw); |
684 | 791 |
} else { |
685 |
/* Try to find a BAT */ |
|
686 |
ret = -1; |
|
687 |
if (check_BATs) |
|
688 |
ret = get_bat(env, ctx, eaddr, rw, access_type); |
|
689 |
if (ret < 0) { |
|
690 |
/* We didn't match any BAT entry */ |
|
691 |
ret = get_segment(env, ctx, eaddr, rw, access_type); |
|
792 |
switch (PPC_MMU(env)) { |
|
793 |
case PPC_FLAGS_MMU_32B: |
|
794 |
case PPC_FLAGS_MMU_SOFT_6xx: |
|
795 |
/* Try to find a BAT */ |
|
796 |
ret = -1; |
|
797 |
if (check_BATs) |
|
798 |
ret = get_bat(env, ctx, eaddr, rw, access_type); |
|
799 |
if (ret < 0) { |
|
800 |
/* We didn't match any BAT entry */ |
|
801 |
ret = get_segment(env, ctx, eaddr, rw, access_type); |
|
802 |
} |
|
803 |
break; |
|
804 |
case PPC_FLAGS_MMU_SOFT_4xx: |
|
805 |
ret = mmu4xx_get_physical_address(env, ctx, eaddr, |
|
806 |
rw, access_type); |
|
807 |
break; |
|
808 |
default: |
|
809 |
/* XXX: TODO */ |
|
810 |
cpu_abort(env, "MMU model not implemented\n"); |
|
811 |
return -1; |
|
692 | 812 |
} |
693 | 813 |
} |
694 | 814 |
#if 0 |
... | ... | |
753 | 873 |
error_code = 1 << 18; |
754 | 874 |
goto tlb_miss; |
755 | 875 |
} else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { |
756 |
/* XXX: TODO */ |
|
876 |
exception = EXCP_40x_ITLBMISS; |
|
877 |
error_code = 0; |
|
878 |
env->spr[SPR_40x_DEAR] = address; |
|
879 |
env->spr[SPR_40x_ESR] = 0x00000000; |
|
757 | 880 |
} else { |
758 | 881 |
error_code = 0x40000000; |
759 | 882 |
} |
... | ... | |
799 | 922 |
/* Do not alter DAR nor DSISR */ |
800 | 923 |
goto out; |
801 | 924 |
} else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { |
802 |
/* XXX: TODO */ |
|
925 |
exception = EXCP_40x_DTLBMISS; |
|
926 |
error_code = 0; |
|
927 |
env->spr[SPR_40x_DEAR] = address; |
|
928 |
if (rw) |
|
929 |
env->spr[SPR_40x_ESR] = 0x00800000; |
|
930 |
else |
|
931 |
env->spr[SPR_40x_ESR] = 0x00000000; |
|
803 | 932 |
} else { |
804 | 933 |
error_code = 0x40000000; |
805 | 934 |
} |
... | ... | |
1518 | 1647 |
switch (PPC_EXCP(env)) { |
1519 | 1648 |
case PPC_FLAGS_EXCP_40x: |
1520 | 1649 |
/* DTLBMISS on 4xx */ |
1521 |
/* XXX: TODO */ |
|
1522 |
cpu_abort(env, |
|
1523 |
"40x DTLBMISS exception is not implemented yet !\n"); |
|
1650 |
msr &= ~0xFFFF0000; |
|
1524 | 1651 |
goto store_next; |
1525 | 1652 |
case PPC_FLAGS_EXCP_602: |
1526 | 1653 |
case PPC_FLAGS_EXCP_603: |
... | ... | |
1538 | 1665 |
switch (PPC_EXCP(env)) { |
1539 | 1666 |
case PPC_FLAGS_EXCP_40x: |
1540 | 1667 |
/* ITLBMISS on 4xx */ |
1541 |
/* XXX: TODO */ |
|
1542 |
cpu_abort(env, |
|
1543 |
"40x ITLBMISS exception is not implemented yet !\n"); |
|
1668 |
msr &= ~0xFFFF0000; |
|
1544 | 1669 |
goto store_next; |
1545 | 1670 |
case PPC_FLAGS_EXCP_602: |
1546 | 1671 |
case PPC_FLAGS_EXCP_603: |
b/target-ppc/op_helper.c | ||
---|---|---|
2365 | 2365 |
way, is_code, CMP, RPN); |
2366 | 2366 |
} |
2367 | 2367 |
|
2368 |
static target_ulong booke_tlb_to_page_size (int size) |
|
2369 |
{ |
|
2370 |
return 1024 << (2 * size); |
|
2371 |
} |
|
2372 |
|
|
2373 |
static int booke_page_size_to_tlb (target_ulong page_size) |
|
2374 |
{ |
|
2375 |
int size; |
|
2376 |
|
|
2377 |
switch (page_size) { |
|
2378 |
case 0x00000400UL: |
|
2379 |
size = 0x0; |
|
2380 |
break; |
|
2381 |
case 0x00001000UL: |
|
2382 |
size = 0x1; |
|
2383 |
break; |
|
2384 |
case 0x00004000UL: |
|
2385 |
size = 0x2; |
|
2386 |
break; |
|
2387 |
case 0x00010000UL: |
|
2388 |
size = 0x3; |
|
2389 |
break; |
|
2390 |
case 0x00040000UL: |
|
2391 |
size = 0x4; |
|
2392 |
break; |
|
2393 |
case 0x00100000UL: |
|
2394 |
size = 0x5; |
|
2395 |
break; |
|
2396 |
case 0x00400000UL: |
|
2397 |
size = 0x6; |
|
2398 |
break; |
|
2399 |
case 0x01000000UL: |
|
2400 |
size = 0x7; |
|
2401 |
break; |
|
2402 |
case 0x04000000UL: |
|
2403 |
size = 0x8; |
|
2404 |
break; |
|
2405 |
case 0x10000000UL: |
|
2406 |
size = 0x9; |
|
2407 |
break; |
|
2408 |
case 0x40000000UL: |
|
2409 |
size = 0xA; |
|
2410 |
break; |
|
2411 |
#if defined (TARGET_PPC64) |
|
2412 |
case 0x000100000000ULL: |
|
2413 |
size = 0xB; |
|
2414 |
break; |
|
2415 |
case 0x000400000000ULL: |
|
2416 |
size = 0xC; |
|
2417 |
break; |
|
2418 |
case 0x001000000000ULL: |
|
2419 |
size = 0xD; |
|
2420 |
break; |
|
2421 |
case 0x004000000000ULL: |
|
2422 |
size = 0xE; |
|
2423 |
break; |
|
2424 |
case 0x010000000000ULL: |
|
2425 |
size = 0xF; |
|
2426 |
break; |
|
2427 |
#endif |
|
2428 |
default: |
|
2429 |
size = -1; |
|
2430 |
break; |
|
2431 |
} |
|
2432 |
|
|
2433 |
return size; |
|
2434 |
} |
|
2435 |
|
|
2368 | 2436 |
/* Helpers for 4xx TLB management */ |
2369 | 2437 |
void do_4xx_tlbia (void) |
2370 | 2438 |
{ |
2371 |
#if 0 |
|
2372 |
ppc_tlb_t *tlb; |
|
2373 |
target_ulong page, end; |
|
2439 |
ppcemb_tlb_t *tlb; |
|
2374 | 2440 |
int i; |
2375 | 2441 |
|
2376 | 2442 |
for (i = 0; i < 64; i++) { |
2377 |
tlb = &env->tlb[i]; |
|
2443 |
tlb = &env->tlb[i].tlbe;
|
|
2378 | 2444 |
if (tlb->prot & PAGE_VALID) { |
2445 |
#if 0 |
|
2379 | 2446 |
end = tlb->EPN + tlb->size; |
2380 | 2447 |
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) |
2381 | 2448 |
tlb_flush_page(env, page); |
2449 |
#endif |
|
2382 | 2450 |
tlb->prot &= ~PAGE_VALID; |
2383 | 2451 |
} |
2384 | 2452 |
} |
2385 |
#endif
|
|
2453 |
tlb_flush(env, 1);
|
|
2386 | 2454 |
} |
2387 | 2455 |
|
2388 | 2456 |
void do_4xx_tlbre_lo (void) |
2389 | 2457 |
{ |
2390 |
#if 0
|
|
2391 |
ppc_tlb_t *tlb;
|
|
2458 |
ppcemb_tlb_t *tlb;
|
|
2459 |
int size;
|
|
2392 | 2460 |
|
2393 | 2461 |
T0 &= 0x3F; |
2394 |
tlb = &env->tlb[T0]; |
|
2395 |
T0 = tlb->stor[0]; |
|
2396 |
env->spr[SPR_40x_PID] = tlb->pid; |
|
2397 |
#endif |
|
2462 |
tlb = &env->tlb[T0].tlbe; |
|
2463 |
T0 = tlb->EPN; |
|
2464 |
if (tlb->prot & PAGE_VALID) |
|
2465 |
T0 |= 0x400; |
|
2466 |
size = booke_page_size_to_tlb(tlb->size); |
|
2467 |
if (size < 0 || size > 0x7) |
|
2468 |
size = 1; |
|
2469 |
T0 |= size << 7; |
|
2470 |
env->spr[SPR_40x_PID] = tlb->PID; |
|
2398 | 2471 |
} |
2399 | 2472 |
|
2400 | 2473 |
void do_4xx_tlbre_hi (void) |
2401 | 2474 |
{ |
2402 |
#if 0 |
|
2403 |
ppc_tlb_t *tlb; |
|
2475 |
ppcemb_tlb_t *tlb; |
|
2404 | 2476 |
|
2405 | 2477 |
T0 &= 0x3F; |
2406 |
tlb = &env->tlb[T0]; |
|
2407 |
T0 = tlb->stor[1]; |
|
2408 |
#endif |
|
2478 |
tlb = &env->tlb[T0].tlbe; |
|
2479 |
T0 = tlb->RPN; |
|
2480 |
if (tlb->prot & PAGE_EXEC) |
|
2481 |
T0 |= 0x200; |
|
2482 |
if (tlb->prot & PAGE_WRITE) |
|
2483 |
T0 |= 0x100; |
|
2409 | 2484 |
} |
2410 | 2485 |
|
2411 | 2486 |
static int tlb_4xx_search (target_ulong virtual) |
2412 | 2487 |
{ |
2413 |
#if 0 |
|
2414 |
ppc_tlb_t *tlb; |
|
2488 |
ppcemb_tlb_t *tlb; |
|
2415 | 2489 |
target_ulong base, mask; |
2416 | 2490 |
int i, ret; |
2417 | 2491 |
|
2418 | 2492 |
/* Default return value is no match */ |
2419 | 2493 |
ret = -1; |
2420 | 2494 |
for (i = 0; i < 64; i++) { |
2421 |
tlb = &env->tlb[i]; |
|
2495 |
tlb = &env->tlb[i].tlbe;
|
|
2422 | 2496 |
/* Check TLB validity */ |
2423 | 2497 |
if (!(tlb->prot & PAGE_VALID)) |
2424 | 2498 |
continue; |
2425 | 2499 |
/* Check TLB PID vs current PID */ |
2426 |
if (tlb->pid != 0 && tlb->pid != env->spr[SPR_40x_PID])
|
|
2500 |
if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID])
|
|
2427 | 2501 |
continue; |
2428 | 2502 |
/* Check TLB address vs virtual address */ |
2429 | 2503 |
base = tlb->EPN; |
... | ... | |
2435 | 2509 |
} |
2436 | 2510 |
|
2437 | 2511 |
return ret; |
2438 |
#else |
|
2439 |
return -1; |
|
2440 |
#endif |
|
2441 | 2512 |
} |
2442 | 2513 |
|
2443 | 2514 |
void do_4xx_tlbsx (void) |
... | ... | |
2457 | 2528 |
|
2458 | 2529 |
void do_4xx_tlbwe_lo (void) |
2459 | 2530 |
{ |
2460 |
#if 0 |
|
2461 |
ppc_tlb_t *tlb; |
|
2531 |
ppcemb_tlb_t *tlb; |
|
2462 | 2532 |
target_ulong page, end; |
2463 | 2533 |
|
2464 | 2534 |
T0 &= 0x3F; |
2465 |
tlb = &env->tlb[T0]; |
|
2535 |
tlb = &env->tlb[T0].tlbe;
|
|
2466 | 2536 |
/* Invalidate previous TLB (if it's valid) */ |
2467 | 2537 |
if (tlb->prot & PAGE_VALID) { |
2468 | 2538 |
end = tlb->EPN + tlb->size; |
2469 | 2539 |
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) |
2470 | 2540 |
tlb_flush_page(env, page); |
2471 | 2541 |
} |
2472 |
tlb->size = 1024 << (2 * ((T1 >> 7) & 0x7));
|
|
2542 |
tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
|
|
2473 | 2543 |
tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); |
2474 | 2544 |
if (T1 & 0x400) |
2475 | 2545 |
tlb->prot |= PAGE_VALID; |
2476 | 2546 |
else |
2477 | 2547 |
tlb->prot &= ~PAGE_VALID; |
2478 |
tlb->pid = env->spr[SPR_BOOKE_PID]; /* PID */ |
|
2548 |
tlb->PID = env->spr[SPR_BOOKE_PID]; /* PID */ |
|
2549 |
tlb->attr = T1 & 0xFF; |
|
2479 | 2550 |
/* Invalidate new TLB (if valid) */ |
2480 | 2551 |
if (tlb->prot & PAGE_VALID) { |
2481 | 2552 |
end = tlb->EPN + tlb->size; |
2482 | 2553 |
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) |
2483 | 2554 |
tlb_flush_page(env, page); |
2484 | 2555 |
} |
2485 |
#endif |
|
2486 | 2556 |
} |
2487 | 2557 |
|
2488 | 2558 |
void do_4xx_tlbwe_hi (void) |
2489 | 2559 |
{ |
2490 |
#if 0 |
|
2491 |
ppc_tlb_t *tlb; |
|
2560 |
ppcemb_tlb_t *tlb; |
|
2492 | 2561 |
|
2493 | 2562 |
T0 &= 0x3F; |
2494 |
tlb = &env->tlb[T0]; |
|
2563 |
tlb = &env->tlb[T0].tlbe;
|
|
2495 | 2564 |
tlb->RPN = T1 & 0xFFFFFC00; |
2496 | 2565 |
tlb->prot = PAGE_READ; |
2497 | 2566 |
if (T1 & 0x200) |
2498 | 2567 |
tlb->prot |= PAGE_EXEC; |
2499 | 2568 |
if (T1 & 0x100) |
2500 | 2569 |
tlb->prot |= PAGE_WRITE; |
2501 |
#endif |
|
2502 | 2570 |
} |
2503 | 2571 |
#endif /* !CONFIG_USER_ONLY */ |
Also available in: Unified diff