diff --git a/.gitlab-ci.d/opentitan/ot-smoke.yml b/.gitlab-ci.d/opentitan/ot-smoke.yml index da4ac2751cf0..21fd36878bf0 100644 --- a/.gitlab-ci.d/opentitan/ot-smoke.yml +++ b/.gitlab-ci.d/opentitan/ot-smoke.yml @@ -11,5 +11,5 @@ smoke-tests-ot: - timeout -s KILL 4 build/qemu-system-riscv32 -M ot-earlgrey,no_epmp_cfg=true -nographic -object ot-rom_img,id=rom,file=build/exit_eg.bin -d in_asm,int - timeout -s KILL 4 build/qemu-system-riscv32 -M ot-darjeeling,no_epmp_cfg=true - -object ot-rom_img,id=rom,file=build/exit_eg.bin -d in_asm,int + -object ot-rom_img,id=rom,file=build/exit_dj.bin -d in_asm,int -nographic -global ot-ibex_wrapper.lc-ignore=on diff --git a/hw/opentitan/Kconfig b/hw/opentitan/Kconfig index 2dc93fd76fb4..ad2b5dd61001 100644 --- a/hw/opentitan/Kconfig +++ b/hw/opentitan/Kconfig @@ -16,13 +16,14 @@ config OT_AON_TIMER config OT_AST_DJ select IBEX_CLOCK_SRC - select OT_RANDOM_SRC select OT_CLOCK_CTRL + select OT_NOISE_SRC bool config OT_AST_EG select IBEX_CLOCK_SRC select OT_CLOCK_CTRL + select OT_NOISE_SRC bool config OT_CLKMGR @@ -52,12 +53,8 @@ config OT_DMA config OT_EDN bool -config OT_ENTROPY_SRC_EG - select OT_RANDOM_SRC - bool - -config OT_ENTROPY_SRC_DJ - select OT_RANDOM_SRC +config OT_ENTROPY_SRC + select OT_NOISE_SRC bool config OT_FLASH @@ -112,6 +109,9 @@ config OT_MBX select OT_COMMON bool +config OT_NOISE_SRC + bool + config OT_OTBN select OT_KEY_SINK select OT_BIGNUMBER @@ -158,9 +158,6 @@ config OT_PWRMGR select OT_CLOCK_CTRL bool -config OT_RANDOM_SRC - bool - config OT_ROM_CTRL bool select OT_COMMON diff --git a/hw/opentitan/meson.build b/hw/opentitan/meson.build index 77a612c9e146..2049687268bc 100644 --- a/hw/opentitan/meson.build +++ b/hw/opentitan/meson.build @@ -18,8 +18,7 @@ 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_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_ENTROPY_SRC', if_true: [files('ot_entropy_src.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')) @@ -33,6 +32,7 @@ system_ss.add(when: 'CONFIG_OT_KEYMGR_DPE', if_true: files('ot_keymgr_dpe.c')) system_ss.add(when: 'CONFIG_OT_KMAC', if_true: [files('ot_kmac.c'), libtomcrypt_dep]) system_ss.add(when: 'CONFIG_OT_LC_CTRL', if_true: files('ot_lc_ctrl.c')) system_ss.add(when: 'CONFIG_OT_MBX', if_true: files('ot_mbx.c')) +system_ss.add(when: 'CONFIG_OT_NOISE_SRC', if_true: files('ot_noise_src.c')) system_ss.add(when: 'CONFIG_OT_OTBN', if_true: files('ot_otbn.c')) system_ss.add(when: 'CONFIG_OT_OTP', if_true: files('ot_otp.c')) system_ss.add(when: 'CONFIG_OT_OTP_BE_IF', if_true: files('ot_otp_be_if.c')) @@ -46,7 +46,6 @@ system_ss.add(when: 'CONFIG_OT_PRESENT', if_true: files('ot_present.c')) system_ss.add(when: 'CONFIG_OT_PRINCE', if_true: files('ot_prince.c')) system_ss.add(when: 'CONFIG_OT_PRNG', if_true: files('ot_prng.c')) system_ss.add(when: 'CONFIG_OT_PWRMGR', if_true: files('ot_pwrmgr.c')) -system_ss.add(when: 'CONFIG_OT_RANDOM_SRC', if_true: files('ot_random_src.c')) system_ss.add(when: 'CONFIG_OT_ROM_CTRL', if_true: files('ot_rom_ctrl.c', 'ot_rom_ctrl_img.c')) system_ss.add(when: 'CONFIG_OT_RSTMGR', if_true: files('ot_rstmgr.c')) system_ss.add(when: 'CONFIG_OT_SENSOR_EG', if_true: files('ot_sensor_eg.c')) diff --git a/hw/opentitan/ot_ast_dj.c b/hw/opentitan/ot_ast_dj.c index 2a0b97fd62ca..39a62d6752dc 100644 --- a/hw/opentitan/ot_ast_dj.c +++ b/hw/opentitan/ot_ast_dj.c @@ -37,7 +37,7 @@ #include "hw/opentitan/ot_ast_dj.h" #include "hw/opentitan/ot_clock_ctrl.h" #include "hw/opentitan/ot_common.h" -#include "hw/opentitan/ot_random_src.h" +#include "hw/opentitan/ot_noise_src.h" #include "hw/qdev-properties.h" #include "hw/registerfields.h" #include "hw/riscv/ibex_clock_src.h" @@ -134,11 +134,8 @@ static const char REGB_NAMES[REGSB_COUNT][6U] = { }; #undef REG_NAME_ENTRY -typedef struct { - QEMUTimer *timer; - uint64_t *buffer; - bool avail; -} OtASTDjRandom; +/* @todo check with HW what is the best default value */ +#define OT_AST_DJ_NOISE_BITRATE_DEFAULT 1000000u /* 1 MHz */ typedef struct { char *name; @@ -154,7 +151,6 @@ struct OtASTDjState { SysBusDevice parent_obj; MemoryRegion mmio; - OtASTDjRandom random; GList *clocks; /* OtASTDjClock */ @@ -163,6 +159,7 @@ struct OtASTDjState { char *cfg_topclocks; char *cfg_aonclocks; + uint32_t noise_bitrate; }; struct OtASTDjClass { @@ -170,56 +167,6 @@ struct OtASTDjClass { ResettablePhases parent_phases; }; -#define OT_AST_DJ_RANDOM_FILL_RATE_NS 1000000ull /* arbitrary: 1 ms */ - -/* -------------------------------------------------------------------------- */ -/* Private implementation */ -/* -------------------------------------------------------------------------- */ - -static int ot_ast_dj_get_random( - OtRandomSrcIf *dev, uint64_t random[OT_RANDOM_SRC_DWORD_COUNT], bool *fips) -{ - OtASTDjState *s = OT_AST_DJ(dev); - OtASTDjRandom *rnd = &s->random; - - if (!rnd->avail) { - /* not ready */ - trace_ot_ast_no_entropy(0); - int wait_ns; - if (timer_pending(s->random.timer)) { - wait_ns = 1; - } else { - /* computed delay fits into a 31-bit value */ - wait_ns = (int)(timer_expire_time_ns(s->random.timer) - - qemu_clock_get_ns(OT_VIRTUAL_CLOCK)); - } - return wait_ns; - } - - memcpy(random, rnd->buffer, OT_RANDOM_SRC_DWORD_COUNT * sizeof(uint64_t)); - rnd->avail = false; - - /* note: fips compliancy is only simulated here for now */ - *fips = true; - - uint64_t now = qemu_clock_get_ns(OT_VIRTUAL_CLOCK); - timer_mod(rnd->timer, (int64_t)(now + OT_AST_DJ_RANDOM_FILL_RATE_NS)); - - return 0; -} - -static void ot_ast_dj_random_scheduler(void *opaque) -{ - OtASTDjState *s = opaque; - OtASTDjRandom *rnd = &s->random; - - qemu_guest_getrandom_nofail(rnd->buffer, - OT_RANDOM_SRC_DWORD_COUNT * sizeof(uint64_t)); - - rnd->avail = true; -} - - static const char *CFGSEP = ","; static gint ot_ast_dj_match_clock_by_name(gconstpointer a, gconstpointer b) @@ -309,6 +256,21 @@ static void ot_ast_dj_clock_ext_freq_select(OtClockCtrlIf *dev, bool enable) qemu_log_mask(LOG_UNIMP, "%s: not implemented: %u\n", __func__, enable); } +static unsigned ot_ast_dj_get_fill_rate(OtNoiseSrcIf *dev) +{ + OtASTDjState *s = OT_AST_DJ(dev); + + return s->noise_bitrate / 8u; /* bit to byte */ +} + +static void ot_ast_dj_get_noise(OtNoiseSrcIf *dev, uint8_t *buffer, + size_t length) +{ + (void)dev; + + qemu_guest_getrandom_nofail((void *)buffer, length); +} + static void ot_ast_dj_parse_clocks(OtASTDjState *s, Error **errp) { if (!s->cfg_topclocks) { @@ -510,6 +472,8 @@ static void ot_ast_dj_regs_write(void *opaque, hwaddr addr, uint64_t val64, static Property ot_ast_dj_properties[] = { DEFINE_PROP_STRING("topclocks", OtASTDjState, cfg_topclocks), DEFINE_PROP_STRING("aonclocks", OtASTDjState, cfg_aonclocks), + DEFINE_PROP_UINT32("noise-bitrate", OtASTDjState, noise_bitrate, + OT_AST_DJ_NOISE_BITRATE_DEFAULT), DEFINE_PROP_END_OF_LIST(), }; @@ -525,16 +489,11 @@ static void ot_ast_dj_reset_enter(Object *obj, ResetType type) { OtASTDjClass *c = OT_AST_DJ_GET_CLASS(obj); OtASTDjState *s = OT_AST_DJ(obj); - OtASTDjRandom *rnd = &s->random; if (c->parent_phases.enter) { c->parent_phases.enter(obj, type); } - timer_del(rnd->timer); - memset(rnd->buffer, 0, OT_RANDOM_SRC_DWORD_COUNT * sizeof(uint64_t)); - rnd->avail = false; - memset(s->regsa, 0, REGSA_SIZE); memset(s->regsb, 0, REGSB_SIZE); @@ -584,15 +543,11 @@ static void ot_ast_dj_reset_exit(Object *obj, ResetType type) { OtASTDjClass *c = OT_AST_DJ_GET_CLASS(obj); OtASTDjState *s = OT_AST_DJ(obj); - OtASTDjRandom *rnd = &s->random; if (c->parent_phases.exit) { c->parent_phases.exit(obj, type); } - uint64_t now = qemu_clock_get_ns(OT_VIRTUAL_CLOCK); - timer_mod(rnd->timer, (int64_t)(now + OT_AST_DJ_RANDOM_FILL_RATE_NS)); - g_list_foreach(s->clocks, ot_ast_dj_update_clock, s); } @@ -614,11 +569,6 @@ static void ot_ast_dj_init(Object *obj) s->regsa = g_new0(uint32_t, REGSA_COUNT); s->regsb = g_new0(uint32_t, REGSB_COUNT); - - OtASTDjRandom *rnd = &s->random; - - rnd->timer = timer_new_ns(OT_VIRTUAL_CLOCK, &ot_ast_dj_random_scheduler, s); - rnd->buffer = g_new0(uint64_t, OT_RANDOM_SRC_DWORD_COUNT); } static void ot_ast_dj_class_init(ObjectClass *klass, void *data) @@ -636,15 +586,16 @@ static void ot_ast_dj_class_init(ObjectClass *klass, void *data) &ot_ast_dj_reset_exit, &ac->parent_phases); - OtRandomSrcIfClass *rdc = OT_RANDOM_SRC_IF_CLASS(klass); - rdc->get_random_values = &ot_ast_dj_get_random; - IbexClockSrcIfClass *ic = IBEX_CLOCK_SRC_IF_CLASS(klass); ic->get_clock_source = &ot_ast_dj_get_clock_source; OtClockCtrlIfClass *cc = OT_CLOCK_CTRL_IF_CLASS(klass); cc->clock_enable = &ot_ast_dj_clock_enable; cc->clock_ext_freq_select = &ot_ast_dj_clock_ext_freq_select; + + OtNoiseSrcIfClass *nc = OT_NOISE_SRC_IF_CLASS(klass); + nc->get_fill_rate = &ot_ast_dj_get_fill_rate; + nc->get_noise = &ot_ast_dj_get_noise; } static const TypeInfo ot_ast_dj_info = { @@ -656,9 +607,9 @@ static const TypeInfo ot_ast_dj_info = { .class_init = &ot_ast_dj_class_init, .interfaces = (InterfaceInfo[]){ - { TYPE_OT_RANDOM_SRC_IF }, { TYPE_IBEX_CLOCK_SRC_IF }, { TYPE_OT_CLOCK_CTRL_IF }, + { TYPE_OT_NOISE_SRC_IF }, {}, }, }; diff --git a/hw/opentitan/ot_ast_eg.c b/hw/opentitan/ot_ast_eg.c index 08d2b1102848..ecbf99ce941f 100644 --- a/hw/opentitan/ot_ast_eg.c +++ b/hw/opentitan/ot_ast_eg.c @@ -36,6 +36,7 @@ #include "hw/opentitan/ot_ast_eg.h" #include "hw/opentitan/ot_clock_ctrl.h" #include "hw/opentitan/ot_common.h" +#include "hw/opentitan/ot_noise_src.h" #include "hw/qdev-properties.h" #include "hw/registerfields.h" #include "hw/riscv/ibex_clock_src.h" @@ -132,6 +133,8 @@ static const char REGB_NAMES[REGSB_COUNT][6U] = { }; #undef REG_NAME_ENTRY +#define OT_AST_EG_NOISE_4BIT_RATE 50000u /* 50 kHz */ + typedef struct { char *name; unsigned frequency; @@ -161,16 +164,6 @@ struct OtASTEgClass { ResettablePhases parent_phases; }; -/* -------------------------------------------------------------------------- */ -/* Public API */ -/* -------------------------------------------------------------------------- */ - -void ot_ast_eg_getrandom(void *buf, size_t len) -{ - qemu_guest_getrandom_nofail(buf, len); -} - - static const char *CFGSEP = ","; static gint ot_ast_eg_match_clock_by_name(gconstpointer a, gconstpointer b) @@ -260,6 +253,21 @@ static void ot_ast_eg_clock_ext_freq_select(OtClockCtrlIf *dev, bool enable) qemu_log_mask(LOG_UNIMP, "%s: not implemented: %u\n", __func__, enable); } +static unsigned ot_ast_eg_get_fill_rate(OtNoiseSrcIf *dev) +{ + (void)dev; + + return OT_AST_EG_NOISE_4BIT_RATE / 2u; /* 4 bits to byte */ +} + +static void ot_ast_eg_get_noise(OtNoiseSrcIf *dev, uint8_t *buffer, + size_t length) +{ + (void)dev; + + qemu_guest_getrandom_nofail((void *)buffer, length); +} + static void ot_ast_eg_parse_clocks(OtASTEgState *s, Error **errp) { if (!s->cfg_topclocks) { @@ -580,6 +588,10 @@ static void ot_ast_eg_class_init(ObjectClass *klass, void *data) OtClockCtrlIfClass *cc = OT_CLOCK_CTRL_IF_CLASS(klass); cc->clock_enable = &ot_ast_eg_clock_enable; cc->clock_ext_freq_select = &ot_ast_eg_clock_ext_freq_select; + + OtNoiseSrcIfClass *nc = OT_NOISE_SRC_IF_CLASS(klass); + nc->get_fill_rate = &ot_ast_eg_get_fill_rate; + nc->get_noise = &ot_ast_eg_get_noise; } static const TypeInfo ot_ast_eg_info = { @@ -593,6 +605,7 @@ static const TypeInfo ot_ast_eg_info = { (InterfaceInfo[]){ { TYPE_IBEX_CLOCK_SRC_IF }, { TYPE_OT_CLOCK_CTRL_IF }, + { TYPE_OT_NOISE_SRC_IF }, {}, }, }; diff --git a/hw/opentitan/ot_csrng.c b/hw/opentitan/ot_csrng.c index 2f320e8381df..f21cf113f3d8 100644 --- a/hw/opentitan/ot_csrng.c +++ b/hw/opentitan/ot_csrng.c @@ -37,9 +37,9 @@ #include "hw/opentitan/ot_alert.h" #include "hw/opentitan/ot_common.h" #include "hw/opentitan/ot_csrng.h" +#include "hw/opentitan/ot_entropy_src.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" @@ -227,9 +227,9 @@ static const char *CMD_NAMES[] = { #define CMD_NAME(_cmd_) \ (((size_t)(_cmd_)) < ARRAY_SIZE(CMD_NAMES) ? CMD_NAMES[(_cmd_)] : "?") -static_assert(OT_CSRNG_PACKET_WORD_COUNT <= OT_RANDOM_SRC_WORD_COUNT, +static_assert(OT_CSRNG_PACKET_WORD_COUNT <= OT_ENTROPY_SRC_WORD_COUNT, "CSRNG packet cannot be larger than entropy_src packet"); -static_assert((OT_RANDOM_SRC_WORD_COUNT % OT_CSRNG_PACKET_WORD_COUNT) == 0, +static_assert((OT_ENTROPY_SRC_WORD_COUNT % OT_CSRNG_PACKET_WORD_COUNT) == 0, "CSRNG packet should be a multiple of entropy_src packet"); static_assert(OT_CSRNG_AES_BLOCK_SIZE + OT_CSRNG_AES_KEY_SIZE == OT_CSRNG_SEED_BYTE_COUNT, @@ -352,7 +352,7 @@ struct OtCSRNGState { OtCSRNGInstance *instances; OtCSRNGQueue cmd_requests; - DeviceState *random_src; + OtEntropySrcState *entropy_src; OtOTPState *otp_ctrl; }; @@ -421,8 +421,7 @@ static void ot_csrng_release_hw_app(OtCSRNGInstance *inst); static void ot_csrng_update_irqs(OtCSRNGState *s); static void ot_csrng_update_alerts(OtCSRNGState *s); -static OtCSRNDCmdResult -ot_csrng_drng_reseed(OtCSRNGInstance *inst, DeviceState *rand_dev, bool flag0); +static OtCSRNDCmdResult ot_csrng_drng_reseed(OtCSRNGInstance *inst, bool flag0); /* -------------------------------------------------------------------------- */ /* Client API */ @@ -658,8 +657,8 @@ static void ot_csrng_drng_increment(OtCSRNGDrng *drng) } } -static OtCSRNDCmdResult ot_csrng_drng_instantiate( - OtCSRNGInstance *inst, DeviceState *rand_dev, bool flag0) +static OtCSRNDCmdResult +ot_csrng_drng_instantiate(OtCSRNGInstance *inst, bool flag0) { OtCSRNGDrng *drng = &inst->drng; if (drng->instantiated) { @@ -680,7 +679,7 @@ static OtCSRNDCmdResult ot_csrng_drng_instantiate( memcpy(drng->key, key, OT_CSRNG_AES_KEY_SIZE); drng->instantiated = true; - res = ot_csrng_drng_reseed(inst, rand_dev, flag0); + res = ot_csrng_drng_reseed(inst, flag0); if (res) { drng->instantiated = false; return res; @@ -764,8 +763,7 @@ static void ot_csrng_drng_update(OtCSRNGInstance *inst) OT_CSRNG_AES_BLOCK_SIZE); } -static OtCSRNDCmdResult -ot_csrng_drng_reseed(OtCSRNGInstance *inst, DeviceState *rand_dev, bool flag0) +static OtCSRNDCmdResult ot_csrng_drng_reseed(OtCSRNGInstance *inst, bool flag0) { OtCSRNGState *s = inst->parent; OtCSRNGDrng *drng = &inst->drng; @@ -775,19 +773,19 @@ ot_csrng_drng_reseed(OtCSRNGInstance *inst, DeviceState *rand_dev, bool flag0) drng->seeded = false; if (!flag0) { - uint64_t buffer[OT_RANDOM_SRC_DWORD_COUNT]; + uint64_t buffer[OT_ENTROPY_SRC_DWORD_COUNT]; memset(buffer, 0, sizeof(buffer)); unsigned len = drng->material_len * sizeof(uint32_t); memcpy(buffer, drng->material, MIN(len, sizeof(buffer))); - uint64_t entropy[OT_RANDOM_SRC_DWORD_COUNT]; + uint64_t entropy[OT_ENTROPY_SRC_DWORD_COUNT]; int res; bool fips; trace_ot_csrng_request_entropy(slot); - OtRandomSrcIfClass *cls = OT_RANDOM_SRC_IF_GET_CLASS(rand_dev); - OtRandomSrcIf *randif = OT_RANDOM_SRC_IF(rand_dev); - res = cls->get_random_values(randif, entropy, &fips); + OtEntropySrcState *ess = inst->parent->entropy_src; + OtEntropySrcClass *esc = OT_ENTROPY_SRC_GET_CLASS(ess); + res = esc->get_entropy(ess, entropy, &fips); if (res < 0) { s->entropy_delay = 0; @@ -802,7 +800,7 @@ ot_csrng_drng_reseed(OtCSRNGInstance *inst, DeviceState *rand_dev, bool flag0) } /* always perform XOR which is a no-op if material_len is zero */ - for (unsigned ix = 0; ix < OT_RANDOM_SRC_DWORD_COUNT; ix++) { + for (unsigned ix = 0; ix < OT_ENTROPY_SRC_DWORD_COUNT; ix++) { buffer[ix] ^= entropy[ix]; } memcpy(drng->material, buffer, sizeof(entropy)); @@ -1136,7 +1134,7 @@ ot_csrng_handle_instantiate(OtCSRNGState *s, unsigned slot) int res; - res = ot_csrng_drng_instantiate(inst, s->random_src, flag0); + res = ot_csrng_drng_instantiate(inst, flag0); if ((res == CSRNG_CMD_OK) && !flag0) { /* if flag0 is set, entropy source is not used for reseeding */ s->regs[R_INTR_STATE] |= INTR_CS_ENTROPY_REQ_MASK; @@ -1237,7 +1235,7 @@ static OtCSRNDCmdResult ot_csrng_handle_reseed(OtCSRNGState *s, unsigned slot) } int res; - res = ot_csrng_drng_reseed(inst, s->random_src, flag0); + res = ot_csrng_drng_reseed(inst, flag0); if ((res == CSRNG_CMD_OK) && !flag0) { /* if flag0 is set, entropy source is not used for reseeding */ s->regs[R_INTR_STATE] |= INTR_CS_ENTROPY_REQ_MASK; @@ -1824,24 +1822,18 @@ static void ot_csrng_regs_write(void *opaque, hwaddr addr, uint64_t val64, if (change) { xtrace_ot_csrng_info("handling CTRL change", val32); ot_csrng_handle_enable(s); - bool granted; OtOTPClass *oc = OBJECT_GET_CLASS(OtOTPClass, s->otp_ctrl, TYPE_OT_OTP); - const OtOTPEntropyCfg *entropy_cfg = - oc->get_entropy_cfg(s->otp_ctrl); - if (entropy_cfg) { - granted = - entropy_cfg->en_csrng_sw_app_read == OT_MULTIBITBOOL8_TRUE; - } else { - /* defaults to granted if no entropy config in OTP */ - granted = true; - } - if (granted) { + const OtOTPHWCfg *hw_cfg = oc->get_hw_cfg(s->otp_ctrl); + g_assert(hw_cfg); + if (hw_cfg->en_csrng_sw_app_read_mb8 == OT_MULTIBITBOOL8_TRUE) { uint32_t sw_app_en = FIELD_EX32(val32, CTRL, SW_APP_ENABLE); s->sw_app_granted = sw_app_en == OT_MULTIBITBOOL4_TRUE; uint32_t read_int = FIELD_EX32(val32, CTRL, READ_INT_STATE); s->read_int_granted = read_int == OT_MULTIBITBOOL4_TRUE; } else { + qemu_log_mask(LOG_GUEST_ERROR, "%s: SW APP disabled in OTP\n", + __func__); s->sw_app_granted = false; s->read_int_granted = false; } @@ -1944,9 +1936,9 @@ static void ot_csrng_regs_write(void *opaque, hwaddr addr, uint64_t val64, }; static Property ot_csrng_properties[] = { - DEFINE_PROP_LINK("random_src", OtCSRNGState, random_src, TYPE_DEVICE, - DeviceState *), - DEFINE_PROP_LINK("otp_ctrl", OtCSRNGState, otp_ctrl, TYPE_OT_OTP, + DEFINE_PROP_LINK("entropy-src", OtCSRNGState, entropy_src, + TYPE_OT_ENTROPY_SRC, OtEntropySrcState *), + DEFINE_PROP_LINK("otp-ctrl", OtCSRNGState, otp_ctrl, TYPE_OT_OTP, OtOTPState *), DEFINE_PROP_END_OF_LIST(), }; @@ -2019,8 +2011,7 @@ static void ot_csrng_realize(DeviceState *dev, Error **errp) OtCSRNGState *s = OT_CSRNG(dev); (void)errp; - g_assert(s->random_src); - OBJECT_CHECK(OtRandomSrcIf, s->random_src, TYPE_OT_RANDOM_SRC_IF); + g_assert(s->entropy_src); g_assert(s->otp_ctrl); } diff --git a/hw/opentitan/ot_entropy_src.c b/hw/opentitan/ot_entropy_src.c new file mode 100644 index 000000000000..2bfee3f802c8 --- /dev/null +++ b/hw/opentitan/ot_entropy_src.c @@ -0,0 +1,1990 @@ +/* + * 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. + * + * v2: based on OpenTitan 011b6ea1fe + * v3: based on OpenTitan 5fe6fe8605 + */ + +#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_common.h" +#include "hw/opentitan/ot_entropy_src.h" +#include "hw/opentitan/ot_fifo32.h" +#include "hw/opentitan/ot_noise_src.h" +#include "hw/opentitan/ot_otp.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 NUM_ALERTS 2u +#define NUM_IRQS 4u +#define DISTR_FIFO_V2_DEPTH 2u +#define DISTR_FIFO_V3_DEPTH 3u +#define ES_FIFO_DEPTH 3u +#define OBSERVE_FIFO_DEPTH 32u +/* only in v3 */ +#define RNG_BUS_WIDTH 4u +#define RNG_BUS_BIT_SEL_WIDTH 2u +#define HEALTH_TEST_WINDOW_WIDTH 18u + +/* + * Note about the register split into different groups: + * ENTROPY_SRC module is supported in two variants, v2 and v3 + * There are very similar, but unfortunately v2 introduces a "version register" + * which has been subsequently removed in v3, and this register is inserted + * between other registers. This cause the address of all the subsequent + * registers that follow to shift down 4 bytes. In order for QEMU to support + * both versions with the same implementation, registers are therefore split + * into two groups, called "lo" and "hi", which are located on each side of + * the deprecated REV register. The register groups are mapped using two + * different memory regions, in order to simplify support for both versions. + * + * There are a couple of register bitfields that also differ between versions, + * namely the CONF and RECOV_ALERT_STS register, whose handling is specific + * to the instantiated module version. + */ + +/* clang-format off */ + +/* first group of registers, "lo" */ +REG32(INTR_STATE, 0x00u) + 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, 0x04u) +REG32(INTR_TEST, 0x08u) +REG32(ALERT_TEST, 0x0cu) + 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, VAL, 0u, 1u) +REG32(REGWEN, 0x18u) + FIELD(REGWEN, EN, 0u, 1u) + +/* second group of registers, "rev", only used with v2 */ +REG32(REV, 0x00u) + FIELD(REV, ABI_REVISION, 0u, 8u) + FIELD(REV, HW_REVISION, 8u, 8u) + FIELD(REV, CHIP_TYPE, 16u, 8u) + +/* third group of registers, "hi" */ +REG32(MODULE_ENABLE, 0x00u) + FIELD(MODULE_ENABLE, MODULE_ENABLE, 0u, 4u) +REG32(CONF, 0x04u) + /* common bitfields for all versions */ + 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) + /* bitfields only defined on version 2 */ + FIELD(CONF, V2_RNG_BIT_SEL, 16u, 2u) + FIELD(CONF, V2_THRESHOLD_SCOPE, 18u, 4u) + FIELD(CONF, V2_ENTROPY_DATA_REG_ENABLE, 22u, 4u) + /* bitfields only defined on for version 3 */ + FIELD(CONF, V3_THRESHOLD_SCOPE, 16u, 4u) + FIELD(CONF, V3_ENTROPY_DATA_REG_ENABLE, 20u, 4u) + FIELD(CONF, V3_RNG_BIT_SEL, 24u, 8u) +REG32(ENTROPY_CONTROL, 0x08u) + FIELD(ENTROPY_CONTROL, ES_ROUTE, 0u, 4u) + FIELD(ENTROPY_CONTROL, ES_TYPE, 4u, 4u) +REG32(ENTROPY_DATA, 0x0cu) +REG32(HEALTH_TEST_WINDOWS, 0x10u) + FIELD(HEALTH_TEST_WINDOWS, FIPS_WINDOW, 0u, 16u) + FIELD(HEALTH_TEST_WINDOWS, BYPASS_WINDOW, 16u, 16u) +REG32(REPCNT_THRESHOLDS, 0x14u) + SHARED_FIELD(THRESHOLDS_FIPS, 0u, 16u) + SHARED_FIELD(THRESHOLDS_BYPASS, 16u, 16u) +REG32(REPCNTS_THRESHOLDS, 0x18u) +REG32(ADAPTP_HI_THRESHOLDS, 0x1cu) +REG32(ADAPTP_LO_THRESHOLDS, 0x20u) +REG32(BUCKET_THRESHOLDS, 0x24u) +REG32(MARKOV_HI_THRESHOLDS, 0x28u) +REG32(MARKOV_LO_THRESHOLDS, 0x2cu) +REG32(EXTHT_HI_THRESHOLDS, 0x30u) +REG32(EXTHT_LO_THRESHOLDS, 0x34u) +REG32(REPCNT_HI_WATERMARKS, 0x38u) + SHARED_FIELD(WATERMARK_FIPS, 0u, 16u) + SHARED_FIELD(WATERMARK_BYPASS, 16u, 16u) +REG32(REPCNTS_HI_WATERMARKS, 0x3cu) +REG32(ADAPTP_HI_WATERMARKS, 0x40u) +REG32(ADAPTP_LO_WATERMARKS, 0x44u) +REG32(EXTHT_HI_WATERMARKS, 0x48u) +REG32(EXTHT_LO_WATERMARKS, 0x4cu) +REG32(BUCKET_HI_WATERMARKS, 0x50u) +REG32(MARKOV_HI_WATERMARKS, 0x54u) +REG32(MARKOV_LO_WATERMARKS, 0x58u) +REG32(REPCNT_TOTAL_FAILS, 0x5cu) +REG32(REPCNTS_TOTAL_FAILS, 0x60u) +REG32(ADAPTP_HI_TOTAL_FAILS, 0x64u) +REG32(ADAPTP_LO_TOTAL_FAILS, 0x68u) +REG32(BUCKET_TOTAL_FAILS, 0x6cu) +REG32(MARKOV_HI_TOTAL_FAILS, 0x70u) +REG32(MARKOV_LO_TOTAL_FAILS, 0x74u) +REG32(EXTHT_HI_TOTAL_FAILS, 0x78u) +REG32(EXTHT_LO_TOTAL_FAILS, 0x7cu) +REG32(ALERT_THRESHOLD, 0x80u) + FIELD(ALERT_THRESHOLD, VAL, 0u, 16u) + FIELD(ALERT_THRESHOLD, INV, 16u, 16u) +REG32(ALERT_SUMMARY_FAIL_COUNTS, 0x84u) + FIELD(ALERT_SUMMARY_FAIL_COUNTS, ANY_FAIL_COUNT, 0u, 16u) +REG32(ALERT_FAIL_COUNTS, 0x88u) + 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, 0x8cu) + FIELD(EXTHT_FAIL_COUNTS, EXTHT_HI_FAIL_COUNT, 0u, 4u) + FIELD(EXTHT_FAIL_COUNTS, EXTHT_LO_FAIL_COUNT, 4u, 4u) +REG32(FW_OV_CONTROL, 0x90u) + FIELD(FW_OV_CONTROL, FW_OV_MODE, 0u, 4u) + FIELD(FW_OV_CONTROL, FW_OV_ENTROPY_INSERT, 4u, 4u) +REG32(FW_OV_SHA3_START, 0x94u) + FIELD(FW_OV_SHA3_START, FW_OV_INSERT_START, 0u, 4u) +REG32(FW_OV_WR_FIFO_FULL, 0x98u) + FIELD(FW_OV_WR_FIFO_FULL, VAL, 0u, 1u) +REG32(FW_OV_RD_FIFO_OVERFLOW, 0x9cu) + FIELD(FW_OV_RD_FIFO_OVERFLOW, VAL, 0u, 1u) +REG32(FW_OV_RD_DATA, 0xa0u) +REG32(FW_OV_WR_DATA, 0xa4u) +REG32(OBSERVE_FIFO_THRESH, 0xa8u) + FIELD(OBSERVE_FIFO_THRESH, VAL, 0u, 6u) +REG32(OBSERVE_FIFO_DEPTH, 0xacu) + FIELD(OBSERVE_FIFO_DEPTH, VAL, 0u, 6u) +REG32(DEBUG_STATUS, 0xb0u) + 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, 0xb4u) + 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_SHA3_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, 0xb8u) + 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, 0xbcu) + FIELD(ERR_CODE_TEST, VAL, 0u, 5u) +REG32(MAIN_SM_STATE, 0xc0u) + FIELD(MAIN_SM_STATE, VAL, 0u, 9u) +/* clang-format on */ + +#define INTR_WMASK \ + (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_WMASK \ + (R_ALERT_TEST_RECOV_ALERT_MASK | R_ALERT_TEST_FATAL_ALERT_MASK) +#define CONF_V2_WMASK \ + (R_CONF_FIPS_ENABLE_MASK | R_CONF_FIPS_FLAG_MASK | R_CONF_RNG_FIPS_MASK | \ + R_CONF_RNG_BIT_ENABLE_MASK | R_CONF_V2_RNG_BIT_SEL_MASK | \ + R_CONF_V2_THRESHOLD_SCOPE_MASK | R_CONF_V2_ENTROPY_DATA_REG_ENABLE_MASK) +#define CONF_V3_WMASK UINT32_MAX +#define ENTROPY_CONTROL_WMASK \ + (R_ENTROPY_CONTROL_ES_ROUTE_MASK | R_ENTROPY_CONTROL_ES_TYPE_MASK) +#define FW_OV_CONTROL_WMASK \ + (R_FW_OV_CONTROL_FW_OV_MODE_MASK | \ + R_FW_OV_CONTROL_FW_OV_ENTROPY_INSERT_MASK) +#define RECOV_ALERT_STS_WMASK \ + (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_SHA3_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) + +/* + * this is an alias for the CHECK_MULTIBOOT macro, as the RECOV_ALERT_STS + * bit for the FW_OV_SHA3_START register is the only register bit that does + * not follow the same naming as its relative register + * */ +#define R_RECOV_ALERT_STS_FW_OV_INSERT_START_FIELD_ALERT_SHIFT \ + R_RECOV_ALERT_STS_FW_OV_SHA3_START_FIELD_ALERT_SHIFT + +#define ALERT_STATUS_BIT(_x_) R_RECOV_ALERT_STS_##_x_##_FIELD_ALERT_SHIFT + +#define R32_OFF(_r_) ((_r_) / sizeof(uint32_t)) + +#define R_LAST_LO_REG (R_REGWEN) +#define REGS_LO_COUNT (R_LAST_LO_REG + 1u) +#define REGS_LO_SIZE (REGS_LO_COUNT * sizeof(uint32_t)) +#define REGS_LO_BASE 0x00u +#define REG_LO_NAME(_reg_) \ + ((((_reg_) <= REGS_LO_COUNT) && REG_LO_NAMES[_reg_]) ? \ + REG_LO_NAMES[_reg_] : \ + "?") + +/* only used in version 2 */ +#define R_LAST_REV_REG (R_REV) +#define REGS_REV_COUNT (R_LAST_REV_REG + 1u) +#define REGS_REV_SIZE (REGS_REV_COUNT * sizeof(uint32_t)) +#define REGS_REV_BASE 0x1cu +#define REG_REV_NAME(_reg_) \ + ((((_reg_) <= REGS_REV_COUNT) && REG_REV_NAMES[_reg_]) ? \ + REG_REV_NAMES[_reg_] : \ + "?") + +#define R_LAST_HI_REG (R_MAIN_SM_STATE) +#define REGS_HI_COUNT (R_LAST_HI_REG + 1u) +#define REGS_HI_SIZE (REGS_HI_COUNT * sizeof(uint32_t)) +#define REGS_HI_V2_BASE 0x20u +#define REGS_HI_V3_BASE 0x1cu +#define REG_HI_NAME(_reg_) \ + ((((_reg_) <= REGS_HI_COUNT) && REG_HI_NAMES[_reg_]) ? \ + REG_HI_NAMES[_reg_] : \ + "?") + +#define REG_NAME_ENTRY(_reg_) [R_##_reg_] = stringify(_reg_) +static const char *REG_LO_NAMES[REGS_LO_COUNT] = { + /* clang-format off */ + 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), + /* clang-format on */ +}; + +/* only used in version 2 */ +static const char *REG_REV_NAMES[REGS_REV_COUNT] = { + /* clang-format off */ + REG_NAME_ENTRY(REV), + /* clang-format on */ +}; + +static const char *REG_HI_NAMES[REGS_HI_COUNT] = { + /* clang-format off */ + 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), + /* clang-format on */ +}; +#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 OT_ENTROPY_SRC_FILL_WORD_COUNT (ES_FILL_BITS / (8u * sizeof(uint32_t))) +#define ES_WORD_COUNT (OT_ENTROPY_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 */ +/* + * 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 */ + +enum { + ALERT_RECOVERABLE, + ALERT_FATAL, + ALERT_COUNT, +}; + +static_assert(ALERT_COUNT == 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_MSG_DONE, + ENTROPY_SRC_SHA3_PROCESS, + ENTROPY_SRC_SHA3_VALID, + ENTROPY_SRC_SHA3_DONE, + ENTROPY_SRC_ALERT_STATE, + ENTROPY_SRC_ALERT_HANG, + ENTROPY_SRC_ERROR, +} OtEntropySrcFsmState; + +struct OtEntropySrcState { + SysBusDevice parent_obj; + + MemoryRegion mmio; + MemoryRegion mmio_lo; + MemoryRegion mmio_rev; /* only in v2 */ + MemoryRegion mmio_hi; + IbexIRQ irqs[NUM_IRQS]; + IbexIRQ alerts[NUM_ALERTS]; + QEMUTimer *scheduler; + + uint32_t *regs_lo; + uint32_t *regs_rev; /* only on v2 */ + uint32_t *regs_hi; + + 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 */ + OtEntropySrcFsmState state; + uint64_t noise_fill_pace_ns; + 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 */ + + char *ot_id; + unsigned version; /* emulated version */ + DeviceState *noise_src; + OtOTPState *otp_ctrl; +}; + +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_MSG_DONE] = 0b100001111, + [ENTROPY_SRC_SHA3_PROCESS] = 0b011111000, + [ENTROPY_SRC_SHA3_VALID] = 0b010111111, + [ENTROPY_SRC_SHA3_DONE] = 0b110011000, + [ENTROPY_SRC_ALERT_STATE] = 0b111001101, + [ENTROPY_SRC_ALERT_HANG] = 0b111111011, + [ENTROPY_SRC_ERROR] = 0b001110011, +}; + +#define STATE_NAME_ENTRY(_st_) [ENTROPY_SRC_##_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_MSG_DONE), + STATE_NAME_ENTRY(SHA3_PROCESS), + STATE_NAME_ENTRY(SHA3_VALID), + STATE_NAME_ENTRY(SHA3_DONE), + 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_, _g_, _reg_, _fld_) \ + (FIELD_EX32((_s_)->regs##_##_g_[R_##_reg_], _reg_, _fld_) == \ + OT_MULTIBITBOOL4_TRUE) +#define REG_MB4_IS_FALSE(_s_, _g_, _reg_, _fld_) \ + (FIELD_EX32((_s_)->regs##_##_g_[R_##_reg_], _reg_, _fld_) == \ + OT_MULTIBITBOOL4_FALSE) + +#define xtrace_ot_entropy_src_show_buffer(_s_, _msg_, _buf_, _len_) \ + ot_entropy_src_show_buffer(_s_, __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 int ot_entropy_src_get_entropy( + OtEntropySrcState *ess, uint64_t random[OT_ENTROPY_SRC_DWORD_COUNT], + bool *fips) +{ + if (!ot_entropy_src_is_module_enabled(ess)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: entropy_src is down\n", __func__); + return -1; + } + + bool fips_compliant; + + switch (ess->state) { + case ENTROPY_SRC_BOOT_PHASE_DONE: + fips_compliant = false; + break; + case ENTROPY_SRC_CONT_HT_RUNNING: + case ENTROPY_SRC_CONT_HT_START: + case ENTROPY_SRC_SHA3_MSG_DONE: + case ENTROPY_SRC_SHA3_PROCESS: + case ENTROPY_SRC_SHA3_VALID: + case ENTROPY_SRC_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: { + int64_t wait_ns; + if (timer_pending(ess->scheduler)) { + /* computed delay fits into a 31-bit value */ + wait_ns = ((int64_t)timer_expire_time_ns(ess->scheduler)) - + qemu_clock_get_ns(OT_VIRTUAL_CLOCK); + wait_ns = MAX(wait_ns, OT_ENTROPY_SRC_WAIT_DELAY_NS); + } else { + wait_ns = OT_ENTROPY_SRC_WAIT_DELAY_NS; + } + trace_ot_entropy_src_init_ongoing(ess->ot_id, STATE_NAME(ess->state), + ess->state, (int)wait_ns); + /* not ready */ + return (int)wait_ns; + } + case ENTROPY_SRC_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_ALERT_STATE: + case ENTROPY_SRC_ALERT_HANG: + case ENTROPY_SRC_ERROR: + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid state: [%s:%d]\n", __func__, + STATE_NAME(ess->state), ess->state); + return -1; + } + + if (!ot_entropy_src_is_hw_route(ess)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: HW route not selected\n", __func__); + return -1; + } + + if (ot_fifo32_num_used(&ess->final_fifo) < ES_WORD_COUNT) { + trace_ot_entropy_src_no_entropy(ess->ot_id, + ot_fifo32_num_used(&ess->final_fifo)); + return OT_ENTROPY_SRC_WAIT_DELAY_NS; + } + + uint32_t *randu32 = (uint32_t *)random; + size_t pos = 0; + while (pos < ES_WORD_COUNT) { + g_assert(!ot_fifo32_is_empty(&ess->final_fifo)); + randu32[pos++] = ot_fifo32_pop(&ess->final_fifo); + } + + bool fips_capable = ot_entropy_src_is_fips_capable(ess); + + /* note: fips compliancy is only simulated here for now */ + *fips = fips_compliant && fips_capable; + + trace_ot_entropy_src_get_random_fips( + ess->ot_id, STATE_NAME(ess->state), ot_entropy_src_is_fips_enabled(ess), + REG_MB4_IS_TRUE(ess, hi, ENTROPY_CONTROL, ES_ROUTE), + REG_MB4_IS_TRUE(ess, hi, ENTROPY_CONTROL, ES_TYPE), + REG_MB4_IS_FALSE(ess, hi, CONF, RNG_BIT_ENABLE), fips_capable, + fips_compliant, *fips); + + if (ot_fifo32_num_used(&ess->final_fifo) < ES_WORD_COUNT) { + ot_entropy_src_update_filler(ess); + } + + return 0; +} + +static void ot_entropy_src_show_buffer( + const OtEntropySrcState *s, 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(s->ot_id, func, line, msg, hexstr); + } +} + +static inline uint32_t ot_entropy_src_hi_reg_base(const OtEntropySrcState *s) +{ + return (s->version < 3) ? REGS_HI_V2_BASE : REGS_HI_V3_BASE; +} + +static inline uint32_t +ot_entropy_src_hi_reg_addr(const OtEntropySrcState *s, uint32_t addr) +{ + return ot_entropy_src_hi_reg_base(s) + addr; +} + +static bool ot_entropy_src_is_module_enabled(const OtEntropySrcState *s) +{ + return REG_MB4_IS_TRUE(s, hi, MODULE_ENABLE, MODULE_ENABLE); +} + +static bool ot_entropy_src_is_module_disabled(const OtEntropySrcState *s) +{ + return REG_MB4_IS_FALSE(s, hi, MODULE_ENABLE, MODULE_ENABLE); +} + +static bool ot_entropy_src_is_fips_enabled(const OtEntropySrcState *s) +{ + return REG_MB4_IS_TRUE(s, hi, CONF, FIPS_ENABLE); +} + +static void ot_entropy_src_update_irqs(OtEntropySrcState *s) +{ + uint32_t levels = s->regs_lo[R_INTR_STATE] & s->regs_lo[R_INTR_ENABLE]; + for (unsigned ix = 0; ix < NUM_IRQS; ix++) { + ibex_irq_set(&s->irqs[ix], (int)((levels >> ix) & 0x1u)); + } +} + +static bool +ot_entropy_src_is_final_fifo_slot_available(const OtEntropySrcState *s) +{ + return ot_fifo32_num_free(&s->final_fifo) >= ES_WORD_COUNT; +} + +static bool ot_entropy_src_is_hw_route(const OtEntropySrcState *s) +{ + return REG_MB4_IS_FALSE(s, hi, ENTROPY_CONTROL, ES_ROUTE); +} + +static bool ot_entropy_src_is_fw_route(const OtEntropySrcState *s) +{ + return REG_MB4_IS_TRUE(s, hi, ENTROPY_CONTROL, ES_ROUTE); +} + +static bool ot_entropy_src_is_bypass_mode(const OtEntropySrcState *s) +{ + return !ot_entropy_src_is_fips_enabled(s) || + (ot_entropy_src_is_fw_route(s) && + REG_MB4_IS_TRUE(s, hi, ENTROPY_CONTROL, ES_TYPE)); +} + +static bool ot_entropy_src_is_fw_ov_mode(const OtEntropySrcState *s) +{ + return REG_MB4_IS_TRUE(s, hi, FW_OV_CONTROL, FW_OV_MODE); +} + +static bool ot_entropy_src_is_fw_ov_entropy_insert(const OtEntropySrcState *s) +{ + return REG_MB4_IS_TRUE(s, hi, FW_OV_CONTROL, FW_OV_ENTROPY_INSERT); +} + +static bool ot_entropy_src_is_fips_capable(const OtEntropySrcState *s) +{ + return ot_entropy_src_is_fips_enabled(s) && + !(REG_MB4_IS_TRUE(s, hi, ENTROPY_CONTROL, ES_ROUTE) && + REG_MB4_IS_TRUE(s, hi, ENTROPY_CONTROL, ES_TYPE)) && + REG_MB4_IS_FALSE(s, hi, CONF, RNG_BIT_ENABLE); +} + +static unsigned ot_alert_get_alert_fail_count(const OtEntropySrcState *s) +{ + unsigned count; + + count = FIELD_EX32(s->regs_hi[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + REPCNT_FAIL_COUNT); + count += FIELD_EX32(s->regs_hi[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + ADAPTP_HI_FAIL_COUNT); + count += FIELD_EX32(s->regs_hi[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + ADAPTP_LO_FAIL_COUNT); + count += FIELD_EX32(s->regs_hi[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + BUCKET_FAIL_COUNT); + count += FIELD_EX32(s->regs_hi[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + MARKOV_HI_FAIL_COUNT); + count += FIELD_EX32(s->regs_hi[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + MARKOV_LO_FAIL_COUNT); + count += FIELD_EX32(s->regs_hi[R_ALERT_FAIL_COUNTS], ALERT_FAIL_COUNTS, + REPCNTS_FAIL_COUNT); + + return count; +} + +static void ot_entropy_src_change_state_line( + OtEntropySrcState *s, OtEntropySrcFsmState state, int line) +{ + OtEntropySrcFsmState old_state = s->state; + + switch (s->state) { + case ENTROPY_SRC_ALERT_STATE: + s->state = ENTROPY_SRC_ALERT_HANG; + break; + case ENTROPY_SRC_ALERT_HANG: + if ((state == ENTROPY_SRC_IDLE) && + ot_entropy_src_is_module_disabled(s)) { + s->state = state; + } + break; + default: + s->state = state; + break; + } + + if (old_state != s->state) { + trace_ot_entropy_src_change_state(s->ot_id, line, STATE_NAME(old_state), + old_state, STATE_NAME(s->state), + s->state); + } + + if (s->state == ENTROPY_SRC_ERROR) { + s->regs_hi[R_ERR_CODE] |= R_ERR_CODE_ES_MAIN_SM_ERR_MASK; + ot_entropy_src_update_alerts(s); + } +} + +#define ot_entropy_src_change_state(_s_, _st_) \ + ot_entropy_src_change_state_line(_s_, _st_, __LINE__) + +static void ot_entropy_src_update_alerts(OtEntropySrcState *s) +{ + unsigned alert_threshold = + FIELD_EX32(s->regs_hi[R_ALERT_THRESHOLD], ALERT_THRESHOLD, VAL); + unsigned alert_count = ot_alert_get_alert_fail_count(s); + bool recoverable = (bool)s->regs_hi[R_RECOV_ALERT_STS]; + uint32_t level = s->regs_lo[R_ALERT_TEST]; + if (alert_count >= alert_threshold || recoverable) { + level |= 1u << ALERT_RECOVERABLE; + } + uint32_t fatal_alert = s->regs_hi[R_ERR_CODE] & ERR_CODE_FATAL_ERROR_MASK; + fatal_alert |= + (1u << s->regs_hi[R_ERR_CODE_TEST]) & ERR_CODE_FATAL_ERROR_MASK; + if (fatal_alert) { + level |= 1u << ALERT_FATAL; + } + + for (unsigned ix = 0; ix < NUM_ALERTS; ix++) { + ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + } +} + +static bool ot_entropy_src_check_multibitboot( + OtEntropySrcState *s, uint8_t mbbool, uint32_t alert_bit) +{ + switch (mbbool) { + case OT_MULTIBITBOOL4_TRUE: + case OT_MULTIBITBOOL4_FALSE: + return true; + default: + break; + } + + s->regs_hi[R_RECOV_ALERT_STS] |= 1u << alert_bit; + ot_entropy_src_update_alerts(s); + return false; +} + +static bool ot_entropy_src_can_consume_entropy(const OtEntropySrcState *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)); +} + +static void ot_entropy_src_update_filler(OtEntropySrcState *s) +{ + /* fill granule is OT_ENTROPY_SRC_FILL_WORD_COUNT bits */ + bool input = + ot_fifo32_num_free(&s->input_fifo) >= OT_ENTROPY_SRC_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 accept_entropy = input && output && process; + trace_ot_entropy_src_update_filler(s->ot_id, 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(s->ot_id, "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(s->ot_id, "reschedule"); + uint64_t now = qemu_clock_get_ns(OT_VIRTUAL_CLOCK); + timer_mod(s->scheduler, (int64_t)(now + s->noise_fill_pace_ns)); + } + } +} + +static bool ot_entropy_src_can_condition_entropy(const OtEntropySrcState *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)) { + /* room in output FIFO */ + return true; + } + + return false; +} + +static bool ot_entropy_src_can_bypass_entropy(const OtEntropySrcState *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)) { + /* room in output FIFO */ + return true; + } + + return false; +} + +static bool +ot_entropy_src_push_entropy_to_conditioner(OtEntropySrcState *s, uint32_t word) +{ + int res; + if (s->cond_word == 0) { + res = sha3_384_init(&s->sha3_state); + 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_change_state(s, ENTROPY_SRC_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(s, "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_can_hash(const OtEntropySrcState *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) +{ + uint32_t hash[OT_ENTROPY_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_show_buffer(s, "sha3 md", hash, + OT_ENTROPY_SRC_WORD_COUNT * + sizeof(uint32_t)); + + ot_entropy_src_change_state(s, ENTROPY_SRC_SHA3_MSG_DONE); + + for (unsigned ix = 0; ix < OT_ENTROPY_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_change_state(s, REG_MB4_IS_TRUE(s, hi, FW_OV_SHA3_START, + FW_OV_INSERT_START) ? + ENTROPY_SRC_IDLE : + ENTROPY_SRC_CONT_HT_START); +} + +static bool +ot_entropy_src_push_bypass_entropy(OtEntropySrcState *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 */ + 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(s->ot_id, + ot_fifo32_num_used( + &s->final_fifo) / + OT_ENTROPY_SRC_WORD_COUNT); + + return true; +} + +static void ot_entropy_src_update_fw_route(OtEntropySrcState *s) +{ + if (ot_fifo32_num_used(&s->final_fifo) >= ES_WORD_COUNT) { + trace_ot_entropy_src_info(s->ot_id, "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_lo[R_INTR_STATE] |= INTR_ES_ENTROPY_VALID_MASK; + trace_ot_entropy_src_available(s->ot_id, STATE_NAME(s->state), + s->state); + ot_entropy_src_update_filler(s); + } + } +} + +static bool ot_entropy_src_consume_entropy(OtEntropySrcState *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); + + 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); + } + + if (!(fill_obs_fifo || hw_path)) { + /* no way to consume noise, stop here */ + trace_ot_entropy_src_info(s->ot_id, "cannot consume noise for now"); + return false; + } + + s->noise_count += 1u; + trace_ot_entropy_src_consume_entropy(s->ot_id, 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(s->ot_id, "observe FIFO overflow", + STATE_NAME(s->state), s->state); + s->regs_hi[R_FW_OV_RD_FIFO_OVERFLOW] |= + R_FW_OV_RD_FIFO_OVERFLOW_VAL_MASK; + } else { + if (s->obs_fifo_en) { + unsigned threshold = s->regs_hi[R_OBSERVE_FIFO_THRESH]; + ot_fifo32_push(&s->observe_fifo, word); + trace_ot_entropy_src_obs_fifo(s->ot_id, + 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(s->ot_id, "observe FIFO is full"); + s->obs_fifo_en = false; + } + /* is it > or >= ? */ + if (ot_fifo32_num_used(&s->observe_fifo) >= threshold) { + s->regs_lo[R_INTR_STATE] |= INTR_ES_OBSERVE_FIFO_READY_MASK; + } + } else { + trace_ot_entropy_src_info(s->ot_id, "observe FIFO not enabled"); + } + } + } + + if (hw_path) { + if (ot_entropy_src_is_bypass_mode(s)) { + ot_entropy_src_push_bypass_entropy(s, word); + } else { + if (ot_entropy_src_push_entropy_to_conditioner(s, word)) { + if (ot_entropy_src_can_hash(s)) { + trace_ot_entropy_src_info(s->ot_id, "can hash"); + ot_entropy_src_perform_hash(s); + } + } + } + } + + if (ot_entropy_src_is_fw_route(s)) { + ot_entropy_src_update_fw_route(s); + } + + return true; +} + +static uint32_t ot_entropy_src_get_entropy_data(OtEntropySrcState *s) +{ + bool is_entropy_data_enabled = + (s->version < 3) ? + REG_MB4_IS_TRUE(s, hi, CONF, V2_ENTROPY_DATA_REG_ENABLE) : + REG_MB4_IS_TRUE(s, hi, CONF, V3_ENTROPY_DATA_REG_ENABLE); + + if (ot_entropy_src_is_module_enabled(s) && is_entropy_data_enabled && + ot_entropy_src_is_fw_route(s)) { + if (!ot_fifo32_is_empty(&s->swread_fifo)) { + return ot_fifo32_pop(&s->swread_fifo); + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: Entropy data not available\n", + __func__); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Entropy data not configured\n", + __func__); + } + + return 0u; +} + +static bool ot_entropy_src_fill_noise(OtEntropySrcState *s) +{ + unsigned count = ot_fifo32_num_free(&s->input_fifo); + if (count < OT_ENTROPY_SRC_FILL_WORD_COUNT) { + /* no room left, should be resheduled */ + return false; + } + + uint32_t buffer[OT_ENTROPY_SRC_FILL_WORD_COUNT]; + /* synchronous read */ + OtNoiseSrcIfClass *nsc = OT_NOISE_SRC_IF_GET_CLASS(s->noise_src); + OtNoiseSrcIf *nsi = OT_NOISE_SRC_IF(s->noise_src); + nsc->get_noise(nsi, (uint8_t *)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(s->ot_id, 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_consume_entropy(s, ot_fifo32_pop(&s->input_fifo))) { + break; + } + } + + ot_entropy_src_update_irqs(s); + + return true; +} + +static void ot_entropy_src_noise_refill(void *opaque) +{ + OtEntropySrcState *s = opaque; + + if (!ot_entropy_src_fill_noise(s)) { + trace_ot_entropy_src_info(s->ot_id, "FIFO already filled up"); + return; + } + + switch (s->state) { + case ENTROPY_SRC_BOOT_HT_RUNNING: + if (s->packet_count > 0) { + ot_entropy_src_change_state(s, ENTROPY_SRC_BOOT_PHASE_DONE); + } + break; + case ENTROPY_SRC_STARTUP_HT_START: + ot_entropy_src_change_state(s, ENTROPY_SRC_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_VALID: + case ENTROPY_SRC_SHA3_PROCESS: + case ENTROPY_SRC_SHA3_DONE: + case ENTROPY_SRC_SHA3_MSG_DONE: + break; + default: + trace_ot_entropy_src_error(s->ot_id, "unexpected state", + STATE_NAME(s->state), s->state); + break; + } + + ot_entropy_src_update_filler(s); +} + +static void ot_entropy_src_scheduler(void *opaque) +{ + OtEntropySrcState *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_VALID: + case ENTROPY_SRC_SHA3_PROCESS: + case ENTROPY_SRC_SHA3_DONE: + case ENTROPY_SRC_SHA3_MSG_DONE: + ot_entropy_src_noise_refill(s); + break; + case ENTROPY_SRC_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_ALERT_STATE: + case ENTROPY_SRC_ALERT_HANG: + case ENTROPY_SRC_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); +} + +static uint64_t +ot_entropy_src_lo_regs_read(void *opaque, hwaddr addr, unsigned size) +{ + OtEntropySrcState *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: + val32 = s->regs_lo[reg]; + break; + case R_REGWEN: + val32 = (uint32_t)(s->regs_lo[R_SW_REGUPD] == R_SW_REGUPD_VAL_MASK && + ot_entropy_src_is_module_disabled(s)); + break; + case R_INTR_TEST: + case R_ALERT_TEST: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: W/O register 0x%02" HWADDR_PRIx " (%s)\n", + __func__, s->ot_id, addr, REG_LO_NAME(reg)); + val32 = 0; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, + s->ot_id, addr); + val32 = 0; + break; + } + uint32_t pc = ibex_get_current_pc(); + trace_ot_entropy_src_io_read_out(s->ot_id, (uint32_t)addr, REG_LO_NAME(reg), + val32, pc); + + return (uint64_t)val32; +} + +static uint64_t +ot_entropy_src_rev_regs_read(void *opaque, hwaddr addr, unsigned size) +{ + OtEntropySrcState *s = opaque; + (void)size; + uint32_t val32; + + g_assert(s->version < 3 && s->regs_rev); + + hwaddr reg = R32_OFF(addr); + + /* NOLINTNEXTLINE(hicpp-multiway-paths-covered) */ + switch (reg) { + case R_REV: + val32 = s->regs_rev[reg]; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, + s->ot_id, addr + REGS_REV_BASE); + val32 = 0; + break; + } + uint32_t pc = ibex_get_current_pc(); + trace_ot_entropy_src_io_read_out(s->ot_id, (uint32_t)addr + REGS_REV_BASE, + REG_REV_NAME(reg), val32, pc); + + return (uint64_t)val32; +} + +static uint64_t +ot_entropy_src_hi_regs_read(void *opaque, hwaddr addr, unsigned size) +{ + OtEntropySrcState *s = opaque; + (void)size; + uint32_t val32; + + hwaddr reg = R32_OFF(addr); + + switch (reg) { + 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_hi[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_IDLE)); + val32 = FIELD_DP32(val32, DEBUG_STATUS, MAIN_SM_BOOT_DONE, + (uint32_t)(s->state == ENTROPY_SRC_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]; + } + break; + case R_ALERT_SUMMARY_FAIL_COUNTS: + val32 = (uint32_t)ot_alert_get_alert_fail_count(s); + break; + case R_ENTROPY_DATA: + val32 = ot_entropy_src_get_entropy_data(s); + 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); + } else { + can_write = ot_entropy_src_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_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_FW_OV_WR_DATA: + qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: W/O register 0x%02x (%s)\n", + __func__, s->ot_id, ot_entropy_src_hi_reg_addr(s, addr), + REG_HI_NAME(reg)); + val32 = 0; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: Bad offset 0x%x\n", __func__, + s->ot_id, ot_entropy_src_hi_reg_addr(s, addr)); + val32 = 0; + break; + } + uint32_t pc = ibex_get_current_pc(); + trace_ot_entropy_src_io_read_out(s->ot_id, + ot_entropy_src_hi_reg_addr(s, addr), + REG_HI_NAME(reg), val32, pc); + + return (uint64_t)val32; +} + +#define CHECK_MULTIBOOT(_s_, _g_, _r_, _b_) \ + do { \ + if (!ot_entropy_src_check_multibitboot( \ + (_s_), FIELD_EX32(s->regs##_##_g_[R_##_r_], _r_, _b_), \ + ALERT_STATUS_BIT(_b_))) { \ + qemu_log_mask(LOG_GUEST_ERROR, \ + "%s: %s: invalid multiboot value 0x%1x\n", __func__, \ + (_s_)->ot_id, \ + FIELD_EX32((_s_)->regs##_##_g_[R_##_r_], _r_, _b_)); \ + } \ + } while (0) + +#define CHECK_MULTIBOOT_VER(_s_, _g_, _r_, _v_, _b_) \ + do { \ + if (!ot_entropy_src_check_multibitboot( \ + (_s_), FIELD_EX32(s->regs##_##_g_[R_##_r_], _r_, _v_##_##_b_), \ + ALERT_STATUS_BIT(_b_))) { \ + qemu_log_mask(LOG_GUEST_ERROR, \ + "%s: %s: invalid multiboot value 0x%1x\n", __func__, \ + (_s_)->ot_id, \ + FIELD_EX32((_s_)->regs##_##_g_[R_##_r_], _r_, \ + _v_##_##_b_)); \ + } \ + } while (0) + +static void ot_entropy_src_lo_regs_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned size) +{ + OtEntropySrcState *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(s->ot_id, (uint32_t)addr, REG_LO_NAME(reg), + val32, pc); + + switch (reg) { + case R_INTR_STATE: + val32 &= INTR_WMASK; + s->regs_lo[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_lo[R_INTR_STATE] |= INTR_ES_ENTROPY_VALID_MASK; + } + if (!ot_fifo32_is_empty(&s->observe_fifo)) { + s->regs_lo[R_INTR_STATE] |= INTR_ES_OBSERVE_FIFO_READY_MASK; + } + ot_entropy_src_update_irqs(s); + break; + case R_INTR_ENABLE: + val32 &= INTR_WMASK; + s->regs_lo[reg] = val32; + ot_entropy_src_update_irqs(s); + break; + case R_INTR_TEST: + val32 &= INTR_WMASK; + s->regs_lo[R_INTR_STATE] |= val32; + ot_entropy_src_update_irqs(s); + break; + case R_ALERT_TEST: + val32 &= ALERT_TEST_WMASK; + s->regs_lo[reg] = val32; + ot_entropy_src_update_alerts(s); + break; + case R_ME_REGWEN: + val32 &= R_ME_REGWEN_EN_MASK; + s->regs_lo[reg] &= val32; /* RW0C */ + break; + case R_SW_REGUPD: + val32 &= R_SW_REGUPD_VAL_MASK; + s->regs_lo[reg] &= val32; /* RW0C */ + break; + case R_REGWEN: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: R/O register 0x%02" HWADDR_PRIx " (%s)\n", + __func__, s->ot_id, addr, REG_LO_NAME(reg)); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, + s->ot_id, addr); + break; + } +}; + +static void ot_entropy_src_rev_regs_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned size) +{ + OtEntropySrcState *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(s->ot_id, (uint32_t)addr + REGS_REV_BASE, + REG_REV_NAME(reg), val32, pc); + + /* NOLINTNEXTLINE(hicpp-multiway-paths-covered) */ + switch (reg) { + case R_REV: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: R/O register 0x%02" HWADDR_PRIx " (%s)\n", + __func__, s->ot_id, addr + REGS_REV_BASE, + REG_REV_NAME(reg)); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, + s->ot_id, addr + REGS_REV_BASE); + break; + } +}; + +static void ot_entropy_src_hi_regs_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned size) +{ + OtEntropySrcState *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(s->ot_id, ot_entropy_src_hi_reg_addr(s, addr), + REG_HI_NAME(reg), val32, pc); + + switch (reg) { + case R_MODULE_ENABLE: + if (s->regs_lo[R_ME_REGWEN]) { + uint32_t old = s->regs_hi[reg]; + val32 &= R_MODULE_ENABLE_MODULE_ENABLE_MASK; + s->regs_hi[reg] = val32; + CHECK_MULTIBOOT(s, hi, MODULE_ENABLE, MODULE_ENABLE); + if (ot_entropy_src_is_module_disabled(s)) { + /* reset takes care of cancelling the scheduler timer */ + resettable_reset(OBJECT(s), RESET_TYPE_COLD); + break; + } + if ((old ^ s->regs_hi[reg]) && + ot_entropy_src_is_module_enabled(s)) { + if (ot_entropy_src_is_fips_enabled(s)) { + /* start up phase */ + ot_entropy_src_change_state(s, + ENTROPY_SRC_STARTUP_HT_START); + } else { + /* boot phase */ + ot_entropy_src_change_state(s, ENTROPY_SRC_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)); + } + break; + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: ME_REGWEN not enabled\n", __func__); + break; + case R_CONF: + if (s->regs_lo[R_REGWEN]) { + val32 &= (s->version < 3) ? CONF_V2_WMASK : CONF_V3_WMASK; + s->regs_hi[reg] = val32; + CHECK_MULTIBOOT(s, hi, CONF, FIPS_ENABLE); + CHECK_MULTIBOOT(s, hi, CONF, RNG_BIT_ENABLE); + if (s->version < 3) { + CHECK_MULTIBOOT_VER(s, hi, CONF, V2, ENTROPY_DATA_REG_ENABLE); + CHECK_MULTIBOOT_VER(s, hi, CONF, V2, THRESHOLD_SCOPE); + } else { + CHECK_MULTIBOOT_VER(s, hi, CONF, V3, ENTROPY_DATA_REG_ENABLE); + CHECK_MULTIBOOT_VER(s, hi, CONF, V3, THRESHOLD_SCOPE); + } + } + break; + case R_ENTROPY_CONTROL: + if (s->regs_lo[R_REGWEN]) { + val32 &= ENTROPY_CONTROL_WMASK; + s->regs_hi[reg] = val32; + CHECK_MULTIBOOT(s, hi, ENTROPY_CONTROL, ES_ROUTE); + CHECK_MULTIBOOT(s, hi, ENTROPY_CONTROL, ES_TYPE); + } + break; + case R_HEALTH_TEST_WINDOWS: + if (s->regs_lo[R_REGWEN]) { + s->regs_hi[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_lo[R_REGWEN]) { + s->regs_hi[reg] = val32; + ot_entropy_src_update_alerts(s); + } + break; + case R_ALERT_THRESHOLD: + if (s->regs_lo[R_REGWEN]) { + if ((uint16_t)(val32) != (uint16_t)(~(val32 >> 16u))) { + s->regs_hi[R_RECOV_ALERT_STS] |= + R_RECOV_ALERT_STS_ES_THRESH_CFG_ALERT_MASK; + } else { + s->regs_hi[reg] = val32; + } + ot_entropy_src_update_alerts(s); + } + break; + case R_FW_OV_CONTROL: + if (s->regs_lo[R_REGWEN]) { + val32 &= FW_OV_CONTROL_WMASK; + s->regs_hi[reg] = val32; + CHECK_MULTIBOOT(s, hi, FW_OV_CONTROL, FW_OV_MODE); + CHECK_MULTIBOOT(s, hi, FW_OV_CONTROL, FW_OV_ENTROPY_INSERT); + s->obs_fifo_en = ot_entropy_src_is_fw_ov_mode(s); + } + break; + case R_FW_OV_SHA3_START: + if (!ot_entropy_src_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_hi[reg] = val32; + CHECK_MULTIBOOT(s, hi, FW_OV_SHA3_START, FW_OV_INSERT_START); + if (REG_MB4_IS_TRUE(s, hi, 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); + } else { /* default to false */ + if (s->state == ENTROPY_SRC_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); + } + } 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); + } + } + break; + case R_FW_OV_RD_FIFO_OVERFLOW: + val32 &= R_FW_OV_RD_FIFO_OVERFLOW_VAL_MASK; + s->regs_hi[reg] &= val32; /* RW0C */ + break; + case R_FW_OV_WR_DATA: + if (!ot_entropy_src_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)) { + bool can_write; + if (ot_entropy_src_is_bypass_mode(s)) { + can_write = ot_entropy_src_can_bypass_entropy(s); + if (can_write) { + ot_entropy_src_push_bypass_entropy(s, val32); + } + } else { + can_write = ot_entropy_src_can_condition_entropy(s); + if (can_write) { + ot_entropy_src_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_lo[R_REGWEN]) { + val32 &= R_OBSERVE_FIFO_THRESH_VAL_MASK; + s->regs_hi[reg] = val32; + ot_entropy_src_update_irqs(s); + } + break; + case R_RECOV_ALERT_STS: + val32 &= RECOV_ALERT_STS_WMASK; + s->regs_hi[reg] &= val32; /* RW0C */ + break; + case R_ERR_CODE_TEST: + val32 &= R_ERR_CODE_TEST_VAL_MASK; + s->regs_hi[R_ERR_CODE_TEST] = val32; + ot_entropy_src_update_irqs(s); + ot_entropy_src_update_alerts(s); + break; + 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%02x (%s)\n", + __func__, ot_entropy_src_hi_reg_addr(s, addr), + REG_HI_NAME(reg)); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%02x\n", __func__, + ot_entropy_src_hi_reg_addr(s, addr)); + break; + } +}; + +static const MemoryRegionOps ot_entropy_src_lo_ops = { + .read = &ot_entropy_src_lo_regs_read, + .write = &ot_entropy_src_lo_regs_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4u, + .max_access_size = 4u, + }, +}; + +static const MemoryRegionOps ot_entropy_src_rev_ops = { + .read = &ot_entropy_src_rev_regs_read, + .write = &ot_entropy_src_rev_regs_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4u, + .max_access_size = 4u, + }, +}; + +static const MemoryRegionOps ot_entropy_src_hi_ops = { + .read = &ot_entropy_src_hi_regs_read, + .write = &ot_entropy_src_hi_regs_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4u, + .max_access_size = 4u, + }, +}; + +static Property ot_entropy_src_properties[] = { + DEFINE_PROP_STRING(OT_COMMON_DEV_ID, OtEntropySrcState, ot_id), + DEFINE_PROP_UINT32("version", OtEntropySrcState, version, 0), + DEFINE_PROP_LINK("noise-src", OtEntropySrcState, noise_src, TYPE_DEVICE, + DeviceState *), + DEFINE_PROP_LINK("otp-ctrl", OtEntropySrcState, otp_ctrl, TYPE_OT_OTP, + OtOTPState *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ot_entropy_src_reset_enter(Object *obj, ResetType type) +{ + OtEntropySrcClass *c = OT_ENTROPY_SRC_GET_CLASS(obj); + OtEntropySrcState *s = OT_ENTROPY_SRC(obj); + + trace_ot_entropy_src_reset(s->ot_id, "enter"); + + if (c->parent_phases.enter) { + c->parent_phases.enter(obj, type); + } + + memset(s->regs_lo, 0, REGS_LO_SIZE); + if (s->version < 3) { + memset(s->regs_rev, 0, REGS_REV_SIZE); + } + memset(s->regs_hi, 0, REGS_HI_SIZE); + + s->regs_lo[R_ME_REGWEN] = 0x00000001u; + s->regs_lo[R_SW_REGUPD] = 0x00000001u; + s->regs_lo[R_REGWEN] = 0x00000001u; + if (s->version < 3) { + s->regs_rev[R_REV] = 0x10303u; + s->regs_hi[R_CONF] = 0x2649999u; + s->regs_hi[R_HEALTH_TEST_WINDOWS] = 0x600200u; + } else { + s->regs_hi[R_CONF] = 0x999999u; + s->regs_hi[R_HEALTH_TEST_WINDOWS] = 0x1800200u; + } + + s->regs_hi[R_MODULE_ENABLE] = 0x9u; + s->regs_hi[R_ENTROPY_CONTROL] = 0x99u; + s->regs_hi[R_REPCNT_THRESHOLDS] = 0xffffffffu; + s->regs_hi[R_REPCNTS_THRESHOLDS] = 0xffffffffu; + s->regs_hi[R_ADAPTP_HI_THRESHOLDS] = 0xffffffffu; + s->regs_hi[R_BUCKET_THRESHOLDS] = 0xffffffffu; + s->regs_hi[R_MARKOV_HI_THRESHOLDS] = 0xffffffffu; + s->regs_hi[R_EXTHT_HI_THRESHOLDS] = 0xffffffffu; + s->regs_hi[R_ADAPTP_LO_WATERMARKS] = 0xffffffffu; + s->regs_hi[R_EXTHT_LO_WATERMARKS] = 0xffffffffu; + s->regs_hi[R_MARKOV_LO_WATERMARKS] = 0xffffffffu; + s->regs_hi[R_ALERT_THRESHOLD] = 0xfffd0002u; + s->regs_hi[R_FW_OV_CONTROL] = 0x99u; + s->regs_hi[R_FW_OV_SHA3_START] = 0x9u; + s->regs_hi[R_OBSERVE_FIFO_THRESH] = 0x10u; + s->regs_hi[R_DEBUG_STATUS] = 0x10000u; + s->regs_hi[R_MAIN_SM_STATE] = 0xf5u; + 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_update_irqs(s); + for (unsigned ix = 0; ix < NUM_ALERTS; ix++) { + ibex_irq_set(&s->alerts[ix], 0); + } + + ot_entropy_src_change_state(s, ENTROPY_SRC_IDLE); +} + +static void ot_entropy_src_reset_exit(Object *obj, ResetType type) +{ + OtEntropySrcClass *c = OT_ENTROPY_SRC_GET_CLASS(obj); + OtEntropySrcState *s = OT_ENTROPY_SRC(obj); + + trace_ot_entropy_src_reset(s->ot_id, "exit"); + + if (c->parent_phases.enter) { + c->parent_phases.enter(obj, type); + } + + OtNoiseSrcIfClass *nsc = OT_NOISE_SRC_IF_GET_CLASS(s->noise_src); + OtNoiseSrcIf *nsi = OT_NOISE_SRC_IF(s->noise_src); + uint64_t noise_file_rate = nsc->get_fill_rate(nsi); + s->noise_fill_pace_ns = + (NANOSECONDS_PER_SECOND * ES_FILL_BITS) / (noise_file_rate * 8ull); +} + +static void ot_entropy_src_realize(DeviceState *dev, Error **errp) +{ + (void)errp; + + OtEntropySrcState *s = OT_ENTROPY_SRC(dev); + + /* emulated version should be specified */ + g_assert(s->version > 0); + g_assert(s->noise_src); + g_assert(s->otp_ctrl); + + (void)OBJECT_CHECK(OtNoiseSrcIf, s->noise_src, TYPE_OT_NOISE_SRC_IF); +} + +static void ot_entropy_src_init(Object *obj) +{ + OtEntropySrcState *s = OT_ENTROPY_SRC(obj); + +#define OT_ENTROPY_SRC_APERTURE 0x100u + + memory_region_init(&s->mmio, obj, TYPE_OT_ENTROPY_SRC "-regs", + OT_ENTROPY_SRC_APERTURE); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); + + memory_region_init_io(&s->mmio_lo, obj, &ot_entropy_src_lo_ops, s, + TYPE_OT_ENTROPY_SRC "-regs-lo", REGS_LO_SIZE); + memory_region_add_subregion(&s->mmio, REGS_LO_BASE, &s->mmio_lo); + + if (s->version < 3) { + memory_region_init_io(&s->mmio_rev, obj, &ot_entropy_src_rev_ops, s, + TYPE_OT_ENTROPY_SRC "-regs-rev", REGS_REV_SIZE); + memory_region_add_subregion(&s->mmio, REGS_REV_BASE, &s->mmio_rev); + } + + memory_region_init_io(&s->mmio_hi, obj, &ot_entropy_src_hi_ops, s, + TYPE_OT_ENTROPY_SRC "-regs-hi", REGS_HI_SIZE); + memory_region_add_subregion(&s->mmio, ot_entropy_src_hi_reg_base(s), + &s->mmio_hi); + + s->regs_lo = g_new0(uint32_t, REGS_LO_COUNT); + if (s->version < 3) { + s->regs_rev = g_new0(uint32_t, REGS_REV_COUNT); + } + s->regs_hi = g_new0(uint32_t, REGS_HI_COUNT); + + for (unsigned ix = 0; ix < NUM_IRQS; ix++) { + ibex_sysbus_init_irq(obj, &s->irqs[ix]); + } + + for (unsigned ix = 0; ix < NUM_ALERTS; ix++) { + 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->precon_fifo, sizeof(uint64_t) / sizeof(uint32_t)); + ot_fifo32_create(&s->bypass_fifo, ES_WORD_COUNT); + ot_fifo32_create(&s->observe_fifo, 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); +} + +static void ot_entropy_src_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); + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + OtEntropySrcClass *ec = OT_ENTROPY_SRC_CLASS(klass); + ec->get_entropy = &ot_entropy_src_get_entropy; + + ResettableClass *rc = RESETTABLE_CLASS(klass); + resettable_class_set_parent_phases(rc, &ot_entropy_src_reset_enter, NULL, + &ot_entropy_src_reset_exit, + &ec->parent_phases); +} + +static const TypeInfo ot_entropy_src_info = { + .name = TYPE_OT_ENTROPY_SRC, + .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, +}; + +static void ot_entropy_src_register_types(void) +{ + type_register_static(&ot_entropy_src_info); +} + +type_init(ot_entropy_src_register_types); diff --git a/hw/opentitan/ot_entropy_src_dj.c b/hw/opentitan/ot_entropy_src_dj.c deleted file mode 100644 index fe648321c1d7..000000000000 --- a/hw/opentitan/ot_entropy_src_dj.c +++ /dev/null @@ -1,1691 +0,0 @@ -/* - * QEMU OpenTitan Darjeeling 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_dj.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(MODULE_ENABLE, 0x1cu) - FIELD(MODULE_ENABLE, MODULE_ENABLE, 0u, 4u) -REG32(CONF, 0x20u) - 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, 0x24u) - FIELD(ENTROPY_CONTROL, ES_ROUTE, 0u, 4u) - FIELD(ENTROPY_CONTROL, ES_TYPE, 4u, 4u) -REG32(ENTROPY_DATA, 0x28u) -REG32(HEALTH_TEST_WINDOWS, 0x2cu) - FIELD(HEALTH_TEST_WINDOWS, FIPS_WINDOW, 0u, 16u) - FIELD(HEALTH_TEST_WINDOWS, BYPASS_WINDOW, 16u, 16u) -REG32(REPCNT_THRESHOLDS, 0x30u) - SHARED_FIELD(THRESHOLDS_FIPS, 0u, 16u) - SHARED_FIELD(THRESHOLDS_BYPASS, 16u, 16u) -REG32(REPCNTS_THRESHOLDS, 0x34u) -REG32(ADAPTP_HI_THRESHOLDS, 0x38u) -REG32(ADAPTP_LO_THRESHOLDS, 0x3cu) -REG32(BUCKET_THRESHOLDS, 0x40u) -REG32(MARKOV_HI_THRESHOLDS, 0x44u) -REG32(MARKOV_LO_THRESHOLDS, 0x48u) -REG32(EXTHT_HI_THRESHOLDS, 0x4cu) -REG32(EXTHT_LO_THRESHOLDS, 0x50u) -REG32(REPCNT_HI_WATERMARKS, 0x54u) - SHARED_FIELD(WATERMARK_FIPS, 0u, 16u) - SHARED_FIELD(WATERMARK_BYPASS, 16u, 16u) -REG32(REPCNTS_HI_WATERMARKS, 0x58u) -REG32(ADAPTP_HI_WATERMARKS, 0x5cu) -REG32(ADAPTP_LO_WATERMARKS, 0x60u) -REG32(EXTHT_HI_WATERMARKS, 0x64u) -REG32(EXTHT_LO_WATERMARKS, 0x68u) -REG32(BUCKET_HI_WATERMARKS, 0x6cu) -REG32(MARKOV_HI_WATERMARKS, 0x70u) -REG32(MARKOV_LO_WATERMARKS, 0x74u) -REG32(REPCNT_TOTAL_FAILS, 0x78u) -REG32(REPCNTS_TOTAL_FAILS, 0x7cu) -REG32(ADAPTP_HI_TOTAL_FAILS, 0x80u) -REG32(ADAPTP_LO_TOTAL_FAILS, 0x84u) -REG32(BUCKET_TOTAL_FAILS, 0x88u) -REG32(MARKOV_HI_TOTAL_FAILS, 0x8cu) -REG32(MARKOV_LO_TOTAL_FAILS, 0x90u) -REG32(EXTHT_HI_TOTAL_FAILS, 0x94u) -REG32(EXTHT_LO_TOTAL_FAILS, 0x98u) -REG32(ALERT_THRESHOLD, 0x9cu) - FIELD(ALERT_THRESHOLD, ALERT_THRESHOLD, 0u, 16u) - FIELD(ALERT_THRESHOLD, ALERT_THRESHOLD_INV, 16u, 16u) -REG32(ALERT_SUMMARY_FAIL_COUNTS, 0xa0u) - FIELD(ALERT_SUMMARY_FAIL_COUNTS, ANY_FAIL_COUNT, 0u, 16u) -REG32(ALERT_FAIL_COUNTS, 0xa4u) - 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, 0xa8u) - FIELD(EXTHT_FAIL_COUNTS, EXTHT_HI_FAIL_COUNT, 0u, 4u) - FIELD(EXTHT_FAIL_COUNTS, EXTHT_LO_FAIL_COUNT, 4u, 4u) -REG32(FW_OV_CONTROL, 0xacu) - FIELD(FW_OV_CONTROL, FW_OV_MODE, 0u, 4u) - FIELD(FW_OV_CONTROL, FW_OV_ENTROPY_INSERT, 4u, 4u) -REG32(FW_OV_SHA3_START, 0xb0u) - FIELD(FW_OV_SHA3_START, FW_OV_INSERT_START, 0u, 4u) -REG32(FW_OV_WR_FIFO_FULL, 0xb4u) - FIELD(FW_OV_WR_FIFO_FULL, VAL, 0u, 1u) -REG32(FW_OV_RD_FIFO_OVERFLOW, 0xb8u) - FIELD(FW_OV_RD_FIFO_OVERFLOW, VAL, 0u, 1u) -REG32(FW_OV_RD_DATA, 0xbcu) -REG32(FW_OV_WR_DATA, 0xc0u) -REG32(OBSERVE_FIFO_THRESH, 0xc4u) - FIELD(OBSERVE_FIFO_THRESH, VAL, 0u, 6u) -REG32(OBSERVE_FIFO_DEPTH, 0xc8u) - FIELD(OBSERVE_FIFO_DEPTH, VAL, 0u, 6u) -REG32(DEBUG_STATUS, 0xccu) - 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, 0xd0u) - 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, 0xd4u) - 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, 0xd8u) - FIELD(ERR_CODE_TEST, VAL, 0u, 5u) -REG32(MAIN_SM_STATE, 0xdcu) - 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(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_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_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_DJ_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_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; - 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 */ - 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 */ - bool obs_fifo_en; /* observe FIFO accept incoming data */ - - OtASTEgState *ast; - OtOTPState *otp_ctrl; -}; - -struct OtEntropySrcDjClass { - SysBusDeviceClass parent_class; - ResettablePhases parent_phases; -}; - -static const uint16_t OtEDNFsmStateCode[] = { - [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_DJ_##_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_dj_show_buffer(_msg_, _buf_, _len_) \ - ot_entropy_src_dj_show_buffer(__func__, __LINE__, _msg_, _buf_, _len_) - -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_dj_get_random( - OtRandomSrcIf *dev, uint64_t random[OT_RANDOM_SRC_DWORD_COUNT], bool *fips) -{ - OtEntropySrcDjState *s = OT_ENTROPY_SRC_DJ(dev); - - if (!ot_entropy_src_dj_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_DJ_BOOT_PHASE_DONE: - fips_compliant = false; - break; - 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_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_DJ_WAIT_DELAY_NS); - } else { - 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_DJ_IDLE: - qemu_log_mask(LOG_GUEST_ERROR, "%s: module is not enabled\n", __func__); - return -1; - 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_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_DJ_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_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_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_dj_update_filler(s); - } - - return 0; -} - -/* -------------------------------------------------------------------------- */ -/* Private implementation */ -/* -------------------------------------------------------------------------- */ - -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) && - 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_dj_is_module_enabled(const OtEntropySrcDjState *s) -{ - return REG_MB4_IS_TRUE(s, MODULE_ENABLE, MODULE_ENABLE); -} - -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_dj_is_fips_enabled(const OtEntropySrcDjState *s) -{ - return REG_MB4_IS_TRUE(s, CONF, FIPS_ENABLE); -} - -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++) { - ibex_irq_set(&s->irqs[ix], (int)((levels >> ix) & 0x1u)); - } -} - -static bool -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_dj_is_hw_route(const OtEntropySrcDjState *s) -{ - return REG_MB4_IS_FALSE(s, ENTROPY_CONTROL, ES_ROUTE); -} - -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_dj_is_bypass_mode(const OtEntropySrcDjState *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_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_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_dj_is_fips_capable(const OtEntropySrcDjState *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 OtEntropySrcDjState *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_dj_change_state_line( - OtEntropySrcDjState *s, OtEntropySrcDjFsmState state, int line) -{ - OtEntropySrcDjFsmState old_state = s->state; - - switch (s->state) { - case ENTROPY_SRC_DJ_ALERT_STATE: - s->state = ENTROPY_SRC_DJ_ALERT_HANG; - break; - case ENTROPY_SRC_DJ_ALERT_HANG: - if ((state == ENTROPY_SRC_DJ_IDLE) && - ot_entropy_src_dj_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_DJ_ERROR) { - s->regs[R_ERR_CODE] |= R_ERR_CODE_ES_MAIN_SM_ERR_MASK; - ot_entropy_src_dj_update_alerts(s); - } -} - -#define ot_entropy_src_dj_change_state(_s_, _st_) \ - ot_entropy_src_dj_change_state_line(_s_, _st_, __LINE__) - -static void ot_entropy_src_dj_update_alerts(OtEntropySrcDjState *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_dj_check_multibitboot( - OtEntropySrcDjState *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_dj_update_alerts(s); - return false; -} - -static bool ot_entropy_src_dj_can_consume_entropy(const OtEntropySrcDjState *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_dj_update_filler(OtEntropySrcDjState *s) -{ - /* fill granule is OT_ENTROPY_SRC_DJ_FILL_WORD_COUNT bits */ - bool input = - 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_dj_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_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_dj_is_final_fifo_slot_available(s)) { - /* room in output FIFO */ - return true; - } - - return false; -} - -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_dj_is_final_fifo_slot_available(s)) { - /* room in output FIFO */ - return true; - } - - return false; -} - -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_dj_change_state(s, ENTROPY_SRC_DJ_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_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_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); - s->cond_word += size; - ot_fifo32_reset(&s->precon_fifo); - - return true; -} - -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_dj_perform_hash(OtEntropySrcDjState *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_dj_show_buffer("sha3 md", hash, - OT_RANDOM_SRC_WORD_COUNT * - sizeof(uint32_t)); - - 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)); - ot_fifo32_push(&s->final_fifo, hash[ix]); - } - s->packet_count += 1u; - - 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_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_DJ_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_dj_update_fw_route(OtEntropySrcDjState *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_dj_update_filler(s); - } - } -} - -static bool -ot_entropy_src_dj_consume_entropy(OtEntropySrcDjState *s, uint32_t word) -{ - 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_dj_can_bypass_entropy(s) : - ot_entropy_src_dj_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_dj_is_bypass_mode(s)) { - ot_entropy_src_dj_push_bypass_entropy(s, word); - } else { - 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_dj_perform_hash(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_dj_fill_noise(OtEntropySrcDjState *s) -{ - unsigned count = ot_fifo32_num_free(&s->input_fifo); - if (count < OT_ENTROPY_SRC_DJ_FILL_WORD_COUNT) { - /* no room left, should be resheduled */ - return false; - } - - uint32_t buffer[OT_ENTROPY_SRC_DJ_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_dj_consume_entropy(s, - ot_fifo32_pop(&s->input_fifo))) { - break; - } - } - - ot_entropy_src_dj_update_irqs(s); - - return true; -} - -static void ot_entropy_src_dj_noise_refill(void *opaque) -{ - OtEntropySrcDjState *s = opaque; - - if (!ot_entropy_src_dj_fill_noise(s)) { - trace_ot_entropy_src_info("FIFO already filled up"); - return; - } - - switch (s->state) { - case ENTROPY_SRC_DJ_BOOT_HT_RUNNING: - if (s->packet_count > 0) { - ot_entropy_src_dj_change_state(s, ENTROPY_SRC_DJ_BOOT_PHASE_DONE); - } - break; - case ENTROPY_SRC_DJ_STARTUP_HT_START: - ot_entropy_src_dj_change_state(s, ENTROPY_SRC_DJ_CONT_HT_RUNNING); - break; - 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), - s->state); - break; - } - - ot_entropy_src_dj_update_filler(s); -} - -static void ot_entropy_src_dj_scheduler(void *opaque) -{ - OtEntropySrcDjState *s = opaque; - - switch (s->state) { - 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_DJ_IDLE: - break; - 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_dj_update_alerts(s); - ot_entropy_src_dj_update_irqs(s); -} - -static uint64_t -ot_entropy_src_dj_regs_read(void *opaque, hwaddr addr, unsigned size) -{ - OtEntropySrcDjState *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_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_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_DJ_ERROR]; - } - break; - case R_REGWEN: - val32 = (uint32_t)(s->regs[R_SW_REGUPD] == R_SW_REGUPD_UPD_MASK && - 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_dj_is_module_enabled(s) && - REG_MB4_IS_TRUE(s, CONF, ENTROPY_DATA_REG_ENABLE) && - ot_entropy_src_dj_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_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_dj_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_dj_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_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_dj_regs_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned size) -{ - OtEntropySrcDjState *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_dj_update_irqs(s); - break; - case R_INTR_ENABLE: - val32 &= INTR_MASK; - s->regs[reg] = val32; - ot_entropy_src_dj_update_irqs(s); - break; - case R_INTR_TEST: - val32 &= INTR_MASK; - s->regs[R_INTR_STATE] |= val32; - ot_entropy_src_dj_update_irqs(s); - break; - case R_ALERT_TEST: - val32 &= ALERT_TEST_MASK; - s->regs[reg] = val32; - ot_entropy_src_dj_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_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_dj_is_module_enabled(s)) { - if (ot_entropy_src_dj_is_fips_enabled(s)) { - /* start up phase */ - ot_entropy_src_dj_change_state( - s, ENTROPY_SRC_DJ_STARTUP_HT_START); - } else { - /* boot phase */ - 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_DJ_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_dj_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_dj_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_dj_is_fw_ov_mode(s); - } - break; - case R_FW_OV_SHA3_START: - if (!ot_entropy_src_dj_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)) { - 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_DJ_SHA3_PROCESS) { - /* handle SHA3 processing */ - if (ot_fifo32_is_empty(&s->precon_fifo)) { - 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 { - 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; - 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_dj_is_module_enabled(s)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: module not enabled\n", - __func__); - break; - } - 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_dj_is_bypass_mode(s)) { - can_write = ot_entropy_src_dj_can_bypass_entropy(s); - if (can_write) { - ot_entropy_src_dj_push_bypass_entropy(s, val32); - } - } else { - can_write = ot_entropy_src_dj_can_condition_entropy(s); - if (can_write) { - ot_entropy_src_dj_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_dj_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_dj_update_irqs(s); - ot_entropy_src_dj_update_alerts(s); - break; - case R_REGWEN: - 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_dj_properties[] = { - DEFINE_PROP_LINK("ast", OtEntropySrcDjState, ast, TYPE_OT_AST_EG, - OtASTEgState *), - DEFINE_PROP_LINK("otp_ctrl", OtEntropySrcDjState, otp_ctrl, TYPE_OT_OTP, - OtOTPState *), - DEFINE_PROP_END_OF_LIST(), -}; - -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_dj_reset_enter(Object *obj, ResetType type) -{ - OtEntropySrcDjClass *c = OT_ENTROPY_SRC_DJ_GET_CLASS(obj); - OtEntropySrcDjState *s = OT_ENTROPY_SRC_DJ(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_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_dj_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_dj_change_state(s, ENTROPY_SRC_DJ_IDLE); -} - -static void ot_entropy_src_dj_realize(DeviceState *dev, Error **errp) -{ - (void)errp; - - OtEntropySrcDjState *s = OT_ENTROPY_SRC_DJ(dev); - - g_assert(s->ast); - g_assert(s->otp_ctrl); -} - -static void ot_entropy_src_dj_init(Object *obj) -{ - OtEntropySrcDjState *s = OT_ENTROPY_SRC_DJ(obj); - - 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); - 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_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_dj_scheduler, s); -} - -static void ot_entropy_src_dj_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - (void)data; - - 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); - 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_dj_get_random; -} - -static const TypeInfo ot_entropy_src_dj_info = { - .name = TYPE_OT_ENTROPY_SRC_DJ, - .parent = TYPE_SYS_BUS_DEVICE, - .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 }, - {}, - }, -}; - -static void ot_entropy_src_dj_register_types(void) -{ - type_register_static(&ot_entropy_src_dj_info); -} - -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 deleted file mode 100644 index 5722ea8782e2..000000000000 --- a/hw/opentitan/ot_entropy_src_eg.c +++ /dev/null @@ -1,1699 +0,0 @@ -/* - * 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_keymgr.c b/hw/opentitan/ot_keymgr.c index b8b430e4c350..a4b59f803b42 100644 --- a/hw/opentitan/ot_keymgr.c +++ b/hw/opentitan/ot_keymgr.c @@ -2330,9 +2330,9 @@ static Property ot_keymgr_properties[] = { OtFlashState *), DEFINE_PROP_LINK("kmac", OtKeyMgrState, kmac, TYPE_OT_KMAC, OtKMACState *), DEFINE_PROP_UINT8("kmac-app", OtKeyMgrState, kmac_app, UINT8_MAX), - DEFINE_PROP_LINK("lc_ctrl", OtKeyMgrState, lc_ctrl, TYPE_OT_LC_CTRL, + DEFINE_PROP_LINK("lc-ctrl", OtKeyMgrState, lc_ctrl, TYPE_OT_LC_CTRL, OtLcCtrlState *), - DEFINE_PROP_LINK("otp_ctrl", OtKeyMgrState, otp_ctrl, TYPE_OT_OTP, + DEFINE_PROP_LINK("otp-ctrl", OtKeyMgrState, otp_ctrl, TYPE_OT_OTP, OtOTPState *), DEFINE_PROP_LINK("rom_ctrl", OtKeyMgrState, rom_ctrl, TYPE_OT_ROM_CTRL, OtRomCtrlState *), diff --git a/hw/opentitan/ot_keymgr_dpe.c b/hw/opentitan/ot_keymgr_dpe.c index e6d08f4241e3..422607e2df22 100644 --- a/hw/opentitan/ot_keymgr_dpe.c +++ b/hw/opentitan/ot_keymgr_dpe.c @@ -2002,9 +2002,9 @@ static Property ot_keymgr_dpe_properties[] = { DEFINE_PROP_LINK("kmac", OtKeyMgrDpeState, kmac, TYPE_OT_KMAC, OtKMACState *), DEFINE_PROP_UINT8("kmac-app", OtKeyMgrDpeState, kmac_app, UINT8_MAX), - DEFINE_PROP_LINK("lc_ctrl", OtKeyMgrDpeState, lc_ctrl, TYPE_OT_LC_CTRL, + DEFINE_PROP_LINK("lc-ctrl", OtKeyMgrDpeState, lc_ctrl, TYPE_OT_LC_CTRL, OtLcCtrlState *), - DEFINE_PROP_LINK("otp_ctrl", OtKeyMgrDpeState, otp, TYPE_OT_OTP, + DEFINE_PROP_LINK("otp-ctrl", OtKeyMgrDpeState, otp, TYPE_OT_OTP, OtOTPState *), DEFINE_PROP_LINK("rom0", OtKeyMgrDpeState, rom_ctrl[0], TYPE_OT_ROM_CTRL, OtRomCtrlState *), diff --git a/hw/opentitan/ot_lc_ctrl.c b/hw/opentitan/ot_lc_ctrl.c index cba7905e304b..25be5342bd50 100644 --- a/hw/opentitan/ot_lc_ctrl.c +++ b/hw/opentitan/ot_lc_ctrl.c @@ -2137,7 +2137,7 @@ static void ot_lc_ctrl_get_keymgr_div(const OtLcCtrlState *s, static Property ot_lc_ctrl_properties[] = { DEFINE_PROP_STRING(OT_COMMON_DEV_ID, OtLcCtrlState, ot_id), - DEFINE_PROP_LINK("otp_ctrl", OtLcCtrlState, otp_ctrl, TYPE_OT_OTP, + DEFINE_PROP_LINK("otp-ctrl", OtLcCtrlState, otp_ctrl, TYPE_OT_OTP, OtOTPState *), DEFINE_PROP_LINK("kmac", OtLcCtrlState, kmac, TYPE_OT_KMAC, OtKMACState *), DEFINE_PROP_STRING("raw_unlock_token", OtLcCtrlState, diff --git a/hw/opentitan/ot_random_src.c b/hw/opentitan/ot_noise_src.c similarity index 76% rename from hw/opentitan/ot_random_src.c rename to hw/opentitan/ot_noise_src.c index c637a86085ac..6564a3a56071 100644 --- a/hw/opentitan/ot_random_src.c +++ b/hw/opentitan/ot_noise_src.c @@ -1,7 +1,7 @@ /* - * QEMU OpenTitan Random Source interface + * QEMU OpenTitan Noise Source interface * - * Copyright (c) 2023 Rivos, Inc. + * Copyright (c) 2025 Rivos, Inc. * * Author(s): * Emmanuel Blot @@ -26,17 +26,17 @@ */ #include "qemu/osdep.h" -#include "hw/opentitan/ot_random_src.h" +#include "hw/opentitan/ot_noise_src.h" -static const TypeInfo ot_random_src_info = { - .name = TYPE_OT_RANDOM_SRC_IF, +static const TypeInfo ot_noise_src_info = { + .name = TYPE_OT_NOISE_SRC_IF, .parent = TYPE_INTERFACE, - .class_size = sizeof(OtRandomSrcIfClass), + .class_size = sizeof(OtNoiseSrcIfClass), }; -static void ot_random_src_register_types(void) +static void ot_noise_src_register_types(void) { - type_register_static(&ot_random_src_info); + type_register_static(&ot_noise_src_info); } -type_init(ot_random_src_register_types); +type_init(ot_noise_src_register_types); diff --git a/hw/opentitan/ot_otp_dj.c b/hw/opentitan/ot_otp_dj.c index 7f2759cc2bf0..1b11fff5700a 100644 --- a/hw/opentitan/ot_otp_dj.c +++ b/hw/opentitan/ot_otp_dj.c @@ -2926,14 +2926,7 @@ static const OtOTPHWCfg *ot_otp_dj_get_hw_cfg(const OtOTPState *s) { const OtOTPDjState *ds = OT_OTP_DJ(s); - return ds->hw_cfg; -} - -static const OtOTPEntropyCfg *ot_otp_dj_get_entropy_cfg(const OtOTPState *s) -{ - (void)s; - /* not present Darjeeling OTP */ - return NULL; + return (const OtOTPHWCfg *)ds->hw_cfg; } static void ot_otp_dj_request_entropy_bh(void *opaque) @@ -3547,9 +3540,13 @@ static void ot_otp_dj_pwr_load_hw_cfg(OtOTPDjState *s) memcpy(hw_cfg->soc_dbg_state, &otp->data[R_HW_CFG1_SOC_DBG_STATE], sizeof(hw_cfg->soc_dbg_state)); /* do not prevent execution from SRAM if no OTP configuration is loaded */ - hw_cfg->en_sram_ifetch = + hw_cfg->en_sram_ifetch_mb8 = s->blk ? (uint8_t)otp->data[R_HW_CFG1_EN_SRAM_IFETCH] : OT_MULTIBITBOOL8_TRUE; + /* do not prevent CSRNG app reads if no OTP configuration is loaded */ + hw_cfg->en_csrng_sw_app_read_mb8 = + s->blk ? (uint8_t)otp->data[R_HW_CFG1_EN_CSRNG_SW_APP_READ] : + OT_MULTIBITBOOL8_TRUE; } static void ot_otp_dj_pwr_load_tokens(OtOTPDjState *s) @@ -3960,7 +3957,7 @@ static void ot_otp_dj_reset_enter(Object *obj, ResetType type) * * File back-end storage (loading) is processed from * the ot_otp_dj_pwr_otp_bh handler, to ensure data is reloaded from the - * backend on each reset, prior to this very reset fuction. This reset + * backend on each reset, prior to this very reset function. This reset * function should not alter the storage content. * * Ideally the OTP reset functions should be decoupled from the regular @@ -3988,6 +3985,7 @@ static void ot_otp_dj_reset_enter(Object *obj, ResetType type) s->keygen->edn_sched = false; memset(s->regs, 0, REGS_COUNT * sizeof(uint32_t)); + memset(s->hw_cfg, 0, sizeof(*s->hw_cfg)); s->regs[R_DIRECT_ACCESS_REGWEN] = 0x00000001u; s->regs[R_CHECK_TRIGGER_REGWEN] = 0x00000001u; @@ -4070,7 +4068,7 @@ static void ot_otp_dj_realize(DeviceState *dev, Error **errp) /* * Set the OTP drive's permissions now during realization. We can't leave it - * until reset because QEMU might have `-deamonize`d and changed directory, + * until reset because QEMU might have `-daemonize`d and changed directory, * invalidating the filesystem path to the OTP image. */ if (s->blk) { @@ -4187,7 +4185,6 @@ static void ot_otp_dj_class_init(ObjectClass *klass, void *data) oc->get_lc_info = &ot_otp_dj_get_lc_info; oc->get_hw_cfg = &ot_otp_dj_get_hw_cfg; - oc->get_entropy_cfg = &ot_otp_dj_get_entropy_cfg; oc->get_otp_key = &ot_otp_dj_get_otp_key; oc->get_keymgr_secret = &ot_otp_dj_get_keymgr_secret; oc->program_req = &ot_otp_dj_program_req; diff --git a/hw/opentitan/ot_otp_eg.c b/hw/opentitan/ot_otp_eg.c index e33913d80da0..62841414aa00 100644 --- a/hw/opentitan/ot_otp_eg.c +++ b/hw/opentitan/ot_otp_eg.c @@ -699,7 +699,6 @@ struct OtOTPEgState { OtOTPStorage *otp; OtOTPHWCfg *hw_cfg; - OtOTPEntropyCfg *entropy_cfg; OtOTPTokens *tokens; char *hexstr; @@ -2803,14 +2802,7 @@ static const OtOTPHWCfg *ot_otp_eg_get_hw_cfg(const OtOTPState *s) { const OtOTPEgState *es = OT_OTP_EG(s); - return es->hw_cfg; -} - -static const OtOTPEntropyCfg *ot_otp_eg_get_entropy_cfg(const OtOTPState *s) -{ - const OtOTPEgState *es = OT_OTP_EG(s); - - return es->entropy_cfg; + return (const OtOTPHWCfg *)es->hw_cfg; } static void ot_otp_eg_request_entropy_bh(void *opaque) @@ -3425,18 +3417,17 @@ static void ot_otp_eg_pwr_load_hw_cfg(OtOTPEgState *s) { OtOTPStorage *otp = s->otp; OtOTPHWCfg *hw_cfg = s->hw_cfg; - OtOTPEntropyCfg *entropy_cfg = s->entropy_cfg; memcpy(hw_cfg->device_id, &otp->data[R_HW_CFG0_DEVICE_ID], sizeof(hw_cfg->device_id)); memcpy(hw_cfg->manuf_state, &otp->data[R_HW_CFG0_MANUF_STATE], sizeof(hw_cfg->manuf_state)); /* do not prevent execution from SRAM if no OTP configuration is loaded */ - hw_cfg->en_sram_ifetch = + hw_cfg->en_sram_ifetch_mb8 = s->blk ? (uint8_t)otp->data[R_HW_CFG1_EN_SRAM_IFETCH] : OT_MULTIBITBOOL8_TRUE; /* do not prevent CSRNG app reads if no OTP configuration is loaded */ - entropy_cfg->en_csrng_sw_app_read = + hw_cfg->en_csrng_sw_app_read_mb8 = s->blk ? (uint8_t)otp->data[R_HW_CFG1_EN_CSRNG_SW_APP_READ] : OT_MULTIBITBOOL8_TRUE; } @@ -3944,7 +3935,7 @@ static void ot_otp_eg_reset_enter(Object *obj, ResetType type) * * File back-end storage (loading) is processed from * the ot_otp_eg_pwr_otp_bh handler, to ensure data is reloaded from the - * backend on each reset, prior to this very reset fuction. This reset + * backend on each reset, prior to this very reset function. This reset * function should not alter the storage content. * * Ideally the OTP reset functions should be decoupled from the regular @@ -3972,6 +3963,7 @@ static void ot_otp_eg_reset_enter(Object *obj, ResetType type) s->keygen->edn_sched = false; memset(s->regs, 0, REGS_COUNT * sizeof(uint32_t)); + memset(s->hw_cfg, 0, sizeof(*s->hw_cfg)); s->regs[R_DIRECT_ACCESS_REGWEN] = 0x1u; s->regs[R_CHECK_TRIGGER_REGWEN] = 0x1u; @@ -4044,7 +4036,7 @@ static void ot_otp_eg_realize(DeviceState *dev, Error **errp) /* * Set the OTP drive's permissions now during realization. We can't leave it - * until reset because QEMU might have `-deamonize`d and changed directory, + * until reset because QEMU might have `-daemonize`d and changed directory, * invalidating the filesystem path to the OTP image. */ if (s->blk) { @@ -4104,7 +4096,6 @@ static void ot_otp_eg_init(Object *obj) OT_LC_BROADCAST, OT_OTP_LC_BROADCAST_COUNT); s->hw_cfg = g_new0(OtOTPHWCfg, 1u); - s->entropy_cfg = g_new0(OtOTPEntropyCfg, 1u); s->tokens = g_new0(OtOTPTokens, 1u); s->regs = g_new0(uint32_t, REGS_COUNT); s->dai = g_new0(OtOTPDAIController, 1u); @@ -4163,7 +4154,6 @@ static void ot_otp_eg_class_init(ObjectClass *klass, void *data) oc->get_lc_info = &ot_otp_eg_get_lc_info; oc->get_hw_cfg = &ot_otp_eg_get_hw_cfg; - oc->get_entropy_cfg = &ot_otp_eg_get_entropy_cfg; oc->get_otp_key = &ot_otp_eg_get_otp_key; oc->get_keymgr_secret = &ot_otp_eg_get_keymgr_secret; oc->program_req = &ot_otp_eg_program_req; diff --git a/hw/opentitan/ot_pwrmgr.c b/hw/opentitan/ot_pwrmgr.c index a65e1b4fe875..9e74a4a66e79 100644 --- a/hw/opentitan/ot_pwrmgr.c +++ b/hw/opentitan/ot_pwrmgr.c @@ -984,7 +984,7 @@ static void ot_pwrmgr_regs_write(void *opaque, hwaddr addr, uint64_t val64, static Property ot_pwrmgr_properties[] = { DEFINE_PROP_STRING(OT_COMMON_DEV_ID, OtPwrMgrState, ot_id), DEFINE_PROP_STRING("clocks", OtPwrMgrState, cfg_clocks), - DEFINE_PROP_LINK("clock_ctrl", OtPwrMgrState, clock_ctrl, TYPE_DEVICE, + DEFINE_PROP_LINK("clock-ctrl", OtPwrMgrState, clock_ctrl, TYPE_DEVICE, DeviceState *), DEFINE_PROP_UINT8("num-rom", OtPwrMgrState, num_rom, 0), DEFINE_PROP_UINT8("version", OtPwrMgrState, version, UINT8_MAX), diff --git a/hw/opentitan/ot_sram_ctrl.c b/hw/opentitan/ot_sram_ctrl.c index 0b3e4b5f2e02..99c689e85c07 100644 --- a/hw/opentitan/ot_sram_ctrl.c +++ b/hw/opentitan/ot_sram_ctrl.c @@ -356,7 +356,7 @@ static void ot_sram_ctrl_update_exec(OtSramCtrlState *s) */ if (s->otp_ctrl) { OtOTPClass *oc = OBJECT_GET_CLASS(OtOTPClass, s->otp_ctrl, TYPE_OT_OTP); - s->otp_ifetch = oc->get_hw_cfg(s->otp_ctrl)->en_sram_ifetch == + s->otp_ifetch = oc->get_hw_cfg(s->otp_ctrl)->en_sram_ifetch_mb8 == OT_MULTIBITBOOL8_TRUE; } @@ -668,7 +668,7 @@ static MemTxResult ot_sram_ctrl_mem_init_write_with_attrs( static Property ot_sram_ctrl_properties[] = { DEFINE_PROP_STRING(OT_COMMON_DEV_ID, OtSramCtrlState, ot_id), - DEFINE_PROP_LINK("otp_ctrl", OtSramCtrlState, otp_ctrl, TYPE_OT_OTP, + DEFINE_PROP_LINK("otp-ctrl", OtSramCtrlState, otp_ctrl, TYPE_OT_OTP, OtOTPState *), DEFINE_PROP_LINK("vmapper", OtSramCtrlState, vmapper, TYPE_OT_VMAPPER, OtVMapperState *), diff --git a/hw/opentitan/trace-events b/hw/opentitan/trace-events index 76ce0226c7a9..c3764ccebda1 100644 --- a/hw/opentitan/trace-events +++ b/hw/opentitan/trace-events @@ -178,22 +178,22 @@ ot_edn_xinfo(unsigned appid, const char *func, int line, const char *msg, uint32 # ot_entropy_src.c -ot_entropy_src_available(const char *state, int st) "entropy source is ready in [%s:%u]" -ot_entropy_src_change_state(int line, const char *old, int nold, const char *new, int nnew) "@ %d [%s:%d] -> [%s:%d]" -ot_entropy_src_consume_entropy(bool obs_fifo, bool bypass, bool hw_path, unsigned ncount) "obs_fifo %u, bypass %u, hw_path %u ncount %u" -ot_entropy_src_error(const char *msg, const char *state, int st) "%s [%s:%u]" -ot_entropy_src_fill_noise(unsigned count, unsigned infifo) "up to %u, input fifo %u" -ot_entropy_src_get_random_fips(const char *state, bool en, bool es_route, bool es_type, bool rng_bit_en, bool cap, bool comp, bool fips) "st:%s en:%u rt:%u tp:%u !rb:%u cap:%u comp:%u => %u" -ot_entropy_src_info(const char *msg) "%s" -ot_entropy_src_init_ongoing(const char *state, int st, int ns) "ES still initializing in [%s:%u] %d ns to go" -ot_entropy_src_io_read_out(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" -ot_entropy_src_io_write(uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "addr=0x%02x (%s), val=0x%x, pc=0x%x" -ot_entropy_src_no_entropy(unsigned count) "only %u words available" -ot_entropy_src_obs_fifo(unsigned level, unsigned thold) "level %u, threshold %u" -ot_entropy_src_push_bypass_entropy(unsigned slot) "final FIFO depth: %u" -ot_entropy_src_reset(void) "" -ot_entropy_src_show_buffer(const char *func, int line, const char *msg, const char *hexstr) "%s:%u %s: %s" -ot_entropy_src_update_filler(bool iok, bool ook, bool pok, bool all) "in %u, out %u, proc %u -> %u" +ot_entropy_src_available(const char *id, const char *state, int st) "%s: entropy source is ready in [%s:%u]" +ot_entropy_src_change_state(const char *id, int line, const char *old, int nold, const char *new, int nnew) "%s: @ %d [%s:%d] -> [%s:%d]" +ot_entropy_src_consume_entropy(const char *id, bool obs_fifo, bool bypass, bool hw_path, unsigned ncount) "%s: obs_fifo %u, bypass %u, hw_path %u ncount %u" +ot_entropy_src_error(const char *id, const char *msg, const char *state, int st) "%s: %s [%s:%u]" +ot_entropy_src_fill_noise(const char *id, unsigned count, unsigned infifo) "%s: up to %u, input fifo %u" +ot_entropy_src_get_random_fips(const char *id, const char *state, bool en, bool es_route, bool es_type, bool rng_bit_en, bool cap, bool comp, bool fips) "%s: st:%s en:%u rt:%u tp:%u !rb:%u cap:%u comp:%u => %u" +ot_entropy_src_info(const char *id, const char *msg) "%s: %s" +ot_entropy_src_init_ongoing(const char *id, const char *state, int st, int ns) "%s: ES still initializing in [%s:%u] %d ns to go" +ot_entropy_src_io_read_out(const char *id, uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" +ot_entropy_src_io_write(const char *id, uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" +ot_entropy_src_no_entropy(const char *id, unsigned count) "%s: only %u words available" +ot_entropy_src_obs_fifo(const char *id, unsigned level, unsigned thold) "%s: level %u, threshold %u" +ot_entropy_src_push_bypass_entropy(const char *id, unsigned slot) "%s: final FIFO depth: %u" +ot_entropy_src_reset(const char *id, const char *phase) "%s: %s" +ot_entropy_src_show_buffer(const char *id, const char *func, int line, const char *msg, const char *hexstr) "%s: %s:%u %s: %s" +ot_entropy_src_update_filler(const char *id, bool iok, bool ook, bool pok, bool all) "%s: in %u, out %u, proc %u -> %u" # ot_flash.c diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 76e503af08d7..18ea1b3ce6cc 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -33,7 +33,7 @@ config OT_DARJEELING select OT_DEV_PROXY select OT_DM_TL select OT_DMA - select OT_ENTROPY_SRC_DJ + select OT_ENTROPY_SRC select OT_EDN select OT_GPIO_DJ select OT_HMAC @@ -78,7 +78,7 @@ config OT_EARLGREY select OT_CLKMGR select OT_CSRNG select OT_EDN - select OT_ENTROPY_SRC_EG + select OT_ENTROPY_SRC select OT_FLASH select OT_GPIO_EG select OT_HMAC diff --git a/hw/riscv/dtm.c b/hw/riscv/dtm.c index 121e93346543..cfaa2c4ca2d1 100644 --- a/hw/riscv/dtm.c +++ b/hw/riscv/dtm.c @@ -516,7 +516,7 @@ static void riscv_dtm_activate_dms(RISCVDTMState *s) static Property riscv_dtm_properties[] = { DEFINE_PROP_UINT32("abits", RISCVDTMState, abits, 0x7u), - DEFINE_PROP_LINK("tap_ctrl", RISCVDTMState, tap_ctrl, TYPE_DEVICE, + DEFINE_PROP_LINK("tap-ctrl", RISCVDTMState, tap_ctrl, TYPE_DEVICE, DeviceState *), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/riscv/ibexdemo.c b/hw/riscv/ibexdemo.c index e8a468cce749..97affe33a150 100644 --- a/hw/riscv/ibexdemo.c +++ b/hw/riscv/ibexdemo.c @@ -152,7 +152,7 @@ static const IbexDeviceDef ibexdemo_soc_devices[] = { [IBEXDEMO_SOC_DEV_DTM] = { .type = TYPE_RISCV_DTM, .link = IBEXDEVICELINKDEFS( - IBEXDEMO_SOC_DEVLINK("tap_ctrl", TAP_CTRL) + IBEXDEMO_SOC_DEVLINK("tap-ctrl", TAP_CTRL) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("abits", 7u) diff --git a/hw/riscv/ot_darjeeling.c b/hw/riscv/ot_darjeeling.c index d4d92f0495c7..b267500cb050 100644 --- a/hw/riscv/ot_darjeeling.c +++ b/hw/riscv/ot_darjeeling.c @@ -44,7 +44,7 @@ #include "hw/opentitan/ot_dm_tl.h" #include "hw/opentitan/ot_dma.h" #include "hw/opentitan/ot_edn.h" -#include "hw/opentitan/ot_entropy_src_dj.h" +#include "hw/opentitan/ot_entropy_src.h" #include "hw/opentitan/ot_gpio_dj.h" #include "hw/opentitan/ot_hmac.h" #include "hw/opentitan/ot_i2c.h" @@ -523,7 +523,7 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { [OT_DJ_SOC_DEV_DTM] = { .type = TYPE_RISCV_DTM, .link = IBEXDEVICELINKDEFS( - OT_DJ_SOC_DEVLINK("tap_ctrl", TAP_CTRL) + OT_DJ_SOC_DEVLINK("tap-ctrl", TAP_CTRL) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("abits", 12u) @@ -716,8 +716,8 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { OT_DJ_SOC_DEVLINK("edn", EDN0), OT_DJ_SOC_DEVLINK("kmac", KMAC), OT_DJ_SOC_DEVLINK("otbn", OTBN), - OT_DJ_SOC_DEVLINK("lc_ctrl", LC_CTRL), - OT_DJ_SOC_DEVLINK("otp_ctrl", OTP_CTRL), + OT_DJ_SOC_DEVLINK("lc-ctrl", LC_CTRL), + OT_DJ_SOC_DEVLINK("otp-ctrl", OTP_CTRL), OT_DJ_SOC_DEVLINK("rom0", ROM_CTRL0), OT_DJ_SOC_DEVLINK("rom1", ROM_CTRL1) ), @@ -740,50 +740,31 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { OT_DJ_SOC_GPIO_ALERT(1, 34) ), .link = IBEXDEVICELINKDEFS( - OT_DJ_SOC_DEVLINK("random_src", AST), - OT_DJ_SOC_DEVLINK("otp_ctrl", OTP_CTRL) + OT_DJ_SOC_DEVLINK("entropy-src", ENTROPY_SRC), + OT_DJ_SOC_DEVLINK("otp-ctrl", OTP_CTRL) ), }, [OT_DJ_SOC_DEV_ENTROPY_SRC] = { - .type = TYPE_OT_UNIMP, - .cfg = &ibex_unimp_configure, + .type = TYPE_OT_ENTROPY_SRC, .memmap = MEMMAPENTRIES( - { .base = 0x21160000u } - ), - .prop = IBEXDEVICEPROPDEFS( - IBEX_DEV_STRING_PROP(OT_COMMON_DEV_ID, "entropy_src"), - IBEX_DEV_UINT_PROP("size", 0x100u), - IBEX_DEV_UINT_PROP("alert-count", 2u), - IBEX_DEV_BOOL_PROP("warn-once", true) + { .base = 0x21160000u } ), .gpio = IBEXGPIOCONNDEFS( - OT_DJ_SOC_GPIO_ALERT(0, 35), - OT_DJ_SOC_GPIO_ALERT(1, 36) + OT_DJ_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 89), + OT_DJ_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 90), + OT_DJ_SOC_GPIO_SYSBUS_IRQ(2, PLIC, 91), + OT_DJ_SOC_GPIO_SYSBUS_IRQ(3, PLIC, 92), + OT_DJ_SOC_GPIO_ALERT(0, 35), + OT_DJ_SOC_GPIO_ALERT(1, 36) + ), + .link = IBEXDEVICELINKDEFS( + OT_DJ_SOC_DEVLINK("noise-src", AST), + OT_DJ_SOC_DEVLINK("otp-ctrl", OTP_CTRL) + ), + .prop = IBEXDEVICEPROPDEFS( + IBEX_DEV_UINT_PROP("version", 3) ), }, - /* - * @todo enable DJ entropy source once implemented, replacing the above - * unimplemented fake device - * - * [OT_DJ_SOC_DEV_ENTROPY_SRC] = { - * .type = TYPE_OT_ENTROPY_SRC, - * .memmap = MEMMAPENTRIES( - * { .base = 0x21160000u } - * ), - * .gpio = IBEXGPIOCONNDEFS( - * OT_DJ_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 89), - * OT_DJ_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 90), - * OT_DJ_SOC_GPIO_SYSBUS_IRQ(2, PLIC, 91), - * OT_DJ_SOC_GPIO_SYSBUS_IRQ(3, PLIC, 92), - * OT_DJ_SOC_GPIO_ALERT(0, 35), - * OT_DJ_SOC_GPIO_ALERT(1, 36) - * ), - * .link = IBEXDEVICELINKDEFS( - * OT_DJ_SOC_DEVLINK("ast", AST), - * OT_DJ_SOC_DEVLINK("otp_ctrl", OTP_CTRL) - * ), - * }, - */ [OT_DJ_SOC_DEV_EDN0] = { .type = TYPE_OT_EDN, .memmap = MEMMAPENTRIES( @@ -830,7 +811,7 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { OT_DJ_SOC_GPIO_ALERT(0, 41) ), .link = IBEXDEVICELINKDEFS( - OT_DJ_SOC_DEVLINK("otp_ctrl", OTP_CTRL), + OT_DJ_SOC_DEVLINK("otp-ctrl", OTP_CTRL), OT_DJ_SOC_DEVLINK("vmapper", VMAPPER) ), .prop = IBEXDEVICEPROPDEFS( @@ -849,7 +830,7 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { OT_DJ_SOC_GPIO_ALERT(0, 42) ), .link = IBEXDEVICELINKDEFS( - OT_DJ_SOC_DEVLINK("otp_ctrl", OTP_CTRL), + OT_DJ_SOC_DEVLINK("otp-ctrl", OTP_CTRL), OT_DJ_SOC_DEVLINK("vmapper", VMAPPER) ), .prop = IBEXDEVICEPROPDEFS( @@ -1194,7 +1175,7 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { OT_DJ_SOC_RSP(OT_PWRMGR_LC, PWRMGR) ), .link = IBEXDEVICELINKDEFS( - OT_DJ_SOC_DEVLINK("otp_ctrl", OTP_CTRL), + OT_DJ_SOC_DEVLINK("otp-ctrl", OTP_CTRL), OT_DJ_SOC_DEVLINK("kmac", KMAC) ), .prop = IBEXDEVICEPROPDEFS( @@ -1304,7 +1285,7 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { OT_RSTMGR_RST_REQ, 0) ), .link = IBEXDEVICELINKDEFS( - OT_DJ_SOC_DEVLINK("clock_ctrl", AST) + OT_DJ_SOC_DEVLINK("clock-ctrl", AST) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_STRING_PROP("clocks", "main,io"), @@ -1440,7 +1421,7 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { OT_DJ_SOC_GPIO_ALERT(0, 21) ), .link = IBEXDEVICELINKDEFS( - OT_DJ_SOC_DEVLINK("otp_ctrl", OTP_CTRL), + OT_DJ_SOC_DEVLINK("otp-ctrl", OTP_CTRL), OT_DJ_SOC_DEVLINK("vmapper", VMAPPER) ), .prop = IBEXDEVICEPROPDEFS( diff --git a/hw/riscv/ot_earlgrey.c b/hw/riscv/ot_earlgrey.c index 0bb082af3e0f..0fdfc591cefb 100644 --- a/hw/riscv/ot_earlgrey.c +++ b/hw/riscv/ot_earlgrey.c @@ -46,7 +46,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_eg.h" +#include "hw/opentitan/ot_entropy_src.h" #include "hw/opentitan/ot_flash.h" #include "hw/opentitan/ot_gpio_eg.h" #include "hw/opentitan/ot_hmac.h" @@ -363,7 +363,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { [OT_EG_SOC_DEV_DTM] = { .type = TYPE_RISCV_DTM, .link = IBEXDEVICELINKDEFS( - OT_EG_SOC_DEVLINK("tap_ctrl", TAP_CTRL) + OT_EG_SOC_DEVLINK("tap-ctrl", TAP_CTRL) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("abits", 7u) @@ -776,7 +776,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_LC_BROADCAST, OT_OTP_LC_CHECK_BYP_EN) ), .link = IBEXDEVICELINKDEFS( - OT_EG_SOC_DEVLINK("otp_ctrl", OTP_CTRL), + OT_EG_SOC_DEVLINK("otp-ctrl", OTP_CTRL), OT_EG_SOC_DEVLINK("kmac", KMAC) ), .prop = IBEXDEVICEPROPDEFS( @@ -912,7 +912,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_RSTMGR_RST_REQ, 0) ), .link = IBEXDEVICELINKDEFS( - OT_EG_SOC_DEVLINK("clock_ctrl", AST) + OT_EG_SOC_DEVLINK("clock-ctrl", AST) ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_STRING_PROP("clocks", "main,io,usb"), @@ -1076,7 +1076,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_ALERT(0, 34) ), .link = IBEXDEVICELINKDEFS( - OT_EG_SOC_DEVLINK("otp_ctrl", OTP_CTRL), + OT_EG_SOC_DEVLINK("otp-ctrl", OTP_CTRL), OT_EG_SOC_DEVLINK("vmapper", VMAPPER) ), .prop = IBEXDEVICEPROPDEFS( @@ -1204,9 +1204,9 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_DEVLINK("edn", EDN0), OT_EG_SOC_DEVLINK("flash_ctrl", FLASH_CTRL), OT_EG_SOC_DEVLINK("kmac", KMAC), - OT_EG_SOC_DEVLINK("lc_ctrl", LC_CTRL), + OT_EG_SOC_DEVLINK("lc-ctrl", LC_CTRL), OT_EG_SOC_DEVLINK("otbn", OTBN), - OT_EG_SOC_DEVLINK("otp_ctrl", OTP_CTRL), + OT_EG_SOC_DEVLINK("otp-ctrl", OTP_CTRL), OT_EG_SOC_DEVLINK("rom_ctrl", ROM_CTRL) ), .prop = IBEXDEVICEPROPDEFS( @@ -1228,12 +1228,12 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_ALERT(1, 52) ), .link = IBEXDEVICELINKDEFS( - OT_EG_SOC_DEVLINK("random_src", ENTROPY_SRC), - OT_EG_SOC_DEVLINK("otp_ctrl", OTP_CTRL) + OT_EG_SOC_DEVLINK("entropy-src", ENTROPY_SRC), + OT_EG_SOC_DEVLINK("otp-ctrl", OTP_CTRL) ), }, [OT_EG_SOC_DEV_ENTROPY_SRC] = { - .type = TYPE_OT_ENTROPY_SRC_EG, + .type = TYPE_OT_ENTROPY_SRC, .memmap = MEMMAPENTRIES( { .base = 0x41160000u } ), @@ -1246,8 +1246,11 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_ALERT(1, 54) ), .link = IBEXDEVICELINKDEFS( - OT_EG_SOC_DEVLINK("ast", AST), - OT_EG_SOC_DEVLINK("otp_ctrl", OTP_CTRL) + OT_EG_SOC_DEVLINK("noise-src", AST), + OT_EG_SOC_DEVLINK("otp-ctrl", OTP_CTRL) + ), + .prop = IBEXDEVICEPROPDEFS( + IBEX_DEV_UINT_PROP("version", 2) ), }, [OT_EG_SOC_DEV_EDN0] = { @@ -1296,7 +1299,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_GPIO_ALERT(0, 59) ), .link = IBEXDEVICELINKDEFS( - OT_EG_SOC_DEVLINK("otp_ctrl", OTP_CTRL), + OT_EG_SOC_DEVLINK("otp-ctrl", OTP_CTRL), OT_EG_SOC_DEVLINK("vmapper", VMAPPER) ), .prop = IBEXDEVICEPROPDEFS( diff --git a/include/hw/opentitan/ot_ast_eg.h b/include/hw/opentitan/ot_ast_eg.h index 04e297a60bd7..fc55015c84f8 100644 --- a/include/hw/opentitan/ot_ast_eg.h +++ b/include/hw/opentitan/ot_ast_eg.h @@ -33,8 +33,4 @@ #define TYPE_OT_AST_EG "ot-ast-eg" OBJECT_DECLARE_TYPE(OtASTEgState, OtASTEgClass, OT_AST_EG) -#define OT_AST_EG_RANDOM_4BIT_RATE 50000u /* 50 kHz */ - -void ot_ast_eg_getrandom(void *buf, size_t len); - #endif /* HW_OPENTITAN_OT_AST_EG_H */ diff --git a/include/hw/opentitan/ot_common.h b/include/hw/opentitan/ot_common.h index b53a5f937edc..8e9824935ada 100644 --- a/include/hw/opentitan/ot_common.h +++ b/include/hw/opentitan/ot_common.h @@ -71,6 +71,12 @@ #define OT_MULTIBITBOOL_LC4_TRUE 0xau #define OT_MULTIBITBOOL_LC4_FALSE 0x5u +typedef uint8_t ot_mb4_t; +typedef uint8_t ot_mb8_t; +typedef uint16_t ot_mb12_t; +typedef uint16_t ot_mb16_t; +typedef uint8_t ot_mb_lc4_t; + /* * Performs a logical OR operation between two multibit values. * This treats "act" as logical 1, and all other values are treated as 0. diff --git a/include/hw/opentitan/ot_random_src.h b/include/hw/opentitan/ot_entropy_src.h similarity index 62% rename from include/hw/opentitan/ot_random_src.h rename to include/hw/opentitan/ot_entropy_src.h index 606ef74091de..85971db981c1 100644 --- a/include/hw/opentitan/ot_random_src.h +++ b/include/hw/opentitan/ot_entropy_src.h @@ -1,10 +1,9 @@ /* - * QEMU OpenTitan Random Source interface + * QEMU OpenTitan Entropy Source device * - * Copyright (c) 2023-2024 Rivos, Inc. + * Copyright (c) 2023-2025 Rivos, Inc. * Copyright (c) 2025 lowRISC contributors. * - * * Author(s): * Emmanuel Blot * @@ -27,33 +26,29 @@ * THE SOFTWARE. */ -#ifndef HW_OPENTITAN_OT_RANDOM_SRC_H -#define HW_OPENTITAN_OT_RANDOM_SRC_H +#ifndef HW_OPENTITAN_OT_ENTROPY_SRC_H +#define HW_OPENTITAN_OT_ENTROPY_SRC_H #include "qom/object.h" -#define TYPE_OT_RANDOM_SRC_IF "ot-random_src_if" -typedef struct OtRandomSrcIfClass OtRandomSrcIfClass; -DECLARE_CLASS_CHECKERS(OtRandomSrcIfClass, OT_RANDOM_SRC_IF, - TYPE_OT_RANDOM_SRC_IF) -#define OT_RANDOM_SRC_IF(_obj_) \ - INTERFACE_CHECK(OtRandomSrcIf, (_obj_), TYPE_OT_RANDOM_SRC_IF) - -#define OT_RANDOM_SRC_PACKET_SIZE_BITS 384u +#define TYPE_OT_ENTROPY_SRC "ot-entropy_src" +OBJECT_DECLARE_TYPE(OtEntropySrcState, OtEntropySrcClass, OT_ENTROPY_SRC) -#define OT_RANDOM_SRC_BYTE_COUNT (OT_RANDOM_SRC_PACKET_SIZE_BITS / 8u) -#define OT_RANDOM_SRC_WORD_COUNT (OT_RANDOM_SRC_BYTE_COUNT / sizeof(uint32_t)) -#define OT_RANDOM_SRC_DWORD_COUNT (OT_RANDOM_SRC_BYTE_COUNT / sizeof(uint64_t)) +#define OT_ENTROPY_SRC_PACKET_SIZE_BITS 384u -typedef struct OtRandomSrcIf OtRandomSrcIf; +#define OT_ENTROPY_SRC_BYTE_COUNT (OT_ENTROPY_SRC_PACKET_SIZE_BITS / 8u) +#define OT_ENTROPY_SRC_WORD_COUNT (OT_ENTROPY_SRC_BYTE_COUNT / sizeof(uint32_t)) +#define OT_ENTROPY_SRC_DWORD_COUNT \ + (OT_ENTROPY_SRC_BYTE_COUNT / sizeof(uint64_t)) -struct OtRandomSrcIfClass { - InterfaceClass parent_class; +struct OtEntropySrcClass { + SysBusDeviceClass parent_class; + ResettablePhases parent_phases; /* * Fill up a buffer with random values * - * @dev the random source instance + * @ess the entropy source instance * @random the buffer to fill in with random data * @fips on success, updated to @true if random data are FIPS-compliant * @return 0 on success, @@ -63,9 +58,8 @@ struct OtRandomSrcIfClass { * -1 if the random source is not available, i.e. if the module is * not enabled or if the selected route is not the HW one, */ - int (*get_random_values)(OtRandomSrcIf *dev, - uint64_t random[OT_RANDOM_SRC_DWORD_COUNT], - bool *fips); + int (*get_entropy)(OtEntropySrcState *ess, + uint64_t random[OT_ENTROPY_SRC_DWORD_COUNT], bool *fips); }; -#endif /* HW_OPENTITAN_OT_RANDOM_SRC_H */ +#endif /* HW_OPENTITAN_OT_ENTROPY_SRC_H */ diff --git a/include/hw/opentitan/ot_entropy_src_dj.h b/include/hw/opentitan/ot_entropy_src_dj.h deleted file mode 100644 index 7aa1ea225287..000000000000 --- a/include/hw/opentitan/ot_entropy_src_dj.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * QEMU OpenTitan Darjeeling 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_DJ_H -#define HW_OPENTITAN_OT_ENTROPY_SRC_DJ_H - -#include "qom/object.h" - -#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_DJ_H */ diff --git a/include/hw/opentitan/ot_entropy_src_eg.h b/include/hw/opentitan/ot_noise_src.h similarity index 56% rename from include/hw/opentitan/ot_entropy_src_eg.h rename to include/hw/opentitan/ot_noise_src.h index cd76e8303bbe..c88b869110d6 100644 --- a/include/hw/opentitan/ot_entropy_src_eg.h +++ b/include/hw/opentitan/ot_noise_src.h @@ -1,7 +1,7 @@ /* - * QEMU OpenTitan Earlgrey 1.0.0 Entropy Source device + * QEMU OpenTitan Noise Source interface * - * Copyright (c) 2023-2025 Rivos, Inc. + * Copyright (c) 2025 Rivos, Inc. * Copyright (c) 2025 lowRISC contributors. * * Author(s): @@ -26,12 +26,36 @@ * THE SOFTWARE. */ -#ifndef HW_OPENTITAN_OT_ENTROPY_SRC_EG_H -#define HW_OPENTITAN_OT_ENTROPY_SRC_EG_H +#ifndef HW_OPENTITAN_OT_NOISE_SRC_H +#define HW_OPENTITAN_OT_NOISE_SRC_H #include "qom/object.h" -#define TYPE_OT_ENTROPY_SRC_EG "ot-entropy_src-eg" -OBJECT_DECLARE_TYPE(OtEntropySrcEgState, OtEntropySrcEgClass, OT_ENTROPY_SRC_EG) +#define TYPE_OT_NOISE_SRC_IF "ot-noise_src_if" +typedef struct OtNoiseSrcIfClass OtNoiseSrcIfClass; +DECLARE_CLASS_CHECKERS(OtNoiseSrcIfClass, OT_NOISE_SRC_IF, TYPE_OT_NOISE_SRC_IF) +#define OT_NOISE_SRC_IF(_obj_) \ + INTERFACE_CHECK(OtNoiseSrcIf, (_obj_), TYPE_OT_NOISE_SRC_IF) -#endif /* HW_OPENTITAN_OT_ENTROPY_SRC_EG_H */ +typedef struct OtNoiseSrcIf OtNoiseSrcIf; + +struct OtNoiseSrcIfClass { + InterfaceClass parent_class; + + /* + * Report the fill rate of this source. + * + * @return the fill rate, in bytes per second + */ + unsigned (*get_fill_rate)(OtNoiseSrcIf *dev); + + /* + * Fill up a buffer with noise data + * + * @buffer destination buffer + * @length number of bytes to fill in + */ + void (*get_noise)(OtNoiseSrcIf *dev, uint8_t *buffer, size_t length); +}; + +#endif /* HW_OPENTITAN_OT_NOISE_SRC_H */ diff --git a/include/hw/opentitan/ot_otp.h b/include/hw/opentitan/ot_otp.h index 7378376f72cc..12a9fdc56016 100644 --- a/include/hw/opentitan/ot_otp.h +++ b/include/hw/opentitan/ot_otp.h @@ -30,6 +30,7 @@ #define HW_OPENTITAN_OT_OTP_H #include "qom/object.h" +#include "hw/opentitan/ot_common.h" #include "hw/sysbus.h" #define TYPE_OT_OTP "ot-otp" @@ -57,22 +58,22 @@ typedef enum { #define OT_OTP_HWCFG_SOC_DBG_STATE_BYTES 4u /* - * Hardware configuration (for HW_CFG partition) + * Hardware configuration (for HW_CFG partitions). + * + * Digests are not added to this structure since real HW does not use them + * + * Note that some fields may be meaningless / not initialized depending on the + * actual OpenTitan top. */ typedef struct { uint8_t device_id[OT_OTP_HWCFG_DEVICE_ID_BYTES]; uint8_t manuf_state[OT_OTP_HWCFG_MANUF_STATE_BYTES]; - /* soc_dbg_state may be meaningless, dep. on the platform */ uint8_t soc_dbg_state[OT_OTP_HWCFG_SOC_DBG_STATE_BYTES]; - /* the following value is stored as OT_MULTIBITBOOL8 */ - uint8_t en_sram_ifetch; + ot_mb8_t en_sram_ifetch_mb8; + ot_mb8_t en_csrng_sw_app_read_mb8; + ot_mb_lc4_t valid_lc4; /* seems generated but no used on real HW */ } OtOTPHWCfg; -typedef struct { - /* the following values are stored as OT_MULTIBITBOOL8 */ - uint8_t en_csrng_sw_app_read; -} OtOTPEntropyCfg; - typedef enum { OTP_TOKEN_TEST_UNLOCK, OTP_TOKEN_TEST_EXIT, @@ -158,14 +159,6 @@ struct OtOTPClass { */ const OtOTPHWCfg *(*get_hw_cfg)(const OtOTPState *s); - /* - * Retrieve entropy configuration. - * - * @s the OTP device - * @return the entropy config data (may be NULL if not present in OTP) - */ - const OtOTPEntropyCfg *(*get_entropy_cfg)(const OtOTPState *s); - /* * Retrieve SRAM scrambling key. *