static uint32_t nvic_readl()

in hw/intc/armv7m_nvic.c [998:1561]


static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
{
    ARMCPU *cpu = s->cpu;
    uint32_t val;

    switch (offset) {
    case 4: /* Interrupt Control Type.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) {
            goto bad_offset;
        }
        return ((s->num_irq - NVIC_FIRST_IRQ) / 32) - 1;
    case 0xc: /* CPPWR */
        if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            goto bad_offset;
        }
        /* We make the IMPDEF choice that nothing can ever go into a
         * non-retentive power state, which allows us to RAZ/WI this.
         */
        return 0;
    case 0x380 ... 0x3bf: /* NVIC_ITNS<n> */
    {
        int startvec = 8 * (offset - 0x380) + NVIC_FIRST_IRQ;
        int i;

        if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            goto bad_offset;
        }
        if (!attrs.secure) {
            return 0;
        }
        val = 0;
        for (i = 0; i < 32 && startvec + i < s->num_irq; i++) {
            if (s->itns[startvec + i]) {
                val |= (1 << i);
            }
        }
        return val;
    }
    case 0xcfc:
        if (!arm_feature(&cpu->env, ARM_FEATURE_V8_1M)) {
            goto bad_offset;
        }
        return cpu->revidr;
    case 0xd00: /* CPUID Base.  */
        return cpu->midr;
    case 0xd04: /* Interrupt Control State (ICSR) */
        /* VECTACTIVE */
        val = cpu->env.v7m.exception;
        /* VECTPENDING */
        if (s->vectpending) {
            /*
             * From v8.1M VECTPENDING must read as 1 if accessed as
             * NonSecure and the highest priority pending and enabled
             * exception targets Secure.
             */
            int vp = s->vectpending;
            if (!attrs.secure && arm_feature(&cpu->env, ARM_FEATURE_V8_1M) &&
                vectpending_targets_secure(s)) {
                vp = 1;
            }
            val |= (vp & 0x1ff) << 12;
        }
        /* ISRPENDING - set if any external IRQ is pending */
        if (nvic_isrpending(s)) {
            val |= (1 << 22);
        }
        /* RETTOBASE - set if only one handler is active */
        if (nvic_rettobase(s)) {
            val |= (1 << 11);
        }
        if (attrs.secure) {
            /* PENDSTSET */
            if (s->sec_vectors[ARMV7M_EXCP_SYSTICK].pending) {
                val |= (1 << 26);
            }
            /* PENDSVSET */
            if (s->sec_vectors[ARMV7M_EXCP_PENDSV].pending) {
                val |= (1 << 28);
            }
        } else {
            /* PENDSTSET */
            if (s->vectors[ARMV7M_EXCP_SYSTICK].pending) {
                val |= (1 << 26);
            }
            /* PENDSVSET */
            if (s->vectors[ARMV7M_EXCP_PENDSV].pending) {
                val |= (1 << 28);
            }
        }
        /* NMIPENDSET */
        if ((attrs.secure || (cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK))
            && s->vectors[ARMV7M_EXCP_NMI].pending) {
            val |= (1 << 31);
        }
        /* ISRPREEMPT: RES0 when halting debug not implemented */
        /* STTNS: RES0 for the Main Extension */
        return val;
    case 0xd08: /* Vector Table Offset.  */
        return cpu->env.v7m.vecbase[attrs.secure];
    case 0xd0c: /* Application Interrupt/Reset Control (AIRCR) */
        val = 0xfa050000 | (s->prigroup[attrs.secure] << 8);
        if (attrs.secure) {
            /* s->aircr stores PRIS, BFHFNMINS, SYSRESETREQS */
            val |= cpu->env.v7m.aircr;
        } else {
            if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
                /* BFHFNMINS is R/O from NS; other bits are RAZ/WI. If
                 * security isn't supported then BFHFNMINS is RAO (and
                 * the bit in env.v7m.aircr is always set).
                 */
                val |= cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK;
            }
        }
        return val;
    case 0xd10: /* System Control.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) {
            goto bad_offset;
        }
        return cpu->env.v7m.scr[attrs.secure];
    case 0xd14: /* Configuration Control.  */
        /*
         * Non-banked bits: BFHFNMIGN (stored in the NS copy of the register)
         * and TRD (stored in the S copy of the register)
         */
        val = cpu->env.v7m.ccr[attrs.secure];
        val |= cpu->env.v7m.ccr[M_REG_NS] & R_V7M_CCR_BFHFNMIGN_MASK;
        /* BFHFNMIGN is RAZ/WI from NS if AIRCR.BFHFNMINS is 0 */
        if (!attrs.secure) {
            if (!(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
                val &= ~R_V7M_CCR_BFHFNMIGN_MASK;
            }
        }
        return val;
    case 0xd24: /* System Handler Control and State (SHCSR) */
        if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) {
            goto bad_offset;
        }
        val = 0;
        if (attrs.secure) {
            if (s->sec_vectors[ARMV7M_EXCP_MEM].active) {
                val |= (1 << 0);
            }
            if (s->sec_vectors[ARMV7M_EXCP_HARD].active) {
                val |= (1 << 2);
            }
            if (s->sec_vectors[ARMV7M_EXCP_USAGE].active) {
                val |= (1 << 3);
            }
            if (s->sec_vectors[ARMV7M_EXCP_SVC].active) {
                val |= (1 << 7);
            }
            if (s->sec_vectors[ARMV7M_EXCP_PENDSV].active) {
                val |= (1 << 10);
            }
            if (s->sec_vectors[ARMV7M_EXCP_SYSTICK].active) {
                val |= (1 << 11);
            }
            if (s->sec_vectors[ARMV7M_EXCP_USAGE].pending) {
                val |= (1 << 12);
            }
            if (s->sec_vectors[ARMV7M_EXCP_MEM].pending) {
                val |= (1 << 13);
            }
            if (s->sec_vectors[ARMV7M_EXCP_SVC].pending) {
                val |= (1 << 15);
            }
            if (s->sec_vectors[ARMV7M_EXCP_MEM].enabled) {
                val |= (1 << 16);
            }
            if (s->sec_vectors[ARMV7M_EXCP_USAGE].enabled) {
                val |= (1 << 18);
            }
            if (s->sec_vectors[ARMV7M_EXCP_HARD].pending) {
                val |= (1 << 21);
            }
            /* SecureFault is not banked but is always RAZ/WI to NS */
            if (s->vectors[ARMV7M_EXCP_SECURE].active) {
                val |= (1 << 4);
            }
            if (s->vectors[ARMV7M_EXCP_SECURE].enabled) {
                val |= (1 << 19);
            }
            if (s->vectors[ARMV7M_EXCP_SECURE].pending) {
                val |= (1 << 20);
            }
        } else {
            if (s->vectors[ARMV7M_EXCP_MEM].active) {
                val |= (1 << 0);
            }
            if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
                /* HARDFAULTACT, HARDFAULTPENDED not present in v7M */
                if (s->vectors[ARMV7M_EXCP_HARD].active) {
                    val |= (1 << 2);
                }
                if (s->vectors[ARMV7M_EXCP_HARD].pending) {
                    val |= (1 << 21);
                }
            }
            if (s->vectors[ARMV7M_EXCP_USAGE].active) {
                val |= (1 << 3);
            }
            if (s->vectors[ARMV7M_EXCP_SVC].active) {
                val |= (1 << 7);
            }
            if (s->vectors[ARMV7M_EXCP_PENDSV].active) {
                val |= (1 << 10);
            }
            if (s->vectors[ARMV7M_EXCP_SYSTICK].active) {
                val |= (1 << 11);
            }
            if (s->vectors[ARMV7M_EXCP_USAGE].pending) {
                val |= (1 << 12);
            }
            if (s->vectors[ARMV7M_EXCP_MEM].pending) {
                val |= (1 << 13);
            }
            if (s->vectors[ARMV7M_EXCP_SVC].pending) {
                val |= (1 << 15);
            }
            if (s->vectors[ARMV7M_EXCP_MEM].enabled) {
                val |= (1 << 16);
            }
            if (s->vectors[ARMV7M_EXCP_USAGE].enabled) {
                val |= (1 << 18);
            }
        }
        if (attrs.secure || (cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
            if (s->vectors[ARMV7M_EXCP_BUS].active) {
                val |= (1 << 1);
            }
            if (s->vectors[ARMV7M_EXCP_BUS].pending) {
                val |= (1 << 14);
            }
            if (s->vectors[ARMV7M_EXCP_BUS].enabled) {
                val |= (1 << 17);
            }
            if (arm_feature(&cpu->env, ARM_FEATURE_V8) &&
                s->vectors[ARMV7M_EXCP_NMI].active) {
                /* NMIACT is not present in v7M */
                val |= (1 << 5);
            }
        }

        /* TODO: this is RAZ/WI from NS if DEMCR.SDME is set */
        if (s->vectors[ARMV7M_EXCP_DEBUG].active) {
            val |= (1 << 8);
        }
        return val;
    case 0xd2c: /* Hard Fault Status.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->env.v7m.hfsr;
    case 0xd30: /* Debug Fault Status.  */
        return cpu->env.v7m.dfsr;
    case 0xd34: /* MMFAR MemManage Fault Address */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->env.v7m.mmfar[attrs.secure];
    case 0xd38: /* Bus Fault Address.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        if (!attrs.secure &&
            !(s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
            return 0;
        }
        return cpu->env.v7m.bfar;
    case 0xd3c: /* Aux Fault Status.  */
        /* TODO: Implement fault status registers.  */
        qemu_log_mask(LOG_UNIMP,
                      "Aux Fault status registers unimplemented\n");
        return 0;
    case 0xd40: /* PFR0.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_pfr0;
    case 0xd44: /* PFR1.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_pfr1;
    case 0xd48: /* DFR0.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_dfr0;
    case 0xd4c: /* AFR0.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->id_afr0;
    case 0xd50: /* MMFR0.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_mmfr0;
    case 0xd54: /* MMFR1.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_mmfr1;
    case 0xd58: /* MMFR2.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_mmfr2;
    case 0xd5c: /* MMFR3.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_mmfr3;
    case 0xd60: /* ISAR0.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_isar0;
    case 0xd64: /* ISAR1.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_isar1;
    case 0xd68: /* ISAR2.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_isar2;
    case 0xd6c: /* ISAR3.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_isar3;
    case 0xd70: /* ISAR4.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_isar4;
    case 0xd74: /* ISAR5.  */
        if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
            goto bad_offset;
        }
        return cpu->isar.id_isar5;
    case 0xd78: /* CLIDR */
        return cpu->clidr;
    case 0xd7c: /* CTR */
        return cpu->ctr;
    case 0xd80: /* CSSIDR */
    {
        int idx = cpu->env.v7m.csselr[attrs.secure] & R_V7M_CSSELR_INDEX_MASK;
        return cpu->ccsidr[idx];
    }
    case 0xd84: /* CSSELR */
        return cpu->env.v7m.csselr[attrs.secure];
    case 0xd88: /* CPACR */
        if (!cpu_isar_feature(aa32_vfp_simd, cpu)) {
            return 0;
        }
        return cpu->env.v7m.cpacr[attrs.secure];
    case 0xd8c: /* NSACR */
        if (!attrs.secure || !cpu_isar_feature(aa32_vfp_simd, cpu)) {
            return 0;
        }
        return cpu->env.v7m.nsacr;
    /* 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;
    case 0xd94: /* MPU_CTRL */
        return cpu->env.v7m.mpu_ctrl[attrs.secure];
    case 0xd98: /* MPU_RNR */
        return cpu->env.pmsav7.rnr[attrs.secure];
    case 0xd9c: /* MPU_RBAR */
    case 0xda4: /* MPU_RBAR_A1 */
    case 0xdac: /* MPU_RBAR_A2 */
    case 0xdb4: /* MPU_RBAR_A3 */
    {
        int region = cpu->env.pmsav7.rnr[attrs.secure];

        if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            /* PMSAv8M handling of the aliases is different from v7M:
             * aliases A1, A2, A3 override the low two bits of the region
             * number in MPU_RNR, and there is no 'region' field in the
             * RBAR register.
             */
            int aliasno = (offset - 0xd9c) / 8; /* 0..3 */
            if (aliasno) {
                region = deposit32(region, 0, 2, aliasno);
            }
            if (region >= cpu->pmsav7_dregion) {
                return 0;
            }
            return cpu->env.pmsav8.rbar[attrs.secure][region];
        }

        if (region >= cpu->pmsav7_dregion) {
            return 0;
        }
        return (cpu->env.pmsav7.drbar[region] & ~0x1f) | (region & 0xf);
    }
    case 0xda0: /* MPU_RASR (v7M), MPU_RLAR (v8M) */
    case 0xda8: /* MPU_RASR_A1 (v7M), MPU_RLAR_A1 (v8M) */
    case 0xdb0: /* MPU_RASR_A2 (v7M), MPU_RLAR_A2 (v8M) */
    case 0xdb8: /* MPU_RASR_A3 (v7M), MPU_RLAR_A3 (v8M) */
    {
        int region = cpu->env.pmsav7.rnr[attrs.secure];

        if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            /* PMSAv8M handling of the aliases is different from v7M:
             * aliases A1, A2, A3 override the low two bits of the region
             * number in MPU_RNR.
             */
            int aliasno = (offset - 0xda0) / 8; /* 0..3 */
            if (aliasno) {
                region = deposit32(region, 0, 2, aliasno);
            }
            if (region >= cpu->pmsav7_dregion) {
                return 0;
            }
            return cpu->env.pmsav8.rlar[attrs.secure][region];
        }

        if (region >= cpu->pmsav7_dregion) {
            return 0;
        }
        return ((cpu->env.pmsav7.dracr[region] & 0xffff) << 16) |
            (cpu->env.pmsav7.drsr[region] & 0xffff);
    }
    case 0xdc0: /* MPU_MAIR0 */
        if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            goto bad_offset;
        }
        return cpu->env.pmsav8.mair0[attrs.secure];
    case 0xdc4: /* MPU_MAIR1 */
        if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            goto bad_offset;
        }
        return cpu->env.pmsav8.mair1[attrs.secure];
    case 0xdd0: /* SAU_CTRL */
        if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            goto bad_offset;
        }
        if (!attrs.secure) {
            return 0;
        }
        return cpu->env.sau.ctrl;
    case 0xdd4: /* SAU_TYPE */
        if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            goto bad_offset;
        }
        if (!attrs.secure) {
            return 0;
        }
        return cpu->sau_sregion;
    case 0xdd8: /* SAU_RNR */
        if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            goto bad_offset;
        }
        if (!attrs.secure) {
            return 0;
        }
        return cpu->env.sau.rnr;
    case 0xddc: /* SAU_RBAR */
    {
        int region = cpu->env.sau.rnr;

        if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            goto bad_offset;
        }
        if (!attrs.secure) {
            return 0;
        }
        if (region >= cpu->sau_sregion) {
            return 0;
        }
        return cpu->env.sau.rbar[region];
    }
    case 0xde0: /* SAU_RLAR */
    {
        int region = cpu->env.sau.rnr;

        if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            goto bad_offset;
        }
        if (!attrs.secure) {
            return 0;
        }
        if (region >= cpu->sau_sregion) {
            return 0;
        }
        return cpu->env.sau.rlar[region];
    }
    case 0xde4: /* SFSR */
        if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            goto bad_offset;
        }
        if (!attrs.secure) {
            return 0;
        }
        return cpu->env.v7m.sfsr;
    case 0xde8: /* SFAR */
        if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
            goto bad_offset;
        }
        if (!attrs.secure) {
            return 0;
        }
        return cpu->env.v7m.sfar;
    case 0xf04: /* RFSR */
        if (!cpu_isar_feature(aa32_ras, cpu)) {
            goto bad_offset;
        }
        /* We provide minimal-RAS only: RFSR is RAZ/WI */
        return 0;
    case 0xf34: /* FPCCR */
        if (!cpu_isar_feature(aa32_vfp_simd, cpu)) {
            return 0;
        }
        if (attrs.secure) {
            return cpu->env.v7m.fpccr[M_REG_S];
        } else {
            /*
             * NS can read LSPEN, CLRONRET and MONRDY. It can read
             * BFRDY and HFRDY if AIRCR.BFHFNMINS != 0;
             * other non-banked bits RAZ.
             * TODO: MONRDY should RAZ/WI if DEMCR.SDME is set.
             */
            uint32_t value = cpu->env.v7m.fpccr[M_REG_S];
            uint32_t mask = R_V7M_FPCCR_LSPEN_MASK |
                R_V7M_FPCCR_CLRONRET_MASK |
                R_V7M_FPCCR_MONRDY_MASK;

            if (s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) {
                mask |= R_V7M_FPCCR_BFRDY_MASK | R_V7M_FPCCR_HFRDY_MASK;
            }

            value &= mask;

            value |= cpu->env.v7m.fpccr[M_REG_NS];
            return value;
        }
    case 0xf38: /* FPCAR */
        if (!cpu_isar_feature(aa32_vfp_simd, cpu)) {
            return 0;
        }
        return cpu->env.v7m.fpcar[attrs.secure];
    case 0xf3c: /* FPDSCR */
        if (!cpu_isar_feature(aa32_vfp_simd, cpu)) {
            return 0;
        }
        return cpu->env.v7m.fpdscr[attrs.secure];
    case 0xf40: /* MVFR0 */
        return cpu->isar.mvfr0;
    case 0xf44: /* MVFR1 */
        return cpu->isar.mvfr1;
    case 0xf48: /* MVFR2 */
        return cpu->isar.mvfr2;
    default:
    bad_offset:
        qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
        return 0;
    }
}