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;
}
}