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 */ | ... | ... |