summaryrefslogtreecommitdiff
path: root/hw/intc
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-06-02 13:05:06 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-06-02 13:05:06 +0100
commit7693cd7cb6229ca034faa88497ddb3a5f27cfb41 (patch)
tree608beeca076587496c1b9bb07a4cf1f3c8b5c001 /hw/intc
parent43771d5d92312504305c19abe29ec5bfabd55f01 (diff)
parentc7637c04be257968e6df30de961a6a23a0ac3dd8 (diff)
downloadqemu-7693cd7cb6229ca034faa88497ddb3a5f27cfb41.zip
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20170602' into staging
target-arm queue: * virt: numa: provide ACPI distance info when needed * aspeed: fix i2c controller bugs * M profile: support MPU * gicv3: fix mishandling of BPR1, VBPR1 * load_uboot_image: don't assume a full header read * libvixl: Correct build failures on NetBSD # gpg: Signature made Fri 02 Jun 2017 12:00:42 BST # gpg: using RSA key 0x3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20170602: (25 commits) hw/arm/virt: fdt: generate distance-map when needed hw/arm/virt-acpi-build: build SLIT when needed aspeed: add some I2C devices to the Aspeed machines aspeed/i2c: introduce a state machine aspeed/i2c: handle LAST command under the RX command aspeed/i2c: improve command handling arm: Implement HFNMIENA support for M profile MPU arm: add MPU support to M profile CPUs armv7m: Classify faults as MemManage or BusFault arm: All M profile cores are PMSA armv7m: Implement M profile default memory map armv7m: Improve "-d mmu" tracing for PMSAv7 MPU arm: Remove unnecessary check on cpu->pmsav7_dregion arm: Don't let no-MPU PMSA cores write to SCTLR.M arm: Don't clear ARM_FEATURE_PMSA for no-mpu configs arm: Clean up handling of no-MPU PMSA CPUs arm: Use different ARMMMUIdx values for M profile arm: Add support for M profile CPUs having different MMU index semantics arm: Use the mmu_idx we're passed in arm_cpu_do_unaligned_access() target/arm: clear PMUVER field of AA64DFR0 when vPMU=off ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/arm_gicv3_cpuif.c50
-rw-r--r--hw/intc/armv7m_nvic.c104
2 files changed, 149 insertions, 5 deletions
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 0b208560bd..09d8ba0547 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -216,18 +216,35 @@ static uint32_t icv_gprio_mask(GICv3CPUState *cs, int group)
{
/* Return a mask word which clears the subpriority bits from
* a priority value for a virtual interrupt in the specified group.
- * This depends on the VBPR value:
+ * This depends on the VBPR value.
+ * If using VBPR0 then:
* a BPR of 0 means the group priority bits are [7:1];
* a BPR of 1 means they are [7:2], and so on down to
* a BPR of 7 meaning no group priority bits at all.
+ * If using VBPR1 then:
+ * a BPR of 0 is impossible (the minimum value is 1)
+ * a BPR of 1 means the group priority bits are [7:1];
+ * a BPR of 2 means they are [7:2], and so on down to
+ * a BPR of 7 meaning the group priority is [7].
+ *
* Which BPR to use depends on the group of the interrupt and
* the current ICH_VMCR_EL2.VCBPR settings.
+ *
+ * This corresponds to the VGroupBits() pseudocode.
*/
+ int bpr;
+
if (group == GICV3_G1NS && cs->ich_vmcr_el2 & ICH_VMCR_EL2_VCBPR) {
group = GICV3_G0;
}
- return ~0U << (read_vbpr(cs, group) + 1);
+ bpr = read_vbpr(cs, group);
+ if (group == GICV3_G1NS) {
+ assert(bpr > 0);
+ bpr--;
+ }
+
+ return ~0U << (bpr + 1);
}
static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr)
@@ -674,20 +691,37 @@ static uint32_t icc_gprio_mask(GICv3CPUState *cs, int group)
{
/* Return a mask word which clears the subpriority bits from
* a priority value for an interrupt in the specified group.
- * This depends on the BPR value:
+ * This depends on the BPR value. For CBPR0 (S or NS):
* a BPR of 0 means the group priority bits are [7:1];
* a BPR of 1 means they are [7:2], and so on down to
* a BPR of 7 meaning no group priority bits at all.
+ * For CBPR1 NS:
+ * a BPR of 0 is impossible (the minimum value is 1)
+ * a BPR of 1 means the group priority bits are [7:1];
+ * a BPR of 2 means they are [7:2], and so on down to
+ * a BPR of 7 meaning the group priority is [7].
+ *
* Which BPR to use depends on the group of the interrupt and
* the current ICC_CTLR.CBPR settings.
+ *
+ * This corresponds to the GroupBits() pseudocode.
*/
+ int bpr;
+
if ((group == GICV3_G1 && cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_CBPR) ||
(group == GICV3_G1NS &&
cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR)) {
group = GICV3_G0;
}
- return ~0U << ((cs->icc_bpr[group] & 7) + 1);
+ bpr = cs->icc_bpr[group] & 7;
+
+ if (group == GICV3_G1NS) {
+ assert(bpr > 0);
+ bpr--;
+ }
+
+ return ~0U << (bpr + 1);
}
static bool icc_no_enabled_hppi(GICv3CPUState *cs)
@@ -1388,6 +1422,7 @@ static void icc_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri,
{
GICv3CPUState *cs = icc_cs_from_env(env);
int grp = (ri->crm == 8) ? GICV3_G0 : GICV3_G1;
+ uint64_t minval;
if (icv_access(env, grp == GICV3_G0 ? HCR_FMO : HCR_IMO)) {
icv_bpr_write(env, ri, value);
@@ -1415,6 +1450,11 @@ static void icc_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri,
return;
}
+ minval = (grp == GICV3_G1NS) ? GIC_MIN_BPR_NS : GIC_MIN_BPR;
+ if (value < minval) {
+ value = minval;
+ }
+
cs->icc_bpr[grp] = value & 7;
gicv3_cpuif_update(cs);
}
@@ -2014,7 +2054,7 @@ static void icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
cs->ich_hcr_el2 = 0;
memset(cs->ich_lr_el2, 0, sizeof(cs->ich_lr_el2));
cs->ich_vmcr_el2 = ICH_VMCR_EL2_VFIQEN |
- (icv_min_vbpr(cs) << ICH_VMCR_EL2_VBPR1_SHIFT) |
+ ((icv_min_vbpr(cs) + 1) << ICH_VMCR_EL2_VBPR1_SHIFT) |
(icv_min_vbpr(cs) << ICH_VMCR_EL2_VBPR0_SHIFT);
}
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 32ffa0bf35..26a4b2dcb5 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -19,6 +19,7 @@
#include "hw/arm/arm.h"
#include "hw/arm/armv7m_nvic.h"
#include "target/arm/cpu.h"
+#include "exec/exec-all.h"
#include "qemu/log.h"
#include "trace.h"
@@ -528,6 +529,39 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
case 0xd70: /* ISAR4. */
return 0x01310102;
/* TODO: Implement debug registers. */
+ case 0xd90: /* MPU_TYPE */
+ /* Unified MPU; if the MPU is not present this value is zero */
+ return cpu->pmsav7_dregion << 8;
+ break;
+ case 0xd94: /* MPU_CTRL */
+ return cpu->env.v7m.mpu_ctrl;
+ case 0xd98: /* MPU_RNR */
+ return cpu->env.cp15.c6_rgnr;
+ case 0xd9c: /* MPU_RBAR */
+ case 0xda4: /* MPU_RBAR_A1 */
+ case 0xdac: /* MPU_RBAR_A2 */
+ case 0xdb4: /* MPU_RBAR_A3 */
+ {
+ int region = cpu->env.cp15.c6_rgnr;
+
+ if (region >= cpu->pmsav7_dregion) {
+ return 0;
+ }
+ return (cpu->env.pmsav7.drbar[region] & 0x1f) | (region & 0xf);
+ }
+ case 0xda0: /* MPU_RASR */
+ case 0xda8: /* MPU_RASR_A1 */
+ case 0xdb0: /* MPU_RASR_A2 */
+ case 0xdb8: /* MPU_RASR_A3 */
+ {
+ int region = cpu->env.cp15.c6_rgnr;
+
+ if (region >= cpu->pmsav7_dregion) {
+ return 0;
+ }
+ return ((cpu->env.pmsav7.dracr[region] & 0xffff) << 16) |
+ (cpu->env.pmsav7.drsr[region] & 0xffff);
+ }
default:
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
return 0;
@@ -627,6 +661,76 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
qemu_log_mask(LOG_UNIMP,
"NVIC: Aux fault status registers unimplemented\n");
break;
+ case 0xd90: /* MPU_TYPE */
+ return; /* RO */
+ case 0xd94: /* MPU_CTRL */
+ if ((value &
+ (R_V7M_MPU_CTRL_HFNMIENA_MASK | R_V7M_MPU_CTRL_ENABLE_MASK))
+ == R_V7M_MPU_CTRL_HFNMIENA_MASK) {
+ qemu_log_mask(LOG_GUEST_ERROR, "MPU_CTRL: HFNMIENA and !ENABLE is "
+ "UNPREDICTABLE\n");
+ }
+ cpu->env.v7m.mpu_ctrl = value & (R_V7M_MPU_CTRL_ENABLE_MASK |
+ R_V7M_MPU_CTRL_HFNMIENA_MASK |
+ R_V7M_MPU_CTRL_PRIVDEFENA_MASK);
+ tlb_flush(CPU(cpu));
+ break;
+ case 0xd98: /* MPU_RNR */
+ if (value >= cpu->pmsav7_dregion) {
+ qemu_log_mask(LOG_GUEST_ERROR, "MPU region out of range %"
+ PRIu32 "/%" PRIu32 "\n",
+ value, cpu->pmsav7_dregion);
+ } else {
+ cpu->env.cp15.c6_rgnr = value;
+ }
+ break;
+ case 0xd9c: /* MPU_RBAR */
+ case 0xda4: /* MPU_RBAR_A1 */
+ case 0xdac: /* MPU_RBAR_A2 */
+ case 0xdb4: /* MPU_RBAR_A3 */
+ {
+ int region;
+
+ if (value & (1 << 4)) {
+ /* VALID bit means use the region number specified in this
+ * value and also update MPU_RNR.REGION with that value.
+ */
+ region = extract32(value, 0, 4);
+ if (region >= cpu->pmsav7_dregion) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "MPU region out of range %u/%" PRIu32 "\n",
+ region, cpu->pmsav7_dregion);
+ return;
+ }
+ cpu->env.cp15.c6_rgnr = region;
+ } else {
+ region = cpu->env.cp15.c6_rgnr;
+ }
+
+ if (region >= cpu->pmsav7_dregion) {
+ return;
+ }
+
+ cpu->env.pmsav7.drbar[region] = value & ~0x1f;
+ tlb_flush(CPU(cpu));
+ break;
+ }
+ case 0xda0: /* MPU_RASR */
+ case 0xda8: /* MPU_RASR_A1 */
+ case 0xdb0: /* MPU_RASR_A2 */
+ case 0xdb8: /* MPU_RASR_A3 */
+ {
+ int region = cpu->env.cp15.c6_rgnr;
+
+ if (region >= cpu->pmsav7_dregion) {
+ return;
+ }
+
+ cpu->env.pmsav7.drsr[region] = value & 0xff3f;
+ cpu->env.pmsav7.dracr[region] = (value >> 16) & 0x173f;
+ tlb_flush(CPU(cpu));
+ break;
+ }
case 0xf00: /* Software Triggered Interrupt Register */
{
/* user mode can only write to STIR if CCR.USERSETMPEND permits it */