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,7 +251,7 @@ static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm, | ||
| 251 | ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; | 251 | ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; |
| 252 | s->env->cp15.c1_sys = 0; | 252 | s->env->cp15.c1_sys = 0; |
| 253 | s->env->cp15.c1_coproc = 0; | 253 | s->env->cp15.c1_coproc = 0; |
| 254 | - s->env->cp15.c2 = 0; | 254 | + s->env->cp15.c2_base = 0; |
| 255 | s->env->cp15.c3 = 0; | 255 | s->env->cp15.c3 = 0; |
| 256 | s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ | 256 | s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ |
| 257 | s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ | 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,7 +77,7 @@ For system emulation, the following hardware targets are supported: | ||
| 77 | @item Sun4m (32-bit Sparc processor) | 77 | @item Sun4m (32-bit Sparc processor) |
| 78 | @item Sun4u (64-bit Sparc processor, in progress) | 78 | @item Sun4u (64-bit Sparc processor, in progress) |
| 79 | @item Malta board (32-bit MIPS processor) | 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 | @item ARM Versatile baseboard (ARM926E) | 81 | @item ARM Versatile baseboard (ARM926E) |
| 82 | @item ARM RealView Emulation baseboard (ARM926EJ-S) | 82 | @item ARM RealView Emulation baseboard (ARM926EJ-S) |
| 83 | @item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor) | 83 | @item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor) |
| @@ -1722,7 +1722,7 @@ devices: | @@ -1722,7 +1722,7 @@ devices: | ||
| 1722 | 1722 | ||
| 1723 | @itemize @minus | 1723 | @itemize @minus |
| 1724 | @item | 1724 | @item |
| 1725 | -ARM926E or ARM1026E CPU | 1725 | +ARM926E, ARM1026E or ARM946E CPU |
| 1726 | @item | 1726 | @item |
| 1727 | Two PL011 UARTs | 1727 | Two PL011 UARTs |
| 1728 | @item | 1728 | @item |
target-arm/cpu.h
| @@ -83,10 +83,14 @@ typedef struct CPUARMState { | @@ -83,10 +83,14 @@ typedef struct CPUARMState { | ||
| 83 | uint32_t c0_cachetype; | 83 | uint32_t c0_cachetype; |
| 84 | uint32_t c1_sys; /* System control register. */ | 84 | uint32_t c1_sys; /* System control register. */ |
| 85 | uint32_t c1_coproc; /* Coprocessor access register. */ | 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 | uint32_t c5_insn; /* Fault status registers. */ | 91 | uint32_t c5_insn; /* Fault status registers. */ |
| 89 | uint32_t c5_data; | 92 | uint32_t c5_data; |
| 93 | + uint32_t c6_region[8]; /* MPU base/size registers. */ | ||
| 90 | uint32_t c6_insn; /* Fault address registers. */ | 94 | uint32_t c6_insn; /* Fault address registers. */ |
| 91 | uint32_t c6_data; | 95 | uint32_t c6_data; |
| 92 | uint32_t c9_insn; /* Cache lockdown registers. */ | 96 | uint32_t c9_insn; /* Cache lockdown registers. */ |
| @@ -241,7 +245,8 @@ enum arm_features { | @@ -241,7 +245,8 @@ enum arm_features { | ||
| 241 | ARM_FEATURE_VFP, | 245 | ARM_FEATURE_VFP, |
| 242 | ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */ | 246 | ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */ |
| 243 | ARM_FEATURE_XSCALE, /* Intel XScale extensions. */ | 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 | static inline int arm_feature(CPUARMState *env, int feature) | 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,6 +263,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, | ||
| 258 | 263 | ||
| 259 | #define ARM_CPUID_ARM1026 0x4106a262 | 264 | #define ARM_CPUID_ARM1026 0x4106a262 |
| 260 | #define ARM_CPUID_ARM926 0x41069265 | 265 | #define ARM_CPUID_ARM926 0x41069265 |
| 266 | +#define ARM_CPUID_ARM946 0x41059461 | ||
| 261 | #define ARM_CPUID_PXA250 0x69052100 | 267 | #define ARM_CPUID_PXA250 0x69052100 |
| 262 | #define ARM_CPUID_PXA255 0x69052d00 | 268 | #define ARM_CPUID_PXA255 0x69052d00 |
| 263 | #define ARM_CPUID_PXA260 0x69052903 | 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,6 +19,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) | ||
| 19 | env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; | 19 | env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; |
| 20 | env->cp15.c0_cachetype = 0x1dd20d2; | 20 | env->cp15.c0_cachetype = 0x1dd20d2; |
| 21 | break; | 21 | break; |
| 22 | + case ARM_CPUID_ARM946: | ||
| 23 | + set_feature(env, ARM_FEATURE_MPU); | ||
| 24 | + env->cp15.c0_cachetype = 0x0f004006; | ||
| 25 | + break; | ||
| 22 | case ARM_CPUID_ARM1026: | 26 | case ARM_CPUID_ARM1026: |
| 23 | set_feature(env, ARM_FEATURE_VFP); | 27 | set_feature(env, ARM_FEATURE_VFP); |
| 24 | set_feature(env, ARM_FEATURE_AUXCR); | 28 | set_feature(env, ARM_FEATURE_AUXCR); |
| @@ -90,6 +94,7 @@ struct arm_cpu_t { | @@ -90,6 +94,7 @@ struct arm_cpu_t { | ||
| 90 | 94 | ||
| 91 | static const struct arm_cpu_t arm_cpu_names[] = { | 95 | static const struct arm_cpu_t arm_cpu_names[] = { |
| 92 | { ARM_CPUID_ARM926, "arm926"}, | 96 | { ARM_CPUID_ARM926, "arm926"}, |
| 97 | + { ARM_CPUID_ARM946, "arm946"}, | ||
| 93 | { ARM_CPUID_ARM1026, "arm1026"}, | 98 | { ARM_CPUID_ARM1026, "arm1026"}, |
| 94 | { ARM_CPUID_PXA250, "pxa250" }, | 99 | { ARM_CPUID_PXA250, "pxa250" }, |
| 95 | { ARM_CPUID_PXA255, "pxa255" }, | 100 | { ARM_CPUID_PXA255, "pxa255" }, |
| @@ -392,13 +397,67 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type, | @@ -392,13 +397,67 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type, | ||
| 392 | address += env->cp15.c13_fcse; | 397 | address += env->cp15.c13_fcse; |
| 393 | 398 | ||
| 394 | if ((env->cp15.c1_sys & 1) == 0) { | 399 | if ((env->cp15.c1_sys & 1) == 0) { |
| 395 | - /* MMU diusabled. */ | 400 | + /* MMU/MPU disabled. */ |
| 396 | *phys_ptr = address; | 401 | *phys_ptr = address; |
| 397 | *prot = PAGE_READ | PAGE_WRITE; | 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 | } else { | 457 | } else { |
| 399 | /* Pagetable walk. */ | 458 | /* Pagetable walk. */ |
| 400 | /* Lookup l1 descriptor. */ | 459 | /* Lookup l1 descriptor. */ |
| 401 | - table = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc); | 460 | + table = (env->cp15.c2_base & 0xffffc000) | ((address >> 18) & 0x3ffc); |
| 402 | desc = ldl_phys(table); | 461 | desc = ldl_phys(table); |
| 403 | type = (desc & 3); | 462 | type = (desc & 3); |
| 404 | domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; | 463 | domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; |
| @@ -539,18 +598,50 @@ uint32_t helper_get_cp(CPUState *env, uint32_t insn) | @@ -539,18 +598,50 @@ uint32_t helper_get_cp(CPUState *env, uint32_t insn) | ||
| 539 | return 0; | 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 | void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) | 631 | void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) |
| 543 | { | 632 | { |
| 544 | uint32_t op2; | 633 | uint32_t op2; |
| 634 | + uint32_t crm; | ||
| 545 | 635 | ||
| 546 | op2 = (insn >> 5) & 7; | 636 | op2 = (insn >> 5) & 7; |
| 637 | + crm = insn & 0xf; | ||
| 547 | switch ((insn >> 16) & 0xf) { | 638 | switch ((insn >> 16) & 0xf) { |
| 548 | case 0: /* ID codes. */ | 639 | case 0: /* ID codes. */ |
| 549 | goto bad_reg; | 640 | goto bad_reg; |
| 550 | case 1: /* System configuration. */ | 641 | case 1: /* System configuration. */ |
| 551 | switch (op2) { | 642 | switch (op2) { |
| 552 | case 0: | 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 | env->cp15.c1_sys = val; | 645 | env->cp15.c1_sys = val; |
| 555 | /* ??? Lots of these bits are not implemented. */ | 646 | /* ??? Lots of these bits are not implemented. */ |
| 556 | /* This may enable/disable the MMU, so do a TLB flush. */ | 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,38 +662,71 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) | ||
| 571 | goto bad_reg; | 662 | goto bad_reg; |
| 572 | } | 663 | } |
| 573 | break; | 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 | break; | 680 | break; |
| 577 | - case 3: /* MMU Domain access control. */ | 681 | + case 3: /* MMU Domain access control / MPU write buffer control. */ |
| 578 | env->cp15.c3 = val; | 682 | env->cp15.c3 = val; |
| 579 | break; | 683 | break; |
| 580 | case 4: /* Reserved. */ | 684 | case 4: /* Reserved. */ |
| 581 | goto bad_reg; | 685 | goto bad_reg; |
| 582 | - case 5: /* MMU Fault status. */ | 686 | + case 5: /* MMU Fault status / MPU access permission. */ |
| 583 | switch (op2) { | 687 | switch (op2) { |
| 584 | case 0: | 688 | case 0: |
| 689 | + if (arm_feature(env, ARM_FEATURE_MPU)) | ||
| 690 | + val = extended_mpu_ap_bits(val); | ||
| 585 | env->cp15.c5_data = val; | 691 | env->cp15.c5_data = val; |
| 586 | break; | 692 | break; |
| 587 | case 1: | 693 | case 1: |
| 694 | + if (arm_feature(env, ARM_FEATURE_MPU)) | ||
| 695 | + val = extended_mpu_ap_bits(val); | ||
| 588 | env->cp15.c5_insn = val; | 696 | env->cp15.c5_insn = val; |
| 589 | break; | 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 | break; | 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 | break; | 707 | break; |
| 602 | default: | 708 | default: |
| 603 | goto bad_reg; | 709 | goto bad_reg; |
| 604 | } | 710 | } |
| 605 | break; | 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 | case 7: /* Cache control. */ | 730 | case 7: /* Cache control. */ |
| 607 | /* No cache, so nothing to do. */ | 731 | /* No cache, so nothing to do. */ |
| 608 | break; | 732 | break; |
| @@ -629,14 +753,23 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) | @@ -629,14 +753,23 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) | ||
| 629 | goto bad_reg; | 753 | goto bad_reg; |
| 630 | } | 754 | } |
| 631 | break; | 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 | break; | 769 | break; |
| 770 | + case 1: /* TCM memory region registers. */ | ||
| 771 | + /* Not implemented. */ | ||
| 772 | + goto bad_reg; | ||
| 640 | default: | 773 | default: |
| 641 | goto bad_reg; | 774 | goto bad_reg; |
| 642 | } | 775 | } |
| @@ -644,12 +777,13 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) | @@ -644,12 +777,13 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) | ||
| 644 | case 10: /* MMU TLB lockdown. */ | 777 | case 10: /* MMU TLB lockdown. */ |
| 645 | /* ??? TLB lockdown not implemented. */ | 778 | /* ??? TLB lockdown not implemented. */ |
| 646 | break; | 779 | break; |
| 647 | - case 11: /* TCM DMA control. */ | ||
| 648 | case 12: /* Reserved. */ | 780 | case 12: /* Reserved. */ |
| 649 | goto bad_reg; | 781 | goto bad_reg; |
| 650 | case 13: /* Process ID. */ | 782 | case 13: /* Process ID. */ |
| 651 | switch (op2) { | 783 | switch (op2) { |
| 652 | case 0: | 784 | case 0: |
| 785 | + if (!arm_feature(env, ARM_FEATURE_MPU)) | ||
| 786 | + goto bad_reg; | ||
| 653 | /* Unlike real hardware the qemu TLB uses virtual addresses, | 787 | /* Unlike real hardware the qemu TLB uses virtual addresses, |
| 654 | not modified virtual addresses, so this causes a TLB flush. | 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,7 +793,8 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) | ||
| 659 | break; | 793 | break; |
| 660 | case 1: | 794 | case 1: |
| 661 | /* This changes the ASID, so do a TLB flush. */ | 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 | tlb_flush(env, 0); | 798 | tlb_flush(env, 0); |
| 664 | env->cp15.c13_context = val; | 799 | env->cp15.c13_context = val; |
| 665 | break; | 800 | break; |
| @@ -671,7 +806,7 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) | @@ -671,7 +806,7 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) | ||
| 671 | goto bad_reg; | 806 | goto bad_reg; |
| 672 | case 15: /* Implementation specific. */ | 807 | case 15: /* Implementation specific. */ |
| 673 | if (arm_feature(env, ARM_FEATURE_XSCALE)) { | 808 | if (arm_feature(env, ARM_FEATURE_XSCALE)) { |
| 674 | - if (op2 == 0 && (insn & 0xf) == 1) { | 809 | + if (op2 == 0 && crm == 1) { |
| 675 | /* Changes cp0 to cp13 behavior, so needs a TB flush. */ | 810 | /* Changes cp0 to cp13 behavior, so needs a TB flush. */ |
| 676 | tb_flush(env); | 811 | tb_flush(env); |
| 677 | env->cp15.c15_cpar = (val & 0x3fff) | 2; | 812 | env->cp15.c15_cpar = (val & 0x3fff) | 2; |
| @@ -717,31 +852,64 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) | @@ -717,31 +852,64 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) | ||
| 717 | default: | 852 | default: |
| 718 | goto bad_reg; | 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 | return env->cp15.c3; | 871 | return env->cp15.c3; |
| 724 | case 4: /* Reserved. */ | 872 | case 4: /* Reserved. */ |
| 725 | goto bad_reg; | 873 | goto bad_reg; |
| 726 | - case 5: /* MMU Fault status. */ | 874 | + case 5: /* MMU Fault status / MPU access permission. */ |
| 727 | switch (op2) { | 875 | switch (op2) { |
| 728 | case 0: | 876 | case 0: |
| 877 | + if (arm_feature(env, ARM_FEATURE_MPU)) | ||
| 878 | + return simple_mpu_ap_bits(env->cp15.c5_data); | ||
| 729 | return env->cp15.c5_data; | 879 | return env->cp15.c5_data; |
| 730 | case 1: | 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 | return env->cp15.c5_insn; | 891 | return env->cp15.c5_insn; |
| 732 | default: | 892 | default: |
| 733 | goto bad_reg; | 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 | case 7: /* Cache control. */ | 914 | case 7: /* Cache control. */ |
| 747 | /* ??? This is for test, clean and invaidate operations that set the | 915 | /* ??? This is for test, clean and invaidate operations that set the |