From 10d482507204df0f67c6b0e5dee92f0b3bab2ed2 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 7 Jan 2025 10:49:13 +0000 Subject: [PATCH 01/11] [ot] hw/opentitan: ot_aon_timer: Make wakeup timer 64 bits For earlgrey-1.0.0, OpenTitan's aon_timer has been updated so that it's wakeup timer is now a 64-bit counter rather than a 32-bit counter (whereas the watchdog timer remains 32-bit). This requires the implementation of register mapping changes with each wakeup count / threshold register now having a HI/LO counterpart. Signed-off-by: Alex Jones --- hw/opentitan/ot_aon_timer.c | 86 +++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/hw/opentitan/ot_aon_timer.c b/hw/opentitan/ot_aon_timer.c index e8c0ee29b9e2a..d261fa2bf54d7 100644 --- a/hw/opentitan/ot_aon_timer.c +++ b/hw/opentitan/ot_aon_timer.c @@ -47,21 +47,23 @@ REG32(ALERT_TEST, 0x00u) REG32(WKUP_CTRL, 0x04u) FIELD(WKUP_CTRL, ENABLE, 0u, 1u) FIELD(WKUP_CTRL, PRESCALER, 1u, 12u) -REG32(WKUP_THOLD, 0x08) -REG32(WKUP_COUNT, 0x0cu) -REG32(WDOG_REGWEN, 0x10u) +REG32(WKUP_THOLD_HI, 0x08u) +REG32(WKUP_THOLD_LO, 0x0cu) +REG32(WKUP_COUNT_HI, 0x10u) +REG32(WKUP_COUNT_LO, 0x14u) +REG32(WDOG_REGWEN, 0x18u) FIELD(WDOG_REGWEN, REGWEN, 0u, 1u) -REG32(WDOG_CTRL, 0x14u) +REG32(WDOG_CTRL, 0x1cu) FIELD(WDOG_CTRL, ENABLE, 0u, 1u) - FIELD(WDOG_CTRL, PAUSE_IN_SLEEP, 0u, 1u) -REG32(WDOG_BARK_THOLD, 0x18u) -REG32(WDOG_BITE_THOLD, 0x1cu) -REG32(WDOG_COUNT, 0x20u) -REG32(INTR_STATE, 0x24u) + FIELD(WDOG_CTRL, PAUSE_IN_SLEEP, 1u, 1u) +REG32(WDOG_BARK_THOLD, 0x20u) +REG32(WDOG_BITE_THOLD, 0x24u) +REG32(WDOG_COUNT, 0x28u) +REG32(INTR_STATE, 0x2cu) SHARED_FIELD(INTR_WKUP_TIMER_EXPIRED, 0u, 1u) SHARED_FIELD(INTR_WDOG_TIMER_BARK, 1u, 1u) -REG32(INTR_TEST, 0x28u) -REG32(WKUP_CAUSE, 0x2cu) +REG32(INTR_TEST, 0x30u) +REG32(WKUP_CAUSE, 0x34u) FIELD(WKUP_CAUSE, CAUSE, 0u, 1u) /* clang-format on */ @@ -80,8 +82,10 @@ static const char REG_NAMES[REGS_COUNT][20u] = { /* clang-format off */ REG_NAME_ENTRY(ALERT_TEST), REG_NAME_ENTRY(WKUP_CTRL), - REG_NAME_ENTRY(WKUP_THOLD), - REG_NAME_ENTRY(WKUP_COUNT), + REG_NAME_ENTRY(WKUP_THOLD_HI), + REG_NAME_ENTRY(WKUP_THOLD_LO), + REG_NAME_ENTRY(WKUP_COUNT_HI), + REG_NAME_ENTRY(WKUP_COUNT_LO), REG_NAME_ENTRY(WDOG_REGWEN), REG_NAME_ENTRY(WDOG_CTRL), REG_NAME_ENTRY(WDOG_BARK_THOLD), @@ -119,28 +123,30 @@ struct OtAonTimerState { uint32_t pclk; }; -static uint32_t +static uint64_t ot_aon_timer_ns_to_ticks(OtAonTimerState *s, uint32_t prescaler, int64_t ns) { uint64_t ticks = muldiv64((uint64_t)ns, s->pclk, NANOSECONDS_PER_SECOND); - return (uint32_t)(ticks / (prescaler + 1u)); + return ticks / (prescaler + 1u); } static int64_t -ot_aon_timer_ticks_to_ns(OtAonTimerState *s, uint32_t prescaler, uint32_t ticks) +ot_aon_timer_ticks_to_ns(OtAonTimerState *s, uint32_t prescaler, uint64_t ticks) { - uint64_t ns = muldiv64((uint64_t)ticks * (prescaler + 1u), - NANOSECONDS_PER_SECOND, s->pclk); + uint64_t ns = + muldiv64(ticks * (prescaler + 1u), NANOSECONDS_PER_SECOND, s->pclk); if (ns > INT64_MAX) { return INT64_MAX; } return (int64_t)ns; } -static uint32_t ot_aon_timer_get_wkup_count(OtAonTimerState *s, uint64_t now) +static uint64_t ot_aon_timer_get_wkup_count(OtAonTimerState *s, uint64_t now) { uint32_t prescaler = FIELD_EX32(s->regs[R_WKUP_CTRL], WKUP_CTRL, PRESCALER); - return s->regs[R_WKUP_COUNT] + + uint64_t wkup_count = + ((uint64_t)s->regs[R_WKUP_COUNT_HI] << 32u) | s->regs[R_WKUP_COUNT_LO]; + return wkup_count + ot_aon_timer_ns_to_ticks(s, prescaler, (int64_t)(now - s->wkup_origin_ns)); } @@ -148,7 +154,9 @@ static uint32_t ot_aon_timer_get_wkup_count(OtAonTimerState *s, uint64_t now) static uint32_t ot_aon_timer_get_wdog_count(OtAonTimerState *s, uint64_t now) { return s->regs[R_WDOG_COUNT] + - ot_aon_timer_ns_to_ticks(s, 0u, (int64_t)(now - s->wdog_origin_ns)); + (uint32_t) + ot_aon_timer_ns_to_ticks(s, 0u, + (int64_t)(now - s->wdog_origin_ns)); } static int64_t ot_aon_timer_compute_next_timeout(OtAonTimerState *s, @@ -192,7 +200,6 @@ static void ot_aon_timer_update_irqs(OtAonTimerState *s) { bool wkup = (bool)(s->regs[R_INTR_STATE] & INTR_WKUP_TIMER_EXPIRED_MASK); bool bark = (bool)(s->regs[R_INTR_STATE] & INTR_WDOG_TIMER_BARK_MASK); - trace_ot_aon_timer_irqs(s->ot_id, wkup, bark, s->wdog_bite); ibex_irq_set(&s->irq_wkup, wkup); @@ -218,8 +225,9 @@ static void ot_aon_timer_rearm_wkup(OtAonTimerState *s, bool reset_origin) return; } - uint32_t count = ot_aon_timer_get_wkup_count(s, now); - uint32_t threshold = s->regs[R_WKUP_THOLD]; + uint64_t count = ot_aon_timer_get_wkup_count(s, now); + uint64_t threshold = + ((uint64_t)s->regs[R_WKUP_THOLD_HI] << 32u) | s->regs[R_WKUP_THOLD_LO]; if (count >= threshold) { s->regs[R_INTR_STATE] |= INTR_WKUP_TIMER_EXPIRED_MASK; @@ -309,7 +317,8 @@ static uint64_t ot_aon_timer_read(void *opaque, hwaddr addr, unsigned size) hwaddr reg = R32_OFF(addr); switch (reg) { case R_WKUP_CTRL: - case R_WKUP_THOLD: + case R_WKUP_THOLD_HI: + case R_WKUP_THOLD_LO: case R_WDOG_REGWEN: case R_WDOG_CTRL: case R_WDOG_BARK_THOLD: @@ -318,11 +327,18 @@ static uint64_t ot_aon_timer_read(void *opaque, hwaddr addr, unsigned size) case R_WKUP_CAUSE: val32 = s->regs[reg]; break; - case R_WKUP_COUNT: { + case R_WKUP_COUNT_HI: { + uint64_t now = ot_aon_timer_is_wkup_enabled(s) ? + qemu_clock_get_ns(OT_VIRTUAL_CLOCK) : + s->wkup_origin_ns; + val32 = (uint32_t)(ot_aon_timer_get_wkup_count(s, now) >> 32u); + break; + } + case R_WKUP_COUNT_LO: { uint64_t now = ot_aon_timer_is_wkup_enabled(s) ? qemu_clock_get_ns(OT_VIRTUAL_CLOCK) : s->wkup_origin_ns; - val32 = ot_aon_timer_get_wkup_count(s, now); + val32 = (uint32_t)ot_aon_timer_get_wkup_count(s, now); break; } case R_WDOG_COUNT: { @@ -384,19 +400,23 @@ static void ot_aon_timer_write(void *opaque, hwaddr addr, uint64_t value, /* stop timer */ timer_del(s->wkup_timer); /* save current count */ - uint32_t now = qemu_clock_get_ns(OT_VIRTUAL_CLOCK); - s->regs[R_WKUP_COUNT] = ot_aon_timer_get_wkup_count(s, now); + int64_t now = qemu_clock_get_ns(OT_VIRTUAL_CLOCK); + uint64_t count = ot_aon_timer_get_wkup_count(s, now); + s->regs[R_WKUP_COUNT_HI] = (uint32_t)(count >> 32u); + s->regs[R_WKUP_COUNT_LO] = (uint32_t)count; s->wkup_origin_ns = now; } } break; } - case R_WKUP_THOLD: - s->regs[R_WKUP_THOLD] = val32; + case R_WKUP_THOLD_HI: + case R_WKUP_THOLD_LO: + s->regs[reg] = val32; ot_aon_timer_rearm_wkup(s, false); break; - case R_WKUP_COUNT: - s->regs[R_WKUP_COUNT] = val32; + case R_WKUP_COUNT_HI: + case R_WKUP_COUNT_LO: + s->regs[reg] = val32; ot_aon_timer_rearm_wkup(s, true); break; case R_WDOG_REGWEN: From b29e41686944b4dcc96ac0fdb8b047a646f68745 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Thu, 16 Jan 2025 18:08:38 +0000 Subject: [PATCH 02/11] [ot] hw/riscv: ot_earlgrey: Connect device alerts to alert handler Connect the alerts for each of the OpenTitan Earlgrey devices to the alert handler. This is based on the mappings found in the autogenerated `hw/top_earlgrey/sw/autogen/top_earlgrey.h` file for the Earlgrey top found in the OpenTitan repository. Signed-off-by: Alex Jones --- hw/riscv/ot_earlgrey.c | 127 ++++++++++++++++++++++++++++++++--------- 1 file changed, 101 insertions(+), 26 deletions(-) diff --git a/hw/riscv/ot_earlgrey.c b/hw/riscv/ot_earlgrey.c index cd379d6cb6686..7585884e7d725 100644 --- a/hw/riscv/ot_earlgrey.c +++ b/hw/riscv/ot_earlgrey.c @@ -212,6 +212,14 @@ static const uint32_t ot_eg_pmp_addrs[] = { #define OT_EG_SOC_GPIO_SYSBUS_IRQ(_irq_, _target_, _num_) \ IBEX_GPIO_SYSBUS_IRQ(_irq_, OT_EG_SOC_DEV_##_target_, _num_) +#define OT_EG_SOC_GPIO_ALERT(_snum_, _tnum_) \ + OT_EG_SOC_SIGNAL(OT_DEVICE_ALERT, _snum_, ALERT_HANDLER, OT_DEVICE_ALERT, \ + _tnum_) + +#define OT_EG_SOC_GPIO_ESCALATE(_snum_, _tgt_, _tnum_) \ + OT_EG_SOC_SIGNAL(OT_ALERT_ESCALATE, _snum_, _tgt_, OT_ALERT_ESCALATE, \ + _tnum_) + #define OT_EG_SOC_DEVLINK(_pname_, _target_) \ IBEX_DEVLINK(_pname_, OT_EG_SOC_DEV_##_target_) @@ -340,7 +348,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_SYSBUS_IRQ(5, PLIC, 6), OT_EG_SOC_GPIO_SYSBUS_IRQ(6, PLIC, 7), OT_EG_SOC_GPIO_SYSBUS_IRQ(7, PLIC, 8), - OT_EG_SOC_GPIO_SYSBUS_IRQ(8, PLIC, 9) + OT_EG_SOC_GPIO_SYSBUS_IRQ(8, PLIC, 9), + OT_EG_SOC_GPIO_ALERT(0, 0) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("pclk", OT_EG_PERIPHERAL_CLK_HZ) @@ -362,7 +371,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_SYSBUS_IRQ(5, PLIC, 15), OT_EG_SOC_GPIO_SYSBUS_IRQ(6, PLIC, 16), OT_EG_SOC_GPIO_SYSBUS_IRQ(7, PLIC, 17), - OT_EG_SOC_GPIO_SYSBUS_IRQ(8, PLIC, 18) + OT_EG_SOC_GPIO_SYSBUS_IRQ(8, PLIC, 18), + OT_EG_SOC_GPIO_ALERT(0, 1) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("pclk", OT_EG_PERIPHERAL_CLK_HZ) @@ -384,7 +394,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_SYSBUS_IRQ(5, PLIC, 24), OT_EG_SOC_GPIO_SYSBUS_IRQ(6, PLIC, 25), OT_EG_SOC_GPIO_SYSBUS_IRQ(7, PLIC, 26), - OT_EG_SOC_GPIO_SYSBUS_IRQ(8, PLIC, 27) + OT_EG_SOC_GPIO_SYSBUS_IRQ(8, PLIC, 27), + OT_EG_SOC_GPIO_ALERT(0, 2) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("pclk", OT_EG_PERIPHERAL_CLK_HZ) @@ -406,7 +417,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_SYSBUS_IRQ(5, PLIC, 33), OT_EG_SOC_GPIO_SYSBUS_IRQ(6, PLIC, 34), OT_EG_SOC_GPIO_SYSBUS_IRQ(7, PLIC, 35), - OT_EG_SOC_GPIO_SYSBUS_IRQ(8, PLIC, 36) + OT_EG_SOC_GPIO_SYSBUS_IRQ(8, PLIC, 36), + OT_EG_SOC_GPIO_ALERT(0, 3) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("pclk", OT_EG_PERIPHERAL_CLK_HZ) @@ -449,7 +461,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_SYSBUS_IRQ(28, PLIC, 65), OT_EG_SOC_GPIO_SYSBUS_IRQ(29, PLIC, 66), OT_EG_SOC_GPIO_SYSBUS_IRQ(30, PLIC, 67), - OT_EG_SOC_GPIO_SYSBUS_IRQ(31, PLIC, 68) + OT_EG_SOC_GPIO_SYSBUS_IRQ(31, PLIC, 68), + OT_EG_SOC_GPIO_ALERT(0, 4) ) }, [OT_EG_SOC_DEV_SPI_DEVICE] = { @@ -466,7 +479,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_SYSBUS_IRQ(4, PLIC, 73), OT_EG_SOC_GPIO_SYSBUS_IRQ(5, PLIC, 74), OT_EG_SOC_GPIO_SYSBUS_IRQ(6, PLIC, 75), - OT_EG_SOC_GPIO_SYSBUS_IRQ(7, PLIC, 76) + OT_EG_SOC_GPIO_SYSBUS_IRQ(7, PLIC, 76), + OT_EG_SOC_GPIO_ALERT(0, 5) ), }, [OT_EG_SOC_DEV_I2C0] = { @@ -520,7 +534,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO(0, HART, IRQ_M_TIMER), - OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 124) + OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 124), + OT_EG_SOC_GPIO_ALERT(0, 10) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("pclk", OT_EG_PERIPHERAL_CLK_HZ) @@ -534,7 +549,12 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 125), - OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 126) + OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 126), + OT_EG_SOC_GPIO_ALERT(0, 11), + OT_EG_SOC_GPIO_ALERT(1, 12), + OT_EG_SOC_GPIO_ALERT(2, 13), + OT_EG_SOC_GPIO_ALERT(3, 14), + OT_EG_SOC_GPIO_ALERT(4, 15) ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("edn", EDN0), @@ -573,7 +593,10 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { { .base = 0x40140000u } ), .gpio = IBEXGPIOCONNDEFS( - OT_EG_SOC_RSP(OT_PWRMGR_LC, PWRMGR) + OT_EG_SOC_RSP(OT_PWRMGR_LC, PWRMGR), + OT_EG_SOC_GPIO_ALERT(0, 16), + OT_EG_SOC_GPIO_ALERT(1, 17), + OT_EG_SOC_GPIO_ALERT(2, 18) ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("otp_ctrl", OTP_CTRL), @@ -633,7 +656,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 131), - OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 132) + OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 132), + OT_EG_SOC_GPIO_ALERT(0, 19) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("bus-num", 0) @@ -646,7 +670,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 133), - OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 134) + OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 134), + OT_EG_SOC_GPIO_ALERT(0, 20) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("bus-num", 1) @@ -678,7 +703,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_IBEX_WRAPPER_CPU_EN, OT_IBEX_PWRMGR_CPU_EN), OT_EG_SOC_SIGNAL(OT_PWRMGR_RST_REQ, 0, RSTMGR, - OT_RSTMGR_RST_REQ, 0) + OT_RSTMGR_RST_REQ, 0), + OT_EG_SOC_GPIO_ALERT(0, 22) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("num-rom", 1u), @@ -692,7 +718,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_SIGNAL(OT_RSTMGR_SW_RST, 0, PWRMGR, \ - OT_PWRMGR_SW_RST, 0) + OT_PWRMGR_SW_RST, 0), + OT_EG_SOC_GPIO_ALERT(0, 23), + OT_EG_SOC_GPIO_ALERT(1, 24) ), }, [OT_EG_SOC_DEV_CLKMGR] = { @@ -700,6 +728,10 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { .memmap = MEMMAPENTRIES( { .base = 0x40420000u } ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 25), + OT_EG_SOC_GPIO_ALERT(1, 26) + ) }, [OT_EG_SOC_DEV_SYSRST_CTRL] = { .type = TYPE_UNIMPLEMENTED_DEVICE, @@ -739,6 +771,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { .memmap = MEMMAPENTRIES( { .base = 0x40460000u } ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 30) + ) }, [OT_EG_SOC_DEV_AON_TIMER] = { .type = TYPE_OT_AON_TIMER, @@ -751,7 +786,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_SIGNAL(OT_AON_TIMER_WKUP, 0, PWRMGR, \ OT_PWRMGR_WKUP, OT_PWRMGR_WAKEUP_AON_TIMER), OT_EG_SOC_SIGNAL(OT_AON_TIMER_BITE, 0, PWRMGR, \ - OT_PWRMGR_RST, OT_EG_RESET_AON_TIMER) + OT_PWRMGR_RST, OT_EG_RESET_AON_TIMER), + OT_EG_SOC_GPIO_ALERT(0, 31) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("pclk", OT_EG_AON_CLK_HZ) @@ -768,6 +804,10 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { .memmap = MEMMAPENTRIES( { .base = 0x40490000u } ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 32), + OT_EG_SOC_GPIO_ALERT(1, 33) + ) }, [OT_EG_SOC_DEV_SRAM_RET_CTRL] = { .type = TYPE_OT_SRAM_CTRL, @@ -775,6 +815,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { { .base = 0x40500000u }, { .base = 0x40600000u } ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 34) + ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("otp_ctrl", OTP_CTRL) ), @@ -797,7 +840,12 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_SYSBUS_IRQ(2, PLIC, 162), OT_EG_SOC_GPIO_SYSBUS_IRQ(3, PLIC, 163), OT_EG_SOC_GPIO_SYSBUS_IRQ(4, PLIC, 164), - OT_EG_SOC_GPIO_SYSBUS_IRQ(5, PLIC, 165) + OT_EG_SOC_GPIO_SYSBUS_IRQ(5, PLIC, 165), + OT_EG_SOC_GPIO_ALERT(0, 35), + OT_EG_SOC_GPIO_ALERT(1, 36), + OT_EG_SOC_GPIO_ALERT(2, 37), + OT_EG_SOC_GPIO_ALERT(3, 38), + OT_EG_SOC_GPIO_ALERT(4, 39) ), }, [OT_EG_SOC_DEV_AES] = { @@ -806,7 +854,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { { .base = 0x41100000u } ), .gpio = IBEXGPIOCONNDEFS( - OT_EG_SOC_CLKMGR_HINT(OT_CLKMGR_HINT_AES) + OT_EG_SOC_CLKMGR_HINT(OT_CLKMGR_HINT_AES), + OT_EG_SOC_GPIO_ALERT(0, 42), + OT_EG_SOC_GPIO_ALERT(1, 43) ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("edn", EDN0) @@ -824,7 +874,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 166), OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 167), OT_EG_SOC_GPIO_SYSBUS_IRQ(2, PLIC, 168), - OT_EG_SOC_CLKMGR_HINT(OT_CLKMGR_HINT_HMAC) + OT_EG_SOC_CLKMGR_HINT(OT_CLKMGR_HINT_HMAC), + OT_EG_SOC_GPIO_ALERT(0, 44) ), }, [OT_EG_SOC_DEV_KMAC] = { @@ -835,7 +886,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 169), OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 170), - OT_EG_SOC_GPIO_SYSBUS_IRQ(2, PLIC, 171) + OT_EG_SOC_GPIO_SYSBUS_IRQ(2, PLIC, 171), + OT_EG_SOC_GPIO_ALERT(0, 45), + OT_EG_SOC_GPIO_ALERT(1, 46) ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("edn", EDN0) @@ -852,7 +905,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 172), - OT_EG_SOC_CLKMGR_HINT(OT_CLKMGR_HINT_OTBN) + OT_EG_SOC_CLKMGR_HINT(OT_CLKMGR_HINT_OTBN), + OT_EG_SOC_GPIO_ALERT(0, 47), + OT_EG_SOC_GPIO_ALERT(1, 48) ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("edn-u", EDN0), @@ -884,7 +939,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 174), OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 175), OT_EG_SOC_GPIO_SYSBUS_IRQ(2, PLIC, 176), - OT_EG_SOC_GPIO_SYSBUS_IRQ(3, PLIC, 177) + OT_EG_SOC_GPIO_SYSBUS_IRQ(3, PLIC, 177), + OT_EG_SOC_GPIO_ALERT(0, 51), + OT_EG_SOC_GPIO_ALERT(1, 52) ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("random_src", ENTROPY_SRC), @@ -900,7 +957,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 178), OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 179), OT_EG_SOC_GPIO_SYSBUS_IRQ(2, PLIC, 180), - OT_EG_SOC_GPIO_SYSBUS_IRQ(3, PLIC, 181) + OT_EG_SOC_GPIO_SYSBUS_IRQ(3, PLIC, 181), + OT_EG_SOC_GPIO_ALERT(0, 53), + OT_EG_SOC_GPIO_ALERT(1, 54) ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("ast", AST), @@ -914,7 +973,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 182), - OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 183) + OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 183), + OT_EG_SOC_GPIO_ALERT(0, 55), + OT_EG_SOC_GPIO_ALERT(1, 56) ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("csrng", CSRNG) @@ -930,7 +991,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 184), - OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 185) + OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 185), + OT_EG_SOC_GPIO_ALERT(0, 57), + OT_EG_SOC_GPIO_ALERT(1, 58) ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("csrng", CSRNG) @@ -945,6 +1008,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { { .base = 0x411c0000u }, { .base = 0x10000000u } ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 59) + ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("otp_ctrl", OTP_CTRL) ), @@ -964,7 +1030,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_SIGNAL(OT_ROM_CTRL_GOOD, 0, PWRMGR, \ OT_PWRMGR_ROM_GOOD, 0), OT_EG_SOC_SIGNAL(OT_ROM_CTRL_DONE, 0, PWRMGR, \ - OT_PWRMGR_ROM_DONE, 0) + OT_PWRMGR_ROM_DONE, 0), + OT_EG_SOC_GPIO_ALERT(0, 60) ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("kmac", KMAC) @@ -983,6 +1050,12 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { .memmap = MEMMAPENTRIES( { .base = 0x411f0000u } ), + .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO_ALERT(0, 61), + OT_EG_SOC_GPIO_ALERT(1, 62), + OT_EG_SOC_GPIO_ALERT(2, 63), + OT_EG_SOC_GPIO_ALERT(3, 64) + ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("edn", EDN0) ), @@ -1000,7 +1073,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_DM_CONNECTION(OT_EG_SOC_DEV_DM, 0), OT_EG_SOC_DM_CONNECTION(OT_EG_SOC_DEV_DM, 1), OT_EG_SOC_DM_CONNECTION(OT_EG_SOC_DEV_DM, 2), - OT_EG_SOC_DM_CONNECTION(OT_EG_SOC_DEV_DM, 3) + OT_EG_SOC_DM_CONNECTION(OT_EG_SOC_DEV_DM, 3), + OT_EG_SOC_GPIO_ALERT(0, 40) ), }, [OT_EG_SOC_DEV_PLIC] = { @@ -1032,7 +1106,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { { .base = 0x2c000000u } ), .gpio = IBEXGPIOCONNDEFS( - OT_EG_SOC_GPIO(0, HART, IRQ_M_SOFT) + OT_EG_SOC_GPIO(0, HART, IRQ_M_SOFT), + OT_EG_SOC_GPIO_ALERT(0, 41) ), }, /* clang-format on */ From 764d881306f634657c7a5cbf42ea12f1f67646bb Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 21 Jan 2025 12:35:57 +0000 Subject: [PATCH 03/11] [ot] hw/riscv: ot_earlgrey: Connect alert escalation severities Connects GPIO signals for the four different escalation severities of OpenTitan Earlgrey's Alert handler. For now, escalation signal 3 (phase 3) connects to the pwrmgr, where it causes a shutdown as is the default in Darjeeling. In reality, the alert handler should cause a reset in phase 3 and populate the rstmgr's `reset_info` accordingly, but this requires additional work in other blocks, and as such we simply leave this connected to the pwrmgr shutdown for now to match Darjeeling's functionality. Signed-off-by: Alex Jones --- hw/riscv/ot_earlgrey.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/riscv/ot_earlgrey.c b/hw/riscv/ot_earlgrey.c index 7585884e7d725..6b54f91c5b947 100644 --- a/hw/riscv/ot_earlgrey.c +++ b/hw/riscv/ot_earlgrey.c @@ -636,7 +636,11 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 127), OT_EG_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 128), OT_EG_SOC_GPIO_SYSBUS_IRQ(2, PLIC, 129), - OT_EG_SOC_GPIO_SYSBUS_IRQ(3, PLIC, 130) + OT_EG_SOC_GPIO_SYSBUS_IRQ(3, PLIC, 130), + OT_EG_SOC_GPIO_ESCALATE(0, IBEX_WRAPPER, 0), + OT_EG_SOC_GPIO_ESCALATE(1, LC_CTRL, 0), + OT_EG_SOC_GPIO_ESCALATE(1, LC_CTRL, 1), + OT_EG_SOC_GPIO_ESCALATE(3, PWRMGR, 0) ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("edn", EDN0) From b3e8936c1d33d22effd88f492392fc5d8e609fc4 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Sat, 18 Jan 2025 00:52:26 +0000 Subject: [PATCH 04/11] [ot] hw/opentitan: Use QEMU IRQs instead of Ibex IRQs for alerts Ibex IRQs are defined using the `ibex_irq_set` function such that they are optimised to only propagate the IRQ signal if there has been a change in the level (i.e. they are edge-triggered). Despite this, it is possible for alerts to be sent from harwdare without previously resetting the alert, for example upon a hardware fault. This behaviour can be observed in several OpenTitan tests which force alerts several times without resetting the state of the block in-between. One possible solution would just be to send a signal with level=1 followed by a signal with level=0, but the more efficient and maintainable solution is just to use the original `qemu_irq` for this purpose, as the IbexIRQ wrapping functionality does not make sense in this case. Signed-off-by: Alex Jones --- hw/misc/pulp_rv_dm.c | 8 ++++---- hw/opentitan/ot_aes.c | 9 +++++---- hw/opentitan/ot_aon_timer.c | 6 +++--- hw/opentitan/ot_clkmgr.c | 11 ++++++----- hw/opentitan/ot_csrng.c | 9 +++++---- hw/opentitan/ot_edn.c | 7 ++++--- hw/opentitan/ot_entropy_src.c | 9 +++++---- hw/opentitan/ot_flash.c | 7 ++++--- hw/opentitan/ot_gpio_eg.c | 8 ++++---- hw/opentitan/ot_hmac.c | 6 +++--- hw/opentitan/ot_ibex_wrapper_eg.c | 7 ++++--- hw/opentitan/ot_kmac.c | 7 ++++--- hw/opentitan/ot_lc_ctrl.c | 7 ++++--- hw/opentitan/ot_otbn.c | 9 +++++---- hw/opentitan/ot_otp_eg.c | 7 ++++--- hw/opentitan/ot_pinmux_eg.c | 8 ++++---- hw/opentitan/ot_plic_ext.c | 8 ++++---- hw/opentitan/ot_pwrmgr.c | 10 +++++----- hw/opentitan/ot_rom_ctrl.c | 6 +++--- hw/opentitan/ot_rstmgr.c | 7 ++++--- hw/opentitan/ot_sensor.c | 7 ++++--- hw/opentitan/ot_spi_device.c | 7 ++++--- hw/opentitan/ot_spi_host.c | 8 ++++---- hw/opentitan/ot_sram_ctrl.c | 8 ++++---- hw/opentitan/ot_timer.c | 6 +++--- hw/opentitan/ot_uart.c | 9 ++++----- 26 files changed, 107 insertions(+), 94 deletions(-) diff --git a/hw/misc/pulp_rv_dm.c b/hw/misc/pulp_rv_dm.c index 637957bb10edc..0632763f7b0f9 100644 --- a/hw/misc/pulp_rv_dm.c +++ b/hw/misc/pulp_rv_dm.c @@ -133,7 +133,7 @@ struct PulpRVDMState { MemoryRegion rom; /* ROM */ qemu_irq *ack_out; - IbexIRQ alert; + qemu_irq alert; uint32_t dmflag_regs[PULP_RV_DM_DMFLAG_SIZE / sizeof(uint32_t)]; @@ -259,7 +259,7 @@ static void pulp_rv_dm_regs_write(void *opaque, hwaddr addr, uint64_t val64, switch (R32_OFF(addr)) { case R_ALERT_TEST: val32 &= R_ALERT_TEST_FATAL_FAULT_MASK; - ibex_irq_set(&s->alert, (int)(bool)val32); + qemu_set_irq(s->alert, (int)(bool)val32); break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", @@ -477,7 +477,7 @@ static void pulp_rv_dm_reset(DeviceState *dev) { PulpRVDMState *s = PULP_RV_DM(dev); - ibex_irq_set(&s->alert, false); + qemu_set_irq(s->alert, false); memset(memory_region_get_ram_ptr(&s->prog), 0, PULP_RV_DM_PROG_SIZE); memset(s->dmflag_regs, 0, sizeof(s->dmflag_regs)); @@ -524,7 +524,7 @@ static void pulp_rv_dm_init(Object *obj) pulp_rv_dm_load_rom(s); - ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alert, OT_DEVICE_ALERT, 1); } static void pulp_rv_dm_class_init(ObjectClass *klass, void *data) diff --git a/hw/opentitan/ot_aes.c b/hw/opentitan/ot_aes.c index 2120ff6308a13..6cd1d0246c9de 100644 --- a/hw/opentitan/ot_aes.c +++ b/hw/opentitan/ot_aes.c @@ -237,7 +237,7 @@ enum OtAESMode { struct OtAESState { SysBusDevice parent_obj; MemoryRegion mmio; - IbexIRQ alerts[PARAM_NUM_ALERTS]; + qemu_irq alerts[PARAM_NUM_ALERTS]; IbexIRQ clkmgr; QEMUBH *process_bh; QEMUTimer *retard_timer; /* only used with disabled fast-mode */ @@ -328,7 +328,7 @@ static void ot_aes_update_alert(OtAESState *s) { for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { bool level = (bool)(s->regs->status & (1u << ix)); - ibex_irq_set(&s->alerts[ix], (int)level); + qemu_set_irq(s->alerts[ix], (int)level); } } @@ -1269,7 +1269,7 @@ static void ot_aes_reset(DeviceState *dev) ot_aes_load_reseed_rate(s); for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_irq_set(&s->alerts[ix], 0); + qemu_set_irq(s->alerts[ix], 0); } trace_ot_aes_reseed("reset"); @@ -1294,7 +1294,8 @@ static void ot_aes_init(Object *obj) } for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alerts[ix], OT_DEVICE_ALERT, + 1); } ibex_qdev_init_irq(obj, &s->clkmgr, OT_CLOCK_ACTIVE); diff --git a/hw/opentitan/ot_aon_timer.c b/hw/opentitan/ot_aon_timer.c index d261fa2bf54d7..394fb93a4a9d3 100644 --- a/hw/opentitan/ot_aon_timer.c +++ b/hw/opentitan/ot_aon_timer.c @@ -108,7 +108,7 @@ struct OtAonTimerState { IbexIRQ nmi_bark; IbexIRQ pwrmgr_wkup; IbexIRQ pwrmgr_bite; - IbexIRQ alert; + qemu_irq alert; QEMUTimer *wkup_timer; QEMUTimer *wdog_timer; @@ -193,7 +193,7 @@ static inline bool ot_aon_timer_wdog_register_write_enabled(OtAonTimerState *s) static void ot_aon_timer_update_alert(OtAonTimerState *s) { bool level = s->regs[R_ALERT_TEST] & R_ALERT_TEST_FATAL_FAULT_MASK; - ibex_irq_set(&s->alert, level); + qemu_set_irq(s->alert, level); } static void ot_aon_timer_update_irqs(OtAonTimerState *s) @@ -545,7 +545,7 @@ static void ot_aon_timer_init(Object *obj) ibex_qdev_init_irq(obj, &s->nmi_bark, OT_AON_TIMER_BARK); ibex_qdev_init_irq(obj, &s->pwrmgr_wkup, OT_AON_TIMER_WKUP); ibex_qdev_init_irq(obj, &s->pwrmgr_bite, OT_AON_TIMER_BITE); - ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alert, OT_DEVICE_ALERT, 1); memory_region_init_io(&s->mmio, obj, &ot_aon_timer_ops, s, TYPE_OT_AON_TIMER, REGS_SIZE); diff --git a/hw/opentitan/ot_clkmgr.c b/hw/opentitan/ot_clkmgr.c index c36bfaebb5115..575bce0091bcf 100644 --- a/hw/opentitan/ot_clkmgr.c +++ b/hw/opentitan/ot_clkmgr.c @@ -190,7 +190,7 @@ struct OtClkMgrState { SysBusDevice parent_obj; MemoryRegion mmio; IbexIRQ hints[OT_CLKMGR_HINT_COUNT]; - IbexIRQ alerts[PARAM_NUM_ALERTS]; + qemu_irq alerts[PARAM_NUM_ALERTS]; uint32_t clock_states; /* bit set: active, reset: clock is idle */ uint32_t regs[REGS_COUNT]; /* shadowed slots are not used */ @@ -210,7 +210,7 @@ static void ot_clkmgr_update_alerts(OtClkMgrState *s) { bool recov = (bool)(s->regs[R_RECOV_ERR_CODE] & R_RECOV_ERR_CODE_SHADOW_UPDATE_ERR_MASK); - ibex_irq_set(&s->alerts[ALERT_RECOVERABLE], recov); + qemu_set_irq(s->alerts[ALERT_RECOVERABLE], recov); } static void ot_clkmgr_clock_hint(void *opaque, int irq, int level) @@ -320,7 +320,7 @@ static void ot_clkmgr_write(void *opaque, hwaddr addr, uint64_t val64, case R_ALERT_TEST: val32 &= ALERT_TEST_MASK; for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_irq_set(&s->alerts[ix], (int)((val32 >> ix) & 0x1u)); + qemu_set_irq(s->alerts[ix], (int)((val32 >> ix) & 0x1u)); } break; case R_EXTCLK_CTRL_REGWEN: @@ -565,7 +565,7 @@ static void ot_clkmgr_reset(DeviceState *dev) ot_shadow_reg_init(&s->sdw_regs.usb_meas_ctrl, 0x1ccfau); for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_irq_set(&s->alerts[ix], 0); + qemu_set_irq(s->alerts[ix], 0); } } @@ -578,7 +578,8 @@ static void ot_clkmgr_init(Object *obj) sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alerts[ix], OT_DEVICE_ALERT, + 1); } qdev_init_gpio_in_named(DEVICE(obj), &ot_clkmgr_clock_hint, OT_CLKMGR_HINT, diff --git a/hw/opentitan/ot_csrng.c b/hw/opentitan/ot_csrng.c index 144c4dccef0d6..444922486b139 100644 --- a/hw/opentitan/ot_csrng.c +++ b/hw/opentitan/ot_csrng.c @@ -311,7 +311,7 @@ struct OtCSRNGState { MemoryRegion mmio; IbexIRQ irqs[PARAM_NUM_IRQS]; - IbexIRQ alerts[PARAM_NUM_ALERTS]; + qemu_irq alerts[PARAM_NUM_ALERTS]; QEMUBH *cmd_scheduler; QEMUTimer *entropy_scheduler; @@ -781,7 +781,7 @@ static void ot_csrng_update_alerts(OtCSRNGState *s) } for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + qemu_set_irq(s->alerts[ix], (int)((level >> ix) & 0x1u)); } } @@ -1848,7 +1848,7 @@ static void ot_csrng_reset(DeviceState *dev) } ot_csrng_update_irqs(s); for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_irq_set(&s->alerts[ix], 0); + qemu_set_irq(s->alerts[ix], 0); } while (!QSIMPLEQ_EMPTY(&s->cmd_requests)) { @@ -1875,7 +1875,8 @@ static void ot_csrng_init(Object *obj) ibex_sysbus_init_irq(obj, &s->irqs[ix]); } for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alerts[ix], OT_DEVICE_ALERT, + 1); } qdev_init_gpio_in_named_with_opaque(DEVICE(s), &ot_csrng_hwapp_ready_irq, s, diff --git a/hw/opentitan/ot_edn.c b/hw/opentitan/ot_edn.c index 8c28d9a3c53c4..b868287d510e6 100644 --- a/hw/opentitan/ot_edn.c +++ b/hw/opentitan/ot_edn.c @@ -237,7 +237,7 @@ struct OtEDNState { MemoryRegion mmio; IbexIRQ irqs[PARAM_NUM_IRQS]; - IbexIRQ alerts[PARAM_NUM_ALERTS]; + qemu_irq alerts[PARAM_NUM_ALERTS]; QEMUBH *ep_bh; /**< Endpoint requests */ uint32_t *regs; @@ -377,7 +377,7 @@ static void ot_edn_update_alerts(OtEDNState *s) level |= 1u << ALERT_RECOVERABLE; } for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + qemu_set_irq(s->alerts[ix], (int)((level >> ix) & 0x1u)); } } @@ -1338,7 +1338,8 @@ static void ot_edn_init(Object *obj) ibex_sysbus_init_irq(obj, &s->irqs[ix]); } for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alerts[ix], OT_DEVICE_ALERT, + 1); } qdev_init_gpio_in_named_with_opaque(DEVICE(s), &ot_edn_csrng_ack_irq, s, TYPE_OT_EDN "-req_sts", 1); diff --git a/hw/opentitan/ot_entropy_src.c b/hw/opentitan/ot_entropy_src.c index 78971f58b7927..dbf3920d7acf8 100644 --- a/hw/opentitan/ot_entropy_src.c +++ b/hw/opentitan/ot_entropy_src.c @@ -365,7 +365,7 @@ struct OtEntropySrcState { MemoryRegion mmio; IbexIRQ irqs[PARAM_NUM_IRQS]; - IbexIRQ alerts[PARAM_NUM_ALERTS]; + qemu_irq alerts[PARAM_NUM_ALERTS]; QEMUTimer *scheduler; uint32_t *regs; @@ -728,7 +728,7 @@ static void ot_entropy_src_update_alerts(OtEntropySrcState *s) } for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + qemu_set_irq(s->alerts[ix], (int)((level >> ix) & 0x1u)); } } @@ -1588,7 +1588,7 @@ static void ot_entropy_src_reset(DeviceState *dev) ot_entropy_src_update_irqs(s); for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_irq_set(&s->alerts[ix], 0); + qemu_set_irq(s->alerts[ix], 0); } OtOTPStateClass *oc = @@ -1614,7 +1614,8 @@ static void ot_entropy_src_init(Object *obj) ibex_sysbus_init_irq(obj, &s->irqs[ix]); } for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alerts[ix], OT_DEVICE_ALERT, + 1); } ot_fifo32_create(&s->input_fifo, OT_ENTROPY_SRC_FILL_WORD_COUNT * 2u); diff --git a/hw/opentitan/ot_flash.c b/hw/opentitan/ot_flash.c index 8c98b0eeedda8..34c4d933a074e 100644 --- a/hw/opentitan/ot_flash.c +++ b/hw/opentitan/ot_flash.c @@ -645,7 +645,7 @@ struct OtFlashState { } mmio; QEMUTimer *op_delay; /* simulated long lasting operation */ IbexIRQ irqs[PARAM_NUM_IRQS]; - IbexIRQ alerts[PARAM_NUM_ALERTS]; + qemu_irq alerts[PARAM_NUM_ALERTS]; uint32_t *regs; uint32_t *csrs; @@ -677,7 +677,7 @@ static void ot_flash_update_alerts(OtFlashState *s) uint32_t level = s->regs[R_ALERT_TEST]; for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + qemu_set_irq(s->alerts[ix], (int)((level >> ix) & 0x1u)); } } @@ -1827,7 +1827,8 @@ static void ot_flash_init(Object *obj) ibex_sysbus_init_irq(obj, &s->irqs[ix]); } for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alerts[ix], OT_DEVICE_ALERT, + 1); } s->op_delay = timer_new_ns(OT_VIRTUAL_CLOCK, &ot_flash_op_signal, s); } diff --git a/hw/opentitan/ot_gpio_eg.c b/hw/opentitan/ot_gpio_eg.c index 7decec51e10f9..87efbfc6b956b 100644 --- a/hw/opentitan/ot_gpio_eg.c +++ b/hw/opentitan/ot_gpio_eg.c @@ -112,7 +112,7 @@ struct OtGpioEgState { IbexIRQ *irqs; IbexIRQ *gpos; - IbexIRQ alert; + qemu_irq alert; MemoryRegion mmio; @@ -407,7 +407,7 @@ static void ot_gpio_eg_write(void *opaque, hwaddr addr, uint64_t val64, break; case R_ALERT_TEST: val32 &= ALERT_TEST_MASK; - ibex_irq_set(&s->alert, (int)(bool)val32); + qemu_set_irq(s->alert, (int)(bool)val32); break; case R_DIRECT_OUT: s->regs[reg] = val32; @@ -729,7 +729,7 @@ static void ot_gpio_eg_reset(DeviceState *dev) s->regs[R_DIRECT_OE] = s->reset_oe; ot_gpio_eg_update_irqs(s); - ibex_irq_set(&s->alert, 0); + qemu_set_irq(s->alert, 0); ot_gpio_eg_init_backend(s); ot_gpio_eg_update_data_out(s); @@ -766,7 +766,7 @@ static void ot_gpio_eg_init(Object *obj) ibex_sysbus_init_irq(obj, &s->irqs[ix]); } ibex_qdev_init_irqs_default(obj, s->gpos, OT_GPIO_OUT, PARAM_NUM_IO, -1); - ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alert, OT_DEVICE_ALERT, 1); qdev_init_gpio_in_named(DEVICE(obj), &ot_gpio_eg_in_change, OT_GPIO_IN, PARAM_NUM_IO); diff --git a/hw/opentitan/ot_hmac.c b/hw/opentitan/ot_hmac.c index 7c276e11179c5..d464ed807428e 100644 --- a/hw/opentitan/ot_hmac.c +++ b/hw/opentitan/ot_hmac.c @@ -274,7 +274,7 @@ struct OtHMACState { MemoryRegion fifo_mmio; IbexIRQ irqs[PARAM_NUM_IRQS]; - IbexIRQ alert; + qemu_irq alert; IbexIRQ clkmgr; OtHMACRegisters *regs; @@ -401,7 +401,7 @@ static void ot_hmac_update_irqs(OtHMACState *s) static void ot_hmac_update_alert(OtHMACState *s) { bool level = s->regs->alert_test & R_ALERT_TEST_FATAL_FAULT_MASK; - ibex_irq_set(&s->alert, level); + qemu_set_irq(s->alert, level); } static void ot_hmac_report_error(OtHMACState *s, uint32_t error) @@ -1206,7 +1206,7 @@ static void ot_hmac_init(Object *obj) for (unsigned ix = 0; ix < PARAM_NUM_IRQS; ix++) { ibex_sysbus_init_irq(obj, &s->irqs[ix]); } - ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alert, OT_DEVICE_ALERT, 1); ibex_qdev_init_irq(obj, &s->clkmgr, OT_CLOCK_ACTIVE); memory_region_init(&s->mmio, OBJECT(s), TYPE_OT_HMAC, OT_HMAC_WHOLE_SIZE); diff --git a/hw/opentitan/ot_ibex_wrapper_eg.c b/hw/opentitan/ot_ibex_wrapper_eg.c index 1827e9d1f8416..dd24d5292d65b 100644 --- a/hw/opentitan/ot_ibex_wrapper_eg.c +++ b/hw/opentitan/ot_ibex_wrapper_eg.c @@ -224,7 +224,7 @@ struct OtIbexWrapperEgState { MemoryRegion mmio; MemoryRegion remappers[PARAM_NUM_REGIONS]; - IbexIRQ alerts[PARAM_NUM_ALERTS]; + qemu_irq alerts[PARAM_NUM_ALERTS]; uint32_t *regs; OtIbexTestLogEngine *log_engine; @@ -254,7 +254,7 @@ static void ot_ibex_wrapper_eg_update_alerts(OtIbexWrapperEgState *s) } for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + qemu_set_irq(s->alerts[ix], (int)((level >> ix) & 0x1u)); } } @@ -1014,7 +1014,8 @@ static void ot_ibex_wrapper_eg_init(Object *obj) TYPE_OT_IBEX_WRAPPER_EG, REGS_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alerts[ix], OT_DEVICE_ALERT, + 1); } qdev_init_gpio_in_named(DEVICE(obj), &ot_ibex_wrapper_eg_cpu_enable_recv, diff --git a/hw/opentitan/ot_kmac.c b/hw/opentitan/ot_kmac.c index 013dcc1f49bb3..d82f5fa0ea3f0 100644 --- a/hw/opentitan/ot_kmac.c +++ b/hw/opentitan/ot_kmac.c @@ -379,7 +379,7 @@ struct OtKMACState { MemoryRegion state_mmio; MemoryRegion msgfifo_mmio; IbexIRQ irqs[3u]; - IbexIRQ alerts[KMAC_PARAM_NUM_ALERTS]; + qemu_irq alerts[KMAC_PARAM_NUM_ALERTS]; uint32_t *regs; OtShadowReg cfg; @@ -467,7 +467,7 @@ static void ot_kmac_update_alert(OtKMACState *s) } for (unsigned ix = 0; ix < ARRAY_SIZE(s->alerts); ix++) { - ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + qemu_set_irq(s->alerts[ix], (int)((level >> ix) & 0x1u)); } } @@ -1618,7 +1618,8 @@ static void ot_kmac_init(Object *obj) ibex_sysbus_init_irq(obj, &s->irqs[ix]); } for (unsigned ix = 0; ix < ARRAY_SIZE(s->alerts); ix++) { - ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alerts[ix], OT_DEVICE_ALERT, + 1); } memory_region_init(&s->mmio, OBJECT(s), TYPE_OT_KMAC, OT_KMAC_WHOLE_SIZE); diff --git a/hw/opentitan/ot_lc_ctrl.c b/hw/opentitan/ot_lc_ctrl.c index 47ebb9f8b1c80..1ae867979e410 100644 --- a/hw/opentitan/ot_lc_ctrl.c +++ b/hw/opentitan/ot_lc_ctrl.c @@ -368,7 +368,7 @@ struct OtLcCtrlState { MemoryRegion dmi_mmio; QEMUBH *pwc_lc_bh; QEMUBH *escalate_bh; - IbexIRQ alerts[NUM_ALERTS]; + qemu_irq alerts[NUM_ALERTS]; IbexIRQ broadcasts[OT_LC_BROADCAST_COUNT]; IbexIRQ pwc_lc_rsp; IbexIRQ socdbg_tx; @@ -718,7 +718,7 @@ static void ot_lc_ctrl_update_alerts(OtLcCtrlState *s) uint32_t level = s->regs[R_ALERT_TEST]; for (unsigned ix = 0; ix < NUM_ALERTS; ix++) { - ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + qemu_set_irq(s->alerts[ix], (int)((level >> ix) & 0x1u)); } } @@ -2216,7 +2216,8 @@ static void ot_lc_ctrl_init(Object *obj) s->hashed_tokens = g_new0(OtOTPTokenValue, LC_TK_COUNT); for (unsigned ix = 0; ix < ARRAY_SIZE(s->alerts); ix++) { - ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alerts[ix], OT_DEVICE_ALERT, + 1); } for (unsigned ix = 0; ix < ARRAY_SIZE(s->broadcasts); ix++) { diff --git a/hw/opentitan/ot_otbn.c b/hw/opentitan/ot_otbn.c index afcb297ba47c3..6810fd32c1e30 100644 --- a/hw/opentitan/ot_otbn.c +++ b/hw/opentitan/ot_otbn.c @@ -148,7 +148,7 @@ struct OtOTBNState { MemoryRegion dmem; IbexIRQ irq_done; - IbexIRQ alerts[ALERT_COUNT]; + qemu_irq alerts[ALERT_COUNT]; IbexIRQ clkmgr; QEMUBH *proxy_completion_bh; @@ -194,7 +194,7 @@ static void ot_otbn_update_alert(OtOTBNState *s) if (ix == ALERT_FATAL) { level |= (bool)s->fatal_alert_cause; } - ibex_irq_set(&s->alerts[ix], level); + qemu_set_irq(s->alerts[ix], level); } } @@ -634,7 +634,7 @@ static void ot_otbn_reset(DeviceState *dev) s->last_cmd = OT_OTBN_CMD_NONE; ibex_irq_set(&s->irq_done, 0); for (unsigned ix = 0; ix < ALERT_COUNT; ix++) { - ibex_irq_set(&s->alerts[ix], 0); + qemu_set_irq(s->alerts[ix], 0); } for (unsigned rix = 0; rix < (unsigned)OT_OTBN_RND_COUNT; rix++) { @@ -677,7 +677,8 @@ static void ot_otbn_init(Object *obj) memory_region_add_subregion(&s->mmio, OT_OTBN_DMEM_BASE, &s->dmem); ibex_sysbus_init_irq(obj, &s->irq_done); - ibex_qdev_init_irqs(obj, s->alerts, OT_DEVICE_ALERT, ALERT_COUNT); + qdev_init_gpio_out_named(DEVICE(obj), s->alerts, OT_DEVICE_ALERT, + ALERT_COUNT); ibex_qdev_init_irq(obj, &s->clkmgr, OT_CLOCK_ACTIVE); for (unsigned rix = 0; rix < (unsigned)OT_OTBN_RND_COUNT; rix++) { diff --git a/hw/opentitan/ot_otp_eg.c b/hw/opentitan/ot_otp_eg.c index 905e99b4330e1..47f76198b9bb5 100644 --- a/hw/opentitan/ot_otp_eg.c +++ b/hw/opentitan/ot_otp_eg.c @@ -472,7 +472,7 @@ struct OtOTPEgState { } sub; } mmio; IbexIRQ irqs[NUM_IRQS]; - IbexIRQ alerts[NUM_ALERTS]; + qemu_irq alerts[NUM_ALERTS]; QEMUTimer *dai_delay; /**< Simulate delayed access completion */ @@ -528,7 +528,7 @@ static void ot_otp_eg_update_alerts(OtOTPEgState *s) uint32_t level = s->regs[R_ALERT_TEST]; for (unsigned ix = 0; ix < ARRAY_SIZE(s->alerts); ix++) { - ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + qemu_set_irq(s->alerts[ix], (int)((level >> ix) & 0x1u)); } } @@ -1385,7 +1385,8 @@ static void ot_otp_eg_init(Object *obj) ibex_sysbus_init_irq(obj, &s->irqs[ix]); } for (unsigned ix = 0; ix < ARRAY_SIZE(s->alerts); ix++) { - ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alerts[ix], OT_DEVICE_ALERT, + 1); } s->hw_cfg = g_new0(OtOTPHWCfg, 1u); diff --git a/hw/opentitan/ot_pinmux_eg.c b/hw/opentitan/ot_pinmux_eg.c index 9db1720df9fa7..9a61ec8adbd9f 100644 --- a/hw/opentitan/ot_pinmux_eg.c +++ b/hw/opentitan/ot_pinmux_eg.c @@ -194,7 +194,7 @@ struct OtPinmuxEgState { SysBusDevice parent_obj; MemoryRegion mmio; - IbexIRQ alert; + qemu_irq alert; IbexIRQ *dios; IbexIRQ *mios; @@ -319,7 +319,7 @@ static void ot_pinmux_eg_regs_write(void *opaque, hwaddr addr, uint64_t val64, case R_ALERT_TEST: val32 &= R_ALERT_TEST_FATAL_FAULT_MASK; if (val32) { - ibex_irq_set(&s->alert, (int)val32); + qemu_set_irq(s->alert, (int)val32); } break; case CASE_RANGE(MIO_PERIPH_INSEL_REGWEN, PARAM_N_MIO_PERIPH_IN): @@ -523,7 +523,7 @@ static void ot_pinmux_eg_reset(DeviceState *dev) regs->wkup_detector_regwen[ix] = 0x1u; } - ibex_irq_set(&s->alert, 0); + qemu_set_irq(s->alert, 0); } static void ot_pinmux_eg_init(Object *obj) @@ -535,7 +535,7 @@ static void ot_pinmux_eg_init(Object *obj) sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); s->regs = g_new0(OtPinmuxEgStateRegs, 1u); - ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alert, OT_DEVICE_ALERT, 1); s->dios = g_new(IbexIRQ, PARAM_N_DIO_PADS); s->mios = g_new(IbexIRQ, PARAM_N_MIO_PADS); diff --git a/hw/opentitan/ot_plic_ext.c b/hw/opentitan/ot_plic_ext.c index 9f714c5c55c12..aed8d0fe6496b 100644 --- a/hw/opentitan/ot_plic_ext.c +++ b/hw/opentitan/ot_plic_ext.c @@ -58,7 +58,7 @@ struct OtPlicExtState { MemoryRegion mmio; IbexIRQ irq; - IbexIRQ alert; + qemu_irq alert; uint32_t regs[REGS_COUNT]; @@ -127,7 +127,7 @@ static void ot_plic_ext_regs_write(void *opaque, hwaddr addr, uint64_t val64, case R_ALERT_TEST: val32 &= R_ALERT_TEST_FATAL_FAULT_MASK; s->regs[reg] = val32; - ibex_irq_set(&s->alert, (int)(bool)val32); + qemu_set_irq(s->alert, (int)(bool)val32); break; default: qemu_log_mask(LOG_GUEST_ERROR, @@ -155,7 +155,7 @@ static void ot_plic_ext_reset(DeviceState *dev) OtPlicExtState *s = OT_PLIC_EXT(dev); ibex_irq_set(&s->irq, 0); - ibex_irq_set(&s->alert, 0); + qemu_set_irq(s->alert, 0); } static void ot_plic_ext_realize(DeviceState *dev, Error **errp) @@ -179,7 +179,7 @@ static void ot_plic_ext_init(Object *obj) sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); ibex_qdev_init_irq(obj, &s->irq, NULL); - ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alert, OT_DEVICE_ALERT, 1); } static void ot_plic_ext_class_init(ObjectClass *klass, void *data) diff --git a/hw/opentitan/ot_pwrmgr.c b/hw/opentitan/ot_pwrmgr.c index 9adc7967c6eee..52e9bd65e89d0 100644 --- a/hw/opentitan/ot_pwrmgr.c +++ b/hw/opentitan/ot_pwrmgr.c @@ -235,13 +235,13 @@ struct OtPwrMgrState { QEMUTimer *cdc_sync; QEMUBH *fsm_tick_bh; IbexIRQ irq; /* wake from low power */ - IbexIRQ alert; IbexIRQ strap; IbexIRQ cpu_enable; IbexIRQ pwr_lc_req; IbexIRQ pwr_otp_req; IbexIRQ reset_req; IbexIRQ boot_st; + qemu_irq alert; OtPwrMgrFastState f_state; OtPwrMgrSlowState s_state; @@ -831,8 +831,7 @@ static void ot_pwrmgr_regs_write(void *opaque, hwaddr addr, uint64_t val64, break; case R_ALERT_TEST: val32 &= R_ALERT_TEST_FATAL_FAULT_MASK; - s->regs[reg] = val32; - ibex_irq_set(&s->alert, (int)(bool)val32); + qemu_set_irq(s->alert, (int)(bool)val32); break; case R_CONTROL: /* TODO: clear LOW_POWER_HINT on next WFI? */ @@ -958,9 +957,9 @@ static void ot_pwrmgr_reset_enter(Object *obj, ResetType type) ibex_irq_set(&s->cpu_enable, 0); ibex_irq_set(&s->pwr_otp_req, 0); ibex_irq_set(&s->pwr_lc_req, 0); - ibex_irq_set(&s->alert, 0); ibex_irq_set(&s->reset_req, 0); ibex_irq_set(&s->boot_st, s->boot_status.i32); + qemu_set_irq(s->alert, 0); } static void ot_pwrmgr_reset_exit(Object *obj, ResetType type) @@ -1009,7 +1008,6 @@ static void ot_pwrmgr_init(Object *obj) s->regs = g_new0(uint32_t, REGS_COUNT); ibex_sysbus_init_irq(obj, &s->irq); - ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); ibex_qdev_init_irq(obj, &s->pwr_lc_req, OT_PWRMGR_LC_REQ); ibex_qdev_init_irq(obj, &s->pwr_otp_req, OT_PWRMGR_OTP_REQ); ibex_qdev_init_irq(obj, &s->cpu_enable, OT_PWRMGR_CPU_EN); @@ -1017,6 +1015,8 @@ static void ot_pwrmgr_init(Object *obj) ibex_qdev_init_irq(obj, &s->reset_req, OT_PWRMGR_RST_REQ); ibex_qdev_init_irq(obj, &s->boot_st, OT_PWRMGR_BOOT_STATUS); + qdev_init_gpio_out_named(DEVICE(obj), &s->alert, OT_DEVICE_ALERT, 1); + s->cdc_sync = timer_new_ns(OT_VIRTUAL_CLOCK, &ot_pwrmgr_cdc_sync, s); qdev_init_gpio_in_named(DEVICE(obj), &ot_pwrmgr_wkup, OT_PWRMGR_WKUP, diff --git a/hw/opentitan/ot_rom_ctrl.c b/hw/opentitan/ot_rom_ctrl.c index ca1a1540acab7..aac11dc71abba 100644 --- a/hw/opentitan/ot_rom_ctrl.c +++ b/hw/opentitan/ot_rom_ctrl.c @@ -139,7 +139,7 @@ struct OtRomCtrlState { MemoryRegion mmio; IbexIRQ pwrmgr_good; IbexIRQ pwrmgr_done; - IbexIRQ alert; + qemu_irq alert; uint32_t regs[REGS_COUNT]; @@ -933,7 +933,7 @@ static void ot_rom_ctrl_regs_write(void *opaque, hwaddr addr, uint64_t val64, case R_ALERT_TEST: val32 &= R_ALERT_TEST_FATAL_ERROR_MASK; s->regs[reg] = val32; - ibex_irq_set(&s->alert, (int)(bool)val32); + qemu_set_irq(s->alert, (int)(bool)val32); break; case R_FATAL_ALERT_CAUSE: case R_DIGEST_0: @@ -1194,7 +1194,7 @@ static void ot_rom_ctrl_init(Object *obj) TYPE_OT_ROM_CTRL ".regs", REGS_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); - ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alert, OT_DEVICE_ALERT, 1); fifo8_create(&s->hash_fifo, OT_KMAC_APP_MSG_BYTES); } diff --git a/hw/opentitan/ot_rstmgr.c b/hw/opentitan/ot_rstmgr.c index bd6f740ce32e4..e5e9878c07881 100644 --- a/hw/opentitan/ot_rstmgr.c +++ b/hw/opentitan/ot_rstmgr.c @@ -148,7 +148,7 @@ struct OtRstMgrState { MemoryRegion mmio; IbexIRQ soc_reset; IbexIRQ sw_reset; - IbexIRQ alerts[PARAM_NUM_ALERTS]; + qemu_irq alerts[PARAM_NUM_ALERTS]; QEMUBH *bus_reset_bh; CPUState *cpu; @@ -209,7 +209,7 @@ static void ot_rstmgr_update_alerts(OtRstMgrState *s) uint32_t level = s->regs[R_ALERT_TEST]; for (unsigned ix = 0; ix < ARRAY_SIZE(s->alerts); ix++) { - ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + qemu_set_irq(s->alerts[ix], (int)((level >> ix) & 0x1u)); } } @@ -556,7 +556,8 @@ static void ot_rstmgr_init(Object *obj) ibex_qdev_init_irq(obj, &s->soc_reset, OT_RSTMGR_SOC_RST); ibex_qdev_init_irq(obj, &s->sw_reset, OT_RSTMGR_SW_RST); - ibex_qdev_init_irqs(obj, s->alerts, OT_DEVICE_ALERT, PARAM_NUM_ALERTS); + qdev_init_gpio_out_named(DEVICE(obj), s->alerts, OT_DEVICE_ALERT, + PARAM_NUM_ALERTS); qdev_init_gpio_in_named(DEVICE(obj), &ot_rstmgr_reset_req, OT_RSTMGR_RST_REQ, 1); diff --git a/hw/opentitan/ot_sensor.c b/hw/opentitan/ot_sensor.c index 16d5ca6dcc164..84f9fc95a2756 100644 --- a/hw/opentitan/ot_sensor.c +++ b/hw/opentitan/ot_sensor.c @@ -136,7 +136,7 @@ struct OtSensorState { MemoryRegion mmio; IbexIRQ irqs[2u]; - IbexIRQ alerts[NUM_ALERTS]; + qemu_irq alerts[NUM_ALERTS]; uint32_t *regs; }; @@ -156,7 +156,7 @@ static void ot_sensor_update_alerts(OtSensorState *s) uint32_t level = s->regs[R_ALERT_TEST]; for (unsigned ix = 0; ix < ARRAY_SIZE(s->alerts); ix++) { - ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + qemu_set_irq(s->alerts[ix], (int)((level >> ix) & 0x1u)); } } @@ -296,7 +296,8 @@ static void ot_sensor_init(Object *obj) ibex_sysbus_init_irq(obj, &s->irqs[ix]); } for (unsigned ix = 0; ix < ARRAY_SIZE(s->alerts); ix++) { - ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alerts[ix], OT_DEVICE_ALERT, + 1); } } diff --git a/hw/opentitan/ot_spi_device.c b/hw/opentitan/ot_spi_device.c index 5eeb3e03f26c9..8efd77d7ab0be 100644 --- a/hw/opentitan/ot_spi_device.c +++ b/hw/opentitan/ot_spi_device.c @@ -447,7 +447,7 @@ struct OtSPIDeviceState { MemoryRegion buf; } mmio; IbexIRQ irqs[PARAM_NUM_IRQS]; - IbexIRQ alerts[PARAM_NUM_ALERTS]; + qemu_irq alerts[PARAM_NUM_ALERTS]; SpiDeviceBus bus; SpiDeviceFlash flash; @@ -753,7 +753,7 @@ static void ot_spi_device_update_alerts(OtSPIDeviceState *s) uint32_t level = s->spi_regs[R_ALERT_TEST]; for (unsigned ix = 0; ix < ARRAY_SIZE(s->alerts); ix++) { - ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + qemu_set_irq(s->alerts[ix], (int)((level >> ix) & 0x1u)); } } @@ -2185,7 +2185,8 @@ static void ot_spi_device_init(Object *obj) ibex_sysbus_init_irq(obj, &s->irqs[ix]); } for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { - ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alerts[ix], OT_DEVICE_ALERT, + 1); } /* diff --git a/hw/opentitan/ot_spi_host.c b/hw/opentitan/ot_spi_host.c index 0d20bd33e3da0..83061b17e902a 100644 --- a/hw/opentitan/ot_spi_host.c +++ b/hw/opentitan/ot_spi_host.c @@ -322,7 +322,7 @@ struct OtSPIHostState { QEMUTimer *fsm_delay; /**< Simulate delayed SPI transfer completion */ IbexIRQ irqs[2u]; /**< System bus IRQs */ - IbexIRQ alert; /**< OpenTitan alert */ + qemu_irq alert; /**< OpenTitan alert */ uint32_t events; /**< Active events */ uint32_t last_events; /**< Last detected events */ @@ -690,7 +690,7 @@ static void ot_spi_host_update_alert(OtSPIHostState *s) * register in QEMU */ bool alert = (bool)s->regs[R_ALERT_TEST]; - ibex_irq_set(&s->alert, alert); + qemu_set_irq(s->alert, alert); } /* ------------------------------------------------------------------------ */ @@ -733,7 +733,7 @@ static void ot_spi_host_reset(OtSPIHostState *s) for (unsigned ix = 0u; ix < ARRAY_SIZE(s->irqs); ix++) { ibex_irq_set(&s->irqs[ix], 0); } - ibex_irq_set(&s->alert, 0); + qemu_set_irq(s->alert, 0); ot_spi_host_update_regs(s); ot_spi_host_update_alert(s); @@ -1288,7 +1288,7 @@ static void ot_spi_host_instance_init(Object *obj) ibex_qdev_init_irqs(obj, &s->irqs[0u], SYSBUS_DEVICE_GPIO_IRQ, ARRAY_SIZE(s->irqs)); - ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alert, OT_DEVICE_ALERT, 1); s->regs = g_new0(uint32_t, REGS_COUNT); s->config_opts = g_new0(uint32_t, (size_t)s->num_cs); diff --git a/hw/opentitan/ot_sram_ctrl.c b/hw/opentitan/ot_sram_ctrl.c index f93e6e334ab6a..653c28b17dd52 100644 --- a/hw/opentitan/ot_sram_ctrl.c +++ b/hw/opentitan/ot_sram_ctrl.c @@ -116,7 +116,7 @@ struct OtSramCtrlState { MemoryRegion mmio; /* SRAM controller registers */ OtSramCtrlMem *mem; /* SRAM memory */ - IbexIRQ alert; + qemu_irq alert; QEMUBH *switch_mr_bh; /* switch memory region */ QEMUTimer *init_timer; /* SRAM initialization timer */ @@ -395,7 +395,7 @@ static void ot_sram_ctrl_regs_write(void *opaque, hwaddr addr, uint64_t val64, switch (reg) { case R_ALERT_TEST: val32 &= R_ALERT_TEST_FATAL_ERROR_MASK; - ibex_irq_set(&s->alert, (int)(bool)val32); + qemu_set_irq(s->alert, (int)(bool)val32); break; case R_EXEC_REGWEN: val32 &= R_EXEC_REGWEN_EN_MASK; @@ -679,7 +679,7 @@ static void ot_sram_ctrl_reset(DeviceState *dev) } s->cfg_ifetch = 0u; /* not used for now */ - ibex_irq_set(&s->alert, (int)(bool)s->regs[R_ALERT_TEST]); + qemu_set_irq(s->alert, (int)(bool)s->regs[R_ALERT_TEST]); int64_t now = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); ot_prng_reseed(s->prng, (uint32_t)now); @@ -790,7 +790,7 @@ static void ot_sram_ctrl_init(Object *obj) TYPE_OT_SRAM_CTRL ".regs", REGS_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); - ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alert, OT_DEVICE_ALERT, 1); s->mem = g_new0(OtSramCtrlMem, 1u); s->switch_mr_bh = qemu_bh_new(&ot_sram_ctrl_mem_switch_to_ram_fn, s); diff --git a/hw/opentitan/ot_timer.c b/hw/opentitan/ot_timer.c index 0e85cb0596556..0d9a2e1cbc880 100644 --- a/hw/opentitan/ot_timer.c +++ b/hw/opentitan/ot_timer.c @@ -85,7 +85,7 @@ struct OtTimerState { MemoryRegion mmio; IbexIRQ m_timer_irq; IbexIRQ irq; - IbexIRQ alert; + qemu_irq alert; QEMUTimer *timer; uint32_t regs[REGS_COUNT]; @@ -147,7 +147,7 @@ static inline bool ot_timer_is_active(OtTimerState *s) static void ot_timer_update_alert(OtTimerState *s) { bool level = (bool)(s->regs[R_ALERT_TEST] & R_ALERT_TEST_FATAL_FAULT_MASK); - ibex_irq_set(&s->alert, level); + qemu_set_irq(s->alert, level); } static void ot_timer_update_irqs(OtTimerState *s) @@ -390,7 +390,7 @@ static void ot_timer_init(Object *obj) ibex_sysbus_init_irq(obj, &s->irq); ibex_qdev_init_irq(obj, &s->m_timer_irq, NULL); - ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alert, OT_DEVICE_ALERT, 1); memory_region_init_io(&s->mmio, obj, &ot_timer_ops, s, TYPE_OT_TIMER, REGS_SIZE); diff --git a/hw/opentitan/ot_uart.c b/hw/opentitan/ot_uart.c index a271acdf0529d..821d25f3d5b47 100644 --- a/hw/opentitan/ot_uart.c +++ b/hw/opentitan/ot_uart.c @@ -147,7 +147,7 @@ struct OtUARTState { SysBusDevice parent_obj; MemoryRegion mmio; IbexIRQ irqs[OT_UART_IRQ_NUM]; - IbexIRQ alert; + qemu_irq alert; uint32_t regs[REGS_COUNT]; @@ -486,8 +486,7 @@ static void ot_uart_write(void *opaque, hwaddr addr, uint64_t val64, break; case R_ALERT_TEST: val32 &= R_ALERT_TEST_FATAL_FAULT_MASK; - s->regs[reg] = val32; - ibex_irq_set(&s->alert, (int)(bool)val32); + qemu_set_irq(s->alert, (int)(bool)val32); break; case R_CTRL: if (val32 & ~CTRL_SUP_MASK) { @@ -605,7 +604,7 @@ static void ot_uart_reset(DeviceState *dev) ot_uart_reset_rx_fifo(s); ot_uart_update_irqs(s); - ibex_irq_set(&s->alert, 0); + qemu_set_irq(s->alert, 0); } static void ot_uart_init(Object *obj) @@ -615,7 +614,7 @@ static void ot_uart_init(Object *obj) for (unsigned index = 0; index < OT_UART_IRQ_NUM; index++) { ibex_sysbus_init_irq(obj, &s->irqs[index]); } - ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT); + qdev_init_gpio_out_named(DEVICE(obj), &s->alert, OT_DEVICE_ALERT, 1); memory_region_init_io(&s->mmio, obj, &ot_uart_ops, s, TYPE_OT_UART, REGS_SIZE); From a7079c03c6ca9d5d61a5105af48530a75379608a Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 21 Jan 2025 18:14:54 +0000 Subject: [PATCH 05/11] [ot] target/riscv: Add support for Non-Maskable Interrupts Adds support for Non-Maskable Interrupts (NMIs) to the RISC-V QEMU CPU implementation. NMIs are defined by the RISC-V specification to be independent to regular interrupts, used only for hardware error conditions and causing an immediate jump to an implementation-defined NMI vector running in M-mode, regardless of the values of e.g. MIE/MIP. The spec states that "the values written to mcause on an NMI are implementation-defined"; in Ibex we always use an mcause of 31 (and a corresponding mtvec offset of 0x7C to determine the jump address for the NMI handler). To aid a more generic implementation, this commit introduces a generic `nmi_cause` CPU environment value that can be used alongside the NMI functionality to allow implementations to change the mcause as they see fit. Signed-off-by: Alex Jones --- target/riscv/cpu.c | 9 ++++++++- target/riscv/cpu.h | 7 +++++++ target/riscv/cpu_bits.h | 1 + target/riscv/cpu_helper.c | 14 +++++++++++++- target/riscv/op_helper.c | 1 + 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 02d86bca6341e..b6ceaf41a8b2d 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -954,7 +954,9 @@ bool riscv_cpu_has_work(CPUState *cs) return riscv_cpu_all_pending(env) != 0 || riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE || riscv_cpu_vsirq_pending(env) != RISCV_EXCP_NONE || - env->debug_cs; + env->debug_cs || + env->pending_nmi || + env->processing_nmi; #else return true; #endif @@ -1403,6 +1405,11 @@ static void riscv_cpu_set_irq(void *opaque, int irq, int level) BOOL_TO_MASK(level | env->software_seip)); } break; + case IRQ_NMI: + /* NMIs do not need to update mip */ + env->pending_nmi = true; + riscv_cpu_interrupt(env); + break; default: /* Handle platform / custom local interrupts */ riscv_cpu_update_mip(env, 1ULL << irq, BOOL_TO_MASK(level)); diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 466ccc9356abd..53824159e7878 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -447,6 +447,13 @@ struct CPUArchState { uint64_t dmhaltvec; /* Address of halt handler */ uint64_t dmexcpvec; /* Address of exception handler */ + /* + * NMI support + */ + bool pending_nmi; /* True if an NMI is pending, and must be handled */ + bool processing_nmi; /* True if currently in an NMI handler */ + unsigned nmi_cause; /* Reason for entering NMI */ + /* * CSRs for PointerMasking extension */ diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index cabc22e084ea8..ff1007720af0f 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -731,6 +731,7 @@ typedef enum RISCVException { #define IRQ_M_EXT 11 #define IRQ_S_GEXT 12 #define IRQ_PMU_OVF 13 +#define IRQ_NMI 14 #define IRQ_LOCAL_MAX 64 /* -1 is due to bit zero of hgeip and hgeie being ROZ. */ #define IRQ_LOCAL_GUEST_MAX (TARGET_LONG_BITS - 1) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 6b231a3813316..74ee1af21ffda 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -504,6 +504,18 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request) if (unlikely(env->debug_dm && (env->debugger || get_field(env->dcsr, DCSR_STEP)))) { return false; + } else if (unlikely(env->pending_nmi && !env->processing_nmi)) { + /* + * NMIs are handled in the same way as machine traps, but have an + * implementation-defined cause, and must be signalled via + * additional flags, since they are implementation-specific, and + * not visible through the mip register. + */ + cs->exception_index = RISCV_EXCP_INT_FLAG | env->nmi_cause; + env->pending_nmi = false; + env->processing_nmi = true; + riscv_cpu_do_interrupt(cs); + return true; } int interruptno = riscv_cpu_local_irq_pending(env); if (interruptno >= 0) { @@ -653,7 +665,7 @@ void riscv_cpu_interrupt(CPURISCVState *env) vstip = env->vstime_irq ? MIP_VSTIP : 0; - if (env->mip | vsgein | vstip | irqf) { + if (env->mip | vsgein | vstip | irqf | env->pending_nmi) { cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 8c51292795136..2b1a485100cdc 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -343,6 +343,7 @@ target_ulong helper_mret(CPURISCVState *env) mstatus = set_field(mstatus, MSTATUS_MPRV, 0); } env->mstatus = mstatus; + env->processing_nmi = false; if (riscv_has_ext(env, RVH) && prev_virt) { riscv_cpu_swap_hypervisor_regs(env); From 26878e3bee79fbba56c508c9500430b9d2bb9b2c Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 21 Jan 2025 18:32:06 +0000 Subject: [PATCH 06/11] [ot] hw/opentitan: ot_ibex_wrapper: Add NMI support to Ibex Wrapper Adds support for NMIs to Earlgrey's Ibex wrapper, allowing incoming NMI IRQ signals to be received by the device, which will then be propagated through an external IRQ signal to the Ibex itself (the hart) with the newly introduced IRQ_NMI value. This will allow support for hardware raising NMIs via GPIO signals between the QEMU devices, such that NMI support can be added to Earlgrey. Signed-off-by: Alex Jones --- hw/opentitan/ot_ibex_wrapper_eg.c | 27 ++++++++++++++++++++++++-- hw/opentitan/trace-events | 1 + hw/riscv/ot_earlgrey.c | 1 + include/hw/opentitan/ot_ibex_wrapper.h | 7 +++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/hw/opentitan/ot_ibex_wrapper_eg.c b/hw/opentitan/ot_ibex_wrapper_eg.c index dd24d5292d65b..862fcf49a8d15 100644 --- a/hw/opentitan/ot_ibex_wrapper_eg.c +++ b/hw/opentitan/ot_ibex_wrapper_eg.c @@ -83,8 +83,8 @@ REG32(DBUS_ADDR_MATCHING_1, 0x40u) REG32(DBUS_REMAP_ADDR_0, 0x44u) REG32(DBUS_REMAP_ADDR_1, 0x48u) REG32(NMI_ENABLE, 0x4cu) - SHARED_FIELD(NMI_ALERT_EN_BIT, 0u, 1u) - SHARED_FIELD(NMI_WDOG_EN_BIT, 1u, 1u) + SHARED_FIELD(NMI_ALERT_EN_BIT, OT_IBEX_NMI_ALERT, 1u) + SHARED_FIELD(NMI_WDOG_EN_BIT, OT_IBEX_NMI_WDOG, 1u) REG32(NMI_STATE, 0x50u) REG32(ERR_STATUS, 0x54u) FIELD(ERR_STATUS, REG_INTG, 0u, 1u) @@ -225,6 +225,7 @@ struct OtIbexWrapperEgState { MemoryRegion mmio; MemoryRegion remappers[PARAM_NUM_REGIONS]; qemu_irq alerts[PARAM_NUM_ALERTS]; + IbexIRQ nmi_irq; uint32_t *regs; OtIbexTestLogEngine *log_engine; @@ -770,6 +771,24 @@ static void ot_ibex_wrapper_eg_cpu_enable_recv(void *opaque, int n, int level) ot_ibex_wrapper_eg_update_exec(s); } +static void ot_ibex_wrapper_eg_nmi_recv(void *opaque, int n, int level) +{ + OtIbexWrapperEgState *s = opaque; + + g_assert((unsigned)n < OT_IBEX_NMI_COUNT); + + /* NMI_STATE is rw1c, so must be cleared with a register write. */ + if (level) { + s->regs[R_NMI_STATE] |= 1u << (unsigned)n; + } + + trace_ot_ibex_wrapper_nmi_recv(s->ot_id ?: "", n ? "WDOG" : "ALERT", + (bool)level); + + uint32_t nmi_active = s->regs[R_NMI_ENABLE] & s->regs[R_NMI_STATE]; + ibex_irq_set(&s->nmi_irq, (bool)nmi_active); +} + static void ot_ibex_wrapper_eg_escalate_rx(void *opaque, int n, int level) { OtIbexWrapperEgState *s = opaque; @@ -1020,9 +1039,13 @@ static void ot_ibex_wrapper_eg_init(Object *obj) qdev_init_gpio_in_named(DEVICE(obj), &ot_ibex_wrapper_eg_cpu_enable_recv, OT_IBEX_WRAPPER_CPU_EN, OT_IBEX_CPU_EN_COUNT); + qdev_init_gpio_in_named(DEVICE(obj), &ot_ibex_wrapper_eg_nmi_recv, + OT_IBEX_WRAPPER_NMI, OT_IBEX_NMI_COUNT); qdev_init_gpio_in_named(DEVICE(obj), &ot_ibex_wrapper_eg_escalate_rx, OT_ALERT_ESCALATE, 1); + ibex_qdev_init_irq(obj, &s->nmi_irq, NULL); + s->regs = g_new0(uint32_t, REGS_COUNT); s->log_engine = g_new0(OtIbexTestLogEngine, 1u); } diff --git a/hw/opentitan/trace-events b/hw/opentitan/trace-events index 238d023a8db7d..ba5279a1026d8 100644 --- a/hw/opentitan/trace-events +++ b/hw/opentitan/trace-events @@ -228,6 +228,7 @@ ot_i2c_update_irqs(const char *id, uint32_t active, uint32_t mask, uint32_t eff) # ot_ibex_wrapper.c ot_ibex_wrapper_cpu_enable(const char *id, const char *ch, bool level) "%s: %s:%u" +ot_ibex_wrapper_nmi_recv(const char *id, const char *ch, bool level) "%s: %s:%u" ot_ibex_wrapper_error(const char *id, const char *func, int line, const char *msg) "%s: %s:%d %s" ot_ibex_wrapper_escalate_rx(const char *id, bool level) "%s: %u" ot_ibex_wrapper_exit(const char *id, const char *msg, int val) "%s: %s (%d)" diff --git a/hw/riscv/ot_earlgrey.c b/hw/riscv/ot_earlgrey.c index 6b54f91c5b947..2d1d4276df02e 100644 --- a/hw/riscv/ot_earlgrey.c +++ b/hw/riscv/ot_earlgrey.c @@ -1055,6 +1055,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { { .base = 0x411f0000u } ), .gpio = IBEXGPIOCONNDEFS( + OT_EG_SOC_GPIO(0, HART, IRQ_NMI), OT_EG_SOC_GPIO_ALERT(0, 61), OT_EG_SOC_GPIO_ALERT(1, 62), OT_EG_SOC_GPIO_ALERT(2, 63), diff --git a/include/hw/opentitan/ot_ibex_wrapper.h b/include/hw/opentitan/ot_ibex_wrapper.h index baf862448d6d4..e8849903636cf 100644 --- a/include/hw/opentitan/ot_ibex_wrapper.h +++ b/include/hw/opentitan/ot_ibex_wrapper.h @@ -45,6 +45,7 @@ struct OtIbexWrapperStateClass { }; #define OT_IBEX_WRAPPER_CPU_EN TYPE_OT_IBEX_WRAPPER "-cpu-en" +#define OT_IBEX_WRAPPER_NMI TYPE_OT_IBEX_WRAPPER "-nmi" typedef enum { OT_IBEX_LC_CTRL_CPU_EN, @@ -52,4 +53,10 @@ typedef enum { OT_IBEX_CPU_EN_COUNT } OtIbexWrapperCpuEnable; +typedef enum { + OT_IBEX_NMI_ALERT, + OT_IBEX_NMI_WDOG, + OT_IBEX_NMI_COUNT +} OtIbexWrapperNmi; + #endif /* HW_OPENTITAN_OT_IBEX_WRAPPER_H */ From 3c35b08b82c4356b3977188b7d3b6ce52a3c7175 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 21 Jan 2025 18:35:54 +0000 Subject: [PATCH 07/11] [ot] hw/opentitan: ot_ibex_wrapper: Make NMI registers rw1s/rw1c Signed-off-by: Alex Jones --- hw/opentitan/ot_ibex_wrapper_eg.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/opentitan/ot_ibex_wrapper_eg.c b/hw/opentitan/ot_ibex_wrapper_eg.c index 862fcf49a8d15..32d1caab8302a 100644 --- a/hw/opentitan/ot_ibex_wrapper_eg.c +++ b/hw/opentitan/ot_ibex_wrapper_eg.c @@ -929,6 +929,12 @@ static void ot_ibex_wrapper_eg_regs_write(void *opaque, hwaddr addr, } ot_ibex_wrapper_eg_update_remap(s, true, reg - R_DBUS_REMAP_ADDR_0); break; + case R_NMI_ENABLE: + s->regs[reg] |= val32; /* rw1s */ + break; + case R_NMI_STATE: + s->regs[reg] &= ~val32; /* rw1c */ + break; case R_DV_SIM_STATUS: ot_ibex_wrapper_eg_status_report(s, val32); switch (val32) { From 70bde0139e6df8da8b16c2e24dafb3a2d103e521 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 21 Jan 2025 22:17:05 +0000 Subject: [PATCH 08/11] [ot] hw/riscv: ot_earlgrey: Set NMI mcause for Ibex to 31 This initialises Ibex within Earlgrey with the newly defined `nmi_cause` value as 31, as NMI mcause values are implementation-defined, and Ibex makes the decision to implement all NMIs with a cause of 31, leading to an offset of 0x7c from the mtvec base being loaded into mepc upon an NMI occuring. Signed-off-by: Alex Jones --- hw/riscv/ot_earlgrey.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/riscv/ot_earlgrey.c b/hw/riscv/ot_earlgrey.c index 2d1d4276df02e..76a77391beaf2 100644 --- a/hw/riscv/ot_earlgrey.c +++ b/hw/riscv/ot_earlgrey.c @@ -1214,6 +1214,11 @@ static void ot_eg_soc_hart_configure(DeviceState *dev, const IbexDeviceDef *def, qdev_prop_set_array(dev, "pmp_addr", pmp_addr); qdev_prop_set_uint64(dev, "mseccfg", (uint64_t)OT_EG_MSECCFG); + + /* NMIs are defined in Ibex to all have a mcause of 31 */ + RISCVCPU *cpu = RISCV_CPU(dev); + CPURISCVState *env = &cpu->env; + env->nmi_cause = 31u; } static void ot_eg_soc_otp_ctrl_configure( From 3daef7b5f2399ecb4d12cb04ffe40ad77d19666d Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 21 Jan 2025 18:42:55 +0000 Subject: [PATCH 09/11] [ot] hw/opentitan: ot_aon_timer: Connect watchdog bark NMI The aon timer should send an NMI signal to Ibex when its watchdog timer barks. Now that the NMI functionality is in place, we can appropriately hook up this signal, which should appear before the equivalent IRQ. Signed-off-by: Alex Jones --- hw/opentitan/ot_aon_timer.c | 2 +- hw/riscv/ot_earlgrey.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/opentitan/ot_aon_timer.c b/hw/opentitan/ot_aon_timer.c index 394fb93a4a9d3..5b81882738d86 100644 --- a/hw/opentitan/ot_aon_timer.c +++ b/hw/opentitan/ot_aon_timer.c @@ -203,8 +203,8 @@ static void ot_aon_timer_update_irqs(OtAonTimerState *s) trace_ot_aon_timer_irqs(s->ot_id, wkup, bark, s->wdog_bite); ibex_irq_set(&s->irq_wkup, wkup); - ibex_irq_set(&s->irq_bark, bark); ibex_irq_set(&s->nmi_bark, bark); + ibex_irq_set(&s->irq_bark, bark); ibex_irq_set(&s->pwrmgr_wkup, wkup); ibex_irq_set(&s->pwrmgr_bite, s->wdog_bite); } diff --git a/hw/riscv/ot_earlgrey.c b/hw/riscv/ot_earlgrey.c index 76a77391beaf2..6eecbbd80768f 100644 --- a/hw/riscv/ot_earlgrey.c +++ b/hw/riscv/ot_earlgrey.c @@ -791,6 +791,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_PWRMGR_WKUP, OT_PWRMGR_WAKEUP_AON_TIMER), OT_EG_SOC_SIGNAL(OT_AON_TIMER_BITE, 0, PWRMGR, \ OT_PWRMGR_RST, OT_EG_RESET_AON_TIMER), + OT_EG_SOC_SIGNAL(OT_AON_TIMER_BARK, 0, IBEX_WRAPPER, \ + OT_IBEX_WRAPPER_NMI, OT_IBEX_NMI_WDOG), OT_EG_SOC_GPIO_ALERT(0, 31) ), .prop = IBEXDEVICEPROPDEFS( From 650257af5122f881d938325e2f29fe91e6425249 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 21 Jan 2025 18:48:17 +0000 Subject: [PATCH 10/11] [ot] hw/opentitan: ot_alert: Connect alert phase 0 NMI In escalation phase 0, the alert handler sends an NMI to the CPU, which will interrupt execution so long as the NMI is enabled in Ibex itself. As such, we connect this functionality in the alert handler. See: https://opentitan.org/book/sw/device/silicon_creator/rom/doc/shutdown.html#alert-escalation-phase-actions Signed-off-by: Alex Jones --- hw/opentitan/ot_alert.c | 7 +++++++ hw/riscv/ot_earlgrey.c | 4 +++- include/hw/opentitan/ot_alert.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/hw/opentitan/ot_alert.c b/hw/opentitan/ot_alert.c index 16d2c419f6fd4..dd3f5aeb0c7d4 100644 --- a/hw/opentitan/ot_alert.c +++ b/hw/opentitan/ot_alert.c @@ -220,6 +220,7 @@ struct OtAlertState { MemoryRegion mmio; IbexIRQ *irqs; IbexIRQ *esc_txs; + IbexIRQ nmi_alert; OtAlertScheduler *schedulers; OtAlertRegs regs; /* not ordered by register index */ @@ -571,6 +572,7 @@ static void ot_alert_clear_alert(OtAlertState *s, unsigned nclass) trace_ot_alert_escalation(s->ot_id, ACLASS(nclass), ix, "release"); } ibex_irq_set(esc_tx, 0); + ibex_irq_set(&s->nmi_alert, 0u); } /* * "Software can clear CLASSn_ACCUM_CNT with a write to CLASSA_CLR_SHADOWED" @@ -741,6 +743,10 @@ static void ot_alert_signal_tx(void *opaque, int n, int level) trace_ot_alert_signal_tx(s->ot_id, alert, (bool)level, alert_en); + if (alert_en && level) { + ibex_irq_set(&s->nmi_alert, 1u); + } + if (!alert_en || !level) { /* releasing the alert does not clear it */ return; @@ -1034,6 +1040,7 @@ static void ot_alert_realize(DeviceState *dev, Error **errp) s->esc_txs = g_new0(IbexIRQ, PARAM_N_ESC_SEV); ibex_qdev_init_irqs(OBJECT(dev), s->esc_txs, OT_ALERT_ESCALATE, PARAM_N_ESC_SEV); + ibex_qdev_init_irq(OBJECT(dev), &s->nmi_alert, OT_ALERT_NMI); qdev_init_gpio_in_named(dev, &ot_alert_signal_tx, OT_DEVICE_ALERT, s->n_alerts); diff --git a/hw/riscv/ot_earlgrey.c b/hw/riscv/ot_earlgrey.c index 6eecbbd80768f..e262fd0946d47 100644 --- a/hw/riscv/ot_earlgrey.c +++ b/hw/riscv/ot_earlgrey.c @@ -640,7 +640,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_ESCALATE(0, IBEX_WRAPPER, 0), OT_EG_SOC_GPIO_ESCALATE(1, LC_CTRL, 0), OT_EG_SOC_GPIO_ESCALATE(1, LC_CTRL, 1), - OT_EG_SOC_GPIO_ESCALATE(3, PWRMGR, 0) + OT_EG_SOC_GPIO_ESCALATE(3, PWRMGR, 0), + OT_EG_SOC_SIGNAL(OT_ALERT_NMI, 0, IBEX_WRAPPER, \ + OT_IBEX_WRAPPER_NMI, OT_IBEX_NMI_ALERT) ), .link = IBEXDEVICELINKDEFS( OT_EG_SOC_DEVLINK("edn", EDN0) diff --git a/include/hw/opentitan/ot_alert.h b/include/hw/opentitan/ot_alert.h index 8f93ed4c88194..ed84549375a33 100644 --- a/include/hw/opentitan/ot_alert.h +++ b/include/hw/opentitan/ot_alert.h @@ -37,5 +37,6 @@ OBJECT_DECLARE_TYPE(OtAlertState, OtAlertStateClass, OT_ALERT) #define OT_DEVICE_ALERT TYPE_OT_ALERT "-sig" #define OT_ALERT_ESCALATE TYPE_OT_ALERT "-esc" +#define OT_ALERT_NMI TYPE_OT_ALERT "-nmi" #endif /* HW_OPENTITAN_OT_ALERT_H */ From 7ab767a9802341aa5a8cef33d2ba1cb4ac8cc84d Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 21 Jan 2025 21:33:59 +0000 Subject: [PATCH 11/11] [ot] hw/intc: Only clear pending IRQs at PLIC when claimed See the comment for more details; to allow for proper NMI functionality based on regular IRQ and NMI handling routines, we must ensure that in `sifive_plic_irq_request`, we only clear an IRQs pending status when that IRQ has been claimed. Failure to do so can mean we clear an IRQ at a peripheral as part of an NMI service routine and as such never call into the IRQ handler when the NMI handler returns, as would be expected. This commit updates the SiFive PLIC so that it works as expected. Signed-off-by: Alex Jones --- hw/intc/sifive_plic.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c index 7c0e32d9d41a2..2fd1bd688ea49 100644 --- a/hw/intc/sifive_plic.c +++ b/hw/intc/sifive_plic.c @@ -361,12 +361,29 @@ static void parse_hart_config(SiFivePLICState *plic) static void sifive_plic_irq_request(void *opaque, int irq, int level) { - SiFivePLICState *s = opaque; + SiFivePLICState *plic = opaque; - assert(irq < s->num_sources); + assert(irq < plic->num_sources); - sifive_plic_set_pending(s, irq, level > 0); - sifive_plic_update(s); + /* + * In OpenTitan (or more generally when we have a system with support for + * NMIs), we only want to clear a pending IRQ at the PLIC when it has + * been claimed. Normally this is not a problem - the IRQ will cause + * software to acknowledge the pending IRQ at the peripheral, which will + * propagate to the PLIC, which has already been serviced. But with NMIs, + * we have the case where (a) a peripheral generates an NMI and IRQ, (b) + * the NMI handler disables the IRQ at the peripheral, as part of + * acknowleding the NMI, (c) this would cause the PLIC to de-assert the + * IRQ, but since we haven't claimed it yet we still want it to call our + * ISR handler as normal after the NMI handler exits. So, we should only + * de-assert a pending IRQ when it is claimed. + */ + bool is_claimed = (plic->claimed[irq >> 5] & (1u << (irq & 31))); + bool is_pending = (plic->pending[irq >> 5] & (1u << (irq & 31))); + if (level || (!is_pending || is_claimed)) { + sifive_plic_set_pending(plic, irq, level > 0); + } + sifive_plic_update(plic); } static void sifive_plic_realize(DeviceState *dev, Error **errp)