Commit a8dea12f453851d68c968d23faff2f1b9205d811

Authored by j_mayer
1 parent 1d0a48fb

Merge PowerPC 405 MMU model.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2554 c046a42c-6fe2-441c-8c8c-71466251a162
target-ppc/helper.c
... ... @@ -549,8 +549,6 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
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,6 +630,115 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
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,13 +789,26 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
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,7 +873,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
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,7 +922,13 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
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,9 +1647,7 @@ void do_interrupt (CPUState *env)
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,9 +1665,7 @@ void do_interrupt (CPUState *env)
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:
... ...
target-ppc/op_helper.c
... ... @@ -2365,65 +2365,139 @@ void do_load_6xx_tlb (int is_code)
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,9 +2509,6 @@ static int tlb_4xx_search (target_ulong virtual)
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,47 +2528,44 @@ 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 */
... ...