Commit c294fc587a52f4991b1dcbb328b5a9d09f8c8e2e

Authored by j_mayer
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
target-ppc/cpu.h
@@ -881,9 +881,11 @@ void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value); @@ -881,9 +881,11 @@ void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value);
881 target_ulong load_40x_pit (CPUPPCState *env); 881 target_ulong load_40x_pit (CPUPPCState *env);
882 void store_40x_pit (CPUPPCState *env, target_ulong val); 882 void store_40x_pit (CPUPPCState *env, target_ulong val);
883 void store_40x_dbcr0 (CPUPPCState *env, uint32_t val); 883 void store_40x_dbcr0 (CPUPPCState *env, uint32_t val);
  884 +void store_40x_sler (CPUPPCState *env, uint32_t val);
884 void store_booke_tcr (CPUPPCState *env, target_ulong val); 885 void store_booke_tcr (CPUPPCState *env, target_ulong val);
885 void store_booke_tsr (CPUPPCState *env, target_ulong val); 886 void store_booke_tsr (CPUPPCState *env, target_ulong val);
886 void ppc_tlb_invalidate_all (CPUPPCState *env); 887 void ppc_tlb_invalidate_all (CPUPPCState *env);
  888 +int ppcemb_tlb_search (CPUPPCState *env, target_ulong address);
887 #endif 889 #endif
888 #endif 890 #endif
889 891
target-ppc/helper.c
@@ -632,6 +632,58 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, @@ -632,6 +632,58 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
632 return ret; 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 void ppc4xx_tlb_invalidate_all (CPUState *env) 687 void ppc4xx_tlb_invalidate_all (CPUState *env)
636 { 688 {
637 ppcemb_tlb_t *tlb; 689 ppcemb_tlb_t *tlb;
@@ -656,33 +708,14 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, @@ -656,33 +708,14 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
656 { 708 {
657 ppcemb_tlb_t *tlb; 709 ppcemb_tlb_t *tlb;
658 target_phys_addr_t raddr; 710 target_phys_addr_t raddr;
659 - target_ulong mask;  
660 int i, ret, zsel, zpr; 711 int i, ret, zsel, zpr;
661 712
662 ret = -1; 713 ret = -1;
663 raddr = -1; 714 raddr = -1;
664 for (i = 0; i < env->nb_tlb; i++) { 715 for (i = 0; i < env->nb_tlb; i++) {
665 tlb = &env->tlb[i].tlbe; 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 continue; 718 continue;
685 - raddr = (tlb->RPN & mask) | (address & ~mask);  
686 zsel = (tlb->attr >> 4) & 0xF; 719 zsel = (tlb->attr >> 4) & 0xF;
687 zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3; 720 zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3;
688 if (loglevel != 0) { 721 if (loglevel != 0) {
@@ -692,6 +725,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, @@ -692,6 +725,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
692 if (access_type == ACCESS_CODE) { 725 if (access_type == ACCESS_CODE) {
693 /* Check execute enable bit */ 726 /* Check execute enable bit */
694 switch (zpr) { 727 switch (zpr) {
  728 + case 0x2:
  729 + if (msr_pr)
  730 + goto check_exec_perm;
  731 + goto exec_granted;
695 case 0x0: 732 case 0x0:
696 if (msr_pr) { 733 if (msr_pr) {
697 ctx->prot = 0; 734 ctx->prot = 0;
@@ -700,7 +737,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, @@ -700,7 +737,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
700 } 737 }
701 /* No break here */ 738 /* No break here */
702 case 0x1: 739 case 0x1:
703 - case 0x2: 740 + check_exec_perm:
704 /* Check from TLB entry */ 741 /* Check from TLB entry */
705 if (!(tlb->prot & PAGE_EXEC)) { 742 if (!(tlb->prot & PAGE_EXEC)) {
706 ret = -3; 743 ret = -3;
@@ -714,6 +751,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, @@ -714,6 +751,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
714 } 751 }
715 break; 752 break;
716 case 0x3: 753 case 0x3:
  754 + exec_granted:
717 /* All accesses granted */ 755 /* All accesses granted */
718 ctx->prot = PAGE_READ | PAGE_WRITE; 756 ctx->prot = PAGE_READ | PAGE_WRITE;
719 ret = 0; 757 ret = 0;
@@ -721,6 +759,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, @@ -721,6 +759,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
721 } 759 }
722 } else { 760 } else {
723 switch (zpr) { 761 switch (zpr) {
  762 + case 0x2:
  763 + if (msr_pr)
  764 + goto check_rw_perm;
  765 + goto rw_granted;
724 case 0x0: 766 case 0x0:
725 if (msr_pr) { 767 if (msr_pr) {
726 ctx->prot = 0; 768 ctx->prot = 0;
@@ -729,7 +771,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, @@ -729,7 +771,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
729 } 771 }
730 /* No break here */ 772 /* No break here */
731 case 0x1: 773 case 0x1:
732 - case 0x2: 774 + check_rw_perm:
733 /* Check from TLB entry */ 775 /* Check from TLB entry */
734 /* Check write protection bit */ 776 /* Check write protection bit */
735 if (tlb->prot & PAGE_WRITE) { 777 if (tlb->prot & PAGE_WRITE) {
@@ -744,6 +786,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, @@ -744,6 +786,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
744 } 786 }
745 break; 787 break;
746 case 0x3: 788 case 0x3:
  789 + rw_granted:
747 /* All accesses granted */ 790 /* All accesses granted */
748 ctx->prot = PAGE_READ | PAGE_WRITE; 791 ctx->prot = PAGE_READ | PAGE_WRITE;
749 ret = 0; 792 ret = 0;
@@ -769,6 +812,15 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, @@ -769,6 +812,15 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
769 return ret; 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 static int check_physical (CPUState *env, mmu_ctx_t *ctx, 824 static int check_physical (CPUState *env, mmu_ctx_t *ctx,
773 target_ulong eaddr, int rw) 825 target_ulong eaddr, int rw)
774 { 826 {
target-ppc/op.c
@@ -2459,6 +2459,12 @@ void OPPROTO op_store_40x_dbcr0 (void) @@ -2459,6 +2459,12 @@ void OPPROTO op_store_40x_dbcr0 (void)
2459 store_40x_dbcr0(env, T0); 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 void OPPROTO op_store_booke_tcr (void) 2468 void OPPROTO op_store_booke_tcr (void)
2463 { 2469 {
2464 store_booke_tcr(env, T0); 2470 store_booke_tcr(env, T0);
target-ppc/op_helper.c
@@ -2494,44 +2494,16 @@ void do_4xx_tlbre_hi (void) @@ -2494,44 +2494,16 @@ void do_4xx_tlbre_hi (void)
2494 T0 |= 0x100; 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 void do_4xx_tlbsx (void) 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 void do_4xx_tlbsx_ (void) 2502 void do_4xx_tlbsx_ (void)
2531 { 2503 {
2532 int tmp = xer_ov; 2504 int tmp = xer_ov;
2533 2505
2534 - T0 = tlb_4xx_search(T0); 2506 + T0 = ppcemb_tlb_search(env, T0);
2535 if (T0 != -1) 2507 if (T0 != -1)
2536 tmp |= 0x02; 2508 tmp |= 0x02;
2537 env->crf[0] = tmp; 2509 env->crf[0] = tmp;
@@ -2562,16 +2534,28 @@ void do_4xx_tlbwe_hi (void) @@ -2562,16 +2534,28 @@ void do_4xx_tlbwe_hi (void)
2562 tlb_flush_page(env, page); 2534 tlb_flush_page(env, page);
2563 } 2535 }
2564 tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7); 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 tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); 2545 tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1);
2566 if (T1 & 0x40) 2546 if (T1 & 0x40)
2567 tlb->prot |= PAGE_VALID; 2547 tlb->prot |= PAGE_VALID;
2568 else 2548 else
2569 tlb->prot &= ~PAGE_VALID; 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 tlb->PID = env->spr[SPR_40x_PID]; /* PID */ 2554 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2571 tlb->attr = T1 & 0xFF; 2555 tlb->attr = T1 & 0xFF;
2572 #if defined (DEBUG_SOFTWARE_TLB) 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 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, 2559 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
2576 (int)T0, tlb->RPN, tlb->EPN, tlb->size, 2560 (int)T0, tlb->RPN, tlb->EPN, tlb->size,
2577 tlb->prot & PAGE_READ ? 'r' : '-', 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,6 +355,17 @@ static void spr_write_40x_dbcr0 (void *opaque, int sprn)
355 RET_STOP(ctx); 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 static void spr_write_booke_tcr (void *opaque, int sprn) 369 static void spr_write_booke_tcr (void *opaque, int sprn)
359 { 370 {
360 gen_op_store_booke_tcr(); 371 gen_op_store_booke_tcr();
@@ -1711,10 +1722,9 @@ static void gen_spr_405 (CPUPPCState *env) @@ -1711,10 +1722,9 @@ static void gen_spr_405 (CPUPPCState *env)
1711 &spr_read_generic, &spr_write_generic, 1722 &spr_read_generic, &spr_write_generic,
1712 0x00000000); 1723 0x00000000);
1713 /* Storage control */ 1724 /* Storage control */
1714 - /* XXX : not implemented */  
1715 spr_register(env, SPR_405_SLER, "SLER", 1725 spr_register(env, SPR_405_SLER, "SLER",
1716 SPR_NOACCESS, SPR_NOACCESS, 1726 SPR_NOACCESS, SPR_NOACCESS,
1717 - &spr_read_generic, &spr_write_generic, 1727 + &spr_read_generic, &spr_write_40x_sler,
1718 0x00000000); 1728 0x00000000);
1719 /* XXX : not implemented */ 1729 /* XXX : not implemented */
1720 spr_register(env, SPR_405_SU0R, "SU0R", 1730 spr_register(env, SPR_405_SU0R, "SU0R",
@@ -2837,7 +2847,7 @@ static ppc_def_t ppc_defs[] = { @@ -2837,7 +2847,7 @@ static ppc_def_t ppc_defs[] = {
2837 .pvr_mask = 0xFFFFFFFF, 2847 .pvr_mask = 0xFFFFFFFF,
2838 .insns_flags = PPC_INSNS_405, 2848 .insns_flags = PPC_INSNS_405,
2839 .flags = PPC_FLAGS_405, 2849 .flags = PPC_FLAGS_405,
2840 - .msr_mask = 0x00000000020EFF30ULL, 2850 + .msr_mask = 0x00000000000ED630ULL,
2841 }, 2851 },
2842 #if defined (TODO) 2852 #if defined (TODO)
2843 /* PowerPC 405 EZ */ 2853 /* PowerPC 405 EZ */