Commit c294fc587a52f4991b1dcbb328b5a9d09f8c8e2e
1 parent
9c02f1a2
Improve PowerPC 405 MMU model / share more code for other embedded targets
support. Fix PowerPC 405 MSR mask. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2717 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
111 additions
and
57 deletions
target-ppc/cpu.h
... | ... | @@ -881,9 +881,11 @@ void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value); |
881 | 881 | target_ulong load_40x_pit (CPUPPCState *env); |
882 | 882 | void store_40x_pit (CPUPPCState *env, target_ulong val); |
883 | 883 | void store_40x_dbcr0 (CPUPPCState *env, uint32_t val); |
884 | +void store_40x_sler (CPUPPCState *env, uint32_t val); | |
884 | 885 | void store_booke_tcr (CPUPPCState *env, target_ulong val); |
885 | 886 | void store_booke_tsr (CPUPPCState *env, target_ulong val); |
886 | 887 | void ppc_tlb_invalidate_all (CPUPPCState *env); |
888 | +int ppcemb_tlb_search (CPUPPCState *env, target_ulong address); | |
887 | 889 | #endif |
888 | 890 | #endif |
889 | 891 | ... | ... |
target-ppc/helper.c
... | ... | @@ -632,6 +632,58 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, |
632 | 632 | return ret; |
633 | 633 | } |
634 | 634 | |
635 | +/* Generic TLB check function for embedded PowerPC implementations */ | |
636 | +static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, | |
637 | + target_phys_addr_t *raddrp, | |
638 | + target_ulong address, int i) | |
639 | +{ | |
640 | + target_ulong mask; | |
641 | + | |
642 | + /* Check valid flag */ | |
643 | + if (!(tlb->prot & PAGE_VALID)) { | |
644 | + if (loglevel != 0) | |
645 | + fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); | |
646 | + return -1; | |
647 | + } | |
648 | + mask = ~(tlb->size - 1); | |
649 | + if (loglevel != 0) { | |
650 | + fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " | |
651 | + ADDRX " " ADDRX " %d\n", | |
652 | + __func__, i, address, (int)env->spr[SPR_40x_PID], | |
653 | + tlb->EPN, mask, (int)tlb->PID); | |
654 | + } | |
655 | + /* Check PID */ | |
656 | + if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) | |
657 | + return -1; | |
658 | + /* Check effective address */ | |
659 | + if ((address & mask) != tlb->EPN) | |
660 | + return -1; | |
661 | + *raddrp = (tlb->RPN & mask) | (address & ~mask); | |
662 | + | |
663 | + return 0; | |
664 | +} | |
665 | + | |
666 | +/* Generic TLB search function for PowerPC embedded implementations */ | |
667 | +int ppcemb_tlb_search (CPUState *env, target_ulong address) | |
668 | +{ | |
669 | + ppcemb_tlb_t *tlb; | |
670 | + target_phys_addr_t raddr; | |
671 | + int i, ret; | |
672 | + | |
673 | + /* Default return value is no match */ | |
674 | + ret = -1; | |
675 | + for (i = 0; i < 64; i++) { | |
676 | + tlb = &env->tlb[i].tlbe; | |
677 | + if (ppcemb_tlb_check(env, tlb, &raddr, address, i) == 0) { | |
678 | + ret = i; | |
679 | + break; | |
680 | + } | |
681 | + } | |
682 | + | |
683 | + return ret; | |
684 | +} | |
685 | + | |
686 | +/* Helpers specific to PowerPC 40x implementations */ | |
635 | 687 | void ppc4xx_tlb_invalidate_all (CPUState *env) |
636 | 688 | { |
637 | 689 | ppcemb_tlb_t *tlb; |
... | ... | @@ -656,33 +708,14 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
656 | 708 | { |
657 | 709 | ppcemb_tlb_t *tlb; |
658 | 710 | target_phys_addr_t raddr; |
659 | - target_ulong mask; | |
660 | 711 | int i, ret, zsel, zpr; |
661 | 712 | |
662 | 713 | ret = -1; |
663 | 714 | raddr = -1; |
664 | 715 | for (i = 0; i < env->nb_tlb; i++) { |
665 | 716 | tlb = &env->tlb[i].tlbe; |
666 | - /* Check valid flag */ | |
667 | - if (!(tlb->prot & PAGE_VALID)) { | |
668 | - if (loglevel != 0) | |
669 | - fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); | |
670 | - continue; | |
671 | - } | |
672 | - mask = ~(tlb->size - 1); | |
673 | - if (loglevel != 0) { | |
674 | - fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " | |
675 | - ADDRX " " ADDRX " %d\n", | |
676 | - __func__, i, address, (int)env->spr[SPR_40x_PID], | |
677 | - tlb->EPN, mask, (int)tlb->PID); | |
678 | - } | |
679 | - /* Check PID */ | |
680 | - if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) | |
681 | - continue; | |
682 | - /* Check effective address */ | |
683 | - if ((address & mask) != tlb->EPN) | |
717 | + if (ppcemb_tlb_check(env, tlb, &raddr, address, i) < 0) | |
684 | 718 | continue; |
685 | - raddr = (tlb->RPN & mask) | (address & ~mask); | |
686 | 719 | zsel = (tlb->attr >> 4) & 0xF; |
687 | 720 | zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3; |
688 | 721 | if (loglevel != 0) { |
... | ... | @@ -692,6 +725,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
692 | 725 | if (access_type == ACCESS_CODE) { |
693 | 726 | /* Check execute enable bit */ |
694 | 727 | switch (zpr) { |
728 | + case 0x2: | |
729 | + if (msr_pr) | |
730 | + goto check_exec_perm; | |
731 | + goto exec_granted; | |
695 | 732 | case 0x0: |
696 | 733 | if (msr_pr) { |
697 | 734 | ctx->prot = 0; |
... | ... | @@ -700,7 +737,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
700 | 737 | } |
701 | 738 | /* No break here */ |
702 | 739 | case 0x1: |
703 | - case 0x2: | |
740 | + check_exec_perm: | |
704 | 741 | /* Check from TLB entry */ |
705 | 742 | if (!(tlb->prot & PAGE_EXEC)) { |
706 | 743 | ret = -3; |
... | ... | @@ -714,6 +751,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
714 | 751 | } |
715 | 752 | break; |
716 | 753 | case 0x3: |
754 | + exec_granted: | |
717 | 755 | /* All accesses granted */ |
718 | 756 | ctx->prot = PAGE_READ | PAGE_WRITE; |
719 | 757 | ret = 0; |
... | ... | @@ -721,6 +759,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
721 | 759 | } |
722 | 760 | } else { |
723 | 761 | switch (zpr) { |
762 | + case 0x2: | |
763 | + if (msr_pr) | |
764 | + goto check_rw_perm; | |
765 | + goto rw_granted; | |
724 | 766 | case 0x0: |
725 | 767 | if (msr_pr) { |
726 | 768 | ctx->prot = 0; |
... | ... | @@ -729,7 +771,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
729 | 771 | } |
730 | 772 | /* No break here */ |
731 | 773 | case 0x1: |
732 | - case 0x2: | |
774 | + check_rw_perm: | |
733 | 775 | /* Check from TLB entry */ |
734 | 776 | /* Check write protection bit */ |
735 | 777 | if (tlb->prot & PAGE_WRITE) { |
... | ... | @@ -744,6 +786,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
744 | 786 | } |
745 | 787 | break; |
746 | 788 | case 0x3: |
789 | + rw_granted: | |
747 | 790 | /* All accesses granted */ |
748 | 791 | ctx->prot = PAGE_READ | PAGE_WRITE; |
749 | 792 | ret = 0; |
... | ... | @@ -769,6 +812,15 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
769 | 812 | return ret; |
770 | 813 | } |
771 | 814 | |
815 | +void store_40x_sler (CPUPPCState *env, uint32_t val) | |
816 | +{ | |
817 | + /* XXX: TO BE FIXED */ | |
818 | + if (val != 0x00000000) { | |
819 | + cpu_abort(env, "Little-endian regions are not supported by now\n"); | |
820 | + } | |
821 | + env->spr[SPR_405_SLER] = val; | |
822 | +} | |
823 | + | |
772 | 824 | static int check_physical (CPUState *env, mmu_ctx_t *ctx, |
773 | 825 | target_ulong eaddr, int rw) |
774 | 826 | { | ... | ... |
target-ppc/op.c
... | ... | @@ -2459,6 +2459,12 @@ void OPPROTO op_store_40x_dbcr0 (void) |
2459 | 2459 | store_40x_dbcr0(env, T0); |
2460 | 2460 | } |
2461 | 2461 | |
2462 | +void OPPROTO op_store_40x_sler (void) | |
2463 | +{ | |
2464 | + store_40x_sler(env, T0); | |
2465 | + RETURN(); | |
2466 | +} | |
2467 | + | |
2462 | 2468 | void OPPROTO op_store_booke_tcr (void) |
2463 | 2469 | { |
2464 | 2470 | store_booke_tcr(env, T0); | ... | ... |
target-ppc/op_helper.c
... | ... | @@ -2494,44 +2494,16 @@ void do_4xx_tlbre_hi (void) |
2494 | 2494 | T0 |= 0x100; |
2495 | 2495 | } |
2496 | 2496 | |
2497 | -static int tlb_4xx_search (target_ulong virtual) | |
2498 | -{ | |
2499 | - ppcemb_tlb_t *tlb; | |
2500 | - target_ulong base, mask; | |
2501 | - int i, ret; | |
2502 | - | |
2503 | - /* Default return value is no match */ | |
2504 | - ret = -1; | |
2505 | - for (i = 0; i < 64; i++) { | |
2506 | - tlb = &env->tlb[i].tlbe; | |
2507 | - /* Check TLB validity */ | |
2508 | - if (!(tlb->prot & PAGE_VALID)) | |
2509 | - continue; | |
2510 | - /* Check TLB PID vs current PID */ | |
2511 | - if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) | |
2512 | - continue; | |
2513 | - /* Check TLB address vs virtual address */ | |
2514 | - base = tlb->EPN; | |
2515 | - mask = ~(tlb->size - 1); | |
2516 | - if ((base & mask) != (virtual & mask)) | |
2517 | - continue; | |
2518 | - ret = i; | |
2519 | - break; | |
2520 | - } | |
2521 | - | |
2522 | - return ret; | |
2523 | -} | |
2524 | - | |
2525 | 2497 | void do_4xx_tlbsx (void) |
2526 | 2498 | { |
2527 | - T0 = tlb_4xx_search(T0); | |
2499 | + T0 = ppcemb_tlb_search(env, T0); | |
2528 | 2500 | } |
2529 | 2501 | |
2530 | 2502 | void do_4xx_tlbsx_ (void) |
2531 | 2503 | { |
2532 | 2504 | int tmp = xer_ov; |
2533 | 2505 | |
2534 | - T0 = tlb_4xx_search(T0); | |
2506 | + T0 = ppcemb_tlb_search(env, T0); | |
2535 | 2507 | if (T0 != -1) |
2536 | 2508 | tmp |= 0x02; |
2537 | 2509 | env->crf[0] = tmp; |
... | ... | @@ -2562,16 +2534,28 @@ void do_4xx_tlbwe_hi (void) |
2562 | 2534 | tlb_flush_page(env, page); |
2563 | 2535 | } |
2564 | 2536 | tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7); |
2537 | + /* We cannot handle TLB size < TARGET_PAGE_SIZE. | |
2538 | + * If this ever occurs, one should use the ppcemb target instead | |
2539 | + * of the ppc or ppc64 one | |
2540 | + */ | |
2541 | + if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) { | |
2542 | + cpu_abort(env, "TLB size %u < %u are not supported (%d)\n", | |
2543 | + tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7)); | |
2544 | + } | |
2565 | 2545 | tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); |
2566 | 2546 | if (T1 & 0x40) |
2567 | 2547 | tlb->prot |= PAGE_VALID; |
2568 | 2548 | else |
2569 | 2549 | tlb->prot &= ~PAGE_VALID; |
2550 | + if (T1 & 0x20) { | |
2551 | + /* XXX: TO BE FIXED */ | |
2552 | + cpu_abort(env, "Little-endian TLB entries are not supported by now\n"); | |
2553 | + } | |
2570 | 2554 | tlb->PID = env->spr[SPR_40x_PID]; /* PID */ |
2571 | 2555 | tlb->attr = T1 & 0xFF; |
2572 | 2556 | #if defined (DEBUG_SOFTWARE_TLB) |
2573 | - if (loglevel) { | |
2574 | - fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX | |
2557 | + if (loglevel != 0) { | |
2558 | + fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX | |
2575 | 2559 | " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, |
2576 | 2560 | (int)T0, tlb->RPN, tlb->EPN, tlb->size, |
2577 | 2561 | tlb->prot & PAGE_READ ? 'r' : '-', | ... | ... |
target-ppc/translate_init.c
... | ... | @@ -355,6 +355,17 @@ static void spr_write_40x_dbcr0 (void *opaque, int sprn) |
355 | 355 | RET_STOP(ctx); |
356 | 356 | } |
357 | 357 | |
358 | +static void spr_write_40x_sler (void *opaque, int sprn) | |
359 | +{ | |
360 | + DisasContext *ctx = opaque; | |
361 | + | |
362 | + gen_op_store_40x_sler(); | |
363 | + /* We must stop the translation as we may have changed | |
364 | + * some regions endianness | |
365 | + */ | |
366 | + RET_STOP(ctx); | |
367 | +} | |
368 | + | |
358 | 369 | static void spr_write_booke_tcr (void *opaque, int sprn) |
359 | 370 | { |
360 | 371 | gen_op_store_booke_tcr(); |
... | ... | @@ -1711,10 +1722,9 @@ static void gen_spr_405 (CPUPPCState *env) |
1711 | 1722 | &spr_read_generic, &spr_write_generic, |
1712 | 1723 | 0x00000000); |
1713 | 1724 | /* Storage control */ |
1714 | - /* XXX : not implemented */ | |
1715 | 1725 | spr_register(env, SPR_405_SLER, "SLER", |
1716 | 1726 | SPR_NOACCESS, SPR_NOACCESS, |
1717 | - &spr_read_generic, &spr_write_generic, | |
1727 | + &spr_read_generic, &spr_write_40x_sler, | |
1718 | 1728 | 0x00000000); |
1719 | 1729 | /* XXX : not implemented */ |
1720 | 1730 | spr_register(env, SPR_405_SU0R, "SU0R", |
... | ... | @@ -2837,7 +2847,7 @@ static ppc_def_t ppc_defs[] = { |
2837 | 2847 | .pvr_mask = 0xFFFFFFFF, |
2838 | 2848 | .insns_flags = PPC_INSNS_405, |
2839 | 2849 | .flags = PPC_FLAGS_405, |
2840 | - .msr_mask = 0x00000000020EFF30ULL, | |
2850 | + .msr_mask = 0x00000000000ED630ULL, | |
2841 | 2851 | }, |
2842 | 2852 | #if defined (TODO) |
2843 | 2853 | /* PowerPC 405 EZ */ | ... | ... |