Commit ce8198612e08f737057d9984a9fa1bf18af8ce4b
1 parent
94554550
ARM946 CPU support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2783 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
221 additions
and
47 deletions
hw/pxa2xx.c
... | ... | @@ -251,7 +251,7 @@ static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm, |
251 | 251 | ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; |
252 | 252 | s->env->cp15.c1_sys = 0; |
253 | 253 | s->env->cp15.c1_coproc = 0; |
254 | - s->env->cp15.c2 = 0; | |
254 | + s->env->cp15.c2_base = 0; | |
255 | 255 | s->env->cp15.c3 = 0; |
256 | 256 | s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ |
257 | 257 | s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ | ... | ... |
qemu-doc.texi
... | ... | @@ -77,7 +77,7 @@ For system emulation, the following hardware targets are supported: |
77 | 77 | @item Sun4m (32-bit Sparc processor) |
78 | 78 | @item Sun4u (64-bit Sparc processor, in progress) |
79 | 79 | @item Malta board (32-bit MIPS processor) |
80 | -@item ARM Integrator/CP (ARM926E or 1026E processor) | |
80 | +@item ARM Integrator/CP (ARM926E, 1026E or 946E processor) | |
81 | 81 | @item ARM Versatile baseboard (ARM926E) |
82 | 82 | @item ARM RealView Emulation baseboard (ARM926EJ-S) |
83 | 83 | @item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor) |
... | ... | @@ -1722,7 +1722,7 @@ devices: |
1722 | 1722 | |
1723 | 1723 | @itemize @minus |
1724 | 1724 | @item |
1725 | -ARM926E or ARM1026E CPU | |
1725 | +ARM926E, ARM1026E or ARM946E CPU | |
1726 | 1726 | @item |
1727 | 1727 | Two PL011 UARTs |
1728 | 1728 | @item | ... | ... |
target-arm/cpu.h
... | ... | @@ -83,10 +83,14 @@ typedef struct CPUARMState { |
83 | 83 | uint32_t c0_cachetype; |
84 | 84 | uint32_t c1_sys; /* System control register. */ |
85 | 85 | uint32_t c1_coproc; /* Coprocessor access register. */ |
86 | - uint32_t c2; /* MMU translation table base. */ | |
87 | - uint32_t c3; /* MMU domain access control register. */ | |
86 | + uint32_t c2_base; /* MMU translation table base. */ | |
87 | + uint32_t c2_data; /* MPU data cachable bits. */ | |
88 | + uint32_t c2_insn; /* MPU instruction cachable bits. */ | |
89 | + uint32_t c3; /* MMU domain access control register | |
90 | + MPU write buffer control. */ | |
88 | 91 | uint32_t c5_insn; /* Fault status registers. */ |
89 | 92 | uint32_t c5_data; |
93 | + uint32_t c6_region[8]; /* MPU base/size registers. */ | |
90 | 94 | uint32_t c6_insn; /* Fault address registers. */ |
91 | 95 | uint32_t c6_data; |
92 | 96 | uint32_t c9_insn; /* Cache lockdown registers. */ |
... | ... | @@ -241,7 +245,8 @@ enum arm_features { |
241 | 245 | ARM_FEATURE_VFP, |
242 | 246 | ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */ |
243 | 247 | ARM_FEATURE_XSCALE, /* Intel XScale extensions. */ |
244 | - ARM_FEATURE_IWMMXT /* Intel iwMMXt extension. */ | |
248 | + ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */ | |
249 | + ARM_FEATURE_MPU /* Only has Memory Protection Unit, not full MMU. */ | |
245 | 250 | }; |
246 | 251 | |
247 | 252 | static inline int arm_feature(CPUARMState *env, int feature) |
... | ... | @@ -258,6 +263,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, |
258 | 263 | |
259 | 264 | #define ARM_CPUID_ARM1026 0x4106a262 |
260 | 265 | #define ARM_CPUID_ARM926 0x41069265 |
266 | +#define ARM_CPUID_ARM946 0x41059461 | |
261 | 267 | #define ARM_CPUID_PXA250 0x69052100 |
262 | 268 | #define ARM_CPUID_PXA255 0x69052d00 |
263 | 269 | #define ARM_CPUID_PXA260 0x69052903 | ... | ... |
target-arm/helper.c
... | ... | @@ -19,6 +19,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) |
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,6 +94,7 @@ struct arm_cpu_t { |
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,13 +397,67 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type, |
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,18 +598,50 @@ uint32_t helper_get_cp(CPUState *env, uint32_t insn) |
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,38 +662,71 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) |
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,14 +753,23 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) |
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,12 +777,13 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) |
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,7 +793,8 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) |
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,7 +806,7 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) |
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,31 +852,64 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) |
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 | ... | ... |