diff --git a/docs/opentitan/earlgrey.md b/docs/opentitan/earlgrey.md index 946b0c52099db..f3a153c28d6dc 100644 --- a/docs/opentitan/earlgrey.md +++ b/docs/opentitan/earlgrey.md @@ -2,7 +2,7 @@ ## Supported version -EarlGrey 2.5.2-RC0 +[Earlgrey 1.0.0](https://github.com/lowRISC/opentitan/tree/earlgrey_1.0.0) ## Supported features @@ -20,6 +20,9 @@ EarlGrey 2.5.2-RC0 * AON Timer * CSRNG * EDN +* Flash controller + * missing ECCs/ICVs, scrambling functionality and alerts + * no modelling of erase suspend * HMAC * OTBN * missing side-loading @@ -39,8 +42,6 @@ Devices in this group implement subset(s) of the real HW. * Manage clock dividers, groups, hints, software configurable clocks * Propagate clock signals from source (AST, ...) to devices * Hint management and measurement are not implemented -* Flash controller - * read-only features only * OTP controller * read-only features only, ECC is ignored * Entropy Src @@ -53,6 +54,7 @@ Devices in this group implement subset(s) of the real HW. from Power Manager * KMAC * Side loading is not supported + * Masking is not supported * [ROM controller](rom_ctrl.md) * SRAM controller * Initialization and scrambling with dummy key supported @@ -77,10 +79,17 @@ features are implemented. Devices in this group are mostly implemented with a RAM backend or real CSRs but do not implement any useful feature (only allow guest test code to execute as expected). +Some just use generic `UNIMP` devices to define a memory region. +* Analog Sensor Top +* I2C * Key manager +* Pattern Generator * Pinmux -* Sensor +* PWM +* Sensor Control +* System Reset Controller +* USB Device ## Running the virtual machine diff --git a/hw/opentitan/Kconfig b/hw/opentitan/Kconfig index 36b8b3a55482c..756c1281467e7 100644 --- a/hw/opentitan/Kconfig +++ b/hw/opentitan/Kconfig @@ -52,7 +52,11 @@ config OT_DMA config OT_EDN bool -config OT_ENTROPY_SRC +config OT_ENTROPY_SRC_EG + select OT_RANDOM_SRC + bool + +config OT_ENTROPY_SRC_DJ select OT_RANDOM_SRC bool diff --git a/hw/opentitan/meson.build b/hw/opentitan/meson.build index 1c66e4465c6da..247a030c96bca 100644 --- a/hw/opentitan/meson.build +++ b/hw/opentitan/meson.build @@ -18,7 +18,8 @@ system_ss.add(when: 'CONFIG_OT_DEV_PROXY', if_true: files('ot_dev_proxy.c')) system_ss.add(when: 'CONFIG_OT_DM_TL', if_true: files('ot_dm_tl.c')) system_ss.add(when: 'CONFIG_OT_DMA', if_true: [files('ot_dma.c'), libtomcrypt_dep]) system_ss.add(when: 'CONFIG_OT_EDN', if_true: files('ot_edn.c')) -system_ss.add(when: 'CONFIG_OT_ENTROPY_SRC', if_true: [files('ot_entropy_src.c'), libtomcrypt_dep]) +system_ss.add(when: 'CONFIG_OT_ENTROPY_SRC_DJ', if_true: [files('ot_entropy_src_dj.c'), libtomcrypt_dep]) +system_ss.add(when: 'CONFIG_OT_ENTROPY_SRC_EG', if_true: [files('ot_entropy_src_eg.c'), libtomcrypt_dep]) system_ss.add(when: 'CONFIG_OT_FLASH', if_true: files('ot_flash.c')) system_ss.add(when: 'CONFIG_OT_GPIO_DJ', if_true: files('ot_gpio_dj.c')) system_ss.add(when: 'CONFIG_OT_GPIO_EG', if_true: files('ot_gpio_eg.c')) diff --git a/hw/opentitan/ot_clkmgr.c b/hw/opentitan/ot_clkmgr.c index 6a85e8319a70c..b59e5f79e364c 100644 --- a/hw/opentitan/ot_clkmgr.c +++ b/hw/opentitan/ot_clkmgr.c @@ -265,6 +265,7 @@ struct OtClkMgrState { char *cfg_swcg; /* list of software-hintable groups */ char *cfg_hint; + uint8_t version; }; /* @@ -1129,7 +1130,15 @@ static void ot_clkmgr_write(void *opaque, hwaddr addr, uint64_t val64, s->regs[reg] &= val32; break; case R_JITTER_ENABLE: - if (s->regs[R_JITTER_REGWEN]) { + if (s->regs[R_JITTER_REGWEN] || + s->version == OT_CLKMGR_VERSION_EG_1_0_0) { + if (s->version == OT_CLKMGR_VERSION_EG_1_0_0) { + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: JITTER_ENABLE should be protected w/ REGWEN,\n" + "but is allowed due to a known bug in Earlgrey 1.0.0\n", + __func__); + } val32 &= R_JITTER_ENABLE_VAL_MASK; s->regs[reg] = val32; } else { @@ -1265,6 +1274,7 @@ static Property ot_clkmgr_properties[] = { DEFINE_PROP_STRING("groups", OtClkMgrState, cfg_groups), DEFINE_PROP_STRING("swcg", OtClkMgrState, cfg_swcg), DEFINE_PROP_STRING("hint", OtClkMgrState, cfg_hint), + DEFINE_PROP_UINT8("version", OtClkMgrState, version, UINT8_MAX), DEFINE_PROP_END_OF_LIST(), }; @@ -1322,6 +1332,8 @@ static void ot_clkmgr_realize(DeviceState *dev, Error **errp) g_assert(s->clock_src); OBJECT_CHECK(IbexClockSrcIf, s->clock_src, TYPE_IBEX_CLOCK_SRC_IF); + g_assert(s->version < OT_CLKMGR_VERSION_COUNT); + ot_clkmgr_parse_top_clocks(s, &error_fatal); unsigned top_count = g_list_length(s->clocks); qdev_init_gpio_in_named(DEVICE(s), &ot_clkmgr_clock_input, "clock-in", diff --git a/hw/opentitan/ot_entropy_src.c b/hw/opentitan/ot_entropy_src_dj.c similarity index 72% rename from hw/opentitan/ot_entropy_src.c rename to hw/opentitan/ot_entropy_src_dj.c index 0c999d5a0e2f4..fe648321c1d74 100644 --- a/hw/opentitan/ot_entropy_src.c +++ b/hw/opentitan/ot_entropy_src_dj.c @@ -1,5 +1,5 @@ /* - * QEMU OpenTitan Entropy Source device + * QEMU OpenTitan Darjeeling Entropy Source device * * Copyright (c) 2023-2025 Rivos, Inc. * Copyright (c) 2025 lowRISC contributors. @@ -38,7 +38,7 @@ #include "hw/opentitan/ot_alert.h" #include "hw/opentitan/ot_ast_eg.h" #include "hw/opentitan/ot_common.h" -#include "hw/opentitan/ot_entropy_src.h" +#include "hw/opentitan/ot_entropy_src_dj.h" #include "hw/opentitan/ot_fifo32.h" #include "hw/opentitan/ot_otp.h" #include "hw/opentitan/ot_random_src.h" @@ -324,23 +324,24 @@ static const char *REG_NAMES[REGS_COUNT] = { #define ES_FILL_RATE_NS \ ((NANOSECONDS_PER_SECOND * ES_FILL_BITS) / \ ((uint64_t)OT_AST_EG_RANDOM_4BIT_RATE * 4u)) -#define OT_ENTROPY_SRC_FILL_WORD_COUNT (ES_FILL_BITS / (8u * sizeof(uint32_t))) -#define ES_WORD_COUNT (OT_RANDOM_SRC_WORD_COUNT) -#define ES_SWREAD_FIFO_WORD_COUNT ES_WORD_COUNT -#define ES_FINAL_FIFO_WORD_COUNT (ES_WORD_COUNT * ES_FINAL_FIFO_DEPTH) -#define ES_HEXBUF_SIZE ((8U * 2u + 1u) * ES_WORD_COUNT + 4u) +#define OT_ENTROPY_SRC_DJ_FILL_WORD_COUNT \ + (ES_FILL_BITS / (8u * sizeof(uint32_t))) +#define ES_WORD_COUNT (OT_RANDOM_SRC_WORD_COUNT) +#define ES_SWREAD_FIFO_WORD_COUNT ES_WORD_COUNT +#define ES_FINAL_FIFO_WORD_COUNT (ES_WORD_COUNT * ES_FINAL_FIFO_DEPTH) +#define ES_HEXBUF_SIZE ((8U * 2u + 1u) * ES_WORD_COUNT + 4u) /* * see hw/ip/edn/doc/#multiple-edns-in-boot-time-request-mode * reduce initial delay in QEMU since it takes time to manage the entropy */ -#define OT_ENTROPY_SRC_BOOT_DELAY_NS 500000LL /* 500 us */ +#define OT_ENTROPY_SRC_DJ_BOOT_DELAY_NS 500000LL /* 500 us */ /* * default delay to pace the entropy src client (CSRNG) when no entropy is * available. A better implementation would compute the remaining time before * the next available entropy packet. */ -#define OT_ENTROPY_SRC_WAIT_DELAY_NS 2000LL /* 2 us */ +#define OT_ENTROPY_SRC_DJ_WAIT_DELAY_NS 2000LL /* 2 us */ enum { ALERT_RECOVERABLE, @@ -351,30 +352,30 @@ enum { static_assert(ALERT_COUNT == PARAM_NUM_ALERTS, "Invalid alert count"); typedef enum { - ENTROPY_SRC_IDLE, - ENTROPY_SRC_BOOT_HT_RUNNING, - ENTROPY_SRC_BOOT_POST_HT_CHK, - ENTROPY_SRC_BOOT_PHASE_DONE, - ENTROPY_SRC_STARTUP_HT_START, - ENTROPY_SRC_STARTUP_PHASE1, - ENTROPY_SRC_STARTUP_PASS1, - ENTROPY_SRC_STARTUP_FAIL1, - ENTROPY_SRC_CONT_HT_START, - ENTROPY_SRC_CONT_HT_RUNNING, - ENTROPY_SRC_FW_INSERT_START, - ENTROPY_SRC_FW_INSERT_MSG, - ENTROPY_SRC_SHA3_MSGDONE, - ENTROPY_SRC_SHA3_PREP, - ENTROPY_SRC_SHA3_PROCESS, - ENTROPY_SRC_SHA3_VALID, - ENTROPY_SRC_SHA3_DONE, - ENTROPY_SRC_SHA3_QUIESCE, - ENTROPY_SRC_ALERT_STATE, - ENTROPY_SRC_ALERT_HANG, - ENTROPY_SRC_ERROR, -} OtEntropySrcFsmState; - -struct OtEntropySrcState { + ENTROPY_SRC_DJ_IDLE, + ENTROPY_SRC_DJ_BOOT_HT_RUNNING, + ENTROPY_SRC_DJ_BOOT_POST_HT_CHK, + ENTROPY_SRC_DJ_BOOT_PHASE_DONE, + ENTROPY_SRC_DJ_STARTUP_HT_START, + ENTROPY_SRC_DJ_STARTUP_PHASE1, + ENTROPY_SRC_DJ_STARTUP_PASS1, + ENTROPY_SRC_DJ_STARTUP_FAIL1, + ENTROPY_SRC_DJ_CONT_HT_START, + ENTROPY_SRC_DJ_CONT_HT_RUNNING, + ENTROPY_SRC_DJ_FW_INSERT_START, + ENTROPY_SRC_DJ_FW_INSERT_MSG, + ENTROPY_SRC_DJ_SHA3_MSGDONE, + ENTROPY_SRC_DJ_SHA3_PREP, + ENTROPY_SRC_DJ_SHA3_PROCESS, + ENTROPY_SRC_DJ_SHA3_VALID, + ENTROPY_SRC_DJ_SHA3_DONE, + ENTROPY_SRC_DJ_SHA3_QUIESCE, + ENTROPY_SRC_DJ_ALERT_STATE, + ENTROPY_SRC_DJ_ALERT_HANG, + ENTROPY_SRC_DJ_ERROR, +} OtEntropySrcDjFsmState; + +struct OtEntropySrcDjState { SysBusDevice parent_obj; MemoryRegion mmio; @@ -390,7 +391,7 @@ struct OtEntropySrcState { OtFifo32 swread_fifo; OtFifo32 final_fifo; /* output FIFO */ hash_state sha3_state; /* libtomcrypt hash state */ - OtEntropySrcFsmState state; + OtEntropySrcDjFsmState state; unsigned cond_word; /* count of words processed with SHA3 till hash */ unsigned noise_count; /* count of consumed noise words since enabled */ unsigned packet_count; /* count of output packets since enabled */ @@ -400,36 +401,36 @@ struct OtEntropySrcState { OtOTPState *otp_ctrl; }; -struct OtEntropySrcClass { +struct OtEntropySrcDjClass { SysBusDeviceClass parent_class; ResettablePhases parent_phases; }; static const uint16_t OtEDNFsmStateCode[] = { - [ENTROPY_SRC_IDLE] = 0b011110101, - [ENTROPY_SRC_BOOT_HT_RUNNING] = 0b111010010, - [ENTROPY_SRC_BOOT_POST_HT_CHK] = 0b101101110, - [ENTROPY_SRC_BOOT_PHASE_DONE] = 0b010001110, - [ENTROPY_SRC_STARTUP_HT_START] = 0b000101100, - [ENTROPY_SRC_STARTUP_PHASE1] = 0b100000001, - [ENTROPY_SRC_STARTUP_PASS1] = 0b110100101, - [ENTROPY_SRC_STARTUP_FAIL1] = 0b000010111, - [ENTROPY_SRC_CONT_HT_START] = 0b001000000, - [ENTROPY_SRC_CONT_HT_RUNNING] = 0b110100010, - [ENTROPY_SRC_FW_INSERT_START] = 0b011000011, - [ENTROPY_SRC_FW_INSERT_MSG] = 0b001011001, - [ENTROPY_SRC_SHA3_MSGDONE] = 0b100001111, - [ENTROPY_SRC_SHA3_PREP] = 0b011111000, - [ENTROPY_SRC_SHA3_PROCESS] = 0b010111111, - [ENTROPY_SRC_SHA3_VALID] = 0b101110001, - [ENTROPY_SRC_SHA3_DONE] = 0b110011000, - [ENTROPY_SRC_SHA3_QUIESCE] = 0b111001101, - [ENTROPY_SRC_ALERT_STATE] = 0b111111011, - [ENTROPY_SRC_ALERT_HANG] = 0b101011100, - [ENTROPY_SRC_ERROR] = 0b100111101, + [ENTROPY_SRC_DJ_IDLE] = 0b011110101, + [ENTROPY_SRC_DJ_BOOT_HT_RUNNING] = 0b111010010, + [ENTROPY_SRC_DJ_BOOT_POST_HT_CHK] = 0b101101110, + [ENTROPY_SRC_DJ_BOOT_PHASE_DONE] = 0b010001110, + [ENTROPY_SRC_DJ_STARTUP_HT_START] = 0b000101100, + [ENTROPY_SRC_DJ_STARTUP_PHASE1] = 0b100000001, + [ENTROPY_SRC_DJ_STARTUP_PASS1] = 0b110100101, + [ENTROPY_SRC_DJ_STARTUP_FAIL1] = 0b000010111, + [ENTROPY_SRC_DJ_CONT_HT_START] = 0b001000000, + [ENTROPY_SRC_DJ_CONT_HT_RUNNING] = 0b110100010, + [ENTROPY_SRC_DJ_FW_INSERT_START] = 0b011000011, + [ENTROPY_SRC_DJ_FW_INSERT_MSG] = 0b001011001, + [ENTROPY_SRC_DJ_SHA3_MSGDONE] = 0b100001111, + [ENTROPY_SRC_DJ_SHA3_PREP] = 0b011111000, + [ENTROPY_SRC_DJ_SHA3_PROCESS] = 0b010111111, + [ENTROPY_SRC_DJ_SHA3_VALID] = 0b101110001, + [ENTROPY_SRC_DJ_SHA3_DONE] = 0b110011000, + [ENTROPY_SRC_DJ_SHA3_QUIESCE] = 0b111001101, + [ENTROPY_SRC_DJ_ALERT_STATE] = 0b111111011, + [ENTROPY_SRC_DJ_ALERT_HANG] = 0b101011100, + [ENTROPY_SRC_DJ_ERROR] = 0b100111101, }; -#define STATE_NAME_ENTRY(_st_) [ENTROPY_SRC_##_st_] = stringify(_st_) +#define STATE_NAME_ENTRY(_st_) [ENTROPY_SRC_DJ_##_st_] = stringify(_st_) static const char *STATE_NAMES[] = { STATE_NAME_ENTRY(IDLE), STATE_NAME_ENTRY(BOOT_HT_RUNNING), @@ -462,22 +463,22 @@ static const char *STATE_NAMES[] = { #define REG_MB4_IS_FALSE(_s_, _reg_, _fld_) \ (FIELD_EX32((_s_)->regs[R_##_reg_], _reg_, _fld_) == OT_MULTIBITBOOL4_FALSE) -#define xtrace_ot_entropy_src_show_buffer(_msg_, _buf_, _len_) \ - ot_entropy_src_show_buffer(__func__, __LINE__, _msg_, _buf_, _len_) +#define xtrace_ot_entropy_src_dj_show_buffer(_msg_, _buf_, _len_) \ + ot_entropy_src_dj_show_buffer(__func__, __LINE__, _msg_, _buf_, _len_) -static bool ot_entropy_src_is_module_enabled(const OtEntropySrcState *s); -static bool ot_entropy_src_is_fips_enabled(const OtEntropySrcState *s); -static bool ot_entropy_src_is_hw_route(const OtEntropySrcState *s); -static bool ot_entropy_src_is_fips_capable(const OtEntropySrcState *s); -static void ot_entropy_src_update_alerts(OtEntropySrcState *s); -static void ot_entropy_src_update_filler(OtEntropySrcState *s); +static bool ot_entropy_src_dj_is_module_enabled(const OtEntropySrcDjState *s); +static bool ot_entropy_src_dj_is_fips_enabled(const OtEntropySrcDjState *s); +static bool ot_entropy_src_dj_is_hw_route(const OtEntropySrcDjState *s); +static bool ot_entropy_src_dj_is_fips_capable(const OtEntropySrcDjState *s); +static void ot_entropy_src_dj_update_alerts(OtEntropySrcDjState *s); +static void ot_entropy_src_dj_update_filler(OtEntropySrcDjState *s); -static int ot_entropy_src_get_random( +static int ot_entropy_src_dj_get_random( OtRandomSrcIf *dev, uint64_t random[OT_RANDOM_SRC_DWORD_COUNT], bool *fips) { - OtEntropySrcState *s = OT_ENTROPY_SRC(dev); + OtEntropySrcDjState *s = OT_ENTROPY_SRC_DJ(dev); - if (!ot_entropy_src_is_module_enabled(s)) { + if (!ot_entropy_src_dj_is_module_enabled(s)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: entropy_src is down\n", __func__); return -1; } @@ -485,61 +486,61 @@ static int ot_entropy_src_get_random( bool fips_compliant; switch (s->state) { - case ENTROPY_SRC_BOOT_PHASE_DONE: + case ENTROPY_SRC_DJ_BOOT_PHASE_DONE: fips_compliant = false; break; - case ENTROPY_SRC_CONT_HT_RUNNING: - case ENTROPY_SRC_CONT_HT_START: - case ENTROPY_SRC_SHA3_MSGDONE: - case ENTROPY_SRC_SHA3_PREP: - case ENTROPY_SRC_SHA3_PROCESS: - case ENTROPY_SRC_SHA3_VALID: - case ENTROPY_SRC_SHA3_DONE: + case ENTROPY_SRC_DJ_CONT_HT_RUNNING: + case ENTROPY_SRC_DJ_CONT_HT_START: + case ENTROPY_SRC_DJ_SHA3_MSGDONE: + case ENTROPY_SRC_DJ_SHA3_PREP: + case ENTROPY_SRC_DJ_SHA3_PROCESS: + case ENTROPY_SRC_DJ_SHA3_VALID: + case ENTROPY_SRC_DJ_SHA3_DONE: fips_compliant = true; break; - case ENTROPY_SRC_BOOT_HT_RUNNING: - case ENTROPY_SRC_BOOT_POST_HT_CHK: - case ENTROPY_SRC_STARTUP_HT_START: - case ENTROPY_SRC_STARTUP_PHASE1: - case ENTROPY_SRC_STARTUP_PASS1: - case ENTROPY_SRC_STARTUP_FAIL1: { + case ENTROPY_SRC_DJ_BOOT_HT_RUNNING: + case ENTROPY_SRC_DJ_BOOT_POST_HT_CHK: + case ENTROPY_SRC_DJ_STARTUP_HT_START: + case ENTROPY_SRC_DJ_STARTUP_PHASE1: + case ENTROPY_SRC_DJ_STARTUP_PASS1: + case ENTROPY_SRC_DJ_STARTUP_FAIL1: { int64_t wait_ns; if (timer_pending(s->scheduler)) { /* computed delay fits into a 31-bit value */ wait_ns = ((int64_t)timer_expire_time_ns(s->scheduler)) - qemu_clock_get_ns(OT_VIRTUAL_CLOCK); - wait_ns = MAX(wait_ns, OT_ENTROPY_SRC_WAIT_DELAY_NS); + wait_ns = MAX(wait_ns, OT_ENTROPY_SRC_DJ_WAIT_DELAY_NS); } else { - wait_ns = OT_ENTROPY_SRC_WAIT_DELAY_NS; + wait_ns = OT_ENTROPY_SRC_DJ_WAIT_DELAY_NS; } trace_ot_entropy_src_init_ongoing(STATE_NAME(s->state), s->state, (int)wait_ns); /* not ready */ return (int)wait_ns; } - case ENTROPY_SRC_IDLE: + case ENTROPY_SRC_DJ_IDLE: qemu_log_mask(LOG_GUEST_ERROR, "%s: module is not enabled\n", __func__); return -1; - case ENTROPY_SRC_FW_INSERT_START: - case ENTROPY_SRC_FW_INSERT_MSG: - case ENTROPY_SRC_SHA3_QUIESCE: /* this state is never emulated */ - case ENTROPY_SRC_ALERT_STATE: - case ENTROPY_SRC_ALERT_HANG: - case ENTROPY_SRC_ERROR: + case ENTROPY_SRC_DJ_FW_INSERT_START: + case ENTROPY_SRC_DJ_FW_INSERT_MSG: + case ENTROPY_SRC_DJ_SHA3_QUIESCE: /* this state is never emulated */ + case ENTROPY_SRC_DJ_ALERT_STATE: + case ENTROPY_SRC_DJ_ALERT_HANG: + case ENTROPY_SRC_DJ_ERROR: default: qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid state: [%s:%d]\n", __func__, STATE_NAME(s->state), s->state); return -1; } - if (!ot_entropy_src_is_hw_route(s)) { + if (!ot_entropy_src_dj_is_hw_route(s)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: HW route not selected\n", __func__); return -1; } if (ot_fifo32_num_used(&s->final_fifo) < ES_WORD_COUNT) { trace_ot_entropy_src_no_entropy(ot_fifo32_num_used(&s->final_fifo)); - return OT_ENTROPY_SRC_WAIT_DELAY_NS; + return OT_ENTROPY_SRC_DJ_WAIT_DELAY_NS; } uint32_t *randu32 = (uint32_t *)random; @@ -549,20 +550,20 @@ static int ot_entropy_src_get_random( randu32[pos++] = ot_fifo32_pop(&s->final_fifo); } - bool fips_capable = ot_entropy_src_is_fips_capable(s); + bool fips_capable = ot_entropy_src_dj_is_fips_capable(s); /* note: fips compliancy is only simulated here for now */ *fips = fips_compliant && fips_capable; trace_ot_entropy_src_get_random_fips( - STATE_NAME(s->state), ot_entropy_src_is_fips_enabled(s), + STATE_NAME(s->state), ot_entropy_src_dj_is_fips_enabled(s), REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_ROUTE), REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_TYPE), REG_MB4_IS_FALSE(s, CONF, RNG_BIT_ENABLE), fips_capable, fips_compliant, *fips); if (ot_fifo32_num_used(&s->final_fifo) < ES_WORD_COUNT) { - ot_entropy_src_update_filler(s); + ot_entropy_src_dj_update_filler(s); } return 0; @@ -572,7 +573,7 @@ static int ot_entropy_src_get_random( /* Private implementation */ /* -------------------------------------------------------------------------- */ -static void ot_entropy_src_show_buffer( +static void ot_entropy_src_dj_show_buffer( const char *func, int line, const char *msg, const void *buf, unsigned size) { if (trace_event_get_state(TRACE_OT_ENTROPY_SRC_SHOW_BUFFER) && @@ -600,22 +601,22 @@ static void ot_entropy_src_show_buffer( } } -static bool ot_entropy_src_is_module_enabled(const OtEntropySrcState *s) +static bool ot_entropy_src_dj_is_module_enabled(const OtEntropySrcDjState *s) { return REG_MB4_IS_TRUE(s, MODULE_ENABLE, MODULE_ENABLE); } -static bool ot_entropy_src_is_module_disabled(const OtEntropySrcState *s) +static bool ot_entropy_src_dj_is_module_disabled(const OtEntropySrcDjState *s) { return REG_MB4_IS_FALSE(s, MODULE_ENABLE, MODULE_ENABLE); } -static bool ot_entropy_src_is_fips_enabled(const OtEntropySrcState *s) +static bool ot_entropy_src_dj_is_fips_enabled(const OtEntropySrcDjState *s) { return REG_MB4_IS_TRUE(s, CONF, FIPS_ENABLE); } -static void ot_entropy_src_update_irqs(OtEntropySrcState *s) +static void ot_entropy_src_dj_update_irqs(OtEntropySrcDjState *s) { uint32_t levels = s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE]; for (unsigned ix = 0; ix < PARAM_NUM_IRQS; ix++) { @@ -624,47 +625,48 @@ static void ot_entropy_src_update_irqs(OtEntropySrcState *s) } static bool -ot_entropy_src_is_final_fifo_slot_available(const OtEntropySrcState *s) +ot_entropy_src_dj_is_final_fifo_slot_available(const OtEntropySrcDjState *s) { return ot_fifo32_num_free(&s->final_fifo) >= ES_WORD_COUNT; } -static bool ot_entropy_src_is_hw_route(const OtEntropySrcState *s) +static bool ot_entropy_src_dj_is_hw_route(const OtEntropySrcDjState *s) { return REG_MB4_IS_FALSE(s, ENTROPY_CONTROL, ES_ROUTE); } -static bool ot_entropy_src_is_fw_route(const OtEntropySrcState *s) +static bool ot_entropy_src_dj_is_fw_route(const OtEntropySrcDjState *s) { return REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_ROUTE); } -static bool ot_entropy_src_is_bypass_mode(const OtEntropySrcState *s) +static bool ot_entropy_src_dj_is_bypass_mode(const OtEntropySrcDjState *s) { - return !ot_entropy_src_is_fips_enabled(s) || - (ot_entropy_src_is_fw_route(s) && + return !ot_entropy_src_dj_is_fips_enabled(s) || + (ot_entropy_src_dj_is_fw_route(s) && REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_TYPE)); } -static bool ot_entropy_src_is_fw_ov_mode(const OtEntropySrcState *s) +static bool ot_entropy_src_dj_is_fw_ov_mode(const OtEntropySrcDjState *s) { return REG_MB4_IS_TRUE(s, FW_OV_CONTROL, FW_OV_MODE); } -static bool ot_entropy_src_is_fw_ov_entropy_insert(const OtEntropySrcState *s) +static bool +ot_entropy_src_dj_is_fw_ov_entropy_insert(const OtEntropySrcDjState *s) { return REG_MB4_IS_TRUE(s, FW_OV_CONTROL, FW_OV_ENTROPY_INSERT); } -static bool ot_entropy_src_is_fips_capable(const OtEntropySrcState *s) +static bool ot_entropy_src_dj_is_fips_capable(const OtEntropySrcDjState *s) { - return ot_entropy_src_is_fips_enabled(s) && + return ot_entropy_src_dj_is_fips_enabled(s) && !(REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_ROUTE) && REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_TYPE)) && REG_MB4_IS_FALSE(s, CONF, RNG_BIT_ENABLE); } -static unsigned ot_alert_get_alert_fail_count(const OtEntropySrcState *s) +static unsigned ot_alert_get_alert_fail_count(const OtEntropySrcDjState *s) { unsigned count; @@ -686,18 +688,18 @@ static unsigned ot_alert_get_alert_fail_count(const OtEntropySrcState *s) return count; } -static void ot_entropy_src_change_state_line( - OtEntropySrcState *s, OtEntropySrcFsmState state, int line) +static void ot_entropy_src_dj_change_state_line( + OtEntropySrcDjState *s, OtEntropySrcDjFsmState state, int line) { - OtEntropySrcFsmState old_state = s->state; + OtEntropySrcDjFsmState old_state = s->state; switch (s->state) { - case ENTROPY_SRC_ALERT_STATE: - s->state = ENTROPY_SRC_ALERT_HANG; + case ENTROPY_SRC_DJ_ALERT_STATE: + s->state = ENTROPY_SRC_DJ_ALERT_HANG; break; - case ENTROPY_SRC_ALERT_HANG: - if ((state == ENTROPY_SRC_IDLE) && - ot_entropy_src_is_module_disabled(s)) { + case ENTROPY_SRC_DJ_ALERT_HANG: + if ((state == ENTROPY_SRC_DJ_IDLE) && + ot_entropy_src_dj_is_module_disabled(s)) { s->state = state; } break; @@ -712,16 +714,16 @@ static void ot_entropy_src_change_state_line( s->state); } - if (s->state == ENTROPY_SRC_ERROR) { + if (s->state == ENTROPY_SRC_DJ_ERROR) { s->regs[R_ERR_CODE] |= R_ERR_CODE_ES_MAIN_SM_ERR_MASK; - ot_entropy_src_update_alerts(s); + ot_entropy_src_dj_update_alerts(s); } } -#define ot_entropy_src_change_state(_s_, _st_) \ - ot_entropy_src_change_state_line(_s_, _st_, __LINE__) +#define ot_entropy_src_dj_change_state(_s_, _st_) \ + ot_entropy_src_dj_change_state_line(_s_, _st_, __LINE__) -static void ot_entropy_src_update_alerts(OtEntropySrcState *s) +static void ot_entropy_src_dj_update_alerts(OtEntropySrcDjState *s) { unsigned alert_threshold = FIELD_EX32(s->regs[R_ALERT_THRESHOLD], ALERT_THRESHOLD, ALERT_THRESHOLD); @@ -742,8 +744,8 @@ static void ot_entropy_src_update_alerts(OtEntropySrcState *s) } } -static bool ot_entropy_src_check_multibitboot( - OtEntropySrcState *s, uint8_t mbbool, uint32_t alert_bit) +static bool ot_entropy_src_dj_check_multibitboot( + OtEntropySrcDjState *s, uint8_t mbbool, uint32_t alert_bit) { switch (mbbool) { case OT_MULTIBITBOOL4_TRUE: @@ -754,24 +756,24 @@ static bool ot_entropy_src_check_multibitboot( } s->regs[R_RECOV_ALERT_STS] |= 1u << alert_bit; - ot_entropy_src_update_alerts(s); + ot_entropy_src_dj_update_alerts(s); return false; } -static bool ot_entropy_src_can_consume_entropy(const OtEntropySrcState *s) +static bool ot_entropy_src_dj_can_consume_entropy(const OtEntropySrcDjState *s) { - return ot_entropy_src_is_module_enabled(s) && - !(ot_entropy_src_is_fw_ov_entropy_insert(s) && - !ot_entropy_src_is_fw_ov_mode(s)); + return ot_entropy_src_dj_is_module_enabled(s) && + !(ot_entropy_src_dj_is_fw_ov_entropy_insert(s) && + !ot_entropy_src_dj_is_fw_ov_mode(s)); } -static void ot_entropy_src_update_filler(OtEntropySrcState *s) +static void ot_entropy_src_dj_update_filler(OtEntropySrcDjState *s) { - /* fill granule is OT_ENTROPY_SRC_FILL_WORD_COUNT bits */ + /* fill granule is OT_ENTROPY_SRC_DJ_FILL_WORD_COUNT bits */ bool input = - ot_fifo32_num_free(&s->input_fifo) >= OT_ENTROPY_SRC_FILL_WORD_COUNT; + ot_fifo32_num_free(&s->input_fifo) >= OT_ENTROPY_SRC_DJ_FILL_WORD_COUNT; bool output = ot_fifo32_num_free(&s->final_fifo) >= ES_WORD_COUNT; - bool process = ot_entropy_src_can_consume_entropy(s); + bool process = ot_entropy_src_dj_can_consume_entropy(s); bool accept_entropy = input && output && process; trace_ot_entropy_src_update_filler(input, output, process, accept_entropy); @@ -795,13 +797,14 @@ static void ot_entropy_src_update_filler(OtEntropySrcState *s) } } -static bool ot_entropy_src_can_condition_entropy(const OtEntropySrcState *s) +static bool +ot_entropy_src_dj_can_condition_entropy(const OtEntropySrcDjState *s) { if (!ot_fifo32_is_full(&s->precon_fifo)) { /* room in preconditioner packer */ return true; } - if (ot_entropy_src_is_final_fifo_slot_available(s)) { + if (ot_entropy_src_dj_is_final_fifo_slot_available(s)) { /* room in output FIFO */ return true; } @@ -809,13 +812,13 @@ static bool ot_entropy_src_can_condition_entropy(const OtEntropySrcState *s) return false; } -static bool ot_entropy_src_can_bypass_entropy(const OtEntropySrcState *s) +static bool ot_entropy_src_dj_can_bypass_entropy(const OtEntropySrcDjState *s) { if (!ot_fifo32_is_full(&s->bypass_fifo)) { /* room in bypass packer */ return true; } - if (ot_entropy_src_is_final_fifo_slot_available(s)) { + if (ot_entropy_src_dj_is_final_fifo_slot_available(s)) { /* room in output FIFO */ return true; } @@ -823,13 +826,13 @@ static bool ot_entropy_src_can_bypass_entropy(const OtEntropySrcState *s) return false; } -static bool -ot_entropy_src_push_entropy_to_conditioner(OtEntropySrcState *s, uint32_t word) +static bool ot_entropy_src_dj_push_entropy_to_conditioner( + OtEntropySrcDjState *s, uint32_t word) { int res; if (s->cond_word == 0) { res = sha3_384_init(&s->sha3_state); - ot_entropy_src_change_state(s, ENTROPY_SRC_SHA3_PREP); + ot_entropy_src_dj_change_state(s, ENTROPY_SRC_DJ_SHA3_PREP); g_assert(res == CRYPT_OK); } @@ -841,13 +844,14 @@ ot_entropy_src_push_entropy_to_conditioner(OtEntropySrcState *s, uint32_t word) return false; } - ot_entropy_src_change_state(s, ENTROPY_SRC_SHA3_PROCESS); + ot_entropy_src_dj_change_state(s, ENTROPY_SRC_DJ_SHA3_PROCESS); uint32_t size; const uint32_t *buf; buf = ot_fifo32_peek_buf(&s->precon_fifo, s->precon_fifo.num, &size); g_assert(size == s->precon_fifo.num); - xtrace_ot_entropy_src_show_buffer("sha3 in", buf, size * sizeof(uint32_t)); + xtrace_ot_entropy_src_dj_show_buffer("sha3 in", buf, + size * sizeof(uint32_t)); res = sha3_process(&s->sha3_state, (const uint8_t *)buf, size * sizeof(uint32_t)); g_assert(res == CRYPT_OK); @@ -857,13 +861,13 @@ ot_entropy_src_push_entropy_to_conditioner(OtEntropySrcState *s, uint32_t word) return true; } -static bool ot_entropy_src_can_hash(const OtEntropySrcState *s) +static bool ot_entropy_src_dj_can_hash(const OtEntropySrcDjState *s) { return ot_fifo32_is_empty(&s->precon_fifo) && (s->cond_word >= (2048 / (8u * sizeof(uint32_t)))); } -static void ot_entropy_src_perform_hash(OtEntropySrcState *s) +static void ot_entropy_src_dj_perform_hash(OtEntropySrcDjState *s) { uint32_t hash[OT_RANDOM_SRC_WORD_COUNT]; int res; @@ -871,11 +875,11 @@ static void ot_entropy_src_perform_hash(OtEntropySrcState *s) g_assert(res == CRYPT_OK); s->cond_word = 0; - xtrace_ot_entropy_src_show_buffer("sha3 md", hash, - OT_RANDOM_SRC_WORD_COUNT * - sizeof(uint32_t)); + xtrace_ot_entropy_src_dj_show_buffer("sha3 md", hash, + OT_RANDOM_SRC_WORD_COUNT * + sizeof(uint32_t)); - ot_entropy_src_change_state(s, ENTROPY_SRC_SHA3_MSGDONE); + ot_entropy_src_dj_change_state(s, ENTROPY_SRC_DJ_SHA3_MSGDONE); for (unsigned ix = 0; ix < OT_RANDOM_SRC_WORD_COUNT; ix++) { g_assert(!ot_fifo32_is_full(&s->final_fifo)); @@ -883,20 +887,20 @@ static void ot_entropy_src_perform_hash(OtEntropySrcState *s) } s->packet_count += 1u; - ot_entropy_src_change_state(s, REG_MB4_IS_TRUE(s, FW_OV_SHA3_START, - FW_OV_INSERT_START) ? - ENTROPY_SRC_IDLE : - ENTROPY_SRC_CONT_HT_START); + ot_entropy_src_dj_change_state(s, REG_MB4_IS_TRUE(s, FW_OV_SHA3_START, + FW_OV_INSERT_START) ? + ENTROPY_SRC_DJ_IDLE : + ENTROPY_SRC_DJ_CONT_HT_START); } static bool -ot_entropy_src_push_bypass_entropy(OtEntropySrcState *s, uint32_t word) +ot_entropy_src_dj_push_bypass_entropy(OtEntropySrcDjState *s, uint32_t word) { g_assert(!ot_fifo32_is_full(&s->bypass_fifo)); ot_fifo32_push(&s->bypass_fifo, word); if (!ot_fifo32_is_full(&s->bypass_fifo)) { - /* need a whole OT_ENTROPY_SRC_PACKET_SIZE_BITS packet to move on */ + /* need a whole OT_ENTROPY_SRC_DJ_PACKET_SIZE_BITS packet to move on */ return false; } @@ -913,7 +917,7 @@ ot_entropy_src_push_bypass_entropy(OtEntropySrcState *s, uint32_t word) return true; } -static void ot_entropy_src_update_fw_route(OtEntropySrcState *s) +static void ot_entropy_src_dj_update_fw_route(OtEntropySrcDjState *s) { if (ot_fifo32_num_used(&s->final_fifo) >= ES_WORD_COUNT) { trace_ot_entropy_src_info("FW ROUTE"); @@ -925,21 +929,22 @@ static void ot_entropy_src_update_fw_route(OtEntropySrcState *s) } s->regs[R_INTR_STATE] |= INTR_ES_ENTROPY_VALID_MASK; trace_ot_entropy_src_available(STATE_NAME(s->state), s->state); - ot_entropy_src_update_filler(s); + ot_entropy_src_dj_update_filler(s); } } } -static bool ot_entropy_src_consume_entropy(OtEntropySrcState *s, uint32_t word) +static bool +ot_entropy_src_dj_consume_entropy(OtEntropySrcDjState *s, uint32_t word) { - bool fill_obs_fifo = ot_entropy_src_is_fw_ov_mode(s); - bool hw_path = !ot_entropy_src_is_fw_ov_entropy_insert(s); - bool bypass = ot_entropy_src_is_bypass_mode(s); + bool fill_obs_fifo = ot_entropy_src_dj_is_fw_ov_mode(s); + bool hw_path = !ot_entropy_src_dj_is_fw_ov_entropy_insert(s); + bool bypass = ot_entropy_src_dj_is_bypass_mode(s); if (hw_path) { /* check that HW accept data */ - hw_path = bypass ? ot_entropy_src_can_bypass_entropy(s) : - ot_entropy_src_can_condition_entropy(s); + hw_path = bypass ? ot_entropy_src_dj_can_bypass_entropy(s) : + ot_entropy_src_dj_can_condition_entropy(s); } if (!(fill_obs_fifo || hw_path)) { @@ -981,34 +986,34 @@ static bool ot_entropy_src_consume_entropy(OtEntropySrcState *s, uint32_t word) } if (hw_path) { - if (ot_entropy_src_is_bypass_mode(s)) { - ot_entropy_src_push_bypass_entropy(s, word); + if (ot_entropy_src_dj_is_bypass_mode(s)) { + ot_entropy_src_dj_push_bypass_entropy(s, word); } else { - if (ot_entropy_src_push_entropy_to_conditioner(s, word)) { - if (ot_entropy_src_can_hash(s)) { + if (ot_entropy_src_dj_push_entropy_to_conditioner(s, word)) { + if (ot_entropy_src_dj_can_hash(s)) { trace_ot_entropy_src_info("can hash"); - ot_entropy_src_perform_hash(s); + ot_entropy_src_dj_perform_hash(s); } } } } - if (ot_entropy_src_is_fw_route(s)) { - ot_entropy_src_update_fw_route(s); + if (ot_entropy_src_dj_is_fw_route(s)) { + ot_entropy_src_dj_update_fw_route(s); } return true; } -static bool ot_entropy_src_fill_noise(OtEntropySrcState *s) +static bool ot_entropy_src_dj_fill_noise(OtEntropySrcDjState *s) { unsigned count = ot_fifo32_num_free(&s->input_fifo); - if (count < OT_ENTROPY_SRC_FILL_WORD_COUNT) { + if (count < OT_ENTROPY_SRC_DJ_FILL_WORD_COUNT) { /* no room left, should be resheduled */ return false; } - uint32_t buffer[OT_ENTROPY_SRC_FILL_WORD_COUNT]; + uint32_t buffer[OT_ENTROPY_SRC_DJ_FILL_WORD_COUNT]; /* synchronous read */ ot_ast_eg_getrandom(buffer, sizeof(buffer)); @@ -1022,42 +1027,43 @@ static bool ot_entropy_src_fill_noise(OtEntropySrcState *s) for (unsigned ix = 0; ix < ES_WORD_COUNT && !ot_fifo32_is_empty(&s->input_fifo); ix++) { - if (!ot_entropy_src_consume_entropy(s, ot_fifo32_pop(&s->input_fifo))) { + if (!ot_entropy_src_dj_consume_entropy(s, + ot_fifo32_pop(&s->input_fifo))) { break; } } - ot_entropy_src_update_irqs(s); + ot_entropy_src_dj_update_irqs(s); return true; } -static void ot_entropy_src_noise_refill(void *opaque) +static void ot_entropy_src_dj_noise_refill(void *opaque) { - OtEntropySrcState *s = opaque; + OtEntropySrcDjState *s = opaque; - if (!ot_entropy_src_fill_noise(s)) { + if (!ot_entropy_src_dj_fill_noise(s)) { trace_ot_entropy_src_info("FIFO already filled up"); return; } switch (s->state) { - case ENTROPY_SRC_BOOT_HT_RUNNING: + case ENTROPY_SRC_DJ_BOOT_HT_RUNNING: if (s->packet_count > 0) { - ot_entropy_src_change_state(s, ENTROPY_SRC_BOOT_PHASE_DONE); + ot_entropy_src_dj_change_state(s, ENTROPY_SRC_DJ_BOOT_PHASE_DONE); } break; - case ENTROPY_SRC_STARTUP_HT_START: - ot_entropy_src_change_state(s, ENTROPY_SRC_CONT_HT_RUNNING); + case ENTROPY_SRC_DJ_STARTUP_HT_START: + ot_entropy_src_dj_change_state(s, ENTROPY_SRC_DJ_CONT_HT_RUNNING); break; - case ENTROPY_SRC_CONT_HT_RUNNING: - case ENTROPY_SRC_CONT_HT_START: - case ENTROPY_SRC_BOOT_PHASE_DONE: - case ENTROPY_SRC_SHA3_PREP: - case ENTROPY_SRC_SHA3_VALID: - case ENTROPY_SRC_SHA3_PROCESS: - case ENTROPY_SRC_SHA3_DONE: - case ENTROPY_SRC_SHA3_MSGDONE: + case ENTROPY_SRC_DJ_CONT_HT_RUNNING: + case ENTROPY_SRC_DJ_CONT_HT_START: + case ENTROPY_SRC_DJ_BOOT_PHASE_DONE: + case ENTROPY_SRC_DJ_SHA3_PREP: + case ENTROPY_SRC_DJ_SHA3_VALID: + case ENTROPY_SRC_DJ_SHA3_PROCESS: + case ENTROPY_SRC_DJ_SHA3_DONE: + case ENTROPY_SRC_DJ_SHA3_MSGDONE: break; default: trace_ot_entropy_src_error("unexpected state", STATE_NAME(s->state), @@ -1065,51 +1071,51 @@ static void ot_entropy_src_noise_refill(void *opaque) break; } - ot_entropy_src_update_filler(s); + ot_entropy_src_dj_update_filler(s); } -static void ot_entropy_src_scheduler(void *opaque) +static void ot_entropy_src_dj_scheduler(void *opaque) { - OtEntropySrcState *s = opaque; + OtEntropySrcDjState *s = opaque; switch (s->state) { - case ENTROPY_SRC_BOOT_HT_RUNNING: - case ENTROPY_SRC_BOOT_PHASE_DONE: - case ENTROPY_SRC_STARTUP_HT_START: - case ENTROPY_SRC_CONT_HT_START: - case ENTROPY_SRC_CONT_HT_RUNNING: - case ENTROPY_SRC_SHA3_PREP: - case ENTROPY_SRC_SHA3_VALID: - case ENTROPY_SRC_SHA3_PROCESS: - case ENTROPY_SRC_SHA3_DONE: - case ENTROPY_SRC_SHA3_MSGDONE: - ot_entropy_src_noise_refill(s); + case ENTROPY_SRC_DJ_BOOT_HT_RUNNING: + case ENTROPY_SRC_DJ_BOOT_PHASE_DONE: + case ENTROPY_SRC_DJ_STARTUP_HT_START: + case ENTROPY_SRC_DJ_CONT_HT_START: + case ENTROPY_SRC_DJ_CONT_HT_RUNNING: + case ENTROPY_SRC_DJ_SHA3_PREP: + case ENTROPY_SRC_DJ_SHA3_VALID: + case ENTROPY_SRC_DJ_SHA3_PROCESS: + case ENTROPY_SRC_DJ_SHA3_DONE: + case ENTROPY_SRC_DJ_SHA3_MSGDONE: + ot_entropy_src_dj_noise_refill(s); break; - case ENTROPY_SRC_IDLE: + case ENTROPY_SRC_DJ_IDLE: break; - case ENTROPY_SRC_BOOT_POST_HT_CHK: - case ENTROPY_SRC_STARTUP_PHASE1: - case ENTROPY_SRC_STARTUP_PASS1: - case ENTROPY_SRC_STARTUP_FAIL1: - case ENTROPY_SRC_FW_INSERT_START: - case ENTROPY_SRC_FW_INSERT_MSG: - case ENTROPY_SRC_SHA3_QUIESCE: - case ENTROPY_SRC_ALERT_STATE: - case ENTROPY_SRC_ALERT_HANG: - case ENTROPY_SRC_ERROR: + case ENTROPY_SRC_DJ_BOOT_POST_HT_CHK: + case ENTROPY_SRC_DJ_STARTUP_PHASE1: + case ENTROPY_SRC_DJ_STARTUP_PASS1: + case ENTROPY_SRC_DJ_STARTUP_FAIL1: + case ENTROPY_SRC_DJ_FW_INSERT_START: + case ENTROPY_SRC_DJ_FW_INSERT_MSG: + case ENTROPY_SRC_DJ_SHA3_QUIESCE: + case ENTROPY_SRC_DJ_ALERT_STATE: + case ENTROPY_SRC_DJ_ALERT_HANG: + case ENTROPY_SRC_DJ_ERROR: default: qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid state: [%s:%d]\n", __func__, STATE_NAME(s->state), s->state); } - ot_entropy_src_update_alerts(s); - ot_entropy_src_update_irqs(s); + ot_entropy_src_dj_update_alerts(s); + ot_entropy_src_dj_update_irqs(s); } static uint64_t -ot_entropy_src_regs_read(void *opaque, hwaddr addr, unsigned size) +ot_entropy_src_dj_regs_read(void *opaque, hwaddr addr, unsigned size) { - OtEntropySrcState *s = opaque; + OtEntropySrcDjState *s = opaque; (void)size; uint32_t val32; @@ -1168,28 +1174,29 @@ ot_entropy_src_regs_read(void *opaque, hwaddr addr, unsigned size) val32 = FIELD_DP32(0, DEBUG_STATUS, ENTROPY_FIFO_DEPTH, ot_fifo32_num_used(&s->final_fifo)); val32 = FIELD_DP32(val32, DEBUG_STATUS, MAIN_SM_IDLE, - (uint32_t)(s->state == ENTROPY_SRC_IDLE)); - val32 = FIELD_DP32(val32, DEBUG_STATUS, MAIN_SM_BOOT_DONE, - (uint32_t)(s->state == ENTROPY_SRC_BOOT_PHASE_DONE)); + (uint32_t)(s->state == ENTROPY_SRC_DJ_IDLE)); + val32 = + FIELD_DP32(val32, DEBUG_STATUS, MAIN_SM_BOOT_DONE, + (uint32_t)(s->state == ENTROPY_SRC_DJ_BOOT_PHASE_DONE)); break; case R_MAIN_SM_STATE: if (s->state < ARRAY_SIZE(OtEDNFsmStateCode)) { val32 = OtEDNFsmStateCode[s->state]; } else { - val32 = OtEDNFsmStateCode[ENTROPY_SRC_ERROR]; + val32 = OtEDNFsmStateCode[ENTROPY_SRC_DJ_ERROR]; } break; case R_REGWEN: val32 = (uint32_t)(s->regs[R_SW_REGUPD] == R_SW_REGUPD_UPD_MASK && - ot_entropy_src_is_module_disabled(s)); + ot_entropy_src_dj_is_module_disabled(s)); break; case R_ALERT_SUMMARY_FAIL_COUNTS: val32 = (uint32_t)ot_alert_get_alert_fail_count(s); break; case R_ENTROPY_DATA: - if (ot_entropy_src_is_module_enabled(s) && + if (ot_entropy_src_dj_is_module_enabled(s) && REG_MB4_IS_TRUE(s, CONF, ENTROPY_DATA_REG_ENABLE) && - ot_entropy_src_is_fw_route(s)) { + ot_entropy_src_dj_is_fw_route(s)) { if (!ot_fifo32_is_empty(&s->swread_fifo)) { val32 = ot_fifo32_pop(&s->swread_fifo); } else { @@ -1205,12 +1212,12 @@ ot_entropy_src_regs_read(void *opaque, hwaddr addr, unsigned size) break; case R_FW_OV_WR_FIFO_FULL: { bool can_write; - if (ot_entropy_src_is_fw_ov_mode(s) && - ot_entropy_src_is_fw_ov_entropy_insert(s)) { - if (ot_entropy_src_is_bypass_mode(s)) { - can_write = ot_entropy_src_can_bypass_entropy(s); + if (ot_entropy_src_dj_is_fw_ov_mode(s) && + ot_entropy_src_dj_is_fw_ov_entropy_insert(s)) { + if (ot_entropy_src_dj_is_bypass_mode(s)) { + can_write = ot_entropy_src_dj_can_bypass_entropy(s); } else { - can_write = ot_entropy_src_can_condition_entropy(s); + can_write = ot_entropy_src_dj_can_condition_entropy(s); } } else { can_write = false; @@ -1218,7 +1225,7 @@ ot_entropy_src_regs_read(void *opaque, hwaddr addr, unsigned size) val32 = can_write ? 0u : R_FW_OV_WR_FIFO_FULL_VAL_MASK; } break; case R_FW_OV_RD_DATA: - if (ot_entropy_src_is_fw_ov_mode(s)) { + if (ot_entropy_src_dj_is_fw_ov_mode(s)) { if (!ot_fifo32_is_empty(&s->observe_fifo)) { val32 = ot_fifo32_pop(&s->observe_fifo); } else { @@ -1258,20 +1265,20 @@ ot_entropy_src_regs_read(void *opaque, hwaddr addr, unsigned size) #define CHECK_MULTIBOOT(_s_, _r_, _b_) \ do { \ - if (!ot_entropy_src_check_multibitboot((_s_), \ - FIELD_EX32(s->regs[R_##_r_], \ - _r_, _b_), \ - ALERT_STATUS_BIT(_b_))) { \ + if (!ot_entropy_src_dj_check_multibitboot((_s_), \ + FIELD_EX32(s->regs[R_##_r_], \ + _r_, _b_), \ + ALERT_STATUS_BIT(_b_))) { \ qemu_log_mask(LOG_GUEST_ERROR, \ "%s: invalid multiboot value 0x%1x\n", __func__, \ FIELD_EX32(s->regs[R_##_r_], _r_, _b_)); \ } \ } while (0) -static void ot_entropy_src_regs_write(void *opaque, hwaddr addr, uint64_t val64, - unsigned size) +static void ot_entropy_src_dj_regs_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned size) { - OtEntropySrcState *s = opaque; + OtEntropySrcDjState *s = opaque; (void)size; uint32_t val32 = (uint32_t)val64; @@ -1291,22 +1298,22 @@ static void ot_entropy_src_regs_write(void *opaque, hwaddr addr, uint64_t val64, if (!ot_fifo32_is_empty(&s->observe_fifo)) { s->regs[R_INTR_STATE] |= INTR_ES_OBSERVE_FIFO_READY_MASK; } - ot_entropy_src_update_irqs(s); + ot_entropy_src_dj_update_irqs(s); break; case R_INTR_ENABLE: val32 &= INTR_MASK; s->regs[reg] = val32; - ot_entropy_src_update_irqs(s); + ot_entropy_src_dj_update_irqs(s); break; case R_INTR_TEST: val32 &= INTR_MASK; s->regs[R_INTR_STATE] |= val32; - ot_entropy_src_update_irqs(s); + ot_entropy_src_dj_update_irqs(s); break; case R_ALERT_TEST: val32 &= ALERT_TEST_MASK; s->regs[reg] = val32; - ot_entropy_src_update_alerts(s); + ot_entropy_src_dj_update_alerts(s); break; case R_ME_REGWEN: val32 &= R_ME_REGWEN_EN_MASK; @@ -1322,24 +1329,26 @@ static void ot_entropy_src_regs_write(void *opaque, hwaddr addr, uint64_t val64, val32 &= R_MODULE_ENABLE_MODULE_ENABLE_MASK; s->regs[reg] = val32; CHECK_MULTIBOOT(s, MODULE_ENABLE, MODULE_ENABLE); - if (ot_entropy_src_is_module_disabled(s)) { + if (ot_entropy_src_dj_is_module_disabled(s)) { /* reset takes care of cancelling the scheduler timer */ resettable_reset(OBJECT(s), RESET_TYPE_COLD); break; } - if ((old ^ s->regs[reg]) && ot_entropy_src_is_module_enabled(s)) { - if (ot_entropy_src_is_fips_enabled(s)) { + if ((old ^ s->regs[reg]) && + ot_entropy_src_dj_is_module_enabled(s)) { + if (ot_entropy_src_dj_is_fips_enabled(s)) { /* start up phase */ - ot_entropy_src_change_state(s, - ENTROPY_SRC_STARTUP_HT_START); + ot_entropy_src_dj_change_state( + s, ENTROPY_SRC_DJ_STARTUP_HT_START); } else { /* boot phase */ - ot_entropy_src_change_state(s, ENTROPY_SRC_BOOT_HT_RUNNING); + ot_entropy_src_dj_change_state( + s, ENTROPY_SRC_DJ_BOOT_HT_RUNNING); } uint64_t now = qemu_clock_get_ns(OT_VIRTUAL_CLOCK); timer_mod(s->scheduler, (int64_t)(now + - (uint64_t)OT_ENTROPY_SRC_BOOT_DELAY_NS)); + (uint64_t)OT_ENTROPY_SRC_DJ_BOOT_DELAY_NS)); } break; } @@ -1379,7 +1388,7 @@ static void ot_entropy_src_regs_write(void *opaque, hwaddr addr, uint64_t val64, case R_EXTHT_LO_THRESHOLDS: if (s->regs[R_REGWEN]) { s->regs[reg] = val32; - ot_entropy_src_update_alerts(s); + ot_entropy_src_dj_update_alerts(s); } break; case R_ALERT_THRESHOLD: @@ -1390,7 +1399,7 @@ static void ot_entropy_src_regs_write(void *opaque, hwaddr addr, uint64_t val64, } else { s->regs[reg] = val32; } - ot_entropy_src_update_alerts(s); + ot_entropy_src_dj_update_alerts(s); } break; case R_FW_OV_CONTROL: @@ -1399,11 +1408,11 @@ static void ot_entropy_src_regs_write(void *opaque, hwaddr addr, uint64_t val64, s->regs[reg] = val32; CHECK_MULTIBOOT(s, FW_OV_CONTROL, FW_OV_MODE); CHECK_MULTIBOOT(s, FW_OV_CONTROL, FW_OV_ENTROPY_INSERT); - s->obs_fifo_en = ot_entropy_src_is_fw_ov_mode(s); + s->obs_fifo_en = ot_entropy_src_dj_is_fw_ov_mode(s); } break; case R_FW_OV_SHA3_START: - if (!ot_entropy_src_is_module_enabled(s)) { + if (!ot_entropy_src_dj_is_module_enabled(s)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: module not enabled\n", __func__); break; @@ -1412,29 +1421,29 @@ static void ot_entropy_src_regs_write(void *opaque, hwaddr addr, uint64_t val64, s->regs[reg] = val32; CHECK_MULTIBOOT(s, FW_OV_SHA3_START, FW_OV_INSERT_START); if (REG_MB4_IS_TRUE(s, FW_OV_SHA3_START, FW_OV_INSERT_START)) { - OtEntropySrcFsmState new_state; - new_state = ot_entropy_src_is_bypass_mode(s) ? - ENTROPY_SRC_IDLE : - ENTROPY_SRC_FW_INSERT_START; - ot_entropy_src_change_state(s, new_state); + OtEntropySrcDjFsmState new_state; + new_state = ot_entropy_src_dj_is_bypass_mode(s) ? + ENTROPY_SRC_DJ_IDLE : + ENTROPY_SRC_DJ_FW_INSERT_START; + ot_entropy_src_dj_change_state(s, new_state); } else { /* default to false */ - if (s->state == ENTROPY_SRC_SHA3_PROCESS) { + if (s->state == ENTROPY_SRC_DJ_SHA3_PROCESS) { /* handle SHA3 processing */ if (ot_fifo32_is_empty(&s->precon_fifo)) { - ot_entropy_src_perform_hash(s); - if (ot_entropy_src_is_fw_route(s)) { - ot_entropy_src_update_fw_route(s); + ot_entropy_src_dj_perform_hash(s); + if (ot_entropy_src_dj_is_fw_route(s)) { + ot_entropy_src_dj_update_fw_route(s); } } else { qemu_log_mask(LOG_GUEST_ERROR, "%s: need 1 more word\n", __func__); } } else { - OtEntropySrcFsmState new_state; - new_state = ot_entropy_src_is_bypass_mode(s) ? - ENTROPY_SRC_BOOT_HT_RUNNING : - ENTROPY_SRC_STARTUP_HT_START; - ot_entropy_src_change_state(s, new_state); + OtEntropySrcDjFsmState new_state; + new_state = ot_entropy_src_dj_is_bypass_mode(s) ? + ENTROPY_SRC_DJ_BOOT_HT_RUNNING : + ENTROPY_SRC_DJ_STARTUP_HT_START; + ot_entropy_src_dj_change_state(s, new_state); } } break; @@ -1443,23 +1452,23 @@ static void ot_entropy_src_regs_write(void *opaque, hwaddr addr, uint64_t val64, s->regs[reg] &= val32; /* RW0C */ break; case R_FW_OV_WR_DATA: - if (!ot_entropy_src_is_module_enabled(s)) { + if (!ot_entropy_src_dj_is_module_enabled(s)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: module not enabled\n", __func__); break; } - if (ot_entropy_src_is_fw_ov_mode(s) && - ot_entropy_src_is_fw_ov_entropy_insert(s)) { + if (ot_entropy_src_dj_is_fw_ov_mode(s) && + ot_entropy_src_dj_is_fw_ov_entropy_insert(s)) { bool can_write; - if (ot_entropy_src_is_bypass_mode(s)) { - can_write = ot_entropy_src_can_bypass_entropy(s); + if (ot_entropy_src_dj_is_bypass_mode(s)) { + can_write = ot_entropy_src_dj_can_bypass_entropy(s); if (can_write) { - ot_entropy_src_push_bypass_entropy(s, val32); + ot_entropy_src_dj_push_bypass_entropy(s, val32); } } else { - can_write = ot_entropy_src_can_condition_entropy(s); + can_write = ot_entropy_src_dj_can_condition_entropy(s); if (can_write) { - ot_entropy_src_push_entropy_to_conditioner(s, val32); + ot_entropy_src_dj_push_entropy_to_conditioner(s, val32); } } if (!can_write) { @@ -1475,7 +1484,7 @@ static void ot_entropy_src_regs_write(void *opaque, hwaddr addr, uint64_t val64, if (s->regs[R_REGWEN]) { val32 &= R_OBSERVE_FIFO_THRESH_VAL_MASK; s->regs[reg] = val32; - ot_entropy_src_update_irqs(s); + ot_entropy_src_dj_update_irqs(s); } break; case R_RECOV_ALERT_STS: @@ -1485,8 +1494,8 @@ static void ot_entropy_src_regs_write(void *opaque, hwaddr addr, uint64_t val64, case R_ERR_CODE_TEST: val32 &= R_ERR_CODE_TEST_VAL_MASK; s->regs[R_ERR_CODE_TEST] = val32; - ot_entropy_src_update_irqs(s); - ot_entropy_src_update_alerts(s); + ot_entropy_src_dj_update_irqs(s); + ot_entropy_src_dj_update_alerts(s); break; case R_REGWEN: case R_ENTROPY_DATA: @@ -1528,26 +1537,26 @@ static void ot_entropy_src_regs_write(void *opaque, hwaddr addr, uint64_t val64, } }; -static Property ot_entropy_src_properties[] = { - DEFINE_PROP_LINK("ast", OtEntropySrcState, ast, TYPE_OT_AST_EG, +static Property ot_entropy_src_dj_properties[] = { + DEFINE_PROP_LINK("ast", OtEntropySrcDjState, ast, TYPE_OT_AST_EG, OtASTEgState *), - DEFINE_PROP_LINK("otp_ctrl", OtEntropySrcState, otp_ctrl, TYPE_OT_OTP, + DEFINE_PROP_LINK("otp_ctrl", OtEntropySrcDjState, otp_ctrl, TYPE_OT_OTP, OtOTPState *), DEFINE_PROP_END_OF_LIST(), }; -static const MemoryRegionOps ot_entropy_src_regs_ops = { - .read = &ot_entropy_src_regs_read, - .write = &ot_entropy_src_regs_write, +static const MemoryRegionOps ot_entropy_src_dj_regs_ops = { + .read = &ot_entropy_src_dj_regs_read, + .write = &ot_entropy_src_dj_regs_write, .endianness = DEVICE_NATIVE_ENDIAN, .impl.min_access_size = 4u, .impl.max_access_size = 4u, }; -static void ot_entropy_src_reset_enter(Object *obj, ResetType type) +static void ot_entropy_src_dj_reset_enter(Object *obj, ResetType type) { - OtEntropySrcClass *c = OT_ENTROPY_SRC_GET_CLASS(obj); - OtEntropySrcState *s = OT_ENTROPY_SRC(obj); + OtEntropySrcDjClass *c = OT_ENTROPY_SRC_DJ_GET_CLASS(obj); + OtEntropySrcDjState *s = OT_ENTROPY_SRC_DJ(obj); trace_ot_entropy_src_reset(); @@ -1593,7 +1602,7 @@ static void ot_entropy_src_reset_enter(Object *obj, ResetType type) s->packet_count = 0u; s->obs_fifo_en = false; - ot_entropy_src_update_irqs(s); + ot_entropy_src_dj_update_irqs(s); for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { ibex_irq_set(&s->alerts[ix], 0); } @@ -1602,25 +1611,25 @@ static void ot_entropy_src_reset_enter(Object *obj, ResetType type) const OtOTPEntropyCfg *entropy_cfg = oc->get_entropy_cfg(s->otp_ctrl); g_assert(entropy_cfg); - ot_entropy_src_change_state(s, ENTROPY_SRC_IDLE); + ot_entropy_src_dj_change_state(s, ENTROPY_SRC_DJ_IDLE); } -static void ot_entropy_src_realize(DeviceState *dev, Error **errp) +static void ot_entropy_src_dj_realize(DeviceState *dev, Error **errp) { (void)errp; - OtEntropySrcState *s = OT_ENTROPY_SRC(dev); + OtEntropySrcDjState *s = OT_ENTROPY_SRC_DJ(dev); g_assert(s->ast); g_assert(s->otp_ctrl); } -static void ot_entropy_src_init(Object *obj) +static void ot_entropy_src_dj_init(Object *obj) { - OtEntropySrcState *s = OT_ENTROPY_SRC(obj); + OtEntropySrcDjState *s = OT_ENTROPY_SRC_DJ(obj); - memory_region_init_io(&s->mmio, obj, &ot_entropy_src_regs_ops, s, - TYPE_OT_ENTROPY_SRC, REGS_SIZE); + memory_region_init_io(&s->mmio, obj, &ot_entropy_src_dj_regs_ops, s, + TYPE_OT_ENTROPY_SRC_DJ, REGS_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); s->regs = g_new0(uint32_t, REGS_COUNT); @@ -1631,41 +1640,42 @@ static void ot_entropy_src_init(Object *obj) ibex_qdev_init_irq(obj, &s->alerts[ix], OT_DEVICE_ALERT); } - ot_fifo32_create(&s->input_fifo, OT_ENTROPY_SRC_FILL_WORD_COUNT * 2u); + ot_fifo32_create(&s->input_fifo, OT_ENTROPY_SRC_DJ_FILL_WORD_COUNT * 2u); ot_fifo32_create(&s->precon_fifo, sizeof(uint64_t) / sizeof(uint32_t)); ot_fifo32_create(&s->bypass_fifo, ES_WORD_COUNT); ot_fifo32_create(&s->observe_fifo, PARAM_OBSERVE_FIFO_DEPTH); ot_fifo32_create(&s->swread_fifo, ES_SWREAD_FIFO_WORD_COUNT); ot_fifo32_create(&s->final_fifo, ES_FINAL_FIFO_WORD_COUNT); - s->scheduler = timer_new_ns(OT_VIRTUAL_CLOCK, &ot_entropy_src_scheduler, s); + s->scheduler = + timer_new_ns(OT_VIRTUAL_CLOCK, &ot_entropy_src_dj_scheduler, s); } -static void ot_entropy_src_class_init(ObjectClass *klass, void *data) +static void ot_entropy_src_dj_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); (void)data; - dc->realize = &ot_entropy_src_realize; - device_class_set_props(dc, ot_entropy_src_properties); + dc->realize = &ot_entropy_src_dj_realize; + device_class_set_props(dc, ot_entropy_src_dj_properties); set_bit(DEVICE_CATEGORY_MISC, dc->categories); ResettableClass *rc = RESETTABLE_CLASS(klass); - OtEntropySrcClass *ec = OT_ENTROPY_SRC_CLASS(klass); - resettable_class_set_parent_phases(rc, &ot_entropy_src_reset_enter, NULL, + OtEntropySrcDjClass *ec = OT_ENTROPY_SRC_DJ_CLASS(klass); + resettable_class_set_parent_phases(rc, &ot_entropy_src_dj_reset_enter, NULL, NULL, &ec->parent_phases); OtRandomSrcIfClass *rdc = OT_RANDOM_SRC_IF_CLASS(klass); - rdc->get_random_values = &ot_entropy_src_get_random; + rdc->get_random_values = &ot_entropy_src_dj_get_random; } -static const TypeInfo ot_entropy_src_info = { - .name = TYPE_OT_ENTROPY_SRC, +static const TypeInfo ot_entropy_src_dj_info = { + .name = TYPE_OT_ENTROPY_SRC_DJ, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(OtEntropySrcState), - .instance_init = &ot_entropy_src_init, - .class_size = sizeof(OtEntropySrcClass), - .class_init = &ot_entropy_src_class_init, + .instance_size = sizeof(OtEntropySrcDjState), + .instance_init = &ot_entropy_src_dj_init, + .class_size = sizeof(OtEntropySrcDjClass), + .class_init = &ot_entropy_src_dj_class_init, .interfaces = (InterfaceInfo[]){ { TYPE_OT_RANDOM_SRC_IF }, @@ -1673,9 +1683,9 @@ static const TypeInfo ot_entropy_src_info = { }, }; -static void ot_entropy_src_register_types(void) +static void ot_entropy_src_dj_register_types(void) { - type_register_static(&ot_entropy_src_info); + type_register_static(&ot_entropy_src_dj_info); } -type_init(ot_entropy_src_register_types); +type_init(ot_entropy_src_dj_register_types); diff --git a/hw/opentitan/ot_entropy_src_eg.c b/hw/opentitan/ot_entropy_src_eg.c new file mode 100644 index 0000000000000..5722ea8782e29 --- /dev/null +++ b/hw/opentitan/ot_entropy_src_eg.c @@ -0,0 +1,1699 @@ +/* + * QEMU OpenTitan Earlgrey 1.0.0 Entropy Source device + * + * Copyright (c) 2023-2025 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. + * + * Author(s): + * Emmanuel Blot + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Notes: + * - missing correct handling of ALERT_FAIL_COUNTS, currently never incremented. + * - missing some error handling? ES_MAIN_SM_ERR is the only error that can be + * triggered. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/timer.h" +#include "qemu/typedefs.h" +#include "hw/opentitan/ot_alert.h" +#include "hw/opentitan/ot_ast_eg.h" +#include "hw/opentitan/ot_common.h" +#include "hw/opentitan/ot_entropy_src_eg.h" +#include "hw/opentitan/ot_fifo32.h" +#include "hw/opentitan/ot_otp.h" +#include "hw/opentitan/ot_random_src.h" +#include "hw/qdev-properties.h" +#include "hw/registerfields.h" +#include "hw/riscv/ibex_common.h" +#include "hw/riscv/ibex_irq.h" +#include "hw/sysbus.h" +#include "tomcrypt.h" +#include "trace.h" + + +#define PARAM_NUM_IRQS 4u +#define PARAM_NUM_ALERTS 2u +#define PARAM_OBSERVE_FIFO_DEPTH 64u /* 2048 bits */ + +/* clang-format off */ +REG32(INTR_STATE, 0x0u) + SHARED_FIELD(INTR_ES_ENTROPY_VALID, 0u, 1u) + SHARED_FIELD(INTR_ES_HEALTH_TEST_FAILED, 1u, 1u) + SHARED_FIELD(INTR_ES_OBSERVE_FIFO_READY, 2u, 1u) + SHARED_FIELD(INTR_ES_FATAL_ERR, 3u, 1u) +REG32(INTR_ENABLE, 0x4u) +REG32(INTR_TEST, 0x8u) +REG32(ALERT_TEST, 0xcu) + FIELD(ALERT_TEST, RECOV_ALERT, 0u, 1u) + FIELD(ALERT_TEST, FATAL_ALERT, 1u, 1u) +REG32(ME_REGWEN, 0x10u) + FIELD(ME_REGWEN, EN, 0u, 1u) +REG32(SW_REGUPD, 0x14u) + FIELD(SW_REGUPD, UPD, 0u, 1u) +REG32(REGWEN, 0x18u) + FIELD(REGWEN, EN, 0u, 1u) +REG32(REV, 0x1cu) + FIELD(REV, ABI_REVISION, 0u, 8u) + FIELD(REV, HW_REVISION, 8u, 8u) + FIELD(REV, CHIP_TYPE, 16u, 8u) +REG32(MODULE_ENABLE, 0x20u) + FIELD(MODULE_ENABLE, MODULE_ENABLE, 0u, 4u) +REG32(CONF, 0x24u) + FIELD(CONF, FIPS_ENABLE, 0u, 4u) + FIELD(CONF, FIPS_FLAG, 4u, 4u) + FIELD(CONF, RNG_FIPS, 8u, 4u) + FIELD(CONF, RNG_BIT_ENABLE, 12u, 4u) + FIELD(CONF, RNG_BIT_SEL, 16u, 2u) + FIELD(CONF, THRESHOLD_SCOPE, 18u, 4u) + FIELD(CONF, ENTROPY_DATA_REG_ENABLE, 22u, 4u) +REG32(ENTROPY_CONTROL, 0x28u) + FIELD(ENTROPY_CONTROL, ES_ROUTE, 0u, 4u) + FIELD(ENTROPY_CONTROL, ES_TYPE, 4u, 4u) +REG32(ENTROPY_DATA, 0x2cu) +REG32(HEALTH_TEST_WINDOWS, 0x30u) + FIELD(HEALTH_TEST_WINDOWS, FIPS_WINDOW, 0u, 16u) + FIELD(HEALTH_TEST_WINDOWS, BYPASS_WINDOW, 16u, 16u) +REG32(REPCNT_THRESHOLDS, 0x34u) + SHARED_FIELD(THRESHOLDS_FIPS, 0u, 16u) + SHARED_FIELD(THRESHOLDS_BYPASS, 16u, 16u) +REG32(REPCNTS_THRESHOLDS, 0x38u) +REG32(ADAPTP_HI_THRESHOLDS, 0x3cu) +REG32(ADAPTP_LO_THRESHOLDS, 0x40u) +REG32(BUCKET_THRESHOLDS, 0x44u) +REG32(MARKOV_HI_THRESHOLDS, 0x48u) +REG32(MARKOV_LO_THRESHOLDS, 0x4cu) +REG32(EXTHT_HI_THRESHOLDS, 0x50u) +REG32(EXTHT_LO_THRESHOLDS, 0x54u) +REG32(REPCNT_HI_WATERMARKS, 0x58u) + SHARED_FIELD(WATERMARK_FIPS, 0u, 16u) + SHARED_FIELD(WATERMARK_BYPASS, 16u, 16u) +REG32(REPCNTS_HI_WATERMARKS, 0x5cu) +REG32(ADAPTP_HI_WATERMARKS, 0x60u) +REG32(ADAPTP_LO_WATERMARKS, 0x64u) +REG32(EXTHT_HI_WATERMARKS, 0x68u) +REG32(EXTHT_LO_WATERMARKS, 0x6cu) +REG32(BUCKET_HI_WATERMARKS, 0x70u) +REG32(MARKOV_HI_WATERMARKS, 0x74u) +REG32(MARKOV_LO_WATERMARKS, 0x78u) +REG32(REPCNT_TOTAL_FAILS, 0x7cu) +REG32(REPCNTS_TOTAL_FAILS, 0x80u) +REG32(ADAPTP_HI_TOTAL_FAILS, 0x84u) +REG32(ADAPTP_LO_TOTAL_FAILS, 0x88u) +REG32(BUCKET_TOTAL_FAILS, 0x8cu) +REG32(MARKOV_HI_TOTAL_FAILS, 0x90u) +REG32(MARKOV_LO_TOTAL_FAILS, 0x94u) +REG32(EXTHT_HI_TOTAL_FAILS, 0x98u) +REG32(EXTHT_LO_TOTAL_FAILS, 0x9cu) +REG32(ALERT_THRESHOLD, 0xa0u) + FIELD(ALERT_THRESHOLD, ALERT_THRESHOLD, 0u, 16u) + FIELD(ALERT_THRESHOLD, ALERT_THRESHOLD_INV, 16u, 16u) +REG32(ALERT_SUMMARY_FAIL_COUNTS, 0xa4u) + FIELD(ALERT_SUMMARY_FAIL_COUNTS, ANY_FAIL_COUNT, 0u, 16u) +REG32(ALERT_FAIL_COUNTS, 0xa8u) + FIELD(ALERT_FAIL_COUNTS, REPCNT_FAIL_COUNT, 4u, 4u) + FIELD(ALERT_FAIL_COUNTS, ADAPTP_HI_FAIL_COUNT, 8u, 4u) + FIELD(ALERT_FAIL_COUNTS, ADAPTP_LO_FAIL_COUNT, 12u, 4u) + FIELD(ALERT_FAIL_COUNTS, BUCKET_FAIL_COUNT, 16u, 4u) + FIELD(ALERT_FAIL_COUNTS, MARKOV_HI_FAIL_COUNT, 20u, 4u) + FIELD(ALERT_FAIL_COUNTS, MARKOV_LO_FAIL_COUNT, 24u, 4u) + FIELD(ALERT_FAIL_COUNTS, REPCNTS_FAIL_COUNT, 28u, 4u) +REG32(EXTHT_FAIL_COUNTS, 0xacu) + FIELD(EXTHT_FAIL_COUNTS, EXTHT_HI_FAIL_COUNT, 0u, 4u) + FIELD(EXTHT_FAIL_COUNTS, EXTHT_LO_FAIL_COUNT, 4u, 4u) +REG32(FW_OV_CONTROL, 0xb0u) + FIELD(FW_OV_CONTROL, FW_OV_MODE, 0u, 4u) + FIELD(FW_OV_CONTROL, FW_OV_ENTROPY_INSERT, 4u, 4u) +REG32(FW_OV_SHA3_START, 0xb4u) + FIELD(FW_OV_SHA3_START, FW_OV_INSERT_START, 0u, 4u) +REG32(FW_OV_WR_FIFO_FULL, 0xb8u) + FIELD(FW_OV_WR_FIFO_FULL, VAL, 0u, 1u) +REG32(FW_OV_RD_FIFO_OVERFLOW, 0xbcu) + FIELD(FW_OV_RD_FIFO_OVERFLOW, VAL, 0u, 1u) +REG32(FW_OV_RD_DATA, 0xc0u) +REG32(FW_OV_WR_DATA, 0xc4u) +REG32(OBSERVE_FIFO_THRESH, 0xc8u) + FIELD(OBSERVE_FIFO_THRESH, VAL, 0u, 6u) +REG32(OBSERVE_FIFO_DEPTH, 0xccu) + FIELD(OBSERVE_FIFO_DEPTH, VAL, 0u, 6u) +REG32(DEBUG_STATUS, 0xd0u) + FIELD(DEBUG_STATUS, ENTROPY_FIFO_DEPTH, 0u, 2u) + FIELD(DEBUG_STATUS, SHA3_FSM, 3u, 3u) + FIELD(DEBUG_STATUS, SHA3_BLOCK_PR, 6u, 1u) + FIELD(DEBUG_STATUS, SHA3_SQUEEZING, 7u, 1u) + FIELD(DEBUG_STATUS, SHA3_ABSORBED, 8u, 1u) + FIELD(DEBUG_STATUS, SHA3_ERR, 9u, 1u) + FIELD(DEBUG_STATUS, MAIN_SM_IDLE, 16u, 1u) + FIELD(DEBUG_STATUS, MAIN_SM_BOOT_DONE, 17u, 1u) +REG32(RECOV_ALERT_STS, 0xd4u) + FIELD(RECOV_ALERT_STS, FIPS_ENABLE_FIELD_ALERT, 0u, 1u) + FIELD(RECOV_ALERT_STS, ENTROPY_DATA_REG_ENABLE_FIELD_ALERT, 1u, 1u) + FIELD(RECOV_ALERT_STS, MODULE_ENABLE_FIELD_ALERT, 2u, 1u) + FIELD(RECOV_ALERT_STS, THRESHOLD_SCOPE_FIELD_ALERT, 3u, 1u) + FIELD(RECOV_ALERT_STS, RNG_BIT_ENABLE_FIELD_ALERT, 5u, 1u) + FIELD(RECOV_ALERT_STS, FW_OV_INSERT_START_FIELD_ALERT, 7u, 1u) + FIELD(RECOV_ALERT_STS, FW_OV_MODE_FIELD_ALERT, 8u, 1u) + FIELD(RECOV_ALERT_STS, FW_OV_ENTROPY_INSERT_FIELD_ALERT, 9u, 1u) + FIELD(RECOV_ALERT_STS, ES_ROUTE_FIELD_ALERT, 10u, 1u) + FIELD(RECOV_ALERT_STS, ES_TYPE_FIELD_ALERT, 11u, 1u) + FIELD(RECOV_ALERT_STS, ES_MAIN_SM_ALERT, 12u, 1u) + FIELD(RECOV_ALERT_STS, ES_BUS_CMP_ALERT, 13u, 1u) + FIELD(RECOV_ALERT_STS, ES_THRESH_CFG_ALERT, 14u, 1u) + FIELD(RECOV_ALERT_STS, ES_FW_OV_WR_ALERT, 15u, 1u) + FIELD(RECOV_ALERT_STS, ES_FW_OV_DISABLE_ALERT, 16u, 1u) + FIELD(RECOV_ALERT_STS, FIPS_FLAG_FIELD_ALERT, 17u, 1u) + FIELD(RECOV_ALERT_STS, RNG_FIPS_FIELD_ALERT, 18u, 1u) + FIELD(RECOV_ALERT_STS, POSTHT_ENTROPY_DROP_ALERT, 31u, 1u) +REG32(ERR_CODE, 0xd8u) + FIELD(ERR_CODE, SFIFO_ESRNG_ERR, 0u, 1u) + FIELD(ERR_CODE, SFIFO_DISTR_ERR, 1u, 1u) + FIELD(ERR_CODE, SFIFO_OBSERVE_ERR, 2u, 1u) + FIELD(ERR_CODE, SFIFO_ESFINAL_ERR, 3u, 1u) + FIELD(ERR_CODE, ES_ACK_SM_ERR, 20u, 1u) + FIELD(ERR_CODE, ES_MAIN_SM_ERR, 21u, 1u) + FIELD(ERR_CODE, ES_CNTR_ERR, 22u, 1u) + FIELD(ERR_CODE, SHA3_STATE_ERR, 23u, 1u) + FIELD(ERR_CODE, SHA3_RST_STORAGE_ERR, 24u, 1u) + FIELD(ERR_CODE, FIFO_WRITE_ERR, 28u, 1u) + FIELD(ERR_CODE, FIFO_READ_ERR, 29u, 1u) + FIELD(ERR_CODE, FIFO_STATE_ERR, 30u, 1u) +REG32(ERR_CODE_TEST, 0xdcu) + FIELD(ERR_CODE_TEST, VAL, 0u, 5u) +REG32(MAIN_SM_STATE, 0xe0u) + FIELD(MAIN_SM_STATE, VAL, 0u, 9u) +/* clang-format on */ + +#define R32_OFF(_r_) ((_r_) / sizeof(uint32_t)) + +#define R_LAST_REG (R_MAIN_SM_STATE) +#define REGS_COUNT (R_LAST_REG + 1u) +#define REGS_SIZE (REGS_COUNT * sizeof(uint32_t)) +#define REG_NAME(_reg_) \ + ((((_reg_) <= REGS_COUNT) && REG_NAMES[_reg_]) ? REG_NAMES[_reg_] : "?") + +#define INTR_MASK \ + (INTR_ES_ENTROPY_VALID_MASK | INTR_ES_HEALTH_TEST_FAILED_MASK | \ + INTR_ES_OBSERVE_FIFO_READY_MASK | INTR_ES_FATAL_ERR_MASK) +#define ALERT_TEST_MASK \ + (R_ALERT_TEST_RECOV_ALERT_MASK | R_ALERT_TEST_FATAL_ALERT_MASK) +#define CONF_MASK \ + (R_CONF_FIPS_ENABLE_MASK | R_CONF_FIPS_FLAG_MASK | R_CONF_RNG_FIPS_MASK | \ + R_CONF_RNG_BIT_ENABLE_MASK | R_CONF_RNG_BIT_SEL_MASK | \ + R_CONF_THRESHOLD_SCOPE_MASK | R_CONF_ENTROPY_DATA_REG_ENABLE_MASK) +#define ENTROPY_CONTROL_MASK \ + (R_ENTROPY_CONTROL_ES_ROUTE_MASK | R_ENTROPY_CONTROL_ES_TYPE_MASK) +#define FW_OV_CONTROL_MASK \ + (R_FW_OV_CONTROL_FW_OV_MODE_MASK | \ + R_FW_OV_CONTROL_FW_OV_ENTROPY_INSERT_MASK) +#define RECOV_ALERT_STS_MASK \ + (R_RECOV_ALERT_STS_FIPS_ENABLE_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_ENTROPY_DATA_REG_ENABLE_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_MODULE_ENABLE_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_THRESHOLD_SCOPE_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_RNG_BIT_ENABLE_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_FW_OV_INSERT_START_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_FW_OV_MODE_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_FW_OV_ENTROPY_INSERT_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_ES_ROUTE_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_ES_TYPE_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_ES_MAIN_SM_ALERT_MASK | \ + R_RECOV_ALERT_STS_ES_BUS_CMP_ALERT_MASK | \ + R_RECOV_ALERT_STS_ES_THRESH_CFG_ALERT_MASK | \ + R_RECOV_ALERT_STS_ES_FW_OV_WR_ALERT_MASK | \ + R_RECOV_ALERT_STS_ES_FW_OV_DISABLE_ALERT_MASK | \ + R_RECOV_ALERT_STS_FIPS_FLAG_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_RNG_FIPS_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_POSTHT_ENTROPY_DROP_ALERT_MASK) +#define ERR_CODE_MASK \ + (R_ERR_CODE_SFIFO_ESRNG_ERR_MASK | R_ERR_CODE_SFIFO_DISTR_ERR_MASK | \ + R_ERR_CODE_SFIFO_OBSERVE_ERR_MASK | R_ERR_CODE_SFIFO_ESFINAL_ERR_MASK | \ + R_ERR_CODE_ES_ACK_SM_ERR_MASK | R_ERR_CODE_ES_MAIN_SM_ERR_MASK | \ + R_ERR_CODE_ES_CNTR_ERR_MASK | R_ERR_CODE_SHA3_STATE_ERR_MASK | \ + R_ERR_CODE_SHA3_RST_STORAGE_ERR_MASK | R_ERR_CODE_FIFO_WRITE_ERR_MASK | \ + R_ERR_CODE_FIFO_READ_ERR_MASK | R_ERR_CODE_FIFO_STATE_ERR_MASK) +#define ERR_CODE_FATAL_ERROR_MASK \ + (R_ERR_CODE_ES_ACK_SM_ERR_MASK | R_ERR_CODE_ES_MAIN_SM_ERR_MASK | \ + R_ERR_CODE_ES_CNTR_ERR_MASK | R_ERR_CODE_SHA3_STATE_ERR_MASK | \ + R_ERR_CODE_SHA3_RST_STORAGE_ERR_MASK) + +#define ALERT_STATUS_BIT(_x_) R_RECOV_ALERT_STS_##_x_##_FIELD_ALERT_SHIFT + +#define REG_NAME_ENTRY(_reg_) [R_##_reg_] = stringify(_reg_) +static const char *REG_NAMES[REGS_COUNT] = { + REG_NAME_ENTRY(INTR_STATE), + REG_NAME_ENTRY(INTR_ENABLE), + REG_NAME_ENTRY(INTR_TEST), + REG_NAME_ENTRY(ALERT_TEST), + REG_NAME_ENTRY(ME_REGWEN), + REG_NAME_ENTRY(SW_REGUPD), + REG_NAME_ENTRY(REGWEN), + REG_NAME_ENTRY(REV), + REG_NAME_ENTRY(MODULE_ENABLE), + REG_NAME_ENTRY(CONF), + REG_NAME_ENTRY(ENTROPY_CONTROL), + REG_NAME_ENTRY(ENTROPY_DATA), + REG_NAME_ENTRY(HEALTH_TEST_WINDOWS), + REG_NAME_ENTRY(REPCNT_THRESHOLDS), + REG_NAME_ENTRY(REPCNTS_THRESHOLDS), + REG_NAME_ENTRY(ADAPTP_HI_THRESHOLDS), + REG_NAME_ENTRY(ADAPTP_LO_THRESHOLDS), + REG_NAME_ENTRY(BUCKET_THRESHOLDS), + REG_NAME_ENTRY(MARKOV_HI_THRESHOLDS), + REG_NAME_ENTRY(MARKOV_LO_THRESHOLDS), + REG_NAME_ENTRY(EXTHT_HI_THRESHOLDS), + REG_NAME_ENTRY(EXTHT_LO_THRESHOLDS), + REG_NAME_ENTRY(REPCNT_HI_WATERMARKS), + REG_NAME_ENTRY(REPCNTS_HI_WATERMARKS), + REG_NAME_ENTRY(ADAPTP_HI_WATERMARKS), + REG_NAME_ENTRY(ADAPTP_LO_WATERMARKS), + REG_NAME_ENTRY(EXTHT_HI_WATERMARKS), + REG_NAME_ENTRY(EXTHT_LO_WATERMARKS), + REG_NAME_ENTRY(BUCKET_HI_WATERMARKS), + REG_NAME_ENTRY(MARKOV_HI_WATERMARKS), + REG_NAME_ENTRY(MARKOV_LO_WATERMARKS), + REG_NAME_ENTRY(REPCNT_TOTAL_FAILS), + REG_NAME_ENTRY(REPCNTS_TOTAL_FAILS), + REG_NAME_ENTRY(ADAPTP_HI_TOTAL_FAILS), + REG_NAME_ENTRY(ADAPTP_LO_TOTAL_FAILS), + REG_NAME_ENTRY(BUCKET_TOTAL_FAILS), + REG_NAME_ENTRY(MARKOV_HI_TOTAL_FAILS), + REG_NAME_ENTRY(MARKOV_LO_TOTAL_FAILS), + REG_NAME_ENTRY(EXTHT_HI_TOTAL_FAILS), + REG_NAME_ENTRY(EXTHT_LO_TOTAL_FAILS), + REG_NAME_ENTRY(ALERT_THRESHOLD), + REG_NAME_ENTRY(ALERT_SUMMARY_FAIL_COUNTS), + REG_NAME_ENTRY(ALERT_FAIL_COUNTS), + REG_NAME_ENTRY(EXTHT_FAIL_COUNTS), + REG_NAME_ENTRY(FW_OV_CONTROL), + REG_NAME_ENTRY(FW_OV_SHA3_START), + REG_NAME_ENTRY(FW_OV_WR_FIFO_FULL), + REG_NAME_ENTRY(FW_OV_RD_FIFO_OVERFLOW), + REG_NAME_ENTRY(FW_OV_RD_DATA), + REG_NAME_ENTRY(FW_OV_WR_DATA), + REG_NAME_ENTRY(OBSERVE_FIFO_THRESH), + REG_NAME_ENTRY(OBSERVE_FIFO_DEPTH), + REG_NAME_ENTRY(DEBUG_STATUS), + REG_NAME_ENTRY(RECOV_ALERT_STS), + REG_NAME_ENTRY(ERR_CODE), + REG_NAME_ENTRY(ERR_CODE_TEST), + REG_NAME_ENTRY(MAIN_SM_STATE), +}; +#undef REG_NAME_ENTRY + +/** + * Use a 128-bit incoming packet size (HW uses 4-bit packet) in order to limit + * feed rate to ~0.7 ms max. 128-bit packet can be divided down to 32-bit + * FIFO packets. They are assembled into either 384-bit or 2048-bit packets. + */ +#define ES_FILL_BITS 128u +#define ES_FINAL_FIFO_DEPTH 4u +#define ES_FILL_RATE_NS \ + ((NANOSECONDS_PER_SECOND * ES_FILL_BITS) / \ + ((uint64_t)OT_AST_EG_RANDOM_4BIT_RATE * 4u)) +#define OT_ENTROPY_SRC_EG_FILL_WORD_COUNT \ + (ES_FILL_BITS / (8u * sizeof(uint32_t))) +#define ES_WORD_COUNT (OT_RANDOM_SRC_WORD_COUNT) +#define ES_SWREAD_FIFO_WORD_COUNT ES_WORD_COUNT +#define ES_FINAL_FIFO_WORD_COUNT (ES_WORD_COUNT * ES_FINAL_FIFO_DEPTH) +#define ES_HEXBUF_SIZE ((8U * 2u + 1u) * ES_WORD_COUNT + 4u) + +/* + * see hw/ip/edn/doc/#multiple-edns-in-boot-time-request-mode + * reduce initial delay in QEMU since it takes time to manage the entropy + */ +#define OT_ENTROPY_SRC_EG_BOOT_DELAY_NS 500000LL /* 500 us */ +/* + * default delay to pace the entropy src client (CSRNG) when no entropy is + * available. A better implementation would compute the remaining time before + * the next available entropy packet. + */ +#define OT_ENTROPY_SRC_EG_WAIT_DELAY_NS 2000LL /* 2 us */ + +enum { + ALERT_RECOVERABLE, + ALERT_FATAL, + ALERT_COUNT, +}; + +static_assert(ALERT_COUNT == PARAM_NUM_ALERTS, "Invalid alert count"); + +typedef enum { + ENTROPY_SRC_EG_IDLE, + ENTROPY_SRC_EG_BOOT_HT_RUNNING, + ENTROPY_SRC_EG_BOOT_POST_HT_CHK, + ENTROPY_SRC_EG_BOOT_PHASE_DONE, + ENTROPY_SRC_EG_STARTUP_HT_START, + ENTROPY_SRC_EG_STARTUP_PHASE1, + ENTROPY_SRC_EG_STARTUP_PASS1, + ENTROPY_SRC_EG_STARTUP_FAIL1, + ENTROPY_SRC_EG_CONT_HT_START, + ENTROPY_SRC_EG_CONT_HT_RUNNING, + ENTROPY_SRC_EG_FW_INSERT_START, + ENTROPY_SRC_EG_FW_INSERT_MSG, + ENTROPY_SRC_EG_SHA3_MSGDONE, + ENTROPY_SRC_EG_SHA3_PREP, + ENTROPY_SRC_EG_SHA3_PROCESS, + ENTROPY_SRC_EG_SHA3_VALID, + ENTROPY_SRC_EG_SHA3_DONE, + ENTROPY_SRC_EG_SHA3_QUIESCE, + ENTROPY_SRC_EG_ALERT_STATE, + ENTROPY_SRC_EG_ALERT_HANG, + ENTROPY_SRC_EG_ERROR, +} OtEntropySrcEgFsmState; + +struct OtEntropySrcEgState { + SysBusDevice parent_obj; + + MemoryRegion mmio; + IbexIRQ irqs[PARAM_NUM_IRQS]; + IbexIRQ alerts[PARAM_NUM_ALERTS]; + QEMUTimer *scheduler; + + uint32_t *regs; + OtFifo32 input_fifo; /* not in real HW, used to reduce feed rate */ + OtFifo32 precon_fifo; /* 32-to-64 SHA3 input packer */ + OtFifo32 bypass_fifo; /* 32-to-384 packer */ + OtFifo32 observe_fifo; + OtFifo32 swread_fifo; + OtFifo32 final_fifo; /* output FIFO */ + hash_state sha3_state; /* libtomcrypt hash state */ + OtEntropySrcEgFsmState state; + unsigned cond_word; /* count of words processed with SHA3 till hash */ + unsigned noise_count; /* count of consumed noise words since enabled */ + unsigned packet_count; /* count of output packets since enabled */ + bool obs_fifo_en; /* observe FIFO accept incoming data */ + + OtASTEgState *ast; + OtOTPState *otp_ctrl; +}; + +struct OtEntropySrcEgClass { + SysBusDeviceClass parent_class; + ResettablePhases parent_phases; +}; + +static const uint16_t OtEDNFsmStateCode[] = { + [ENTROPY_SRC_EG_IDLE] = 0b011110101, + [ENTROPY_SRC_EG_BOOT_HT_RUNNING] = 0b111010010, + [ENTROPY_SRC_EG_BOOT_POST_HT_CHK] = 0b101101110, + [ENTROPY_SRC_EG_BOOT_PHASE_DONE] = 0b010001110, + [ENTROPY_SRC_EG_STARTUP_HT_START] = 0b000101100, + [ENTROPY_SRC_EG_STARTUP_PHASE1] = 0b100000001, + [ENTROPY_SRC_EG_STARTUP_PASS1] = 0b110100101, + [ENTROPY_SRC_EG_STARTUP_FAIL1] = 0b000010111, + [ENTROPY_SRC_EG_CONT_HT_START] = 0b001000000, + [ENTROPY_SRC_EG_CONT_HT_RUNNING] = 0b110100010, + [ENTROPY_SRC_EG_FW_INSERT_START] = 0b011000011, + [ENTROPY_SRC_EG_FW_INSERT_MSG] = 0b001011001, + [ENTROPY_SRC_EG_SHA3_MSGDONE] = 0b100001111, + [ENTROPY_SRC_EG_SHA3_PREP] = 0b011111000, + [ENTROPY_SRC_EG_SHA3_PROCESS] = 0b010111111, + [ENTROPY_SRC_EG_SHA3_VALID] = 0b101110001, + [ENTROPY_SRC_EG_SHA3_DONE] = 0b110011000, + [ENTROPY_SRC_EG_SHA3_QUIESCE] = 0b111001101, + [ENTROPY_SRC_EG_ALERT_STATE] = 0b111111011, + [ENTROPY_SRC_EG_ALERT_HANG] = 0b101011100, + [ENTROPY_SRC_EG_ERROR] = 0b100111101, +}; + +#define STATE_NAME_ENTRY(_st_) [ENTROPY_SRC_EG_##_st_] = stringify(_st_) +static const char *STATE_NAMES[] = { + STATE_NAME_ENTRY(IDLE), + STATE_NAME_ENTRY(BOOT_HT_RUNNING), + STATE_NAME_ENTRY(BOOT_POST_HT_CHK), + STATE_NAME_ENTRY(BOOT_PHASE_DONE), + STATE_NAME_ENTRY(STARTUP_HT_START), + STATE_NAME_ENTRY(STARTUP_PHASE1), + STATE_NAME_ENTRY(STARTUP_PASS1), + STATE_NAME_ENTRY(STARTUP_FAIL1), + STATE_NAME_ENTRY(CONT_HT_START), + STATE_NAME_ENTRY(CONT_HT_RUNNING), + STATE_NAME_ENTRY(FW_INSERT_START), + STATE_NAME_ENTRY(FW_INSERT_MSG), + STATE_NAME_ENTRY(SHA3_MSGDONE), + STATE_NAME_ENTRY(SHA3_PREP), + STATE_NAME_ENTRY(SHA3_PROCESS), + STATE_NAME_ENTRY(SHA3_VALID), + STATE_NAME_ENTRY(SHA3_DONE), + STATE_NAME_ENTRY(SHA3_QUIESCE), + STATE_NAME_ENTRY(ALERT_STATE), + STATE_NAME_ENTRY(ALERT_HANG), + STATE_NAME_ENTRY(ERROR), +}; +#undef STATE_NAME_ENTRY +#define STATE_NAME(_st_) \ + ((_st_) >= 0 && (_st_) < ARRAY_SIZE(STATE_NAMES) ? STATE_NAMES[(_st_)] : \ + "?") +#define REG_MB4_IS_TRUE(_s_, _reg_, _fld_) \ + (FIELD_EX32((_s_)->regs[R_##_reg_], _reg_, _fld_) == OT_MULTIBITBOOL4_TRUE) +#define REG_MB4_IS_FALSE(_s_, _reg_, _fld_) \ + (FIELD_EX32((_s_)->regs[R_##_reg_], _reg_, _fld_) == OT_MULTIBITBOOL4_FALSE) + +#define xtrace_ot_entropy_src_eg_show_buffer(_msg_, _buf_, _len_) \ + ot_entropy_src_eg_show_buffer(__func__, __LINE__, _msg_, _buf_, _len_) + +static bool ot_entropy_src_eg_is_module_enabled(const OtEntropySrcEgState *s); +static bool ot_entropy_src_eg_is_fips_enabled(const OtEntropySrcEgState *s); +static bool ot_entropy_src_eg_is_hw_route(const OtEntropySrcEgState *s); +static bool ot_entropy_src_eg_is_fips_capable(const OtEntropySrcEgState *s); +static void ot_entropy_src_eg_update_alerts(OtEntropySrcEgState *s); +static void ot_entropy_src_eg_update_filler(OtEntropySrcEgState *s); + +static int ot_entropy_src_eg_get_random( + OtRandomSrcIf *dev, uint64_t random[OT_RANDOM_SRC_DWORD_COUNT], bool *fips) +{ + OtEntropySrcEgState *s = OT_ENTROPY_SRC_EG(dev); + + if (!ot_entropy_src_eg_is_module_enabled(s)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: entropy_src is down\n", __func__); + return -1; + } + + bool fips_compliant; + + switch (s->state) { + case ENTROPY_SRC_EG_BOOT_PHASE_DONE: + fips_compliant = false; + break; + case ENTROPY_SRC_EG_CONT_HT_RUNNING: + case ENTROPY_SRC_EG_CONT_HT_START: + case ENTROPY_SRC_EG_SHA3_MSGDONE: + case ENTROPY_SRC_EG_SHA3_PREP: + case ENTROPY_SRC_EG_SHA3_PROCESS: + case ENTROPY_SRC_EG_SHA3_VALID: + case ENTROPY_SRC_EG_SHA3_DONE: + fips_compliant = true; + break; + case ENTROPY_SRC_EG_BOOT_HT_RUNNING: + case ENTROPY_SRC_EG_BOOT_POST_HT_CHK: + case ENTROPY_SRC_EG_STARTUP_HT_START: + case ENTROPY_SRC_EG_STARTUP_PHASE1: + case ENTROPY_SRC_EG_STARTUP_PASS1: + case ENTROPY_SRC_EG_STARTUP_FAIL1: { + int64_t wait_ns; + if (timer_pending(s->scheduler)) { + /* computed delay fits into a 31-bit value */ + wait_ns = ((int64_t)timer_expire_time_ns(s->scheduler)) - + qemu_clock_get_ns(OT_VIRTUAL_CLOCK); + wait_ns = MAX(wait_ns, OT_ENTROPY_SRC_EG_WAIT_DELAY_NS); + } else { + wait_ns = OT_ENTROPY_SRC_EG_WAIT_DELAY_NS; + } + trace_ot_entropy_src_init_ongoing(STATE_NAME(s->state), s->state, + (int)wait_ns); + /* not ready */ + return (int)wait_ns; + } + case ENTROPY_SRC_EG_IDLE: + qemu_log_mask(LOG_GUEST_ERROR, "%s: module is not enabled\n", __func__); + return -1; + case ENTROPY_SRC_EG_FW_INSERT_START: + case ENTROPY_SRC_EG_FW_INSERT_MSG: + case ENTROPY_SRC_EG_SHA3_QUIESCE: /* this state is never emulated */ + case ENTROPY_SRC_EG_ALERT_STATE: + case ENTROPY_SRC_EG_ALERT_HANG: + case ENTROPY_SRC_EG_ERROR: + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid state: [%s:%d]\n", __func__, + STATE_NAME(s->state), s->state); + return -1; + } + + if (!ot_entropy_src_eg_is_hw_route(s)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: HW route not selected\n", __func__); + return -1; + } + + if (ot_fifo32_num_used(&s->final_fifo) < ES_WORD_COUNT) { + trace_ot_entropy_src_no_entropy(ot_fifo32_num_used(&s->final_fifo)); + return OT_ENTROPY_SRC_EG_WAIT_DELAY_NS; + } + + uint32_t *randu32 = (uint32_t *)random; + size_t pos = 0; + while (pos < ES_WORD_COUNT) { + g_assert(!ot_fifo32_is_empty(&s->final_fifo)); + randu32[pos++] = ot_fifo32_pop(&s->final_fifo); + } + + bool fips_capable = ot_entropy_src_eg_is_fips_capable(s); + + /* note: fips compliancy is only simulated here for now */ + *fips = fips_compliant && fips_capable; + + trace_ot_entropy_src_get_random_fips( + STATE_NAME(s->state), ot_entropy_src_eg_is_fips_enabled(s), + REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_ROUTE), + REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_TYPE), + REG_MB4_IS_FALSE(s, CONF, RNG_BIT_ENABLE), fips_capable, fips_compliant, + *fips); + + if (ot_fifo32_num_used(&s->final_fifo) < ES_WORD_COUNT) { + ot_entropy_src_eg_update_filler(s); + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* Private implementation */ +/* -------------------------------------------------------------------------- */ + +static void ot_entropy_src_eg_show_buffer( + const char *func, int line, const char *msg, const void *buf, unsigned size) +{ + if (trace_event_get_state(TRACE_OT_ENTROPY_SRC_SHOW_BUFFER) && + qemu_loglevel_mask(LOG_TRACE)) { + static const char _hex[] = "0123456789ABCDEF"; + char hexstr[ES_HEXBUF_SIZE]; + unsigned len = MIN(size, ES_HEXBUF_SIZE / 2u - 4u); + const uint8_t *pbuf = (const uint8_t *)buf; + memset(hexstr, 0, sizeof(hexstr)); + unsigned hix = 0; + for (unsigned ix = 0u; ix < len; ix++) { + if (ix && !(ix & 0x3u)) { + hexstr[hix++] = '-'; + } + hexstr[hix++] = _hex[(pbuf[ix] >> 4u) & 0xfu]; + hexstr[hix++] = _hex[pbuf[ix] & 0xfu]; + } + if (len < size) { + hexstr[hix++] = '.'; + hexstr[hix++] = '.'; + hexstr[hix++] = '.'; + } + + trace_ot_entropy_src_show_buffer(func, line, msg, hexstr); + } +} + +static bool ot_entropy_src_eg_is_module_enabled(const OtEntropySrcEgState *s) +{ + return REG_MB4_IS_TRUE(s, MODULE_ENABLE, MODULE_ENABLE); +} + +static bool ot_entropy_src_eg_is_module_disabled(const OtEntropySrcEgState *s) +{ + return REG_MB4_IS_FALSE(s, MODULE_ENABLE, MODULE_ENABLE); +} + +static bool ot_entropy_src_eg_is_fips_enabled(const OtEntropySrcEgState *s) +{ + return REG_MB4_IS_TRUE(s, CONF, FIPS_ENABLE); +} + +static void ot_entropy_src_eg_update_irqs(OtEntropySrcEgState *s) +{ + uint32_t levels = s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE]; + for (unsigned ix = 0; ix < PARAM_NUM_IRQS; ix++) { + ibex_irq_set(&s->irqs[ix], (int)((levels >> ix) & 0x1u)); + } +} + +static bool +ot_entropy_src_eg_is_final_fifo_slot_available(const OtEntropySrcEgState *s) +{ + return ot_fifo32_num_free(&s->final_fifo) >= ES_WORD_COUNT; +} + +static bool ot_entropy_src_eg_is_hw_route(const OtEntropySrcEgState *s) +{ + return REG_MB4_IS_FALSE(s, ENTROPY_CONTROL, ES_ROUTE); +} + +static bool ot_entropy_src_eg_is_fw_route(const OtEntropySrcEgState *s) +{ + return REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_ROUTE); +} + +static bool ot_entropy_src_eg_is_bypass_mode(const OtEntropySrcEgState *s) +{ + return !ot_entropy_src_eg_is_fips_enabled(s) || + (ot_entropy_src_eg_is_fw_route(s) && + REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_TYPE)); +} + +static bool ot_entropy_src_eg_is_fw_ov_mode(const OtEntropySrcEgState *s) +{ + return REG_MB4_IS_TRUE(s, FW_OV_CONTROL, FW_OV_MODE); +} + +static bool +ot_entropy_src_eg_is_fw_ov_entropy_insert(const OtEntropySrcEgState *s) +{ + return REG_MB4_IS_TRUE(s, FW_OV_CONTROL, FW_OV_ENTROPY_INSERT); +} + +static bool ot_entropy_src_eg_is_fips_capable(const OtEntropySrcEgState *s) +{ + return ot_entropy_src_eg_is_fips_enabled(s) && + !(REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_ROUTE) && + REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_TYPE)) && + REG_MB4_IS_FALSE(s, CONF, RNG_BIT_ENABLE); +} + +static unsigned ot_alert_get_alert_fail_count(const OtEntropySrcEgState *s) +{ + unsigned count; + + count = FIELD_EX32(s->regs[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + REPCNT_FAIL_COUNT); + count += FIELD_EX32(s->regs[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + ADAPTP_HI_FAIL_COUNT); + count += FIELD_EX32(s->regs[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + ADAPTP_LO_FAIL_COUNT); + count += FIELD_EX32(s->regs[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + BUCKET_FAIL_COUNT); + count += FIELD_EX32(s->regs[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + MARKOV_HI_FAIL_COUNT); + count += FIELD_EX32(s->regs[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + MARKOV_LO_FAIL_COUNT); + count += FIELD_EX32(s->regs[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + REPCNTS_FAIL_COUNT); + + return count; +} + +static void ot_entropy_src_eg_change_state_line( + OtEntropySrcEgState *s, OtEntropySrcEgFsmState state, int line) +{ + OtEntropySrcEgFsmState old_state = s->state; + + switch (s->state) { + case ENTROPY_SRC_EG_ALERT_STATE: + s->state = ENTROPY_SRC_EG_ALERT_HANG; + break; + case ENTROPY_SRC_EG_ALERT_HANG: + if ((state == ENTROPY_SRC_EG_IDLE) && + ot_entropy_src_eg_is_module_disabled(s)) { + s->state = state; + } + break; + default: + s->state = state; + break; + } + + if (old_state != s->state) { + trace_ot_entropy_src_change_state(line, STATE_NAME(old_state), + old_state, STATE_NAME(s->state), + s->state); + } + + if (s->state == ENTROPY_SRC_EG_ERROR) { + s->regs[R_ERR_CODE] |= R_ERR_CODE_ES_MAIN_SM_ERR_MASK; + ot_entropy_src_eg_update_alerts(s); + } +} + +#define ot_entropy_src_eg_change_state(_s_, _st_) \ + ot_entropy_src_eg_change_state_line(_s_, _st_, __LINE__) + +static void ot_entropy_src_eg_update_alerts(OtEntropySrcEgState *s) +{ + unsigned alert_threshold = FIELD_EX32(s->regs[R_ALERT_THRESHOLD], + ALERT_THRESHOLD, ALERT_THRESHOLD); + unsigned alert_count = ot_alert_get_alert_fail_count(s); + bool recoverable = (bool)s->regs[R_RECOV_ALERT_STS]; + uint32_t level = s->regs[R_ALERT_TEST]; + if (alert_count >= alert_threshold || recoverable) { + level |= 1u << ALERT_RECOVERABLE; + } + uint32_t fatal_alert = s->regs[R_ERR_CODE] & ERR_CODE_FATAL_ERROR_MASK; + fatal_alert |= (1u << s->regs[R_ERR_CODE_TEST]) & ERR_CODE_FATAL_ERROR_MASK; + if (fatal_alert) { + level |= 1u << ALERT_FATAL; + } + + for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { + ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + } +} + +static bool ot_entropy_src_eg_check_multibitboot( + OtEntropySrcEgState *s, uint8_t mbbool, uint32_t alert_bit) +{ + switch (mbbool) { + case OT_MULTIBITBOOL4_TRUE: + case OT_MULTIBITBOOL4_FALSE: + return true; + default: + break; + } + + s->regs[R_RECOV_ALERT_STS] |= 1u << alert_bit; + ot_entropy_src_eg_update_alerts(s); + return false; +} + +static bool ot_entropy_src_eg_can_consume_entropy(const OtEntropySrcEgState *s) +{ + return ot_entropy_src_eg_is_module_enabled(s) && + !(ot_entropy_src_eg_is_fw_ov_entropy_insert(s) && + !ot_entropy_src_eg_is_fw_ov_mode(s)); +} + +static void ot_entropy_src_eg_update_filler(OtEntropySrcEgState *s) +{ + /* fill granule is OT_ENTROPY_SRC_EG_FILL_WORD_COUNT bits */ + bool input = + ot_fifo32_num_free(&s->input_fifo) >= OT_ENTROPY_SRC_EG_FILL_WORD_COUNT; + bool output = ot_fifo32_num_free(&s->final_fifo) >= ES_WORD_COUNT; + bool process = ot_entropy_src_eg_can_consume_entropy(s); + + bool accept_entropy = input && output && process; + trace_ot_entropy_src_update_filler(input, output, process, accept_entropy); + + if (!accept_entropy) { + /* if cannot accept entropy, stop the entropy scheduler */ + if (timer_pending(s->scheduler)) { + trace_ot_entropy_src_info("stop scheduler"); + timer_del(s->scheduler); + } + } else { + /* + * if entropy can be handled, start the entropy scheduler if + * it is not already active + */ + if (!timer_pending(s->scheduler)) { + trace_ot_entropy_src_info("reschedule"); + uint64_t now = qemu_clock_get_ns(OT_VIRTUAL_CLOCK); + timer_mod(s->scheduler, (int64_t)(now + (uint64_t)ES_FILL_RATE_NS)); + } + } +} + +static bool +ot_entropy_src_eg_can_condition_entropy(const OtEntropySrcEgState *s) +{ + if (!ot_fifo32_is_full(&s->precon_fifo)) { + /* room in preconditioner packer */ + return true; + } + if (ot_entropy_src_eg_is_final_fifo_slot_available(s)) { + /* room in output FIFO */ + return true; + } + + return false; +} + +static bool ot_entropy_src_eg_can_bypass_entropy(const OtEntropySrcEgState *s) +{ + if (!ot_fifo32_is_full(&s->bypass_fifo)) { + /* room in bypass packer */ + return true; + } + if (ot_entropy_src_eg_is_final_fifo_slot_available(s)) { + /* room in output FIFO */ + return true; + } + + return false; +} + +static bool ot_entropy_src_eg_push_entropy_to_conditioner( + OtEntropySrcEgState *s, uint32_t word) +{ + int res; + if (s->cond_word == 0) { + res = sha3_384_init(&s->sha3_state); + ot_entropy_src_eg_change_state(s, ENTROPY_SRC_EG_SHA3_PREP); + g_assert(res == CRYPT_OK); + } + + g_assert(!ot_fifo32_is_full(&s->precon_fifo)); + + ot_fifo32_push(&s->precon_fifo, word); + + if (!ot_fifo32_is_full(&s->precon_fifo)) { + return false; + } + + ot_entropy_src_eg_change_state(s, ENTROPY_SRC_EG_SHA3_PROCESS); + + uint32_t size; + const uint32_t *buf; + buf = ot_fifo32_peek_buf(&s->precon_fifo, s->precon_fifo.num, &size); + g_assert(size == s->precon_fifo.num); + xtrace_ot_entropy_src_eg_show_buffer("sha3 in", buf, + size * sizeof(uint32_t)); + res = sha3_process(&s->sha3_state, (const uint8_t *)buf, + size * sizeof(uint32_t)); + g_assert(res == CRYPT_OK); + s->cond_word += size; + ot_fifo32_reset(&s->precon_fifo); + + return true; +} + +static bool ot_entropy_src_eg_can_hash(const OtEntropySrcEgState *s) +{ + return ot_fifo32_is_empty(&s->precon_fifo) && + (s->cond_word >= (2048 / (8u * sizeof(uint32_t)))); +} + +static void ot_entropy_src_eg_perform_hash(OtEntropySrcEgState *s) +{ + uint32_t hash[OT_RANDOM_SRC_WORD_COUNT]; + int res; + res = sha3_done(&s->sha3_state, (uint8_t *)hash); + g_assert(res == CRYPT_OK); + s->cond_word = 0; + + xtrace_ot_entropy_src_eg_show_buffer("sha3 md", hash, + OT_RANDOM_SRC_WORD_COUNT * + sizeof(uint32_t)); + + ot_entropy_src_eg_change_state(s, ENTROPY_SRC_EG_SHA3_MSGDONE); + + for (unsigned ix = 0; ix < OT_RANDOM_SRC_WORD_COUNT; ix++) { + g_assert(!ot_fifo32_is_full(&s->final_fifo)); + ot_fifo32_push(&s->final_fifo, hash[ix]); + } + s->packet_count += 1u; + + ot_entropy_src_eg_change_state(s, REG_MB4_IS_TRUE(s, FW_OV_SHA3_START, + FW_OV_INSERT_START) ? + ENTROPY_SRC_EG_IDLE : + ENTROPY_SRC_EG_CONT_HT_START); +} + +static bool +ot_entropy_src_eg_push_bypass_entropy(OtEntropySrcEgState *s, uint32_t word) +{ + g_assert(!ot_fifo32_is_full(&s->bypass_fifo)); + + ot_fifo32_push(&s->bypass_fifo, word); + if (!ot_fifo32_is_full(&s->bypass_fifo)) { + /* need a whole OT_ENTROPY_SRC_EG_PACKET_SIZE_BITS packet to move on */ + return false; + } + + /* bypass conditioner full/ready, empty it into the final FIFO */ + while (!ot_fifo32_is_empty(&s->bypass_fifo)) { + g_assert(!ot_fifo32_is_full(&s->final_fifo)); + ot_fifo32_push(&s->final_fifo, ot_fifo32_pop(&s->bypass_fifo)); + } + s->packet_count += 1u; + + trace_ot_entropy_src_push_bypass_entropy( + ot_fifo32_num_used(&s->final_fifo) / OT_RANDOM_SRC_WORD_COUNT); + + return true; +} + +static void ot_entropy_src_eg_update_fw_route(OtEntropySrcEgState *s) +{ + if (ot_fifo32_num_used(&s->final_fifo) >= ES_WORD_COUNT) { + trace_ot_entropy_src_info("FW ROUTE"); + if (ot_fifo32_is_empty(&s->swread_fifo)) { + /* refill swread FIFO */ + unsigned count = ES_WORD_COUNT; + while (count--) { + ot_fifo32_push(&s->swread_fifo, ot_fifo32_pop(&s->final_fifo)); + } + s->regs[R_INTR_STATE] |= INTR_ES_ENTROPY_VALID_MASK; + trace_ot_entropy_src_available(STATE_NAME(s->state), s->state); + ot_entropy_src_eg_update_filler(s); + } + } +} + +static bool +ot_entropy_src_eg_consume_entropy(OtEntropySrcEgState *s, uint32_t word) +{ + bool fill_obs_fifo = ot_entropy_src_eg_is_fw_ov_mode(s); + bool hw_path = !ot_entropy_src_eg_is_fw_ov_entropy_insert(s); + bool bypass = ot_entropy_src_eg_is_bypass_mode(s); + + if (hw_path) { + /* check that HW accept data */ + hw_path = bypass ? ot_entropy_src_eg_can_bypass_entropy(s) : + ot_entropy_src_eg_can_condition_entropy(s); + } + + if (!(fill_obs_fifo || hw_path)) { + /* no way to consume noise, stop here */ + trace_ot_entropy_src_info("cannot consume noise for now"); + return false; + } + + s->noise_count += 1u; + trace_ot_entropy_src_consume_entropy(fill_obs_fifo, bypass, hw_path, + s->noise_count); + + if (fill_obs_fifo) { + if (ot_fifo32_is_full(&s->observe_fifo)) { + trace_ot_entropy_src_error("observe FIFO overflow", + STATE_NAME(s->state), s->state); + s->regs[R_FW_OV_RD_FIFO_OVERFLOW] |= + R_FW_OV_RD_FIFO_OVERFLOW_VAL_MASK; + } else { + if (s->obs_fifo_en) { + unsigned threshold = s->regs[R_OBSERVE_FIFO_THRESH]; + ot_fifo32_push(&s->observe_fifo, word); + trace_ot_entropy_src_obs_fifo(ot_fifo32_num_used( + &s->observe_fifo), + threshold); + if (ot_fifo32_is_full(&s->observe_fifo)) { + /* can only be enabled back once the FIFO is emptied */ + trace_ot_entropy_src_info("observe FIFO is full"); + s->obs_fifo_en = false; + } + /* is it > or >= ? */ + if (ot_fifo32_num_used(&s->observe_fifo) >= threshold) { + s->regs[R_INTR_STATE] |= INTR_ES_OBSERVE_FIFO_READY_MASK; + } + } else { + trace_ot_entropy_src_info("observe FIFO not enabled"); + } + } + } + + if (hw_path) { + if (ot_entropy_src_eg_is_bypass_mode(s)) { + ot_entropy_src_eg_push_bypass_entropy(s, word); + } else { + if (ot_entropy_src_eg_push_entropy_to_conditioner(s, word)) { + if (ot_entropy_src_eg_can_hash(s)) { + trace_ot_entropy_src_info("can hash"); + ot_entropy_src_eg_perform_hash(s); + } + } + } + } + + if (ot_entropy_src_eg_is_fw_route(s)) { + ot_entropy_src_eg_update_fw_route(s); + } + + return true; +} + +static bool ot_entropy_src_eg_fill_noise(OtEntropySrcEgState *s) +{ + unsigned count = ot_fifo32_num_free(&s->input_fifo); + if (count < OT_ENTROPY_SRC_EG_FILL_WORD_COUNT) { + /* no room left, should be resheduled */ + return false; + } + + uint32_t buffer[OT_ENTROPY_SRC_EG_FILL_WORD_COUNT]; + /* synchronous read */ + ot_ast_eg_getrandom(buffer, sizeof(buffer)); + + /* push the whole entropy buffer into the input FIFO */ + unsigned pos = 0; + while (!ot_fifo32_is_full(&s->input_fifo) && pos < ARRAY_SIZE(buffer)) { + ot_fifo32_push(&s->input_fifo, buffer[pos++]); + } + + trace_ot_entropy_src_fill_noise(count, ot_fifo32_num_used(&s->input_fifo)); + + for (unsigned ix = 0; + ix < ES_WORD_COUNT && !ot_fifo32_is_empty(&s->input_fifo); ix++) { + if (!ot_entropy_src_eg_consume_entropy(s, + ot_fifo32_pop(&s->input_fifo))) { + break; + } + } + + ot_entropy_src_eg_update_irqs(s); + + return true; +} + +static void ot_entropy_src_eg_noise_refill(void *opaque) +{ + OtEntropySrcEgState *s = opaque; + + if (!ot_entropy_src_eg_fill_noise(s)) { + trace_ot_entropy_src_info("FIFO already filled up"); + return; + } + + switch (s->state) { + case ENTROPY_SRC_EG_BOOT_HT_RUNNING: + if (s->packet_count > 0) { + ot_entropy_src_eg_change_state(s, ENTROPY_SRC_EG_BOOT_PHASE_DONE); + } + break; + case ENTROPY_SRC_EG_STARTUP_HT_START: + ot_entropy_src_eg_change_state(s, ENTROPY_SRC_EG_CONT_HT_RUNNING); + break; + case ENTROPY_SRC_EG_CONT_HT_RUNNING: + case ENTROPY_SRC_EG_CONT_HT_START: + case ENTROPY_SRC_EG_BOOT_PHASE_DONE: + case ENTROPY_SRC_EG_SHA3_PREP: + case ENTROPY_SRC_EG_SHA3_VALID: + case ENTROPY_SRC_EG_SHA3_PROCESS: + case ENTROPY_SRC_EG_SHA3_DONE: + case ENTROPY_SRC_EG_SHA3_MSGDONE: + break; + default: + trace_ot_entropy_src_error("unexpected state", STATE_NAME(s->state), + s->state); + break; + } + + ot_entropy_src_eg_update_filler(s); +} + +static void ot_entropy_src_eg_scheduler(void *opaque) +{ + OtEntropySrcEgState *s = opaque; + + switch (s->state) { + case ENTROPY_SRC_EG_BOOT_HT_RUNNING: + case ENTROPY_SRC_EG_BOOT_PHASE_DONE: + case ENTROPY_SRC_EG_STARTUP_HT_START: + case ENTROPY_SRC_EG_CONT_HT_START: + case ENTROPY_SRC_EG_CONT_HT_RUNNING: + case ENTROPY_SRC_EG_SHA3_PREP: + case ENTROPY_SRC_EG_SHA3_VALID: + case ENTROPY_SRC_EG_SHA3_PROCESS: + case ENTROPY_SRC_EG_SHA3_DONE: + case ENTROPY_SRC_EG_SHA3_MSGDONE: + ot_entropy_src_eg_noise_refill(s); + break; + case ENTROPY_SRC_EG_IDLE: + break; + case ENTROPY_SRC_EG_BOOT_POST_HT_CHK: + case ENTROPY_SRC_EG_STARTUP_PHASE1: + case ENTROPY_SRC_EG_STARTUP_PASS1: + case ENTROPY_SRC_EG_STARTUP_FAIL1: + case ENTROPY_SRC_EG_FW_INSERT_START: + case ENTROPY_SRC_EG_FW_INSERT_MSG: + case ENTROPY_SRC_EG_SHA3_QUIESCE: + case ENTROPY_SRC_EG_ALERT_STATE: + case ENTROPY_SRC_EG_ALERT_HANG: + case ENTROPY_SRC_EG_ERROR: + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid state: [%s:%d]\n", __func__, + STATE_NAME(s->state), s->state); + } + + ot_entropy_src_eg_update_alerts(s); + ot_entropy_src_eg_update_irqs(s); +} + +static uint64_t +ot_entropy_src_eg_regs_read(void *opaque, hwaddr addr, unsigned size) +{ + OtEntropySrcEgState *s = opaque; + (void)size; + uint32_t val32; + + hwaddr reg = R32_OFF(addr); + + switch (reg) { + case R_INTR_STATE: + case R_INTR_ENABLE: + case R_ME_REGWEN: + case R_SW_REGUPD: + case R_REV: + case R_MODULE_ENABLE: + case R_CONF: + case R_ENTROPY_CONTROL: + case R_HEALTH_TEST_WINDOWS: + case R_REPCNT_THRESHOLDS: + case R_REPCNTS_THRESHOLDS: + case R_ADAPTP_HI_THRESHOLDS: + case R_ADAPTP_LO_THRESHOLDS: + case R_BUCKET_THRESHOLDS: + case R_MARKOV_HI_THRESHOLDS: + case R_MARKOV_LO_THRESHOLDS: + case R_EXTHT_HI_THRESHOLDS: + case R_EXTHT_LO_THRESHOLDS: + case R_REPCNT_HI_WATERMARKS: + case R_REPCNTS_HI_WATERMARKS: + case R_ADAPTP_HI_WATERMARKS: + case R_ADAPTP_LO_WATERMARKS: + case R_EXTHT_HI_WATERMARKS: + case R_EXTHT_LO_WATERMARKS: + case R_BUCKET_HI_WATERMARKS: + case R_MARKOV_HI_WATERMARKS: + case R_MARKOV_LO_WATERMARKS: + case R_REPCNT_TOTAL_FAILS: + case R_REPCNTS_TOTAL_FAILS: + case R_ADAPTP_HI_TOTAL_FAILS: + case R_ADAPTP_LO_TOTAL_FAILS: + case R_BUCKET_TOTAL_FAILS: + case R_MARKOV_HI_TOTAL_FAILS: + case R_MARKOV_LO_TOTAL_FAILS: + case R_EXTHT_HI_TOTAL_FAILS: + case R_EXTHT_LO_TOTAL_FAILS: + case R_ALERT_THRESHOLD: + case R_ALERT_FAIL_COUNTS: + case R_EXTHT_FAIL_COUNTS: + case R_FW_OV_CONTROL: + case R_FW_OV_SHA3_START: + case R_FW_OV_RD_FIFO_OVERFLOW: + case R_OBSERVE_FIFO_THRESH: + case R_RECOV_ALERT_STS: + case R_ERR_CODE: + case R_ERR_CODE_TEST: + val32 = s->regs[reg]; + break; + case R_DEBUG_STATUS: + /* SHA3 block reporting is not supported */ + val32 = FIELD_DP32(0, DEBUG_STATUS, ENTROPY_FIFO_DEPTH, + ot_fifo32_num_used(&s->final_fifo)); + val32 = FIELD_DP32(val32, DEBUG_STATUS, MAIN_SM_IDLE, + (uint32_t)(s->state == ENTROPY_SRC_EG_IDLE)); + val32 = + FIELD_DP32(val32, DEBUG_STATUS, MAIN_SM_BOOT_DONE, + (uint32_t)(s->state == ENTROPY_SRC_EG_BOOT_PHASE_DONE)); + break; + case R_MAIN_SM_STATE: + if (s->state < ARRAY_SIZE(OtEDNFsmStateCode)) { + val32 = OtEDNFsmStateCode[s->state]; + } else { + val32 = OtEDNFsmStateCode[ENTROPY_SRC_EG_ERROR]; + } + break; + case R_REGWEN: + val32 = (uint32_t)(s->regs[R_SW_REGUPD] == R_SW_REGUPD_UPD_MASK && + ot_entropy_src_eg_is_module_disabled(s)); + break; + case R_ALERT_SUMMARY_FAIL_COUNTS: + val32 = (uint32_t)ot_alert_get_alert_fail_count(s); + break; + case R_ENTROPY_DATA: + if (ot_entropy_src_eg_is_module_enabled(s) && + REG_MB4_IS_TRUE(s, CONF, ENTROPY_DATA_REG_ENABLE) && + ot_entropy_src_eg_is_fw_route(s)) { + if (!ot_fifo32_is_empty(&s->swread_fifo)) { + val32 = ot_fifo32_pop(&s->swread_fifo); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Entropy data not available\n", __func__); + val32 = 0; + } + } else { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Entropy data not configured\n", + __func__); + val32 = 0; + } + break; + case R_FW_OV_WR_FIFO_FULL: { + bool can_write; + if (ot_entropy_src_eg_is_fw_ov_mode(s) && + ot_entropy_src_eg_is_fw_ov_entropy_insert(s)) { + if (ot_entropy_src_eg_is_bypass_mode(s)) { + can_write = ot_entropy_src_eg_can_bypass_entropy(s); + } else { + can_write = ot_entropy_src_eg_can_condition_entropy(s); + } + } else { + can_write = false; + } + val32 = can_write ? 0u : R_FW_OV_WR_FIFO_FULL_VAL_MASK; + } break; + case R_FW_OV_RD_DATA: + if (ot_entropy_src_eg_is_fw_ov_mode(s)) { + if (!ot_fifo32_is_empty(&s->observe_fifo)) { + val32 = ot_fifo32_pop(&s->observe_fifo); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Read from empty observe FIFO\n", __func__); + val32 = 0; + } + } else { + qemu_log_mask(LOG_GUEST_ERROR, "%s: FW override mode not active\n", + __func__); + val32 = 0; + } + break; + case R_OBSERVE_FIFO_DEPTH: + val32 = ot_fifo32_num_used(&s->observe_fifo); + break; + case R_INTR_TEST: + case R_ALERT_TEST: + case R_FW_OV_WR_DATA: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: W/O register 0x%02" HWADDR_PRIx " (%s)\n", __func__, + addr, REG_NAME(reg)); + val32 = 0; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, addr); + val32 = 0; + break; + } + + uint32_t pc = ibex_get_current_pc(); + trace_ot_entropy_src_io_read_out((uint32_t)addr, REG_NAME(reg), val32, pc); + + return (uint64_t)val32; +}; + +#define CHECK_MULTIBOOT(_s_, _r_, _b_) \ + do { \ + if (!ot_entropy_src_eg_check_multibitboot((_s_), \ + FIELD_EX32(s->regs[R_##_r_], \ + _r_, _b_), \ + ALERT_STATUS_BIT(_b_))) { \ + qemu_log_mask(LOG_GUEST_ERROR, \ + "%s: invalid multiboot value 0x%1x\n", __func__, \ + FIELD_EX32(s->regs[R_##_r_], _r_, _b_)); \ + } \ + } while (0) + +static void ot_entropy_src_eg_regs_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned size) +{ + OtEntropySrcEgState *s = opaque; + (void)size; + uint32_t val32 = (uint32_t)val64; + + hwaddr reg = R32_OFF(addr); + + uint32_t pc = ibex_get_current_pc(); + trace_ot_entropy_src_io_write((uint32_t)addr, REG_NAME(reg), val32, pc); + + switch (reg) { + case R_INTR_STATE: + val32 &= INTR_MASK; + s->regs[reg] &= ~val32; /* RW1C */ + /* not sure about this behavior, seems to be what the tests expect... */ + if (!ot_fifo32_is_empty(&s->swread_fifo)) { + s->regs[R_INTR_STATE] |= INTR_ES_ENTROPY_VALID_MASK; + } + if (!ot_fifo32_is_empty(&s->observe_fifo)) { + s->regs[R_INTR_STATE] |= INTR_ES_OBSERVE_FIFO_READY_MASK; + } + ot_entropy_src_eg_update_irqs(s); + break; + case R_INTR_ENABLE: + val32 &= INTR_MASK; + s->regs[reg] = val32; + ot_entropy_src_eg_update_irqs(s); + break; + case R_INTR_TEST: + val32 &= INTR_MASK; + s->regs[R_INTR_STATE] |= val32; + ot_entropy_src_eg_update_irqs(s); + break; + case R_ALERT_TEST: + val32 &= ALERT_TEST_MASK; + s->regs[reg] = val32; + ot_entropy_src_eg_update_alerts(s); + break; + case R_ME_REGWEN: + val32 &= R_ME_REGWEN_EN_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; + case R_SW_REGUPD: + val32 &= R_SW_REGUPD_UPD_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; + case R_MODULE_ENABLE: + if (s->regs[R_ME_REGWEN]) { + uint32_t old = s->regs[reg]; + val32 &= R_MODULE_ENABLE_MODULE_ENABLE_MASK; + s->regs[reg] = val32; + CHECK_MULTIBOOT(s, MODULE_ENABLE, MODULE_ENABLE); + if (ot_entropy_src_eg_is_module_disabled(s)) { + /* reset takes care of cancelling the scheduler timer */ + resettable_reset(OBJECT(s), RESET_TYPE_COLD); + break; + } + if ((old ^ s->regs[reg]) && + ot_entropy_src_eg_is_module_enabled(s)) { + if (ot_entropy_src_eg_is_fips_enabled(s)) { + /* start up phase */ + ot_entropy_src_eg_change_state( + s, ENTROPY_SRC_EG_STARTUP_HT_START); + } else { + /* boot phase */ + ot_entropy_src_eg_change_state( + s, ENTROPY_SRC_EG_BOOT_HT_RUNNING); + } + uint64_t now = qemu_clock_get_ns(OT_VIRTUAL_CLOCK); + timer_mod(s->scheduler, + (int64_t)(now + + (uint64_t)OT_ENTROPY_SRC_EG_BOOT_DELAY_NS)); + } + break; + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: ME_REGWEN not enabled\n", __func__); + break; + case R_CONF: + if (s->regs[R_REGWEN]) { + val32 &= CONF_MASK; + s->regs[reg] = val32; + CHECK_MULTIBOOT(s, CONF, FIPS_ENABLE); + CHECK_MULTIBOOT(s, CONF, ENTROPY_DATA_REG_ENABLE); + CHECK_MULTIBOOT(s, CONF, THRESHOLD_SCOPE); + CHECK_MULTIBOOT(s, CONF, RNG_BIT_ENABLE); + } + break; + case R_ENTROPY_CONTROL: + if (s->regs[R_REGWEN]) { + val32 &= ENTROPY_CONTROL_MASK; + s->regs[reg] = val32; + CHECK_MULTIBOOT(s, ENTROPY_CONTROL, ES_ROUTE); + CHECK_MULTIBOOT(s, ENTROPY_CONTROL, ES_TYPE); + } + break; + case R_HEALTH_TEST_WINDOWS: + if (s->regs[R_REGWEN]) { + s->regs[reg] = val32; + } + break; + case R_REPCNT_THRESHOLDS: + case R_REPCNTS_THRESHOLDS: + case R_ADAPTP_HI_THRESHOLDS: + case R_ADAPTP_LO_THRESHOLDS: + case R_BUCKET_THRESHOLDS: + case R_MARKOV_HI_THRESHOLDS: + case R_MARKOV_LO_THRESHOLDS: + case R_EXTHT_HI_THRESHOLDS: + case R_EXTHT_LO_THRESHOLDS: + if (s->regs[R_REGWEN]) { + s->regs[reg] = val32; + ot_entropy_src_eg_update_alerts(s); + } + break; + case R_ALERT_THRESHOLD: + if (s->regs[R_REGWEN]) { + if ((uint16_t)(val32) != (uint16_t)(~(val32 >> 16u))) { + s->regs[R_RECOV_ALERT_STS] |= + R_RECOV_ALERT_STS_ES_THRESH_CFG_ALERT_MASK; + } else { + s->regs[reg] = val32; + } + ot_entropy_src_eg_update_alerts(s); + } + break; + case R_FW_OV_CONTROL: + if (s->regs[R_REGWEN]) { + val32 &= FW_OV_CONTROL_MASK; + s->regs[reg] = val32; + CHECK_MULTIBOOT(s, FW_OV_CONTROL, FW_OV_MODE); + CHECK_MULTIBOOT(s, FW_OV_CONTROL, FW_OV_ENTROPY_INSERT); + s->obs_fifo_en = ot_entropy_src_eg_is_fw_ov_mode(s); + } + break; + case R_FW_OV_SHA3_START: + if (!ot_entropy_src_eg_is_module_enabled(s)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: module not enabled\n", + __func__); + break; + } + val32 &= R_FW_OV_SHA3_START_FW_OV_INSERT_START_MASK; + s->regs[reg] = val32; + CHECK_MULTIBOOT(s, FW_OV_SHA3_START, FW_OV_INSERT_START); + if (REG_MB4_IS_TRUE(s, FW_OV_SHA3_START, FW_OV_INSERT_START)) { + OtEntropySrcEgFsmState new_state; + new_state = ot_entropy_src_eg_is_bypass_mode(s) ? + ENTROPY_SRC_EG_IDLE : + ENTROPY_SRC_EG_FW_INSERT_START; + ot_entropy_src_eg_change_state(s, new_state); + } else { /* default to false */ + if (s->state == ENTROPY_SRC_EG_SHA3_PROCESS) { + /* handle SHA3 processing */ + if (ot_fifo32_is_empty(&s->precon_fifo)) { + ot_entropy_src_eg_perform_hash(s); + if (ot_entropy_src_eg_is_fw_route(s)) { + ot_entropy_src_eg_update_fw_route(s); + } + } else { + qemu_log_mask(LOG_GUEST_ERROR, "%s: need 1 more word\n", + __func__); + } + } else { + OtEntropySrcEgFsmState new_state; + new_state = ot_entropy_src_eg_is_bypass_mode(s) ? + ENTROPY_SRC_EG_BOOT_HT_RUNNING : + ENTROPY_SRC_EG_STARTUP_HT_START; + ot_entropy_src_eg_change_state(s, new_state); + } + } + break; + case R_FW_OV_RD_FIFO_OVERFLOW: + val32 &= R_FW_OV_RD_FIFO_OVERFLOW_VAL_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; + case R_FW_OV_WR_DATA: + if (!ot_entropy_src_eg_is_module_enabled(s)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: module not enabled\n", + __func__); + break; + } + if (ot_entropy_src_eg_is_fw_ov_mode(s) && + ot_entropy_src_eg_is_fw_ov_entropy_insert(s)) { + bool can_write; + if (ot_entropy_src_eg_is_bypass_mode(s)) { + can_write = ot_entropy_src_eg_can_bypass_entropy(s); + if (can_write) { + ot_entropy_src_eg_push_bypass_entropy(s, val32); + } + } else { + can_write = ot_entropy_src_eg_can_condition_entropy(s); + if (can_write) { + ot_entropy_src_eg_push_entropy_to_conditioner(s, val32); + } + } + if (!can_write) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: FW override: FIFO full\n", + __func__); + } + } else { + qemu_log_mask(LOG_GUEST_ERROR, "%s: FW override mode not active\n", + __func__); + } + break; + case R_OBSERVE_FIFO_THRESH: + if (s->regs[R_REGWEN]) { + val32 &= R_OBSERVE_FIFO_THRESH_VAL_MASK; + s->regs[reg] = val32; + ot_entropy_src_eg_update_irqs(s); + } + break; + case R_RECOV_ALERT_STS: + val32 &= RECOV_ALERT_STS_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; + case R_ERR_CODE_TEST: + val32 &= R_ERR_CODE_TEST_VAL_MASK; + s->regs[R_ERR_CODE_TEST] = val32; + ot_entropy_src_eg_update_irqs(s); + ot_entropy_src_eg_update_alerts(s); + break; + case R_REGWEN: + case R_REV: + case R_ENTROPY_DATA: + case R_REPCNT_HI_WATERMARKS: + case R_REPCNTS_HI_WATERMARKS: + case R_ADAPTP_HI_WATERMARKS: + case R_ADAPTP_LO_WATERMARKS: + case R_EXTHT_HI_WATERMARKS: + case R_EXTHT_LO_WATERMARKS: + case R_BUCKET_HI_WATERMARKS: + case R_MARKOV_HI_WATERMARKS: + case R_MARKOV_LO_WATERMARKS: + case R_REPCNT_TOTAL_FAILS: + case R_REPCNTS_TOTAL_FAILS: + case R_ADAPTP_HI_TOTAL_FAILS: + case R_ADAPTP_LO_TOTAL_FAILS: + case R_BUCKET_TOTAL_FAILS: + case R_MARKOV_HI_TOTAL_FAILS: + case R_MARKOV_LO_TOTAL_FAILS: + case R_EXTHT_HI_TOTAL_FAILS: + case R_EXTHT_LO_TOTAL_FAILS: + case R_ALERT_SUMMARY_FAIL_COUNTS: + case R_ALERT_FAIL_COUNTS: + case R_EXTHT_FAIL_COUNTS: + case R_FW_OV_WR_FIFO_FULL: + case R_FW_OV_RD_DATA: + case R_OBSERVE_FIFO_DEPTH: + case R_DEBUG_STATUS: + case R_ERR_CODE: + case R_MAIN_SM_STATE: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: R/O register 0x%02" HWADDR_PRIx " (%s)\n", __func__, + addr, REG_NAME(reg)); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, addr); + break; + } +}; + +static Property ot_entropy_src_eg_properties[] = { + DEFINE_PROP_LINK("ast", OtEntropySrcEgState, ast, TYPE_OT_AST_EG, + OtASTEgState *), + DEFINE_PROP_LINK("otp_ctrl", OtEntropySrcEgState, otp_ctrl, TYPE_OT_OTP, + OtOTPState *), + DEFINE_PROP_END_OF_LIST(), +}; + +static const MemoryRegionOps ot_entropy_src_eg_regs_ops = { + .read = &ot_entropy_src_eg_regs_read, + .write = &ot_entropy_src_eg_regs_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl.min_access_size = 4u, + .impl.max_access_size = 4u, +}; + +static void ot_entropy_src_eg_reset_enter(Object *obj, ResetType type) +{ + OtEntropySrcEgClass *c = OT_ENTROPY_SRC_EG_GET_CLASS(obj); + OtEntropySrcEgState *s = OT_ENTROPY_SRC_EG(obj); + + trace_ot_entropy_src_reset(); + + if (c->parent_phases.enter) { + c->parent_phases.enter(obj, type); + } + + timer_del(s->scheduler); + + memset(s->regs, 0, REGS_SIZE); + + s->regs[R_ME_REGWEN] = 0x1u; + s->regs[R_SW_REGUPD] = 0x1u; + s->regs[R_REGWEN] = 0x1u; + s->regs[R_REV] = 0x10303u; + s->regs[R_MODULE_ENABLE] = 0x9u; + s->regs[R_CONF] = 0x2649999u; + s->regs[R_ENTROPY_CONTROL] = 0x99u; + s->regs[R_HEALTH_TEST_WINDOWS] = 0x600200u; + s->regs[R_REPCNT_THRESHOLDS] = 0xffffffffu; + s->regs[R_REPCNTS_THRESHOLDS] = 0xffffffffu; + s->regs[R_ADAPTP_HI_THRESHOLDS] = 0xffffffffu; + s->regs[R_BUCKET_THRESHOLDS] = 0xffffffffu; + s->regs[R_MARKOV_HI_THRESHOLDS] = 0xffffffffu; + s->regs[R_EXTHT_HI_THRESHOLDS] = 0xffffffffu; + s->regs[R_ADAPTP_LO_WATERMARKS] = 0xffffffffu; + s->regs[R_EXTHT_LO_WATERMARKS] = 0xffffffffu; + s->regs[R_MARKOV_LO_WATERMARKS] = 0xffffffffu; + s->regs[R_ALERT_THRESHOLD] = 0xfffd0002u; + s->regs[R_FW_OV_CONTROL] = 0x99u; + s->regs[R_FW_OV_SHA3_START] = 0x9u; + s->regs[R_OBSERVE_FIFO_THRESH] = 0x10u; + s->regs[R_DEBUG_STATUS] = 0x10000u; + + ot_fifo32_reset(&s->input_fifo); + ot_fifo32_reset(&s->precon_fifo); + ot_fifo32_reset(&s->bypass_fifo); + ot_fifo32_reset(&s->observe_fifo); + ot_fifo32_reset(&s->swread_fifo); + ot_fifo32_reset(&s->final_fifo); + + s->cond_word = 0u; + s->noise_count = 0u; + s->packet_count = 0u; + s->obs_fifo_en = false; + + ot_entropy_src_eg_update_irqs(s); + for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { + ibex_irq_set(&s->alerts[ix], 0); + } + + OtOTPClass *oc = OBJECT_GET_CLASS(OtOTPClass, s->otp_ctrl, TYPE_OT_OTP); + const OtOTPEntropyCfg *entropy_cfg = oc->get_entropy_cfg(s->otp_ctrl); + g_assert(entropy_cfg); + + ot_entropy_src_eg_change_state(s, ENTROPY_SRC_EG_IDLE); +} + +static void ot_entropy_src_eg_realize(DeviceState *dev, Error **errp) +{ + (void)errp; + + OtEntropySrcEgState *s = OT_ENTROPY_SRC_EG(dev); + + g_assert(s->ast); + g_assert(s->otp_ctrl); +} + +static void ot_entropy_src_eg_init(Object *obj) +{ + OtEntropySrcEgState *s = OT_ENTROPY_SRC_EG(obj); + + memory_region_init_io(&s->mmio, obj, &ot_entropy_src_eg_regs_ops, s, + TYPE_OT_ENTROPY_SRC_EG, REGS_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); + + s->regs = g_new0(uint32_t, REGS_COUNT); + for (unsigned ix = 0; ix < PARAM_NUM_IRQS; ix++) { + 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); + } + + ot_fifo32_create(&s->input_fifo, OT_ENTROPY_SRC_EG_FILL_WORD_COUNT * 2u); + ot_fifo32_create(&s->precon_fifo, sizeof(uint64_t) / sizeof(uint32_t)); + ot_fifo32_create(&s->bypass_fifo, ES_WORD_COUNT); + ot_fifo32_create(&s->observe_fifo, PARAM_OBSERVE_FIFO_DEPTH); + ot_fifo32_create(&s->swread_fifo, ES_SWREAD_FIFO_WORD_COUNT); + ot_fifo32_create(&s->final_fifo, ES_FINAL_FIFO_WORD_COUNT); + + s->scheduler = + timer_new_ns(OT_VIRTUAL_CLOCK, &ot_entropy_src_eg_scheduler, s); +} + +static void ot_entropy_src_eg_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + (void)data; + + dc->realize = &ot_entropy_src_eg_realize; + device_class_set_props(dc, ot_entropy_src_eg_properties); + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + ResettableClass *rc = RESETTABLE_CLASS(klass); + OtEntropySrcEgClass *ec = OT_ENTROPY_SRC_EG_CLASS(klass); + resettable_class_set_parent_phases(rc, &ot_entropy_src_eg_reset_enter, NULL, + NULL, &ec->parent_phases); + + OtRandomSrcIfClass *rdc = OT_RANDOM_SRC_IF_CLASS(klass); + rdc->get_random_values = &ot_entropy_src_eg_get_random; +} + +static const TypeInfo ot_entropy_src_eg_info = { + .name = TYPE_OT_ENTROPY_SRC_EG, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(OtEntropySrcEgState), + .instance_init = &ot_entropy_src_eg_init, + .class_size = sizeof(OtEntropySrcEgClass), + .class_init = &ot_entropy_src_eg_class_init, + .interfaces = + (InterfaceInfo[]){ + { TYPE_OT_RANDOM_SRC_IF }, + {}, + }, +}; + +static void ot_entropy_src_eg_register_types(void) +{ + type_register_static(&ot_entropy_src_eg_info); +} + +type_init(ot_entropy_src_eg_register_types); diff --git a/hw/opentitan/ot_pwrmgr.c b/hw/opentitan/ot_pwrmgr.c index f68630f260aab..e8d1c1cb14b51 100644 --- a/hw/opentitan/ot_pwrmgr.c +++ b/hw/opentitan/ot_pwrmgr.c @@ -337,7 +337,7 @@ typedef struct { /* clang-format off */ static const OtPwrMgrConfig PWRMGR_CONFIG[OT_PWRMGR_VERSION_COUNT] = { - [OT_PWRMGR_VERSION_EG_252] = { + [OT_PWRMGR_VERSION_EG_1_0_0] = { .wakeup_count = 6u, .reset_count = 2u, .reset_mask = 0x3u @@ -350,7 +350,7 @@ static const OtPwrMgrConfig PWRMGR_CONFIG[OT_PWRMGR_VERSION_COUNT] = { }; static int PWRMGR_RESET_DISPATCH[OT_PWRMGR_VERSION_COUNT][PARAM_NUM_RST_REQS] = { - [OT_PWRMGR_VERSION_EG_252] = { + [OT_PWRMGR_VERSION_EG_1_0_0] = { [0] = OT_RSTMGR_RESET_SYSCTRL, [1] = OT_RSTMGR_RESET_AON_TIMER, }, @@ -362,7 +362,7 @@ static int PWRMGR_RESET_DISPATCH[OT_PWRMGR_VERSION_COUNT][PARAM_NUM_RST_REQS] = static const char * PWRMGR_WAKEUP_NAMES[OT_PWRMGR_VERSION_COUNT][PWRMGR_WAKEUP_MAX] = { - [OT_PWRMGR_VERSION_EG_252] = { + [OT_PWRMGR_VERSION_EG_1_0_0] = { [0] = "SYSRST", [1] = "ADC_CTRL", [2] = "PINMUX", @@ -381,7 +381,7 @@ PWRMGR_WAKEUP_NAMES[OT_PWRMGR_VERSION_COUNT][PWRMGR_WAKEUP_MAX] = { }; static const char *PWRMGR_RST_NAMES[OT_PWRMGR_VERSION_COUNT][PARAM_NUM_RST_REQS] = { - [OT_PWRMGR_VERSION_EG_252] = { + [OT_PWRMGR_VERSION_EG_1_0_0] = { [0] = "SYSRST", [1] = "AON_TIMER", }, diff --git a/hw/opentitan/ot_rstmgr.c b/hw/opentitan/ot_rstmgr.c index 140e10efb31ef..4332560dcadaa 100644 --- a/hw/opentitan/ot_rstmgr.c +++ b/hw/opentitan/ot_rstmgr.c @@ -198,7 +198,7 @@ typedef struct { } OtRstMgrConfig; static const OtRstMgrConfig RSTMGR_CONFIG[OT_RSTMGR_VERSION_COUNT] = { - [OT_RSTMGR_VERSION_EG_252] = { + [OT_RSTMGR_VERSION_EG_1_0_0] = { .reset_request_codes = { [OT_RSTMGR_RESET_POR] = BIT(0), [OT_RSTMGR_RESET_LOW_POWER] = BIT(1), @@ -619,7 +619,7 @@ static void ot_rstmgr_reset_enter(Object *obj, ResetType type) * TODO: remove this version check when USBDEV and I2C are implemented * and connected to the `rstmgr`. */ - if (rst->typename || s->version == OT_RSTMGR_VERSION_EG_252) { + if (rst->typename || s->version == OT_RSTMGR_VERSION_EG_1_0_0) { s->regs[R_SW_RST_REGWEN_0 + devix] = SW_RST_REGWEN_EN_MASK; s->regs[R_SW_RST_CTRL_N_0 + devix] = SW_RST_CTRL_VAL_MASK; } diff --git a/hw/opentitan/ot_spi_host.c b/hw/opentitan/ot_spi_host.c index a7dbd402e988a..cfc84116d90fa 100644 --- a/hw/opentitan/ot_spi_host.c +++ b/hw/opentitan/ot_spi_host.c @@ -111,10 +111,16 @@ REG32(CONFIGOPTS, 0x18u) REG32(CSID, 0x1cu) FIELD(CSID, CSID, 0u, 32u) REG32(COMMAND, 0x20u) +/* Darjeeling field definitions */ FIELD(COMMAND, CSAAT, 0u, 1u) FIELD(COMMAND, SPEED, 1u, 2u) FIELD(COMMAND, DIRECTION, 3u, 2u) FIELD(COMMAND, LEN, 5u, 20u) +/* Earlgrey 1.0.0 field definitions */ + FIELD(COMMAND, EG_1_0_0_LEN, 0u, 9u) + FIELD(COMMAND, EG_1_0_0_CSAAT, 9u, 1u) + FIELD(COMMAND, EG_1_0_0_SPEED, 10u, 2u) + FIELD(COMMAND, EG_1_0_0_DIRECTION, 12u, 2u) REG32(RXDATA, 0x24u) REG32(TXDATA, 0x28u) REG32(ERROR_ENABLE, 0x2cu) @@ -360,6 +366,7 @@ struct OtSPIHostState { uint32_t completion_delay_ns; /** completion delay/pacing */ uint32_t bus_num; /* SPI host port number */ uint32_t num_cs; /* Supported CS line count */ + uint8_t version; }; /* ------------------------------------------------------------------------ */ @@ -486,6 +493,22 @@ static uint32_t cmdfifo_num_used(const CmdFifo *fifo) /* Helpers */ /* ------------------------------------------------------------------------ */ +static uint32_t ot_spi_host_convert_from_eg_1_0_0_command(uint32_t eg_cmd) +{ + uint32_t csaat = FIELD_EX32(eg_cmd, COMMAND, EG_1_0_0_CSAAT); + uint32_t speed = FIELD_EX32(eg_cmd, COMMAND, EG_1_0_0_SPEED); + uint32_t direction = FIELD_EX32(eg_cmd, COMMAND, EG_1_0_0_DIRECTION); + uint32_t len = FIELD_EX32(eg_cmd, COMMAND, EG_1_0_0_LEN); + + /* EG 1.0.0 has a narrower length field, so this conversion is safe. */ + uint32_t cmd = 0; + cmd = FIELD_DP32(cmd, COMMAND, CSAAT, csaat); + cmd = FIELD_DP32(cmd, COMMAND, SPEED, speed); + cmd = FIELD_DP32(cmd, COMMAND, DIRECTION, direction); + cmd = FIELD_DP32(cmd, COMMAND, LEN, len); + return cmd; +} + static bool ot_spi_host_is_rx(uint32_t command) { return (bool)(FIELD_EX32(command, COMMAND, DIRECTION) & 0x1u); @@ -1134,6 +1157,10 @@ static void ot_spi_host_io_write(void *opaque, hwaddr addr, uint64_t val64, s->regs[reg] = val32; break; case R_COMMAND: { + /* Convert command for back-compat with Earlgrey 1.0.0 fields */ + if (s->version == OT_SPI_HOST_VERSION_EG_1_0_0) { + val32 = ot_spi_host_convert_from_eg_1_0_0_command(val32); + } val32 &= R_COMMAND_MASK; /* IP not enabled */ @@ -1295,6 +1322,7 @@ static Property ot_spi_host_properties[] = { FSM_START_DELAY_NS), DEFINE_PROP_UINT32("completion-delay", OtSPIHostState, completion_delay_ns, 0), + DEFINE_PROP_UINT8("version", OtSPIHostState, version, UINT8_MAX), DEFINE_PROP_END_OF_LIST(), }; @@ -1354,6 +1382,8 @@ static void ot_spi_host_realize(DeviceState *dev, Error **errp) g_assert(s->clock_src); OBJECT_CHECK(IbexClockSrcIf, s->clock_src, TYPE_IBEX_CLOCK_SRC_IF); + g_assert(s->version < OT_SPI_HOST_VERSION_COUNT); + s->cs_lines = g_new0(qemu_irq, (size_t)s->num_cs); qdev_init_gpio_out_named(DEVICE(s), s->cs_lines, SSI_GPIO_CS, diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 830fac0ab7ea3..5d6f7a3b7434a 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -34,7 +34,7 @@ config OT_DARJEELING select OT_DM_TL select OT_DMA select OT_EDN - select OT_ENTROPY_SRC + select OT_ENTROPY_SRC_DJ select OT_GPIO_DJ select OT_HMAC select OT_I2C_DJ @@ -77,7 +77,7 @@ config OT_EARLGREY select OT_CLKMGR select OT_CSRNG select OT_EDN - select OT_ENTROPY_SRC + select OT_ENTROPY_SRC_EG select OT_FLASH select OT_GPIO_EG select OT_HMAC diff --git a/hw/riscv/ot_darjeeling.c b/hw/riscv/ot_darjeeling.c index 3a39ebc0e979c..df9bac453e933 100644 --- a/hw/riscv/ot_darjeeling.c +++ b/hw/riscv/ot_darjeeling.c @@ -1250,7 +1250,8 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_STRING_PROP(OT_COMMON_DEV_ID, "spi0"), IBEX_DEV_UINT_PROP("bus-num", 0), - IBEX_DEV_STRING_PROP("clock-name", "peri.io_div4") + IBEX_DEV_STRING_PROP("clock-name", "peri.io_div4"), + IBEX_DEV_UINT_PROP("version", OT_SPI_HOST_VERSION_DJ_PRE) ), }, [OT_DJ_SOC_DEV_SPI_DEVICE] = { @@ -1342,7 +1343,8 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { "peri:io_div4+io_div2+io+aon+usb," "timers:io_div4+aon"), IBEX_DEV_STRING_PROP("swcg", "peri"), - IBEX_DEV_STRING_PROP("hint", "trans") + IBEX_DEV_STRING_PROP("hint", "trans"), + IBEX_DEV_UINT_PROP("version", OT_CLKMGR_VERSION_DJ_PRE) ), }, [OT_DJ_SOC_DEV_PINMUX] = { diff --git a/hw/riscv/ot_earlgrey.c b/hw/riscv/ot_earlgrey.c index 058c51ee90f28..9eef8fa37fdcd 100644 --- a/hw/riscv/ot_earlgrey.c +++ b/hw/riscv/ot_earlgrey.c @@ -45,7 +45,7 @@ #include "hw/opentitan/ot_common.h" #include "hw/opentitan/ot_csrng.h" #include "hw/opentitan/ot_edn.h" -#include "hw/opentitan/ot_entropy_src.h" +#include "hw/opentitan/ot_entropy_src_eg.h" #include "hw/opentitan/ot_flash.h" #include "hw/opentitan/ot_gpio_eg.h" #include "hw/opentitan/ot_hmac.h" @@ -283,8 +283,13 @@ static const uint32_t ot_eg_pmp_addrs[] = { } \ } -/* Earlgrey M2.5.2-RC0 RV DM */ -#define EG_TAP_IDCODE IBEX_JTAG_IDCODE(0, 1, 0) +/* + * Earlgrey 1.0.0 TAPs + * See https://github.com/lowRISC/part-number-registry/blob/main/jtag_partno.md + */ +#define EG_RV_DM_TAP_IDCODE IBEX_JTAG_IDCODE(0, 1, 1) +#define EG_LC_CTRL_TAP_IDCODE IBEX_JTAG_IDCODE(0, 2, 1) +#define EG_COMBINED_TAP_IDCODE IBEX_JTAG_IDCODE(0, 3, 1) #define PULP_DM_BASE 0x00010000u #define SRAM_MAIN_SIZE 0x20000u @@ -315,7 +320,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { .cfg = &ot_eg_soc_tap_ctrl_configure, .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("ir_length", IBEX_TAP_IR_LENGTH), - IBEX_DEV_UINT_PROP("idcode", EG_TAP_IDCODE) + IBEX_DEV_UINT_PROP("idcode", EG_RV_DM_TAP_IDCODE) ), }, [OT_EG_SOC_DEV_DTM] = { @@ -719,7 +724,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_STRING_PROP(OT_COMMON_DEV_ID, "spi0"), IBEX_DEV_UINT_PROP("bus-num", 0), - IBEX_DEV_STRING_PROP("clock-name", "peri.io_div4") + IBEX_DEV_STRING_PROP("clock-name", "peri.io_div4"), + IBEX_DEV_UINT_PROP("version", OT_SPI_HOST_VERSION_EG_1_0_0) ), }, [OT_EG_SOC_DEV_SPI_HOST1] = { @@ -738,7 +744,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_STRING_PROP(OT_COMMON_DEV_ID, "spi1"), IBEX_DEV_UINT_PROP("bus-num", 1), - IBEX_DEV_STRING_PROP("clock-name", "peri.io_div4") + IBEX_DEV_STRING_PROP("clock-name", "peri.io_div4"), + IBEX_DEV_UINT_PROP("version", OT_SPI_HOST_VERSION_EG_1_0_0) ), }, [OT_EG_SOC_DEV_USBDEV] = { @@ -782,7 +789,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_STRING_PROP("clocks", "main,io,usb"), IBEX_DEV_UINT_PROP("num-rom", 1u), - IBEX_DEV_UINT_PROP("version", OT_PWRMGR_VERSION_EG_252) + IBEX_DEV_UINT_PROP("version", OT_PWRMGR_VERSION_EG_1_0_0) ), }, [OT_EG_SOC_DEV_RSTMGR] = { @@ -797,7 +804,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_ALERT(1, 24) ), .prop = IBEXDEVICEPROPDEFS( - IBEX_DEV_UINT_PROP("version", OT_RSTMGR_VERSION_EG_252) + IBEX_DEV_UINT_PROP("version", OT_RSTMGR_VERSION_EG_1_0_0) ), }, [OT_EG_SOC_DEV_CLKMGR] = { @@ -827,7 +834,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { "peri:io_div4+io_div2+io+aon+usb," "timers:io_div4+aon"), IBEX_DEV_STRING_PROP("swcg", "peri"), - IBEX_DEV_STRING_PROP("hint", "trans") + IBEX_DEV_STRING_PROP("hint", "trans"), + IBEX_DEV_UINT_PROP("version", OT_CLKMGR_VERSION_EG_1_0_0) ), }, [OT_EG_SOC_DEV_SYSRST_CTRL] = { @@ -1090,7 +1098,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), }, [OT_EG_SOC_DEV_ENTROPY_SRC] = { - .type = TYPE_OT_ENTROPY_SRC, + .type = TYPE_OT_ENTROPY_SRC_EG, .memmap = MEMMAPENTRIES( { .base = 0x41160000u } ), @@ -1182,9 +1190,13 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { IBEX_DEV_STRING_PROP(OT_COMMON_DEV_ID, "rom"), IBEX_DEV_UINT_PROP("size", 0x8000u), IBEX_DEV_UINT_PROP("kmac-app", 2u), - /* Earlgrey-M2.5.2-RC0 */ - IBEX_DEV_STRING_PROP("nonce", "755cf00bd7432c3f"), - IBEX_DEV_STRING_PROP("key", "8cd4e7eff1b9ec59ce812447c5714595") + /* + * Nonce & Key for Earlgrey 1.0.0, taken from the auto-generated + * `hw/top_earlgrey/rtl/autogen/top_earlgrey_rnd_cnst_pkg.sv` + * `RndCnstRomCtrlScrNonce` and `RndCnstRomCtrlScrKey` values. + */ + IBEX_DEV_STRING_PROP("nonce", "fee457dee82b6e06"), + IBEX_DEV_STRING_PROP("key", "663c291739ff0e7d644758fee1c58564") ), }, [OT_EG_SOC_DEV_IBEX_WRAPPER] = { diff --git a/include/hw/opentitan/ot_clkmgr.h b/include/hw/opentitan/ot_clkmgr.h index 2ade5dd8ab6d6..624143d0712b9 100644 --- a/include/hw/opentitan/ot_clkmgr.h +++ b/include/hw/opentitan/ot_clkmgr.h @@ -33,6 +33,13 @@ #define TYPE_OT_CLKMGR "ot-clkmgr" OBJECT_DECLARE_TYPE(OtClkMgrState, OtClkMgrClass, OT_CLKMGR) +/* Supported ClockManager versions */ +typedef enum { + OT_CLKMGR_VERSION_EG_1_0_0, + OT_CLKMGR_VERSION_DJ_PRE, + OT_CLKMGR_VERSION_COUNT, +} OtClkMgrVersion; + #define OT_CLOCK_HINT_PREFIX "ot-clock-hint-" #define OT_CLKMGR_CLOCK_INPUT TYPE_OT_CLKMGR "-clock-in" diff --git a/include/hw/opentitan/ot_entropy_src.h b/include/hw/opentitan/ot_entropy_src_dj.h similarity index 77% rename from include/hw/opentitan/ot_entropy_src.h rename to include/hw/opentitan/ot_entropy_src_dj.h index 3802fc1cbc3bc..7aa1ea2252878 100644 --- a/include/hw/opentitan/ot_entropy_src.h +++ b/include/hw/opentitan/ot_entropy_src_dj.h @@ -1,7 +1,8 @@ /* - * QEMU OpenTitan Entropy Source device + * QEMU OpenTitan Darjeeling Entropy Source device * * Copyright (c) 2023-2025 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -25,12 +26,12 @@ * THE SOFTWARE. */ -#ifndef HW_OPENTITAN_OT_ENTROPY_SRC_H -#define HW_OPENTITAN_OT_ENTROPY_SRC_H +#ifndef HW_OPENTITAN_OT_ENTROPY_SRC_DJ_H +#define HW_OPENTITAN_OT_ENTROPY_SRC_DJ_H #include "qom/object.h" -#define TYPE_OT_ENTROPY_SRC "ot-entropy_src" -OBJECT_DECLARE_TYPE(OtEntropySrcState, OtEntropySrcClass, OT_ENTROPY_SRC) +#define TYPE_OT_ENTROPY_SRC_DJ "ot-entropy_src-dj" +OBJECT_DECLARE_TYPE(OtEntropySrcDjState, OtEntropySrcDjClass, OT_ENTROPY_SRC_DJ) -#endif /* HW_OPENTITAN_OT_ENTROPY_SRC_H */ +#endif /* HW_OPENTITAN_OT_ENTROPY_SRC_DJ_H */ diff --git a/include/hw/opentitan/ot_entropy_src_eg.h b/include/hw/opentitan/ot_entropy_src_eg.h new file mode 100644 index 0000000000000..cd76e8303bbe0 --- /dev/null +++ b/include/hw/opentitan/ot_entropy_src_eg.h @@ -0,0 +1,37 @@ +/* + * QEMU OpenTitan Earlgrey 1.0.0 Entropy Source device + * + * Copyright (c) 2023-2025 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. + * + * Author(s): + * Emmanuel Blot + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_OPENTITAN_OT_ENTROPY_SRC_EG_H +#define HW_OPENTITAN_OT_ENTROPY_SRC_EG_H + +#include "qom/object.h" + +#define TYPE_OT_ENTROPY_SRC_EG "ot-entropy_src-eg" +OBJECT_DECLARE_TYPE(OtEntropySrcEgState, OtEntropySrcEgClass, OT_ENTROPY_SRC_EG) + +#endif /* HW_OPENTITAN_OT_ENTROPY_SRC_EG_H */ diff --git a/include/hw/opentitan/ot_pwrmgr.h b/include/hw/opentitan/ot_pwrmgr.h index 33c89ebd91ebd..5971f8e98c53a 100644 --- a/include/hw/opentitan/ot_pwrmgr.h +++ b/include/hw/opentitan/ot_pwrmgr.h @@ -36,7 +36,7 @@ OBJECT_DECLARE_TYPE(OtPwrMgrState, OtPwrMgrClass, OT_PWRMGR) /* Supported PowerManager versions */ typedef enum { - OT_PWRMGR_VERSION_EG_252, + OT_PWRMGR_VERSION_EG_1_0_0, OT_PWRMGR_VERSION_DJ_PRE, OT_PWRMGR_VERSION_COUNT, } OtPwrMgrVersion; diff --git a/include/hw/opentitan/ot_rstmgr.h b/include/hw/opentitan/ot_rstmgr.h index 09711c996e9af..727676a0323b0 100644 --- a/include/hw/opentitan/ot_rstmgr.h +++ b/include/hw/opentitan/ot_rstmgr.h @@ -35,7 +35,7 @@ OBJECT_DECLARE_TYPE(OtRstMgrState, OtRstMgrClass, OT_RSTMGR) /* Supported ResetManager versions */ typedef enum { - OT_RSTMGR_VERSION_EG_252, + OT_RSTMGR_VERSION_EG_1_0_0, OT_RSTMGR_VERSION_DJ_PRE, OT_RSTMGR_VERSION_COUNT, } OtRstMgrVersion; diff --git a/include/hw/opentitan/ot_spi_host.h b/include/hw/opentitan/ot_spi_host.h index 25f1432450fb5..ced150fa244a6 100644 --- a/include/hw/opentitan/ot_spi_host.h +++ b/include/hw/opentitan/ot_spi_host.h @@ -36,4 +36,11 @@ #define TYPE_OT_SPI_HOST "ot-spi_host" OBJECT_DECLARE_TYPE(OtSPIHostState, OtSPIHostClass, OT_SPI_HOST) +/* Supported SPI Host versions */ +typedef enum { + OT_SPI_HOST_VERSION_EG_1_0_0, + OT_SPI_HOST_VERSION_DJ_PRE, + OT_SPI_HOST_VERSION_COUNT, +} OtSPIHostVersion; + #endif /* HW_OPENTITAN_OT_SPI_HOST_H */