19 |
19 |
env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
|
20 |
20 |
env->cp15.c0_cachetype = 0x1dd20d2;
|
21 |
21 |
break;
|
|
22 |
case ARM_CPUID_ARM946:
|
|
23 |
set_feature(env, ARM_FEATURE_MPU);
|
|
24 |
env->cp15.c0_cachetype = 0x0f004006;
|
|
25 |
break;
|
22 |
26 |
case ARM_CPUID_ARM1026:
|
23 |
27 |
set_feature(env, ARM_FEATURE_VFP);
|
24 |
28 |
set_feature(env, ARM_FEATURE_AUXCR);
|
... | ... | |
90 |
94 |
|
91 |
95 |
static const struct arm_cpu_t arm_cpu_names[] = {
|
92 |
96 |
{ ARM_CPUID_ARM926, "arm926"},
|
|
97 |
{ ARM_CPUID_ARM946, "arm946"},
|
93 |
98 |
{ ARM_CPUID_ARM1026, "arm1026"},
|
94 |
99 |
{ ARM_CPUID_PXA250, "pxa250" },
|
95 |
100 |
{ ARM_CPUID_PXA255, "pxa255" },
|
... | ... | |
392 |
397 |
address += env->cp15.c13_fcse;
|
393 |
398 |
|
394 |
399 |
if ((env->cp15.c1_sys & 1) == 0) {
|
395 |
|
/* MMU diusabled. */
|
|
400 |
/* MMU/MPU disabled. */
|
396 |
401 |
*phys_ptr = address;
|
397 |
402 |
*prot = PAGE_READ | PAGE_WRITE;
|
|
403 |
} else if (arm_feature(env, ARM_FEATURE_MPU)) {
|
|
404 |
int n;
|
|
405 |
uint32_t mask;
|
|
406 |
uint32_t base;
|
|
407 |
|
|
408 |
*phys_ptr = address;
|
|
409 |
for (n = 7; n >= 0; n--) {
|
|
410 |
base = env->cp15.c6_region[n];
|
|
411 |
if ((base & 1) == 0)
|
|
412 |
continue;
|
|
413 |
mask = 1 << ((base >> 1) & 0x1f);
|
|
414 |
/* Keep this shift separate from the above to avoid an
|
|
415 |
(undefined) << 32. */
|
|
416 |
mask = (mask << 1) - 1;
|
|
417 |
if (((base ^ address) & ~mask) == 0)
|
|
418 |
break;
|
|
419 |
}
|
|
420 |
if (n < 0)
|
|
421 |
return 2;
|
|
422 |
|
|
423 |
if (access_type == 2) {
|
|
424 |
mask = env->cp15.c5_insn;
|
|
425 |
} else {
|
|
426 |
mask = env->cp15.c5_data;
|
|
427 |
}
|
|
428 |
mask = (mask >> (n * 4)) & 0xf;
|
|
429 |
switch (mask) {
|
|
430 |
case 0:
|
|
431 |
return 1;
|
|
432 |
case 1:
|
|
433 |
if (is_user)
|
|
434 |
return 1;
|
|
435 |
*prot = PAGE_READ | PAGE_WRITE;
|
|
436 |
break;
|
|
437 |
case 2:
|
|
438 |
*prot = PAGE_READ;
|
|
439 |
if (!is_user)
|
|
440 |
*prot |= PAGE_WRITE;
|
|
441 |
break;
|
|
442 |
case 3:
|
|
443 |
*prot = PAGE_READ | PAGE_WRITE;
|
|
444 |
break;
|
|
445 |
case 5:
|
|
446 |
if (is_user)
|
|
447 |
return 1;
|
|
448 |
*prot = PAGE_READ;
|
|
449 |
break;
|
|
450 |
case 6:
|
|
451 |
*prot = PAGE_READ;
|
|
452 |
break;
|
|
453 |
default:
|
|
454 |
/* Bad permission. */
|
|
455 |
return 1;
|
|
456 |
}
|
398 |
457 |
} else {
|
399 |
458 |
/* Pagetable walk. */
|
400 |
459 |
/* Lookup l1 descriptor. */
|
401 |
|
table = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc);
|
|
460 |
table = (env->cp15.c2_base & 0xffffc000) | ((address >> 18) & 0x3ffc);
|
402 |
461 |
desc = ldl_phys(table);
|
403 |
462 |
type = (desc & 3);
|
404 |
463 |
domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3;
|
... | ... | |
539 |
598 |
return 0;
|
540 |
599 |
}
|
541 |
600 |
|
|
601 |
/* Return basic MPU access permission bits. */
|
|
602 |
static uint32_t simple_mpu_ap_bits(uint32_t val)
|
|
603 |
{
|
|
604 |
uint32_t ret;
|
|
605 |
uint32_t mask;
|
|
606 |
int i;
|
|
607 |
ret = 0;
|
|
608 |
mask = 3;
|
|
609 |
for (i = 0; i < 16; i += 2) {
|
|
610 |
ret |= (val >> i) & mask;
|
|
611 |
mask <<= 2;
|
|
612 |
}
|
|
613 |
return ret;
|
|
614 |
}
|
|
615 |
|
|
616 |
/* Pad basic MPU access permission bits to extended format. */
|
|
617 |
static uint32_t extended_mpu_ap_bits(uint32_t val)
|
|
618 |
{
|
|
619 |
uint32_t ret;
|
|
620 |
uint32_t mask;
|
|
621 |
int i;
|
|
622 |
ret = 0;
|
|
623 |
mask = 3;
|
|
624 |
for (i = 0; i < 16; i += 2) {
|
|
625 |
ret |= (val & mask) << i;
|
|
626 |
mask <<= 2;
|
|
627 |
}
|
|
628 |
return ret;
|
|
629 |
}
|
|
630 |
|
542 |
631 |
void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
|
543 |
632 |
{
|
544 |
633 |
uint32_t op2;
|
|
634 |
uint32_t crm;
|
545 |
635 |
|
546 |
636 |
op2 = (insn >> 5) & 7;
|
|
637 |
crm = insn & 0xf;
|
547 |
638 |
switch ((insn >> 16) & 0xf) {
|
548 |
639 |
case 0: /* ID codes. */
|
549 |
640 |
goto bad_reg;
|
550 |
641 |
case 1: /* System configuration. */
|
551 |
642 |
switch (op2) {
|
552 |
643 |
case 0:
|
553 |
|
if (!arm_feature(env, ARM_FEATURE_XSCALE) || (insn & 0xf) == 0)
|
|
644 |
if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0)
|
554 |
645 |
env->cp15.c1_sys = val;
|
555 |
646 |
/* ??? Lots of these bits are not implemented. */
|
556 |
647 |
/* This may enable/disable the MMU, so do a TLB flush. */
|
... | ... | |
571 |
662 |
goto bad_reg;
|
572 |
663 |
}
|
573 |
664 |
break;
|
574 |
|
case 2: /* MMU Page table control. */
|
575 |
|
env->cp15.c2 = val;
|
|
665 |
case 2: /* MMU Page table control / MPU cache control. */
|
|
666 |
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
|
667 |
switch (op2) {
|
|
668 |
case 0:
|
|
669 |
env->cp15.c2_data = val;
|
|
670 |
break;
|
|
671 |
case 1:
|
|
672 |
env->cp15.c2_insn = val;
|
|
673 |
break;
|
|
674 |
default:
|
|
675 |
goto bad_reg;
|
|
676 |
}
|
|
677 |
} else {
|
|
678 |
env->cp15.c2_base = val;
|
|
679 |
}
|
576 |
680 |
break;
|
577 |
|
case 3: /* MMU Domain access control. */
|
|
681 |
case 3: /* MMU Domain access control / MPU write buffer control. */
|
578 |
682 |
env->cp15.c3 = val;
|
579 |
683 |
break;
|
580 |
684 |
case 4: /* Reserved. */
|
581 |
685 |
goto bad_reg;
|
582 |
|
case 5: /* MMU Fault status. */
|
|
686 |
case 5: /* MMU Fault status / MPU access permission. */
|
583 |
687 |
switch (op2) {
|
584 |
688 |
case 0:
|
|
689 |
if (arm_feature(env, ARM_FEATURE_MPU))
|
|
690 |
val = extended_mpu_ap_bits(val);
|
585 |
691 |
env->cp15.c5_data = val;
|
586 |
692 |
break;
|
587 |
693 |
case 1:
|
|
694 |
if (arm_feature(env, ARM_FEATURE_MPU))
|
|
695 |
val = extended_mpu_ap_bits(val);
|
588 |
696 |
env->cp15.c5_insn = val;
|
589 |
697 |
break;
|
590 |
|
default:
|
591 |
|
goto bad_reg;
|
592 |
|
}
|
593 |
|
break;
|
594 |
|
case 6: /* MMU Fault address. */
|
595 |
|
switch (op2) {
|
596 |
|
case 0:
|
597 |
|
env->cp15.c6_data = val;
|
|
698 |
case 2:
|
|
699 |
if (!arm_feature(env, ARM_FEATURE_MPU))
|
|
700 |
goto bad_reg;
|
|
701 |
env->cp15.c5_data = val;
|
598 |
702 |
break;
|
599 |
|
case 1:
|
600 |
|
env->cp15.c6_insn = val;
|
|
703 |
case 3:
|
|
704 |
if (!arm_feature(env, ARM_FEATURE_MPU))
|
|
705 |
goto bad_reg;
|
|
706 |
env->cp15.c5_insn = val;
|
601 |
707 |
break;
|
602 |
708 |
default:
|
603 |
709 |
goto bad_reg;
|
604 |
710 |
}
|
605 |
711 |
break;
|
|
712 |
case 6: /* MMU Fault address / MPU base/size. */
|
|
713 |
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
|
714 |
if (crm >= 8)
|
|
715 |
goto bad_reg;
|
|
716 |
env->cp15.c6_region[crm] = val;
|
|
717 |
} else {
|
|
718 |
switch (op2) {
|
|
719 |
case 0:
|
|
720 |
env->cp15.c6_data = val;
|
|
721 |
break;
|
|
722 |
case 1:
|
|
723 |
env->cp15.c6_insn = val;
|
|
724 |
break;
|
|
725 |
default:
|
|
726 |
goto bad_reg;
|
|
727 |
}
|
|
728 |
}
|
|
729 |
break;
|
606 |
730 |
case 7: /* Cache control. */
|
607 |
731 |
/* No cache, so nothing to do. */
|
608 |
732 |
break;
|
... | ... | |
629 |
753 |
goto bad_reg;
|
630 |
754 |
}
|
631 |
755 |
break;
|
632 |
|
case 9: /* Cache lockdown. */
|
633 |
|
switch (op2) {
|
634 |
|
case 0:
|
635 |
|
env->cp15.c9_data = val;
|
636 |
|
break;
|
637 |
|
case 1:
|
638 |
|
env->cp15.c9_insn = val;
|
|
756 |
case 9:
|
|
757 |
switch (crm) {
|
|
758 |
case 0: /* Cache lockdown. */
|
|
759 |
switch (op2) {
|
|
760 |
case 0:
|
|
761 |
env->cp15.c9_data = val;
|
|
762 |
break;
|
|
763 |
case 1:
|
|
764 |
env->cp15.c9_insn = val;
|
|
765 |
break;
|
|
766 |
default:
|
|
767 |
goto bad_reg;
|
|
768 |
}
|
639 |
769 |
break;
|
|
770 |
case 1: /* TCM memory region registers. */
|
|
771 |
/* Not implemented. */
|
|
772 |
goto bad_reg;
|
640 |
773 |
default:
|
641 |
774 |
goto bad_reg;
|
642 |
775 |
}
|
... | ... | |
644 |
777 |
case 10: /* MMU TLB lockdown. */
|
645 |
778 |
/* ??? TLB lockdown not implemented. */
|
646 |
779 |
break;
|
647 |
|
case 11: /* TCM DMA control. */
|
648 |
780 |
case 12: /* Reserved. */
|
649 |
781 |
goto bad_reg;
|
650 |
782 |
case 13: /* Process ID. */
|
651 |
783 |
switch (op2) {
|
652 |
784 |
case 0:
|
|
785 |
if (!arm_feature(env, ARM_FEATURE_MPU))
|
|
786 |
goto bad_reg;
|
653 |
787 |
/* Unlike real hardware the qemu TLB uses virtual addresses,
|
654 |
788 |
not modified virtual addresses, so this causes a TLB flush.
|
655 |
789 |
*/
|
... | ... | |
659 |
793 |
break;
|
660 |
794 |
case 1:
|
661 |
795 |
/* This changes the ASID, so do a TLB flush. */
|
662 |
|
if (env->cp15.c13_context != val)
|
|
796 |
if (env->cp15.c13_context != val
|
|
797 |
&& !arm_feature(env, ARM_FEATURE_MPU))
|
663 |
798 |
tlb_flush(env, 0);
|
664 |
799 |
env->cp15.c13_context = val;
|
665 |
800 |
break;
|
... | ... | |
671 |
806 |
goto bad_reg;
|
672 |
807 |
case 15: /* Implementation specific. */
|
673 |
808 |
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
|
674 |
|
if (op2 == 0 && (insn & 0xf) == 1) {
|
|
809 |
if (op2 == 0 && crm == 1) {
|
675 |
810 |
/* Changes cp0 to cp13 behavior, so needs a TB flush. */
|
676 |
811 |
tb_flush(env);
|
677 |
812 |
env->cp15.c15_cpar = (val & 0x3fff) | 2;
|
... | ... | |
717 |
852 |
default:
|
718 |
853 |
goto bad_reg;
|
719 |
854 |
}
|
720 |
|
case 2: /* MMU Page table control. */
|
721 |
|
return env->cp15.c2;
|
722 |
|
case 3: /* MMU Domain access control. */
|
|
855 |
case 2: /* MMU Page table control / MPU cache control. */
|
|
856 |
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
|
857 |
switch (op2) {
|
|
858 |
case 0:
|
|
859 |
return env->cp15.c2_data;
|
|
860 |
break;
|
|
861 |
case 1:
|
|
862 |
return env->cp15.c2_insn;
|
|
863 |
break;
|
|
864 |
default:
|
|
865 |
goto bad_reg;
|
|
866 |
}
|
|
867 |
} else {
|
|
868 |
return env->cp15.c2_base;
|
|
869 |
}
|
|
870 |
case 3: /* MMU Domain access control / MPU write buffer control. */
|
723 |
871 |
return env->cp15.c3;
|
724 |
872 |
case 4: /* Reserved. */
|
725 |
873 |
goto bad_reg;
|
726 |
|
case 5: /* MMU Fault status. */
|
|
874 |
case 5: /* MMU Fault status / MPU access permission. */
|
727 |
875 |
switch (op2) {
|
728 |
876 |
case 0:
|
|
877 |
if (arm_feature(env, ARM_FEATURE_MPU))
|
|
878 |
return simple_mpu_ap_bits(env->cp15.c5_data);
|
729 |
879 |
return env->cp15.c5_data;
|
730 |
880 |
case 1:
|
|
881 |
if (arm_feature(env, ARM_FEATURE_MPU))
|
|
882 |
return simple_mpu_ap_bits(env->cp15.c5_data);
|
|
883 |
return env->cp15.c5_insn;
|
|
884 |
case 2:
|
|
885 |
if (!arm_feature(env, ARM_FEATURE_MPU))
|
|
886 |
goto bad_reg;
|
|
887 |
return env->cp15.c5_data;
|
|
888 |
case 3:
|
|
889 |
if (!arm_feature(env, ARM_FEATURE_MPU))
|
|
890 |
goto bad_reg;
|
731 |
891 |
return env->cp15.c5_insn;
|
732 |
892 |
default:
|
733 |
893 |
goto bad_reg;
|
734 |
894 |
}
|
735 |
|
case 6: /* MMU Fault address. */
|
736 |
|
switch (op2) {
|
737 |
|
case 0:
|
738 |
|
return env->cp15.c6_data;
|
739 |
|
case 1:
|
740 |
|
/* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't
|
741 |
|
do any harm. */
|
742 |
|
return env->cp15.c6_insn;
|
743 |
|
default:
|
744 |
|
goto bad_reg;
|
|
895 |
case 6: /* MMU Fault address / MPU base/size. */
|
|
896 |
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
|
897 |
int n;
|
|
898 |
n = (insn & 0xf);
|
|
899 |
if (n >= 8)
|
|
900 |
goto bad_reg;
|
|
901 |
return env->cp15.c6_region[n];
|
|
902 |
} else {
|
|
903 |
switch (op2) {
|
|
904 |
case 0:
|
|
905 |
return env->cp15.c6_data;
|
|
906 |
case 1:
|
|
907 |
/* Arm9 doesn't have an IFAR, but implementing it anyway
|
|
908 |
shouldn't do any harm. */
|
|
909 |
return env->cp15.c6_insn;
|
|
910 |
default:
|
|
911 |
goto bad_reg;
|
|
912 |
}
|
745 |
913 |
}
|
746 |
914 |
case 7: /* Cache control. */
|
747 |
915 |
/* ??? This is for test, clean and invaidate operations that set the
|