Commit a8dea12f453851d68c968d23faff2f1b9205d811
1 parent
1d0a48fb
Merge PowerPC 405 MMU model.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2554 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
243 additions
and
50 deletions
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 */ | ... | ... |