diff --git a/.gitlab-ci.d/opentitan/qemu-ot.yml b/.gitlab-ci.d/opentitan/qemu-ot.yml index e0800b57d884d..2e0fdae3a1ea5 100644 --- a/.gitlab-ci.d/opentitan/qemu-ot.yml +++ b/.gitlab-ci.d/opentitan/qemu-ot.yml @@ -1,5 +1,5 @@ variables: - BAREMETAL_REF: "b0-250310-1" + BAREMETAL_REF: "b0-250325-1" QEMU_BUILD_OPTS: "--disable-install-blobs" include: diff --git a/docs/opentitan/earlgrey.md b/docs/opentitan/earlgrey.md index 1d1c203f6e440..3dd1d3177d8a7 100644 --- a/docs/opentitan/earlgrey.md +++ b/docs/opentitan/earlgrey.md @@ -128,6 +128,9 @@ See [`tools.md`](tools.md) update the vCPU reset vector at startup. When this option is used, with `-kernel` option for example, the application is loaded in memory but the default machine reset vector is used. +* `verilator=true` can be appended to the machine option switch, to select Verilator lowered clocks: + _i.e._ `-M ot-earlgrey,verilator=true` to select Verilator reduced clock rates. + * `-cpu lowrisc-ibex,x-zbr=false` can be used to force disable the Zbr experimental-and-deprecated RISC-V bitmap extension for CRC32 extension. @@ -155,8 +158,12 @@ See [`tools.md`](tools.md) ### OTBN -* `-global ot-otbn.logfile=` dumps executed instructions on OTBN core into the specified - filename. Beware that is even further slows down execution speed, which could likely result into +* `-global ot-otbn.logfile=` output OTBN execution message to the specified logfile. When + _logasm_ option (see below) is not enabled, only execution termination and error messages are + logged. `stderr` can be used to log the messages to the standard error stream instead of a file. + +* `-global ot-otbn.logasm=` dumps executed instructions on OTBN core into the _logfile_ + filename. Beware that this further slows down execution speed, which could likely result in the guest application on the Ibex core to time out. ### OTP diff --git a/hw/opentitan/Kconfig b/hw/opentitan/Kconfig index 68eee35232204..9133ba2a4d86d 100644 --- a/hw/opentitan/Kconfig +++ b/hw/opentitan/Kconfig @@ -138,7 +138,7 @@ config OT_ROM_CTRL config OT_RSTMGR bool -config OT_SENSOR +config OT_SENSOR_EG bool config OT_SOC_PROXY diff --git a/hw/opentitan/meson.build b/hw/opentitan/meson.build index 7fffd4db4144f..6cebf39e835f5 100644 --- a/hw/opentitan/meson.build +++ b/hw/opentitan/meson.build @@ -45,7 +45,7 @@ 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', if_true: files('ot_sensor.c')) +system_ss.add(when: 'CONFIG_OT_SENSOR_EG', if_true: files('ot_sensor_eg.c')) system_ss.add(when: 'CONFIG_OT_SOC_PROXY', if_true: files('ot_soc_proxy.c')) system_ss.add(when: 'CONFIG_OT_SOCDBG_CTRL', if_true: files('ot_socdbg_ctrl.c')) system_ss.add(when: 'CONFIG_OT_SPI_DEVICE', if_true: files('ot_spi_device.c')) diff --git a/hw/opentitan/ot_aes.c b/hw/opentitan/ot_aes.c index 43c0cd51f8868..e0124f1b82acc 100644 --- a/hw/opentitan/ot_aes.c +++ b/hw/opentitan/ot_aes.c @@ -201,6 +201,7 @@ typedef struct OtAESRegisters { DECLARE_BITMAP(data_in_bm, PARAM_NUM_REGS_DATA); DECLARE_BITMAP(data_out_bm, PARAM_NUM_REGS_DATA); uint32_t key[PARAM_NUM_REGS_KEY]; + bool data_out_rdy; /* AES output data exist, not yet published */ } OtAESRegisters; typedef struct OtAESContext { @@ -399,6 +400,8 @@ static inline void ot_aes_load_reseed_rate(OtAESState *s) break; } + trace_ot_aes_reseed_rate(reseed); + s->reseed_count = reseed; } @@ -803,9 +806,7 @@ static void ot_aes_push(OtAESState *s) memcpy(r->data_out, c->dst, sizeof(c->dst)); memcpy(r->iv, c->iv, sizeof(c->iv)); - bitmap_fill(r->data_out_bm, PARAM_NUM_REGS_DATA); - - r->status |= R_STATUS_OUTPUT_VALID_MASK; + r->data_out_rdy = true; } static void ot_aes_process(OtAESState *s) @@ -898,6 +899,15 @@ static void ot_aes_process(OtAESState *s) } } +static void ot_aes_commit_data_out(OtAESRegisters *r) +{ + if (r->data_out_rdy) { + bitmap_fill(r->data_out_bm, PARAM_NUM_REGS_DATA); + r->status |= R_STATUS_OUTPUT_VALID_MASK; + r->data_out_rdy = false; + } +} + static inline void ot_aes_do_process(OtAESState *s) { ot_aes_process(s); @@ -906,10 +916,18 @@ static inline void ot_aes_do_process(OtAESState *s) s->reseed_count -= 1u; } if (!s->reseed_count) { + /* + * delay availability of pushed data till completion of reseed + * otherwise, IDLE status may be false once the vCPU has read the data, + * which would not match the HW behavior + */ trace_ot_aes_reseed("reseed_count reached"); s->regs->trigger |= R_TRIGGER_PRNG_RESEED_MASK; ot_aes_trigger_reseed(s); ot_aes_load_reseed_rate(s); + } else { + /* flag pushed data as immediately available */ + ot_aes_commit_data_out(s->regs); } OtAESRegisters *r = s->regs; @@ -968,6 +986,13 @@ static void ot_aes_fill_entropy(void *opaque, uint32_t bits, bool fips) edn->scheduled = false; r->trigger &= ~R_TRIGGER_PRNG_RESEED_MASK; + /* + * if a previous AES data output generation had completed, flag the output + * as valid, as this state was delayed till entropy collection was + * completed to maintain a coherent IDLE state. + */ + ot_aes_commit_data_out(r); + ot_prng_reseed(s->prng, bits); ot_aes_handle_trigger(s); @@ -1270,6 +1295,7 @@ static void ot_aes_reset(DeviceState *dev) r->ctrl_aux_regwen = 1u; r->trigger = 0xeu; r->status = 0u; + r->data_out_rdy = false; e->scheduled = false; ot_aes_load_reseed_rate(s); diff --git a/hw/opentitan/ot_ast_dj.c b/hw/opentitan/ot_ast_dj.c index cfaad3d521a54..4dda91601ebd2 100644 --- a/hw/opentitan/ot_ast_dj.c +++ b/hw/opentitan/ot_ast_dj.c @@ -1,7 +1,7 @@ /* * QEMU OpenTitan Darjeeling Analog Sensor Top device * - * Copyright (c) 2023-2024 Rivos, Inc. + * Copyright (c) 2023-2025 Rivos, Inc. * * Author(s): * Emmanuel Blot @@ -152,26 +152,12 @@ struct OtASTDjState { /* Private implementation */ /* -------------------------------------------------------------------------- */ -static int ot_ast_dj_get_generation(OtRandomSrcIf *dev) -{ - (void)dev; - - return -1; -} - -static int ot_ast_dj_get_random(OtRandomSrcIf *dev, int genid, - uint64_t random[OT_RANDOM_SRC_DWORD_COUNT], - bool *fips) +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 (genid != -1) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: AST gennum mismatch req:%d\n", - __func__, genid); - return -2; - } - if (!rnd->avail) { /* not ready */ trace_ot_ast_no_entropy(0); @@ -441,7 +427,6 @@ static void ot_ast_dj_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); OtRandomSrcIfClass *rdc = OT_RANDOM_SRC_IF_CLASS(klass); - rdc->get_random_generation = &ot_ast_dj_get_generation; rdc->get_random_values = &ot_ast_dj_get_random; } diff --git a/hw/opentitan/ot_common.c b/hw/opentitan/ot_common.c index 7cf57753f9931..32ff99042c597 100644 --- a/hw/opentitan/ot_common.c +++ b/hw/opentitan/ot_common.c @@ -1,7 +1,8 @@ /* * QEMU OpenTitan utilities * - * Copyright (c) 2023 Rivos, Inc. + * Copyright (c) 2023-2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -221,8 +222,7 @@ AddressSpace *ot_common_get_local_address_space(DeviceState *s) return cpu ? cpu->as : NULL; } -static void -ot_common_configure_device_opts(DeviceState **devices, unsigned count) +void ot_common_configure_device_opts(DeviceState **devices, unsigned count) { // TODO need to use qemu_find_opts_err if no config is ok QemuOptsList *optlist = qemu_find_opts("ot_device"); diff --git a/hw/opentitan/ot_csrng.c b/hw/opentitan/ot_csrng.c index 948ea20ee407f..601d5d57e0961 100644 --- a/hw/opentitan/ot_csrng.c +++ b/hw/opentitan/ot_csrng.c @@ -2,6 +2,7 @@ * QEMU OpenTitan Cryptographically Secure Random Number Generator * * Copyright (c) 2023-2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -28,7 +29,6 @@ */ #include "qemu/osdep.h" -#include "qemu/guest-random.h" #include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/queue.h" @@ -51,6 +51,7 @@ #define PARAM_NUM_IRQS 4u #define PARAM_NUM_ALERTS 2u +#define N_APP_COUNT (OT_CSRNG_HW_APP_MAX + 1u) /* clang-format off */ REG32(INTR_STATE, 0x0u) @@ -84,16 +85,16 @@ REG32(GENBITS_VLD, 0x30u) FIELD(GENBITS_VLD, GENBITS_FIPS, 1u, 1u) REG32(GENBITS, 0x34u) REG32(INT_STATE_READ_ENABLE, 0x38u) - FIELD(INT_STATE_READ_ENABLE, INT_STATE_READ_ENABLE, 0u, 3u) + FIELD(INT_STATE_READ_ENABLE, VAL, 0u, N_APP_COUNT) REG32(INT_STATE_READ_ENABLE_REGWEN, 0x3cu) - FIELD(INT_STATE_READ_ENABLE, INT_STATE_READ_ENABLE_REGWEN, 0u, 1u) + FIELD(INT_STATE_READ_ENABLE_REGWEN, EN, 0u, 1u) REG32(INT_STATE_NUM, 0x40u) FIELD(INT_STATE_NUM, VAL, 0u, 4u) REG32(INT_STATE_VAL, 0x44u) REG32(FIPS_FORCE, 0x48u) - FIELD(FIPS_FORCE, FIPS_FORCE, 0u, 2u) + FIELD(FIPS_FORCE, VAL, 0u, N_APP_COUNT) REG32(HW_EXC_STS, 0x4cu) - FIELD(HW_EXC_STS, HW_EXC_STS, 0u, 16u) + FIELD(HW_EXC_STS, VAL, 0u, 16u) REG32(RECOV_ALERT_STS, 0x50u) FIELD(RECOV_ALERT_STS, ENABLE_FIELD_ALERT, 0u, 1u) FIELD(RECOV_ALERT_STS, SW_APP_ENABLE_FIELD_ALERT, 1u, 1u) @@ -152,19 +153,19 @@ REG32(MAIN_SM_STATE, 0x5cu) (R_ALERT_TEST_RECOV_ALERT_MASK | R_ALERT_TEST_FATAL_ALERT_MASK) #define CTRL_MASK \ (R_CTRL_ENABLE_MASK | R_CTRL_SW_APP_ENABLE_MASK | \ - R_CTRL_READ_INT_STATE_MASK) + R_CTRL_READ_INT_STATE_MASK | R_CTRL_FIPS_FORCE_ENABLE_MASK) #define GENBITS_VLD_MASK \ (R_GENBITS_VLD_GENBITS_VLD_MASK | R_GENBITS_VLD_GENBITS_FIPS_MASK) #define RECOV_ALERT_STS_MASK \ (R_RECOV_ALERT_STS_ENABLE_FIELD_ALERT_MASK | \ R_RECOV_ALERT_STS_SW_APP_ENABLE_FIELD_ALERT_MASK | \ R_RECOV_ALERT_STS_READ_INT_STATE_FIELD_ALERT_MASK | \ - R_RECOV_ALERT_STS_FIPS_FORCE_ENABLE_FIELD_ALERT | \ - R_RECOV_ALERT_STS_ACMD_FLAG0_FIELD_ALERT | \ + R_RECOV_ALERT_STS_FIPS_FORCE_ENABLE_FIELD_ALERT_MASK | \ + R_RECOV_ALERT_STS_ACMD_FLAG0_FIELD_ALERT_MASK | \ R_RECOV_ALERT_STS_CS_BUS_CMP_ALERT_MASK | \ - R_RECOV_ALERT_STS_CMD_STAGE_INVALID_ACMD_ALERT | \ - R_RECOV_ALERT_STS_CMD_STAGE_INVALID_CMD_SEQ_ALERT | \ - R_RECOV_ALERT_STS_CMD_STAGE_RESEED_CNT_ALERT) + R_RECOV_ALERT_STS_CMD_STAGE_INVALID_ACMD_ALERT_MASK | \ + R_RECOV_ALERT_STS_CMD_STAGE_INVALID_CMD_SEQ_ALERT_MASK | \ + R_RECOV_ALERT_STS_CMD_STAGE_INVALID_RESEED_CNT_ALERT_MASK) #define ERR_CODE_MASK 0x77e0ffffu #define OT_CSRNG_AES_KEY_SIZE 32u /* 256 bits */ @@ -173,6 +174,16 @@ REG32(MAIN_SM_STATE, 0x5cu) #define OT_CSRNG_AES_BLOCK_WORD (OT_CSRNG_AES_BLOCK_SIZE / sizeof(uint32_t)) #define OT_CSRNG_AES_BLOCK_DWORD (OT_CSRNG_AES_BLOCK_SIZE / sizeof(uint64_t)) +/* + * Should be limited to OT_CSRNG_CMD_WORD_MAX, but the HW does not enforce it + * so be sure to accept CLEN up to 15, not 12. CLEN being coded on 4 bits, and + * command using 1 slot, the actual CLEN is limited to 15. HW ignores the + * trailing additional data words ([12..15]) + */ +#define CMD_FIFO_CAPACITY (R_OT_CSNRG_CMD_CLEN_MASK + 1u) + +#define SW_INSTANCE_ID OT_CSRNG_HW_APP_MAX + #define ALERT_STATUS_BIT(_x_) R_RECOV_ALERT_STS_##_x_##_FIELD_ALERT_MASK #define REG_NAME_ENTRY(_reg_) [R_##_reg_] = stringify(_reg_) @@ -231,8 +242,6 @@ static_assert(OT_CSRNG_AES_BLOCK_SIZE + OT_CSRNG_AES_KEY_SIZE == #define xtrace_ot_csrng_show_buffer(_id_, _msg_, _buf_, _len_) \ ot_csrng_show_buffer(__func__, __LINE__, _id_, _msg_, _buf_, _len_) -#define SW_INSTANCE_ID OT_CSRNG_HW_APP_MAX - #define ENTROPY_SRC_INITIAL_REQUEST_COUNT 5u enum { @@ -243,12 +252,27 @@ enum { static_assert(ALERT_COUNT == PARAM_NUM_ALERTS, "Invalid alert count"); +/* + * Command execution result. + * + * Zero value signals the success and immediate completion of a command + * Positive values signal a deferred completion of a command + * Negative values signal an error, encoding a OtCSRNGCmdStatus value + */ typedef enum { - CSRNG_CMD_STALLED = -2, /* entropy stack is stalled */ - CSRNG_CMD_ERROR = -1, /* command error, not recoverable */ - CSRNG_CMD_OK = 0, /* command completed ok */ - CSRNG_CMD_RETRY = 1, /* command cannot be executed for now */ - CSRNG_CMD_DEFERRED = 2, /* command completion deferred */ + /* entropy stack is stalled */ + CSRNG_CMD_STALLED = -CSRNG_STATUS_COUNT, + /* command errors, not recoverable */ + CSRNG_CMD_RESEED_CNT_EXCEEDED = -CSRNG_STATUS_RESEED_CNT_EXCEEDED, + CSRNG_CMD_INVALID_CMD_SEQ = -CSRNG_STATUS_INVALID_CMD_SEQ, + CSRNG_CMD_INVALID_GEN_CMD = -CSRNG_STATUS_INVALID_GEN_CMD, + CSRNG_CMD_INVALID_ACMD = -CSRNG_STATUS_INVALID_ACMD, + /* command completed ok */ + CSRNG_CMD_OK = 0, + /* command cannot be executed for now */ + CSRNG_CMD_RETRY = 1, + /* command completion deferred */ + CSRNG_CMD_DEFERRED = 2, } OtCSRNDCmdResult; typedef enum { @@ -275,12 +299,12 @@ typedef struct { uint8_t key[OT_CSRNG_AES_KEY_SIZE]; uint32_t material[OT_CSRNG_SEED_WORD_COUNT]; unsigned material_len; /* in word count */ - /* See https://github.com/lowRISC/opentitan/issues/16499 */ - unsigned reseed_counter; + unsigned reseed_counter; /* generate command count since last reseed */ unsigned rem_packet_count; /* remaining packets to generate */ bool instantiated; bool seeded; /* ready to generate randomness */ - bool fips; + bool no_fips; + bool force_fips; } OtCSRNGDrng; typedef struct OtCSRNGInstance { @@ -319,12 +343,10 @@ struct OtCSRNGState { bool enabled; bool sw_app_granted; bool read_int_granted; - bool es_available; uint32_t scheduled_cmd; unsigned entropy_delay; unsigned es_retry_count; unsigned state_db_ix; - int entropy_gennum; int aes_cipher; /* AES handle for tomcrypt */ OtCSRNGFsmState state; OtCSRNGInstance *instances; @@ -334,16 +356,25 @@ struct OtCSRNGState { OtOTPState *otp_ctrl; }; +/* clang-format off */ static const uint8_t OtCSRNGFsmStateCode[] = { - [CSRNG_IDLE] = 0b01001110, [CSRNG_PARSE_CMD] = 0b10111011, - [CSRNG_INSTANT_PREP] = 0b11000001, [CSRNG_INSTANT_REQ] = 0b01010100, - [CSRNG_RESEED_PREP] = 0b11011101, [CSRNG_RESEED_REQ] = 0b01011011, - [CSRNG_GENERATE_PREP] = 0b11101111, [CSRNG_GENERATE_REQ] = 0b00100100, - [CSRNG_UPDATE_PREP] = 0b00110001, [CSRNG_UPDATE_REQ] = 0b10010000, - [CSRNG_UNINSTANT_PREP] = 0b11110110, [CSRNG_UNINSTANT_REQ] = 0b01100011, - [CSRNG_CLR_A_DATA] = 0b00000010, [CSRNG_CMD_COMP_WAIT] = 0b10111100, - [CSRNG_ERROR] = 0b01111000 + [CSRNG_IDLE] = 0b01001110, // 0x4e: idle + [CSRNG_PARSE_CMD] = 0b10111011, // 0xbb: parse the cmd + [CSRNG_INSTANT_PREP] = 0b11000001, // 0xc1: instantiate prep + [CSRNG_INSTANT_REQ] = 0b01010100, // 0x54: instantiate request + [CSRNG_RESEED_PREP] = 0b11011101, // 0xdd: reseed prep + [CSRNG_RESEED_REQ] = 0b01011011, // 0x5b: reseed request + [CSRNG_GENERATE_PREP] = 0b11101111, // 0xef: generate prep + [CSRNG_GENERATE_REQ] = 0b00100100, // 0x24: generate request + [CSRNG_UPDATE_PREP] = 0b00110001, // 0x31: update prep + [CSRNG_UPDATE_REQ] = 0b00100100, // 0x24: update request + [CSRNG_UNINSTANT_PREP] = 0b11110110, // 0xf6: uninstantiate prep + [CSRNG_UNINSTANT_REQ] = 0b01100011, // 0x63: uninstantiate request + [CSRNG_CLR_A_DATA] = 0b00000010, // 0x02: clear out the add. data fifo + [CSRNG_CMD_COMP_WAIT] = 0b10111100, // 0xbc: wait for command to complete + [CSRNG_ERROR] = 0b01111000 // 0x78: error state }; +/* clang-format on */ #define STATE_NAME_ENTRY(_st_) [_st_] = stringify(_st_) static const char *STATE_NAMES[] = { @@ -378,12 +409,18 @@ static const char *STATE_NAMES[] = { static bool ot_csrng_check_multibitboot(OtCSRNGState *s, uint8_t mbbool, uint32_t alert_bit); static void ot_csrng_command_schedule(OtCSRNGState *s, OtCSRNGInstance *inst); -static bool ot_csrng_instance_is_command_ready(OtCSRNGInstance *inst); -static void ot_csrng_complete_command(OtCSRNGInstance *inst, int res); +static bool +ot_csrng_instance_is_command_ready(const OtCSRNGInstance *inst, bool fatal); +static void ot_csrng_complete_command(OtCSRNGInstance *inst, + OtCSRNGCmdStatus sts); static void ot_csrng_change_state_line(OtCSRNGState *s, OtCSRNGFsmState state, int line); -static unsigned ot_csrng_get_slot(OtCSRNGInstance *inst); -static bool ot_csrng_drng_is_instantiated(OtCSRNGInstance *inst); +static unsigned ot_csrng_get_slot(const OtCSRNGInstance *inst); +static bool ot_csrng_drng_is_instantiated(const OtCSRNGInstance *inst); +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); @@ -391,58 +428,132 @@ ot_csrng_drng_reseed(OtCSRNGInstance *inst, DeviceState *rand_dev, bool flag0); /* Public API */ /* -------------------------------------------------------------------------- */ -qemu_irq ot_csnrg_connect_hw_app(OtCSRNGState *s, unsigned app_id, - qemu_irq req_sts, ot_csrng_genbit_filler_fn fn, - void *opaque) +qemu_irq +ot_csnrg_connect_hw_app(OtCSRNGState *s, unsigned app_id, qemu_irq req_sts, + ot_csrng_genbit_filler_fn filler_fn, void *opaque) { g_assert(app_id < OT_CSRNG_HW_APP_MAX); - g_assert(req_sts); - g_assert(fn); OtCSRNGInstance *inst = &s->instances[app_id]; + + if (!filler_fn) { + if (!inst->hw.filler) { + xtrace_ot_csrng_info("HW app was not connected", app_id); + return NULL; + } + + trace_ot_csrng_disconnection(app_id, true); + ot_csrng_release_hw_app(inst); + + return NULL; + } + + g_assert(req_sts); + /* if connection is invoked many times, there is no reason for changes */ if (inst->hw.filler) { - g_assert(inst->hw.filler == fn); + g_assert(inst->hw.filler == filler_fn); } if (inst->hw.req_sts) { g_assert(inst->hw.req_sts == req_sts); } - inst->hw.filler = fn; + + trace_ot_csrng_connection(app_id, inst->hw.filler == NULL); + + inst->hw.filler = filler_fn; inst->hw.opaque = opaque; inst->hw.req_sts = req_sts; - trace_ot_csrng_connection(app_id); - return qdev_get_gpio_in_named(DEVICE(s), TYPE_OT_CSRNG "-genbits_ready", (int)app_id); } -int ot_csrng_push_command(OtCSRNGState *s, unsigned app_id, - const uint32_t *command) +OtCSRNGCmdStatus ot_csrng_push_command(OtCSRNGState *s, unsigned app_id, + uint32_t word) { g_assert(app_id < OT_CSRNG_HW_APP_MAX); if (s->state == CSRNG_ERROR) { - return -1; + return CSRNG_STATUS_INVALID_CMD_SEQ; } OtCSRNGInstance *inst = &s->instances[app_id]; g_assert(inst->hw.filler); g_assert(inst->hw.req_sts); - ot_fifo32_reset(&inst->cmd_fifo); - uint32_t acmd = FIELD_EX32(command[0], OT_CSNRG_CMD, ACMD); - uint32_t length = FIELD_EX32(command[0], OT_CSNRG_CMD, CLEN) + 1u; + /* FIFO is emptied in #ot_csrng_complete_command */ + if (ot_fifo32_is_full(&inst->cmd_fifo)) { + xtrace_ot_csrng_error("Command FIFO is full"); + return CSRNG_STATUS_INVALID_CMD_SEQ; + } + + bool check_cmd = ot_fifo32_is_empty(&inst->cmd_fifo); + + ot_fifo32_push(&inst->cmd_fifo, word); + uint32_t cmd = ot_fifo32_peek(&inst->cmd_fifo); + + uint32_t acmd = FIELD_EX32(cmd, OT_CSNRG_CMD, ACMD); + uint32_t length = FIELD_EX32(cmd, OT_CSNRG_CMD, CLEN) + 1u; + + if (check_cmd) { + /* NOLINTNEXTLINE */ + switch (acmd) { + case OT_CSRNG_CMD_INSTANTIATE: + case OT_CSRNG_CMD_RESEED: + ot_csrng_check_multibitboot(s, + (uint8_t)FIELD_EX32(cmd, OT_CSNRG_CMD, + FLAG0), + ALERT_STATUS_BIT(ACMD_FLAG0)); + break; + case OT_CSRNG_CMD_GENERATE ... OT_CSRNG_CMD_UNINSTANTIATE: + break; + default: + xtrace_ot_csrng_error("Invalid command opcode"); + ot_fifo32_reset(&inst->cmd_fifo); + return CSRNG_STATUS_INVALID_ACMD; + } + + if (length > CMD_FIFO_CAPACITY) { + xtrace_ot_csrng_error("Invalid command length (overflow)"); + /* + * as CLEN width cannot encode more than CMD_FIFO_CAPACITY, this + * error should never occur. + */ + g_assert_not_reached(); + } + } + + if (ot_fifo32_num_used(&inst->cmd_fifo) > length) { + xtrace_ot_csrng_error("Invalid command length (too many)"); + /* + * as the FIFO should have been handled and emptied in a previous call + * to this function, this error should never occur. + */ + g_assert_not_reached(); + } + if (ot_fifo32_num_used(&inst->cmd_fifo) < length) { + /* more payload is expected */ + return CSRNG_STATUS_SUCCESS; + } + if (acmd == OT_CSRNG_CMD_GENERATE) { - uint32_t glen = FIELD_EX32(command[0], OT_CSNRG_CMD, GLEN); + uint32_t glen = FIELD_EX32(cmd, OT_CSNRG_CMD, GLEN); trace_ot_csrng_push_command(app_id, CMD_NAME(acmd), acmd, 'g', glen); + + const OtCSRNGDrng *drng = &inst->drng; + if (drng->reseed_counter >= s->regs[R_RESEED_INTERVAL]) { + s->regs[R_INTR_STATE] |= INTR_CS_HW_INST_EXC_MASK; + s->regs[R_RECOV_ALERT_STS] |= + R_RECOV_ALERT_STS_CMD_STAGE_INVALID_RESEED_CNT_ALERT_MASK; + ot_fifo32_reset(&inst->cmd_fifo); + ot_csrng_update_irqs(s); + ot_csrng_update_alerts(s); + return CSRNG_STATUS_RESEED_CNT_EXCEEDED; + } } else { trace_ot_csrng_push_command(app_id, CMD_NAME(acmd), acmd, 'c', length); } - if (length > OT_CSRNG_CMD_WORD_MAX) { - xtrace_ot_csrng_error("Invalid command length"); - return -1; - } + if (acmd == OT_CSRNG_CMD_UNINSTANTIATE) { if (!ot_csrng_drng_is_instantiated(inst)) { /* @@ -468,13 +579,9 @@ int ot_csrng_push_command(OtCSRNGState *s, unsigned app_id, } } - while (length--) { - ot_fifo32_push(&inst->cmd_fifo, *command++); - } - ot_csrng_command_schedule(s, inst); - return 0; + return CSRNG_STATUS_SUCCESS; } /* -------------------------------------------------------------------------- */ @@ -530,18 +637,12 @@ static void ot_csrng_drng_clear_material(OtCSRNGInstance *inst) drng->material_len = 0; } -static unsigned ot_csrng_drng_remaining_count(OtCSRNGInstance *inst) +static unsigned ot_csrng_drng_remaining_count(const OtCSRNGInstance *inst) { return inst->drng.rem_packet_count; } -static void ot_csrng_drng_set_count(OtCSRNGInstance *inst, - unsigned packet_count) -{ - inst->drng.rem_packet_count = packet_count; -} - -static bool ot_csrng_drng_is_instantiated(OtCSRNGInstance *inst) +static bool ot_csrng_drng_is_instantiated(const OtCSRNGInstance *inst) { return inst->drng.instantiated; } @@ -562,11 +663,11 @@ static OtCSRNDCmdResult ot_csrng_drng_instantiate( { OtCSRNGDrng *drng = &inst->drng; if (drng->instantiated) { - return CSRNG_CMD_ERROR; + return CSRNG_CMD_INVALID_CMD_SEQ; } memset(drng->v_counter, 0, sizeof(drng->v_counter)); - drng->fips = false; + drng->no_fips = false; uint8_t key[OT_CSRNG_AES_KEY_SIZE]; memset(key, 0, sizeof(key)); @@ -608,7 +709,7 @@ static void ot_csrng_drng_uninstantiate(OtCSRNGInstance *inst) drng->instantiated = false; drng->seeded = false; - drng->fips = false; + drng->no_fips = false; drng->rem_packet_count = 0; /* only to help debugging */ @@ -666,43 +767,40 @@ static void ot_csrng_drng_update(OtCSRNGInstance *inst) static OtCSRNDCmdResult ot_csrng_drng_reseed(OtCSRNGInstance *inst, DeviceState *rand_dev, bool flag0) { + OtCSRNGState *s = inst->parent; OtCSRNGDrng *drng = &inst->drng; g_assert(drng->instantiated); + unsigned slot = ot_csrng_get_slot(inst); drng->seeded = false; if (!flag0) { - if (!inst->parent->es_available) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Cannot request entropy w/o power cycling ES\n", - __func__); - return CSRNG_CMD_ERROR; - } - uint64_t buffer[OT_RANDOM_SRC_DWORD_COUNT]; memset(buffer, 0, sizeof(buffer)); unsigned len = drng->material_len * sizeof(uint32_t); memcpy(buffer, drng->material, MIN(len, sizeof(buffer))); - OtCSRNGState *s = inst->parent; + uint64_t entropy[OT_RANDOM_SRC_DWORD_COUNT]; int res; bool fips; - trace_ot_csrng_request_entropy(ot_csrng_get_slot(inst), - s->entropy_gennum); + 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, s->entropy_gennum, entropy, &fips); - if (res) { + res = cls->get_random_values(randif, entropy, &fips); + + if (res < 0) { + s->entropy_delay = 0; + trace_ot_csrng_entropy_rejected(slot, "error", res); + return CSRNG_CMD_STALLED; + } + + if (res > 0) { s->entropy_delay = (res > 1) ? (unsigned)res : 0; - trace_ot_csrng_entropy_rejected(ot_csrng_get_slot(inst), - res < 0 ? (res == -2 ? "stalled" : - "error") : - "not ready", - res); - return res < 0 ? (res == -2 ? CSRNG_CMD_STALLED : CSRNG_CMD_ERROR) : - CSRNG_CMD_RETRY; + trace_ot_csrng_entropy_rejected(slot, "not ready", res); + return CSRNG_CMD_RETRY; } + /* always perform XOR which is a no-op if material_len is zero */ for (unsigned ix = 0; ix < OT_RANDOM_SRC_DWORD_COUNT; ix++) { buffer[ix] ^= entropy[ix]; @@ -710,15 +808,15 @@ ot_csrng_drng_reseed(OtCSRNGInstance *inst, DeviceState *rand_dev, bool flag0) memcpy(drng->material, buffer, sizeof(entropy)); drng->material_len = sizeof(entropy) / (sizeof(uint32_t)); ot_csrng_drng_update(inst); - drng->fips = fips; + drng->no_fips |= !fips; } else { ot_csrng_drng_update(inst); - drng->fips = false; + drng->no_fips = true; } - drng->reseed_counter = 1u; - + drng->reseed_counter = 0u; drng->seeded = true; + drng->force_fips = (bool)((s->regs[R_FIPS_FORCE] >> slot) & 0x1u); return CSRNG_CMD_OK; } @@ -740,10 +838,11 @@ static void ot_csrng_drng_generate(OtCSRNGInstance *inst, uint32_t *out, xtrace_ot_csrng_show_buffer(ot_csrng_get_slot(inst), "out", out, OT_CSRNG_AES_BLOCK_SIZE); - *fips = drng->fips; + *fips = (!drng->no_fips) || drng->force_fips; if (!ot_csrng_drng_remaining_count(inst)) { ot_csrng_drng_update(inst); + /* last packet generation for the current command */ drng->reseed_counter += 1u; } } @@ -752,7 +851,7 @@ static void ot_csrng_drng_generate(OtCSRNGInstance *inst, uint32_t *out, /* Private implementation */ /* -------------------------------------------------------------------------- */ -static unsigned ot_csrng_get_slot(OtCSRNGInstance *inst) +static unsigned ot_csrng_get_slot(const OtCSRNGInstance *inst) { unsigned slot = (unsigned)(uintptr_t)(inst - &inst->parent->instances[0]); g_assert(slot <= SW_INSTANCE_ID); @@ -771,8 +870,9 @@ static void ot_csrng_update_irqs(OtCSRNGState *s) static void ot_csrng_update_alerts(OtCSRNGState *s) { uint32_t level = s->regs[R_ALERT_TEST]; + s->regs[R_ALERT_TEST] = 0u; - if (__builtin_popcount(s->regs[R_RECOV_ALERT_STS])) { + if (s->regs[R_RECOV_ALERT_STS]) { level |= 1u << ALERT_RECOVERABLE; } @@ -782,6 +882,7 @@ static void ot_csrng_update_alerts(OtCSRNGState *s) for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); + ibex_irq_set(&s->alerts[ix], 0); } } @@ -794,6 +895,8 @@ static void ot_csrng_change_state_line(OtCSRNGState *s, OtCSRNGFsmState state, s->state = state; if (s->state == CSRNG_ERROR) { + s->regs[R_INTR_STATE] |= INTR_CS_FATAL_ERR_MASK; + ot_csrng_update_irqs(s); ot_csrng_update_alerts(s); } } @@ -844,73 +947,38 @@ static bool ot_csrng_is_in_queue(OtCSRNGInstance *inst) cmd_request) == inst; } -static bool ot_csrng_expedite_uninstantiation(OtCSRNGInstance *inst) +static void ot_csrng_release_hw_app(OtCSRNGInstance *inst) { - /* check if the instance has been flagged for uninstantiation */ - if (ot_fifo32_is_empty(&inst->cmd_fifo)) { - return false; - } - - uint32_t cmd = ot_fifo32_peek(&inst->cmd_fifo); - uint32_t acmd = FIELD_EX32(cmd, OT_CSNRG_CMD, ACMD); - if (acmd != OT_CSRNG_CMD_UNINSTANTIATE) { - return false; - } - - unsigned slot = ot_csrng_get_slot(inst); - trace_ot_csrng_expedite_uninstantiation(slot); - /* remove the command from the queue since it is handled right here */ OtCSRNGState *s = inst->parent; - QSIMPLEQ_REMOVE(&s->cmd_requests, inst, OtCSRNGInstance, cmd_request); + if (ot_csrng_is_in_queue(inst)) { + QSIMPLEQ_REMOVE(&s->cmd_requests, inst, OtCSRNGInstance, cmd_request); + } if (QSIMPLEQ_EMPTY(&s->cmd_requests)) { qemu_bh_cancel(s->cmd_scheduler); timer_del(s->entropy_scheduler); } - trace_ot_csrng_instantiate(slot, false); + unsigned slot = ot_csrng_get_slot(inst); + trace_ot_csrng_uninstantiate(slot, false); ot_csrng_drng_uninstantiate(inst); - ot_csrng_complete_command(inst, 0); - return true; + ot_fifo32_reset(&inst->cmd_fifo); + inst->defer_completion = false; + + inst->hw.filler = NULL; + inst->hw.opaque = NULL; + inst->hw.req_sts = NULL; } static void ot_csrng_handle_enable(OtCSRNGState *s) { - /* - * As per EarlGrey 2.5.2-rc0: - * "CSRNG may only be enabled if ENTROPY_SRC is enabled. CSRNG may only be - * disabled if all EDNs are disabled. Once disabled, CSRNG may only be - * re-enabled after ENTROPY_SRC has been disabled and re-enabled." - */ - OtRandomSrcIfClass *cls = OT_RANDOM_SRC_IF_GET_CLASS(s->random_src); - OtRandomSrcIf *randif = OT_RANDOM_SRC_IF(s->random_src); - if (ot_csrng_is_ctrl_enabled(s)) { xtrace_ot_csrng_info("enabling CSRNG", 0); - int gennum = cls->get_random_generation(randif); - if (gennum >= 0) { - /* - * however it is not re-enabling CSRNG w/o cycling the entropy_src - * that is prohibited, but to request entropy from it. The check is - * therefore deferred to the reseed handling which makes use of the - * entropy_src only if flag0 is not set. - */ - s->es_available = gennum > s->entropy_gennum; - xtrace_ot_csrng_info("enable: new ES generation", gennum); - } else { - /* - * tracking enablement/disablement order is not supported by the - * entropy source (such as on Darjeeling) - */ - s->es_available = true; - xtrace_ot_csrng_info("enable: no ES gen tracking", gennum); - } s->enabled = true; s->regs[R_SW_CMD_STS] |= R_SW_CMD_STS_CMD_RDY_MASK; s->es_retry_count = ENTROPY_SRC_INITIAL_REQUEST_COUNT; - s->entropy_gennum = gennum; } if (ot_csrng_is_ctrl_disabled(s)) { @@ -918,27 +986,19 @@ static void ot_csrng_handle_enable(OtCSRNGState *s) /* skip SW instance */ for (unsigned ix = 0u; ix < OT_CSRNG_HW_APP_MAX; ix++) { OtCSRNGInstance *inst = &s->instances[ix]; - if (ot_csrng_drng_is_instantiated(inst)) { - /* - * the instance may have received an unistantiation command - * that has not been dequeued yet. If this is the case, proceed - * with uninstantiation rather than rejecting the disablement of - * the CSRNG - */ - if (!ot_csrng_expedite_uninstantiation(inst)) { - qemu_log_mask( - LOG_GUEST_ERROR, - "%s: Cannot disable CSRNG as EDN #%u still active\n", - __func__, ot_csrng_get_slot(inst)); - return; - } + if (inst->hw.filler) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Forcing CSRNG disablement while EDN #%u " + "still active\n", + __func__, ot_csrng_get_slot(inst)); + + trace_ot_csrng_disconnection(ix, false); + ot_csrng_release_hw_app(inst); } } s->enabled = false; s->regs[R_SW_CMD_STS] &= ~R_SW_CMD_STS_CMD_RDY_MASK; s->es_retry_count = 0; - s->entropy_gennum = cls->get_random_generation(randif); - xtrace_ot_csrng_info("disable: last RS generation", s->entropy_gennum); /* cancel any outstanding asynchronous request */ qemu_bh_cancel(s->cmd_scheduler); @@ -955,22 +1015,24 @@ static void ot_csrng_handle_enable(OtCSRNGState *s) * is an unstantiate command, in which case it is immediately * completed */ - bool success; + OtCSRNGCmdStatus sts; if (!ot_fifo32_is_empty(&inst->cmd_fifo)) { uint32_t cmd = ot_fifo32_peek(&inst->cmd_fifo); uint32_t acmd = FIELD_EX32(cmd, OT_CSNRG_CMD, ACMD); - success = acmd == OT_CSRNG_CMD_UNINSTANTIATE; + sts = acmd == OT_CSRNG_CMD_UNINSTANTIATE ? + CSRNG_STATUS_SUCCESS : + CSRNG_STATUS_INVALID_CMD_SEQ; } else { - success = false; + sts = CSRNG_STATUS_INVALID_CMD_SEQ; } - qemu_set_irq(inst->hw.req_sts, (int)!success); + qemu_set_irq(inst->hw.req_sts, (int)sts); } QSIMPLEQ_REMOVE_HEAD(&s->cmd_requests, cmd_request); } /* reset all instances */ - for (unsigned ix = 0u; ix < OT_CSRNG_HW_APP_MAX + 1u; ix++) { + for (unsigned ix = 0u; ix < N_APP_COUNT; ix++) { inst = &s->instances[ix]; ot_csrng_drng_uninstantiate(inst); ot_fifo32_reset(&inst->cmd_fifo); @@ -1003,12 +1065,14 @@ static void ot_csrng_complete_sw_command(OtCSRNGInstance *inst, bool res) ot_csrng_update_irqs(s); } -static void ot_csrng_complete_hw_command(OtCSRNGInstance *inst, int res) +static void +ot_csrng_complete_hw_command(OtCSRNGInstance *inst, OtCSRNGCmdStatus sts) { - qemu_set_irq(inst->hw.req_sts, res); + qemu_set_irq(inst->hw.req_sts, (int)sts); } -static void ot_csrng_complete_command(OtCSRNGInstance *inst, int res) +static void ot_csrng_complete_command(OtCSRNGInstance *inst, + OtCSRNGCmdStatus sts) { uint32_t num; const uint32_t *buffer = @@ -1032,19 +1096,14 @@ static void ot_csrng_complete_command(OtCSRNGInstance *inst, int res) trace_ot_csrng_show_command("complete", slot, CMD_NAME(acmd), acmd); if (slot == SW_INSTANCE_ID) { - trace_ot_csrng_complete_command(slot, "sw", CMD_NAME(acmd), acmd, res); - ot_csrng_complete_sw_command(inst, res); + trace_ot_csrng_complete_command(slot, "sw", CMD_NAME(acmd), acmd, sts); + ot_csrng_complete_sw_command(inst, sts); } else { - trace_ot_csrng_complete_command(slot, "hw", CMD_NAME(acmd), acmd, res); - ot_csrng_complete_hw_command(inst, res); + trace_ot_csrng_complete_command(slot, "hw", CMD_NAME(acmd), acmd, sts); + ot_csrng_complete_hw_command(inst, sts); } - if (res == 0) { - CHANGE_STATE(s, CSRNG_IDLE); - } else { - CHANGE_STATE(s, CSRNG_ERROR); - ot_csrng_update_alerts(s); - } + CHANGE_STATE(s, CSRNG_IDLE); } static OtCSRNDCmdResult @@ -1052,7 +1111,7 @@ ot_csrng_handle_instantiate(OtCSRNGState *s, unsigned slot) { OtCSRNGInstance *inst = &s->instances[slot]; - trace_ot_csrng_instantiate(slot, true); + trace_ot_csrng_instantiate(slot); uint32_t command = ot_fifo32_peek(&inst->cmd_fifo); uint32_t clen = FIELD_EX32(command, OT_CSNRG_CMD, CLEN); @@ -1067,6 +1126,8 @@ ot_csrng_handle_instantiate(OtCSRNGState *s, unsigned slot) buffer += 1u; if (clen) { + /* ignore trailing additional words, as HW does */ + clen = MIN(clen, OT_CSRNG_CMD_WORD_MAX); xtrace_ot_csrng_show_buffer(ot_csrng_get_slot(inst), "mat", buffer, clen * sizeof(uint32_t)); } @@ -1090,14 +1151,14 @@ ot_csrng_handle_uninstantiate(OtCSRNGState *s, unsigned slot) { OtCSRNGInstance *inst = &s->instances[slot]; - trace_ot_csrng_instantiate(slot, false); + trace_ot_csrng_uninstantiate(slot, true); ot_csrng_drng_uninstantiate(inst); return CSRNG_CMD_OK; } -static int ot_csrng_handle_generate(OtCSRNGState *s, unsigned slot) +static OtCSRNDCmdResult ot_csrng_handle_generate(OtCSRNGState *s, unsigned slot) { OtCSRNGInstance *inst = &s->instances[slot]; @@ -1108,7 +1169,7 @@ static int ot_csrng_handle_generate(OtCSRNGState *s, unsigned slot) xtrace_ot_csrng_error("generation for no packet"); CHANGE_STATE(s, CSRNG_ERROR); ot_csrng_update_alerts(s); - return -1; + return CSRNG_CMD_INVALID_GEN_CMD; } uint32_t clen = FIELD_EX32(command, OT_CSNRG_CMD, CLEN); @@ -1119,6 +1180,9 @@ static int ot_csrng_handle_generate(OtCSRNGState *s, unsigned slot) ot_fifo32_num_used(&inst->cmd_fifo), &num); g_assert(num - 1u == clen); buffer += 1u; + /* ignore trailing additional words, as HW does */ + clen = MIN(clen, OT_CSRNG_CMD_WORD_MAX); + xtrace_ot_csrng_show_buffer(ot_csrng_get_slot(inst), "mat", buffer, clen * sizeof(uint32_t)); ot_csrng_drng_store_material(inst, buffer, clen); @@ -1136,7 +1200,7 @@ static int ot_csrng_handle_generate(OtCSRNGState *s, unsigned slot) /* should we resume? */ } - ot_csrng_drng_set_count(inst, packet_count); + inst->drng.rem_packet_count = packet_count; /* * do not ack command yet, @@ -1163,6 +1227,8 @@ static OtCSRNDCmdResult ot_csrng_handle_reseed(OtCSRNGState *s, unsigned slot) ot_fifo32_num_used(&inst->cmd_fifo), &num); g_assert(num - 1u == clen); buffer += 1u; + /* ignore trailing additional words, as HW does */ + clen = MIN(clen, OT_CSRNG_CMD_WORD_MAX); xtrace_ot_csrng_show_buffer(ot_csrng_get_slot(inst), "mat", buffer, clen * sizeof(uint32_t)); @@ -1197,6 +1263,8 @@ static OtCSRNDCmdResult ot_csrng_handle_update(OtCSRNGState *s, unsigned slot) ot_fifo32_num_used(&inst->cmd_fifo), &num); g_assert(num - 1u == clen); buffer += 1u; + /* ignore trailing additional words, as HW does */ + clen = MIN(clen, OT_CSRNG_CMD_WORD_MAX); xtrace_ot_csrng_show_buffer(ot_csrng_get_slot(inst), "mat", buffer, clen * sizeof(uint32_t)); @@ -1275,7 +1343,7 @@ static void ot_csrng_hwapp_filler_bh(void *opaque) * its readiness status (only generate commands complete async.) */ if (!ot_csrng_drng_remaining_count(inst)) { - ot_csrng_complete_command(inst, 0); + ot_csrng_complete_command(inst, CSRNG_STATUS_SUCCESS); } } } @@ -1299,12 +1367,13 @@ static void ot_csrng_swapp_fill(OtCSRNGInstance *inst) } else { /* check if the instance is running an deferred completion command */ if (inst->defer_completion) { - ot_csrng_complete_command(inst, 0); + ot_csrng_complete_command(inst, CSRNG_STATUS_SUCCESS); } } } -static bool ot_csrng_instance_is_command_ready(OtCSRNGInstance *inst) +static bool +ot_csrng_instance_is_command_ready(const OtCSRNGInstance *inst, bool fatal) { /* there should be a full command stored in the command FIFO */ if (ot_fifo32_is_empty(&inst->cmd_fifo)) { @@ -1313,10 +1382,25 @@ static bool ot_csrng_instance_is_command_ready(OtCSRNGInstance *inst) uint32_t command = ot_fifo32_peek(&inst->cmd_fifo); uint32_t length = FIELD_EX32(command, OT_CSNRG_CMD, CLEN) + 1u; - return ot_fifo32_num_used(&inst->cmd_fifo) == length; + bool is_ready = ot_fifo32_num_used(&inst->cmd_fifo) == length; + + if (fatal && !is_ready) { + unsigned word_count = ot_fifo32_num_used(&inst->cmd_fifo); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %u: command 0x%06x empty: %u, length %u, exp: %u\n", + __func__, ot_csrng_get_slot(inst), command, + ot_fifo32_is_empty(&inst->cmd_fifo), word_count, length); + if (word_count < length) { + xtrace_ot_csrng_error("cannot execute an incomplete command"); + } else { + xtrace_ot_csrng_error("cannot execute an overflowed command"); + } + } + + return is_ready; } -static int ot_csrng_handle_command(OtCSRNGState *s, unsigned slot) +static OtCSRNDCmdResult ot_csrng_handle_command(OtCSRNGState *s, unsigned slot) { OtCSRNGInstance *inst = &s->instances[slot]; @@ -1345,12 +1429,12 @@ static int ot_csrng_handle_command(OtCSRNGState *s, unsigned slot) R_RECOV_ALERT_STS_CMD_STAGE_INVALID_ACMD_ALERT_MASK; CHANGE_STATE(s, CSRNG_ERROR); ot_csrng_update_alerts(s); - return -1; + return CSRNG_CMD_INVALID_ACMD; } if (!s->enabled) { qemu_log_mask(LOG_GUEST_ERROR, "%s: not enabled\n", __func__); - return -1; + return CSRNG_CMD_INVALID_ACMD; } switch (acmd) { @@ -1358,7 +1442,7 @@ static int ot_csrng_handle_command(OtCSRNGState *s, unsigned slot) if (ot_csrng_drng_is_instantiated(inst)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: instance %u already active\n", __func__, slot); - return -1; + return CSRNG_CMD_INVALID_CMD_SEQ; } break; case OT_CSRNG_CMD_UNINSTANTIATE: @@ -1369,11 +1453,11 @@ static int ot_csrng_handle_command(OtCSRNGState *s, unsigned slot) __func__, slot); CHANGE_STATE(s, CSRNG_ERROR); ot_csrng_update_alerts(s); - return -1; + return CSRNG_CMD_INVALID_CMD_SEQ; } } - int res; + OtCSRNDCmdResult res; switch (acmd) { case OT_CSRNG_CMD_INSTANTIATE: @@ -1428,6 +1512,7 @@ static void ot_csrng_command_schedule(OtCSRNGState *s, OtCSRNGInstance *inst) __func__); s->regs[R_INTR_STATE] |= INTR_CS_HW_INST_EXC_MASK; ot_csrng_update_irqs(s); + g_assert(false); return; } @@ -1460,13 +1545,7 @@ static void ot_csrng_command_scheduler(void *opaque) trace_ot_csrng_show_command("pop", slot, CMD_NAME(acmd), acmd); - if (!ot_csrng_instance_is_command_ready(inst)) { - xtrace_ot_csrng_error("cannot execute an incomplete command"); - uint32_t length = FIELD_EX32(command, OT_CSNRG_CMD, CLEN) + 1u; - qemu_log_mask(LOG_GUEST_ERROR, "empty: %u, length %u, exp: %u\n", - ot_fifo32_is_empty(&inst->cmd_fifo), - ot_fifo32_num_used(&inst->cmd_fifo), length); - + if (!ot_csrng_instance_is_command_ready(inst, true)) { g_assert_not_reached(); } @@ -1486,7 +1565,7 @@ static void ot_csrng_command_scheduler(void *opaque) * in this round. */ trace_ot_csrng_command_scheduler(slot, "cmd ready, execute"); - int res; + OtCSRNDCmdResult res; res = ot_csrng_handle_command(s, slot); switch (res) { case CSRNG_CMD_RETRY: @@ -1507,10 +1586,16 @@ static void ot_csrng_command_scheduler(void *opaque) } /* do not complete command either */ break; - case CSRNG_CMD_ERROR: case CSRNG_CMD_OK: + ot_csrng_complete_command(inst, CSRNG_STATUS_SUCCESS); + break; default: - ot_csrng_complete_command(inst, res); + trace_ot_csrng_reject_command(slot, command, res); + /* + * Negative res values are errors, encoding the type of command error. + * Convert the encoded error back into a OtCSRNGCmdStatus. + */ + ot_csrng_complete_command(inst, -res); break; } @@ -1534,7 +1619,19 @@ static void ot_csrng_command_scheduler(void *opaque) static uint32_t ot_csrng_read_state_db(OtCSRNGState *s) { unsigned appid = s->regs[R_INT_STATE_NUM]; - if (appid > OT_CSRNG_HW_APP_MAX) { + if (appid >= N_APP_COUNT) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid appid %d\n", __func__, + appid); + return 0; + } + if (!s->read_int_granted) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: read state db disabled\n", + __func__); + return 0; + } + if (!((s->regs[R_INT_STATE_READ_ENABLE] >> appid) & 0x1)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: read state db not enable for %d\n", + __func__, appid); return 0; } @@ -1553,12 +1650,12 @@ static uint32_t ot_csrng_read_state_db(OtCSRNGState *s) break; case 5u ... 12u: /* Key */ /* use big endian and reverse order to match OpenTitan order */ - base = 12 - s->state_db_ix; + base = 12u - s->state_db_ix; val32 = ldl_be_p(&drng->key[base * sizeof(uint32_t)]); break; case 13u: /* Status + Compliance, only 8 LSBs matter */ val32 = (uint32_t)((((uint8_t)drng->instantiated) << 0u) | - (((uint8_t)drng->fips) << 1u)); + (((uint8_t)!drng->no_fips) << 1u)); break; default: val32 = 0; @@ -1590,6 +1687,7 @@ static uint64_t ot_csrng_regs_read(void *opaque, hwaddr addr, unsigned size) case R_INTR_ENABLE: case R_REGWEN: case R_CTRL: + case R_RESEED_INTERVAL: case R_SW_CMD_STS: case R_INT_STATE_NUM: case R_HW_EXC_STS: @@ -1598,8 +1696,17 @@ static uint64_t ot_csrng_regs_read(void *opaque, hwaddr addr, unsigned size) case R_ERR_CODE_TEST: val32 = s->regs[reg]; break; + case R_RESEED_COUNTER_0: + case R_RESEED_COUNTER_1: + case R_RESEED_COUNTER_2: { + unsigned appid = reg - R_RESEED_COUNTER_0; + g_assert(appid < N_APP_COUNT); + inst = &s->instances[appid]; + const OtCSRNGDrng *drng = &inst->drng; + val32 = drng->reseed_counter; + } break; case R_INT_STATE_VAL: - val32 = s->read_int_granted ? ot_csrng_read_state_db(s) : 0u; + val32 = ot_csrng_read_state_db(s); break; case R_MAIN_SM_STATE: switch (s->state) { @@ -1698,52 +1805,53 @@ static void ot_csrng_regs_write(void *opaque, hwaddr addr, uint64_t val64, break; case R_REGWEN: val32 &= R_REGWEN_EN_MASK; - s->regs[reg] &= val32; + s->regs[reg] &= val32; /* rw0c */ break; case R_CTRL: - if (s->regs[R_REGWEN]) { - uint32_t prev = s->regs[reg]; - val32 &= CTRL_MASK; - s->regs[reg] = val32; - CHECK_MULTIBOOT(s, CTRL, ENABLE); - CHECK_MULTIBOOT(s, CTRL, SW_APP_ENABLE); - CHECK_MULTIBOOT(s, CTRL, READ_INT_STATE); - uint32_t change = val32 ^ prev; - if (change) { - xtrace_ot_csrng_info("handling CTRL change", val32); - ot_csrng_handle_enable(s); - bool granted; - OtOTPStateClass *oc = - OBJECT_GET_CLASS(OtOTPStateClass, 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) { - 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 { - s->sw_app_granted = false; - s->read_int_granted = false; - } + if (!s->regs[R_REGWEN]) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: %s protected w/ REGWEN\n", + __func__, REG_NAME(reg)); + break; + } + uint32_t prev = s->regs[reg]; + val32 &= CTRL_MASK; + s->regs[reg] = val32; + CHECK_MULTIBOOT(s, CTRL, ENABLE); + CHECK_MULTIBOOT(s, CTRL, SW_APP_ENABLE); + CHECK_MULTIBOOT(s, CTRL, READ_INT_STATE); + CHECK_MULTIBOOT(s, CTRL, FIPS_FORCE_ENABLE); + uint32_t change = val32 ^ prev; + if (change) { + xtrace_ot_csrng_info("handling CTRL change", val32); + ot_csrng_handle_enable(s); + bool granted; + OtOTPStateClass *oc = + OBJECT_GET_CLASS(OtOTPStateClass, 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) { + 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 { + s->sw_app_granted = false; + s->read_int_granted = false; } - } else { - qemu_log_mask(LOG_GUEST_ERROR, "%s: CTRL protected w/ REGWEN\n", - __func__); } break; case R_CMD_REQ: inst = &s->instances[SW_INSTANCE_ID]; if (!ot_fifo32_is_full(&inst->cmd_fifo)) { ot_fifo32_push(&inst->cmd_fifo, val32); - if (ot_csrng_instance_is_command_ready(inst)) { + if (ot_csrng_instance_is_command_ready(inst, false)) { /* * assume CMD RDY works the same way as the csrng_req_ready * wire, which is a blind guess, need to check RTL here @@ -1757,6 +1865,23 @@ static void ot_csrng_regs_write(void *opaque, hwaddr addr, uint64_t val64, /* TBC: how to signal this error */ } break; + case R_RESEED_INTERVAL: + s->regs[reg] = val32; + ot_csrng_update_irqs(s); + break; + case R_INT_STATE_READ_ENABLE: + if (!s->regs[R_INT_STATE_READ_ENABLE_REGWEN]) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: %s protected w/ REGWEN\n", + __func__, REG_NAME(reg)); + break; + } + val32 &= R_INT_STATE_READ_ENABLE_VAL_MASK; + s->regs[reg] = val32; + break; + case R_INT_STATE_READ_ENABLE_REGWEN: + val32 &= R_INT_STATE_READ_ENABLE_REGWEN_EN_MASK; + s->regs[reg] &= val32; /* rw0c */ + break; case R_INT_STATE_NUM: if (s->read_int_granted) { val32 &= R_INT_STATE_NUM_VAL_MASK; @@ -1768,12 +1893,38 @@ static void ot_csrng_regs_write(void *opaque, hwaddr addr, uint64_t val64, } } break; + case R_FIPS_FORCE: + if (!s->regs[R_REGWEN]) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: %s protected w/ REGWEN\n", + __func__, REG_NAME(reg)); + break; + } + val32 &= R_FIPS_FORCE_VAL_MASK; + s->regs[reg] = val32; + break; + case R_HW_EXC_STS: + val32 &= R_HW_EXC_STS_VAL_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; + case R_RECOV_ALERT_STS: + val32 &= RECOV_ALERT_STS_MASK; + s->regs[reg] &= val32; /* RW0C */ + ot_csrng_update_alerts(s); + break; case R_ERR_CODE_TEST: + if (!s->regs[R_REGWEN]) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: %s protected w/ REGWEN\n", + __func__, REG_NAME(reg)); + break; + } val32 &= R_ERR_CODE_TEST_VAL_MASK; val32 = 1u << val32; val32 &= ERR_CODE_MASK; s->regs[R_ERR_CODE] = val32; break; + case R_RESEED_COUNTER_0: + case R_RESEED_COUNTER_1: + case R_RESEED_COUNTER_2: case R_SW_CMD_STS: case R_GENBITS_VLD: case R_GENBITS: @@ -1827,16 +1978,15 @@ static void ot_csrng_reset(DeviceState *dev) s->regs[R_CTRL] = 0x9999u; s->regs[R_RESEED_INTERVAL] = 0xffffffffu; s->regs[R_INT_STATE_READ_ENABLE_REGWEN] = 0x1u; + s->regs[R_INT_STATE_READ_ENABLE] = 0x7u; s->regs[R_MAIN_SM_STATE] = 0x4eu; s->enabled = false; - s->es_available = false; - s->entropy_gennum = 0; s->sw_app_granted = false; s->read_int_granted = false; s->es_retry_count = 0; s->state = CSRNG_IDLE; - for (unsigned ix = 0; ix < OT_CSRNG_HW_APP_MAX + 1u; ix++) { + for (unsigned ix = 0; ix < N_APP_COUNT; ix++) { OtCSRNGInstance *inst = &s->instances[ix]; g_assert(inst->parent); ot_fifo32_reset(&inst->cmd_fifo); @@ -1883,13 +2033,15 @@ static void ot_csrng_init(Object *obj) TYPE_OT_CSRNG "-genbits_ready", OT_CSRNG_HW_APP_MAX); + static_assert(CMD_FIFO_CAPACITY >= OT_CSRNG_CMD_WORD_MAX, + "Invalid CMD FIFO size"); /* HW instances + 1 internal SW instance */ - s->instances = g_new0(OtCSRNGInstance, OT_CSRNG_HW_APP_MAX + 1u); + s->instances = g_new0(OtCSRNGInstance, N_APP_COUNT); OtCSRNGInstance *inst = &s->instances[SW_INSTANCE_ID]; - for (unsigned ix = 0; ix < OT_CSRNG_HW_APP_MAX + 1u; ix++) { + for (unsigned ix = 0; ix < N_APP_COUNT; ix++) { inst = &s->instances[ix]; inst->parent = s; - ot_fifo32_create(&inst->cmd_fifo, OT_CSRNG_CMD_WORD_MAX); + ot_fifo32_create(&inst->cmd_fifo, CMD_FIFO_CAPACITY); if (ix != SW_INSTANCE_ID) { inst->hw.filler_bh = qemu_bh_new(&ot_csrng_hwapp_filler_bh, inst); } diff --git a/hw/opentitan/ot_edn.c b/hw/opentitan/ot_edn.c index 99fece34c026a..1c355501c1dc3 100644 --- a/hw/opentitan/ot_edn.c +++ b/hw/opentitan/ot_edn.c @@ -2,6 +2,7 @@ * QEMU OpenTitan Entropy Distribution Network device * * Copyright (c) 2023-2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -23,9 +24,6 @@ * 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. - * - * Note: for now, only a minimalist subset of EDN device is implemented in order - * to enable OpenTitan's ROM boot to progress */ #include "qemu/osdep.h" @@ -42,7 +40,6 @@ #include "hw/riscv/ibex_common.h" #include "hw/riscv/ibex_irq.h" #include "hw/sysbus.h" -#include "sysemu/runstate.h" #include "trace.h" @@ -54,8 +51,8 @@ /* clang-format off */ REG32(INTR_STATE, 0x0u) - SHARED_FIELD(INTR_EDN_CMD_REQ_DONE_BIT, 0u, 1u) - SHARED_FIELD(INTR_EDN_FATAL_ERR_BIT, 1u, 1u) + SHARED_FIELD(INTR_EDN_CMD_REQ_DONE, 0u, 1u) + SHARED_FIELD(INTR_EDN_FATAL_ERR, 1u, 1u) REG32(INTR_ENABLE, 0x4u) REG32(INTR_TEST, 0x8u) REG32(ALERT_TEST, 0xcu) @@ -77,6 +74,11 @@ REG32(SW_CMD_STS, 0x24u) FIELD(SW_CMD_STS, CMD_ACK, 2u, 1u) FIELD(SW_CMD_STS, CMD_STS, 3u, 3u) REG32(HW_CMD_STS, 0x28u) + FIELD(HW_CMD_STS, BOOT_MODE, 0u, 1u) + FIELD(HW_CMD_STS, AUTO_MODE, 1u, 1u) + FIELD(HW_CMD_STS, CMD_TYPE, 2u, 4u) + FIELD(HW_CMD_STS, CMD_ACK, 6u, 1u) + FIELD(HW_CMD_STS, CMD_STS, 7u, 3u) REG32(RESEED_CMD, 0x2cu) REG32(GENERATE_CMD, 0x30u) REG32(MAX_NUM_REQS_BETWEEN_RESEEDS, 0x34u) @@ -86,10 +88,10 @@ REG32(RECOV_ALERT_STS, 0x38u) FIELD(RECOV_ALERT_STS, AUTO_REQ_MODE_FIELD_ALERT, 2u, 1u) FIELD(RECOV_ALERT_STS, CMD_FIFO_RST_FIELD_ALERT, 3u, 1u) FIELD(RECOV_ALERT_STS, EDN_BUS_CMP_ALERT, 12u, 1u) + FIELD(RECOV_ALERT_STS, CSRNG_ACK_ERR, 13u, 1u) REG32(ERR_CODE, 0x3cu) FIELD(ERR_CODE, SFIFO_RESCMD_ERR, 0u, 1u) FIELD(ERR_CODE, SFIFO_GENCMD_ERR, 1u, 1u) - FIELD(ERR_CODE, SFIFO_OUTPUT_ERR, 2u, 1u) FIELD(ERR_CODE, EDN_ACK_SM_ERR, 20u, 1u) FIELD(ERR_CODE, EDN_MAIN_SM_ERR, 21u, 1u) FIELD(ERR_CODE, EDN_CNTR_ERR, 22u, 1u) @@ -110,7 +112,7 @@ REG32(MAIN_SM_STATE, 0x44u) #define REG_NAME(_reg_) \ ((((_reg_) <= REGS_COUNT) && REG_NAMES[_reg_]) ? REG_NAMES[_reg_] : "?") -#define INTR_MASK (INTR_EDN_CMD_REQ_DONE_BIT_MASK | INTR_EDN_FATAL_ERR_BIT_MASK) +#define INTR_MASK (INTR_EDN_CMD_REQ_DONE_MASK | INTR_EDN_FATAL_ERR_MASK) #define ALERT_TEST_MASK \ (R_ALERT_TEST_RECOV_ALERT_MASK | R_ALERT_TEST_FATAL_ALERT_MASK) #define CTRL_MASK \ @@ -124,14 +126,12 @@ REG32(MAIN_SM_STATE, 0x44u) R_RECOV_ALERT_STS_EDN_BUS_CMP_ALERT_MASK) #define ERR_CODE_MASK \ (R_ERR_CODE_SFIFO_RESCMD_ERR_MASK | R_ERR_CODE_SFIFO_GENCMD_ERR_MASK | \ - R_ERR_CODE_SFIFO_OUTPUT_ERR_MASK | R_ERR_CODE_EDN_ACK_SM_ERR_MASK | \ - R_ERR_CODE_EDN_MAIN_SM_ERR_MASK | R_ERR_CODE_EDN_CNTR_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_FIFO_MASK \ - (R_ERR_CODE_SFIFO_RESCMD_ERR_MASK | R_ERR_CODE_SFIFO_GENCMD_ERR_MASK | \ - R_ERR_CODE_SFIFO_OUTPUT_ERR_MASK | R_ERR_CODE_FIFO_WRITE_ERR_MASK | \ + R_ERR_CODE_EDN_ACK_SM_ERR_MASK | R_ERR_CODE_EDN_MAIN_SM_ERR_MASK | \ + R_ERR_CODE_EDN_CNTR_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_ACTIVE_MASK \ + (R_ERR_CODE_EDN_ACK_SM_ERR_MASK | R_ERR_CODE_EDN_MAIN_SM_ERR_MASK | \ + R_ERR_CODE_EDN_CNTR_ERR_MASK) #define ALERT_STATUS_BIT(_x_) R_RECOV_ALERT_STS_##_x_##_FIELD_ALERT_MASK @@ -177,61 +177,65 @@ static_assert(ALERT_COUNT == PARAM_NUM_ALERTS, "Invalid alert count"); typedef enum { EDN_IDLE, /* idle */ + /* Boot */ EDN_BOOT_LOAD_INS, /* boot: load the instantiate command */ - EDN_BOOT_LOAD_GEN, /* boot: load the generate command */ EDN_BOOT_INS_ACK_WAIT, /* boot: wait for instantiate command ack */ - EDN_BOOT_CAPT_GEN_CNT, /* boot: capture the gen fifo count */ - EDN_BOOT_SEND_GEN_CMD, /* boot: send the generate command */ + EDN_BOOT_LOAD_GEN, /* boot: load the generate command */ EDN_BOOT_GEN_ACK_WAIT, /* boot: wait for generate command ack */ EDN_BOOT_PULSE, /* boot: signal a done pulse */ - EDN_BOOT_DONE, /* boot: stay in done state until reset */ + EDN_BOOT_DONE, /* boot: stay in done state until leaving boot */ + EDN_BOOT_LOAD_UNI, /* boot: load the uninstantiate command */ + EDN_BOOT_UNI_ACK_WAIT, /* boot: wait for uninstantiate command ack */ + /* Auto */ EDN_AUTO_LOAD_INS, /* auto: load the instantiate command */ EDN_AUTO_FIRST_ACK_WAIT, /* auto: wait for first instantiate command ack */ - EDN_AUTO_ACK_WAIT, /* auto: wait for auto command ack */ + EDN_AUTO_ACK_WAIT, /* auto: wait for instantiate command ack */ EDN_AUTO_DISPATCH, /* auto: determine next command to be sent */ EDN_AUTO_CAPT_GEN_CNT, /* auto: capture the gen fifo count */ EDN_AUTO_SEND_GEN_CMD, /* auto: send the generate command */ EDN_AUTO_CAPT_RESEED_CNT, /* auto: capture the reseed fifo count */ EDN_AUTO_SEND_RESEED_CMD, /* auto: send the reseed command */ + /* Misc */ EDN_SW_PORT_MODE, /* swport: no hw request mode */ + EDN_REJECT_CSRNG_ENTROPY, /* stop accepting entropy from CSRNG */ EDN_ERROR, /* illegal state reached and hang */ } OtEDNFsmState; -typedef enum { - CSRNG_STATUS_SUCCESS, - CSRNG_STATUS_INVALID_ACMD, - CSRNG_STATUS_INVALID_GEN_CMD, - CSRNG_STATUS_INVALID_CMD_SEQ, - CSRNG_STATUS_RESEED_CNT_EXCEEDED, -} OtCSRNGCmdStatus; - typedef struct { OtCSRNGState *device; /* CSRNG instance */ - OtCSRNGCmdStatus last_cmd_status; /* status of the last CSRNG command */ qemu_irq genbits_ready; /* Set when ready to receive entropy */ uint32_t appid; /* unique HW application id to identify on CSRNG */ - bool instantiated; /* instantiated state, not yet uninstantiated */ - bool no_fips; /* true if 1+ rcv entropy packets were no FIPS-compliant */ unsigned rem_packet_count; /* remaining expected packets in generate cmd */ + OtCSRNGCmdStatus hw_cmd_status; /* status of the last CSRNG command */ + OtCSRNGCmdStatus sw_cmd_status; /* status of the last SW command */ uint32_t buffer[OT_CSRNG_CMD_WORD_MAX]; /* temp buffer for commands */ OtFifo32 bits_fifo; /* input FIFO with entropy received from CSRNG */ - OtFifo32 sw_cmd_fifo; /* generic command output FIFO */ - OtFifo32 cmd_gen_fifo; /* FIFO to store replayed generate command */ - OtFifo32 cmd_reseed_fifo; /* FIFO to store replayed reseed command */ + OtFifo32 cmd_gen_fifo; /* "Replay" FIFO to store generate command */ + OtFifo32 cmd_reseed_fifo; /* "Replay" FIFO to store reseed command */ + uint8_t hw_cmd_type; /* type of the last CSRNG HW command */ + bool hw_ack; /* last SW command has been completed */ + bool sw_ack; /* last SW command has been completed */ + bool instantiated; /* instantiated state, not yet uninstantiated */ + bool no_fips; /* true if 1+ rcv entropy packets were no FIPS-compliant */ } OtEDNCSRNG; typedef struct OtEDNEndPoint { ot_edn_push_entropy_fn fn; /* function to call when entropy is available */ void *opaque; /* opaque pointer forwaded with the fn() call */ OtFifo32 fifo; /* output unpacker */ - bool fips; /* whether stored entropy is FIPS-compliant */ size_t gen_count; /* Number of 32-bit entropy word in current generation */ size_t total_count; /* Total number of 32-bit entropy words */ QSIMPLEQ_ENTRY(OtEDNEndPoint) request; + bool fips; /* whether stored entropy is FIPS-compliant */ } OtEDNEndPoint; typedef QSIMPLEQ_HEAD(OtEndpointQueue, OtEDNEndPoint) OtEndpointQueue; +struct OtEDNClass { + SysBusDeviceClass parent_class; + ResettablePhases parent_phases; +}; + struct OtEDNState { SysBusDevice parent_obj; @@ -241,48 +245,50 @@ struct OtEDNState { QEMUBH *ep_bh; /**< Endpoint requests */ uint32_t *regs; + uint32_t recov_alert_sts; /* track signalled recovery alert */ - unsigned reseed_counter; /* track remaining requests before reseeding */ - bool sw_cmd_ready; /* ready to receive command in SW port mode */ + unsigned max_reqs_cnt; /* track remaining requests before reseeding */ OtEDNFsmState state; /* Main FSM state */ OtEDNCSRNG rng; OtEDNEndPoint endpoints[ENDPOINT_COUNT_MAX]; OtEndpointQueue ep_requests; + bool sw_cmd_ready; /* ready to receive command in SW port mode */ }; static const uint16_t OtEDNFsmStateCode[] = { - [EDN_IDLE] = 0b110000101, - [EDN_BOOT_LOAD_INS] = 0b110110111, + [EDN_IDLE] = 0b011000001, + [EDN_BOOT_LOAD_INS] = 0b111000111, + [EDN_BOOT_INS_ACK_WAIT] = 0b001111001, [EDN_BOOT_LOAD_GEN] = 0b000000011, - [EDN_BOOT_INS_ACK_WAIT] = 0b011010010, - [EDN_BOOT_CAPT_GEN_CNT] = 0b010111010, - [EDN_BOOT_SEND_GEN_CMD] = 0b011100100, - [EDN_BOOT_GEN_ACK_WAIT] = 0b101101100, - [EDN_BOOT_PULSE] = 0b100001010, - [EDN_BOOT_DONE] = 0b011011111, - [EDN_AUTO_LOAD_INS] = 0b001110000, - [EDN_AUTO_FIRST_ACK_WAIT] = 0b001001101, - [EDN_AUTO_ACK_WAIT] = 0b101100011, - [EDN_AUTO_DISPATCH] = 0b110101110, - [EDN_AUTO_CAPT_GEN_CNT] = 0b000110101, - [EDN_AUTO_SEND_GEN_CMD] = 0b111111000, - [EDN_AUTO_CAPT_RESEED_CNT] = 0b000100110, - [EDN_AUTO_SEND_RESEED_CMD] = 0b101010110, - [EDN_SW_PORT_MODE] = 0b100111001, - [EDN_ERROR] = 0b010010001, + [EDN_BOOT_GEN_ACK_WAIT] = 0b001110111, + [EDN_BOOT_PULSE] = 0b010101001, + [EDN_BOOT_DONE] = 0b011110000, + [EDN_BOOT_LOAD_UNI] = 0b100110101, + [EDN_BOOT_UNI_ACK_WAIT] = 0b000101100, + [EDN_AUTO_LOAD_INS] = 0b110111100, + [EDN_AUTO_FIRST_ACK_WAIT] = 0b110100011, + [EDN_AUTO_ACK_WAIT] = 0b010010010, + [EDN_AUTO_DISPATCH] = 0b101100001, + [EDN_AUTO_CAPT_GEN_CNT] = 0b100001110, + [EDN_AUTO_SEND_GEN_CMD] = 0b111011101, + [EDN_AUTO_CAPT_RESEED_CNT] = 0b010111111, + [EDN_AUTO_SEND_RESEED_CMD] = 0b001101010, + [EDN_SW_PORT_MODE] = 0b010010101, + [EDN_REJECT_CSRNG_ENTROPY] = 0b000011000, + [EDN_ERROR] = 0b101111110, }; #define STATE_NAME_ENTRY(_st_) [_st_] = stringify(_st_) static const char *STATE_NAMES[] = { STATE_NAME_ENTRY(EDN_IDLE), STATE_NAME_ENTRY(EDN_BOOT_LOAD_INS), - STATE_NAME_ENTRY(EDN_BOOT_LOAD_GEN), STATE_NAME_ENTRY(EDN_BOOT_INS_ACK_WAIT), - STATE_NAME_ENTRY(EDN_BOOT_CAPT_GEN_CNT), - STATE_NAME_ENTRY(EDN_BOOT_SEND_GEN_CMD), + STATE_NAME_ENTRY(EDN_BOOT_LOAD_GEN), STATE_NAME_ENTRY(EDN_BOOT_GEN_ACK_WAIT), STATE_NAME_ENTRY(EDN_BOOT_PULSE), STATE_NAME_ENTRY(EDN_BOOT_DONE), + STATE_NAME_ENTRY(EDN_BOOT_LOAD_UNI), + STATE_NAME_ENTRY(EDN_BOOT_UNI_ACK_WAIT), STATE_NAME_ENTRY(EDN_AUTO_LOAD_INS), STATE_NAME_ENTRY(EDN_AUTO_FIRST_ACK_WAIT), STATE_NAME_ENTRY(EDN_AUTO_ACK_WAIT), @@ -292,6 +298,7 @@ static const char *STATE_NAMES[] = { STATE_NAME_ENTRY(EDN_AUTO_CAPT_RESEED_CNT), STATE_NAME_ENTRY(EDN_AUTO_SEND_RESEED_CMD), STATE_NAME_ENTRY(EDN_SW_PORT_MODE), + STATE_NAME_ENTRY(EDN_REJECT_CSRNG_ENTROPY), STATE_NAME_ENTRY(EDN_ERROR), }; #undef STATE_NAME_ENTRY @@ -366,75 +373,112 @@ static void ot_edn_update_irqs(OtEDNState *s) static void ot_edn_update_alerts(OtEDNState *s) { uint32_t level = s->regs[R_ALERT_TEST]; - if (s->regs[R_ERR_CODE] & ERR_CODE_MASK) { - /* ERR_CODE is sticky */ + s->regs[R_ALERT_TEST] = 0u; + + /* only these errors seem to generate an alert (from HW observation) */ + if (s->regs[R_ERR_CODE] & ERR_CODE_ACTIVE_MASK) { level |= 1u << ALERT_FATAL; } - if (s->regs[R_ERR_CODE_TEST] & ERR_CODE_MASK) { + if (s->regs[R_ERR_CODE_TEST] & ERR_CODE_ACTIVE_MASK) { level |= 1u << ALERT_FATAL; + /* + * "The action of writing this register will force an error pulse." + * This documented assertion does not seem to hold true. Alert seems + * sticky + */ } if (s->regs[R_RECOV_ALERT_STS] & RECOV_ALERT_STS_MASK) { - level |= 1u << ALERT_RECOVERABLE; + /* recoverable alerts do not trigger stick alert */ + if (!(s->recov_alert_sts & (1u << ALERT_RECOVERABLE))) { + level |= 1u << ALERT_RECOVERABLE; + s->recov_alert_sts |= 1u << ALERT_RECOVERABLE; + } } for (unsigned ix = 0; ix < PARAM_NUM_ALERTS; ix++) { ibex_irq_set(&s->alerts[ix], (int)((level >> ix) & 0x1u)); } } -static void ot_edn_check_multibitboot(OtEDNState *s, uint8_t mbbool, +static bool ot_edn_check_multibitboot(OtEDNState *s, uint8_t mbbool, uint32_t alert_bit) { switch (mbbool) { case OT_MULTIBITBOOL4_TRUE: + return true; case OT_MULTIBITBOOL4_FALSE: - return; + return false; default: break; } s->regs[R_RECOV_ALERT_STS] |= 1u << alert_bit; ot_edn_update_alerts(s); + return false; } -static bool ot_edn_is_enabled(OtEDNState *s) +static bool ot_edn_is_enabled(const OtEDNState *s) { uint32_t enable = FIELD_EX32(s->regs[R_CTRL], CTRL, EDN_ENABLE); return enable == OT_MULTIBITBOOL4_TRUE; } -static bool ot_edn_is_disabled(OtEDNState *s) +static bool ot_edn_is_boot_req_mode(const OtEDNState *s) { - uint32_t enable = FIELD_EX32(s->regs[R_CTRL], CTRL, EDN_ENABLE); + uint32_t auto_req = FIELD_EX32(s->regs[R_CTRL], CTRL, BOOT_REQ_MODE); - return enable == OT_MULTIBITBOOL4_FALSE; + return auto_req == OT_MULTIBITBOOL4_TRUE; } -static bool ot_edn_is_boot_req_mode(OtEDNState *s) +static bool ot_edn_is_auto_req_mode(const OtEDNState *s) { - uint32_t auto_req = FIELD_EX32(s->regs[R_CTRL], CTRL, BOOT_REQ_MODE); + uint32_t auto_req = FIELD_EX32(s->regs[R_CTRL], CTRL, AUTO_REQ_MODE); return auto_req == OT_MULTIBITBOOL4_TRUE; } -static bool ot_edn_is_auto_req_mode(OtEDNState *s) +static bool ot_edn_is_boot_mode(const OtEDNState *s) { - uint32_t auto_req = FIELD_EX32(s->regs[R_CTRL], CTRL, AUTO_REQ_MODE); + /* NOLINTNEXTLINE */ + switch (s->state) { + case EDN_BOOT_INS_ACK_WAIT ... EDN_BOOT_UNI_ACK_WAIT: + return true; + default: + return false; + } +} - return auto_req == OT_MULTIBITBOOL4_TRUE; +static bool ot_edn_is_auto_mode(const OtEDNState *s) +{ + /* NOLINTNEXTLINE */ + switch (s->state) { + case EDN_AUTO_ACK_WAIT ... EDN_AUTO_SEND_RESEED_CMD: + return true; + default: + return false; + } } -static bool ot_edn_is_sw_port_mode(OtEDNState *s) +static bool ot_edn_is_sw_cmd_mode(const OtEDNState *s) { - return !ot_edn_is_boot_req_mode(s) && !ot_edn_is_auto_req_mode(s); + /* NOLINTNEXTLINE */ + switch (s->state) { + case EDN_AUTO_LOAD_INS: + case EDN_AUTO_FIRST_ACK_WAIT: + case EDN_SW_PORT_MODE: + return true; + default: + return false; + } } -static OtCsrngCmd ot_edn_get_last_csrng_command(OtEDNState *s) +static OtCSRNGCmd ot_edn_get_last_csrng_command(const OtEDNState *s) { const OtEDNCSRNG *c = &s->rng; uint32_t last_cmd = FIELD_EX32(c->buffer[0], OT_CSNRG_CMD, ACMD); + /* NOLINTNEXTLINE */ switch (last_cmd) { case OT_CSRNG_CMD_NONE: case OT_CSRNG_CMD_INSTANTIATE: @@ -442,26 +486,33 @@ static OtCsrngCmd ot_edn_get_last_csrng_command(OtEDNState *s) case OT_CSRNG_CMD_GENERATE: case OT_CSRNG_CMD_UPDATE: case OT_CSRNG_CMD_UNINSTANTIATE: - return (OtCsrngCmd)last_cmd; + return (OtCSRNGCmd)last_cmd; default: g_assert_not_reached(); } } -static bool ot_edn_is_cmd_rdy(OtEDNState *s, bool check_fifo) +static bool ot_edn_is_cmd_reg_rdy(const OtEDNState *s) { - if (!ot_edn_is_enabled(s)) { - return false; - } - if (check_fifo && ot_fifo32_is_full(&s->rng.sw_cmd_fifo)) { + /* NOLINTNEXTLINE */ + switch (s->state) { + case EDN_AUTO_LOAD_INS: + case EDN_AUTO_FIRST_ACK_WAIT: + case EDN_AUTO_DISPATCH: + return true; + case EDN_SW_PORT_MODE: + return s->sw_cmd_ready; + default: return false; } +} + +static bool ot_edn_is_cmd_rdy(const OtEDNState *s) +{ + /* NOLINTNEXTLINE */ switch (s->state) { - case EDN_IDLE: - case EDN_BOOT_PULSE: - case EDN_BOOT_DONE: case EDN_AUTO_LOAD_INS: - case EDN_AUTO_FIRST_ACK_WAIT: + case EDN_AUTO_DISPATCH: return true; case EDN_SW_PORT_MODE: return s->sw_cmd_ready; @@ -470,23 +521,77 @@ static bool ot_edn_is_cmd_rdy(OtEDNState *s, bool check_fifo) } } +static void ot_edn_reset_replay_fifos(OtEDNState *s) +{ + /* + * "The generate and reseed FIFOs are reset under four circumstances. These + * circumstances are: + * (a) when the EDN is disabled, + * (b) when the SWPortMode state is entered, + * (c) when the boot sequence has completed, or + * (d) when the EDN enters the Idle state after it finishes operation in + * auto mode." + */ + OtEDNCSRNG *c = &s->rng; + + trace_ot_edn_reset_replay_fifos(c->appid); + + ot_fifo32_reset(&c->cmd_gen_fifo); + ot_fifo32_reset(&c->cmd_reseed_fifo); +} + +static void ot_edn_manage_error(OtEDNState *s) +{ + s->regs[R_INTR_STATE] |= INTR_EDN_FATAL_ERR_MASK; + if (s->regs[R_ERR_CODE] & R_ERR_CODE_EDN_MAIN_SM_ERR_MASK) { + /* real HW seems to add this error on clock cycle after main error */ + s->regs[R_ERR_CODE] |= R_ERR_CODE_EDN_ACK_SM_ERR_MASK; + } + ot_edn_update_irqs(s); + ot_edn_update_alerts(s); +} + static void ot_edn_change_state_line(OtEDNState *s, OtEDNFsmState state, int line) { - trace_ot_edn_change_state(s->rng.appid, line, STATE_NAME(s->state), - s->state, STATE_NAME(state), state); + if (state != s->state) { + trace_ot_edn_change_state(s->rng.appid, line, STATE_NAME(s->state), + s->state, STATE_NAME(state), state); + } s->state = state; - if (s->state == EDN_ERROR) { - s->regs[R_ERR_CODE] |= R_ERR_CODE_EDN_MAIN_SM_ERR_MASK; - ot_edn_update_alerts(s); + switch (s->state) { + case EDN_ERROR: + s->rng.hw_cmd_type = (uint8_t)OT_CSRNG_CMD_NONE; + ot_edn_manage_error(s); + break; + case EDN_IDLE: + case EDN_REJECT_CSRNG_ENTROPY: + s->rng.hw_cmd_type = (uint8_t)OT_CSRNG_CMD_NONE; + break; + default: + break; } } #define ot_edn_change_state(_s_, _st_) \ ot_edn_change_state_line(_s_, _st_, __LINE__) +static void ot_edn_connect_csrng(OtEDNState *s) +{ + OtEDNCSRNG *c = &s->rng; + + /* if the IRQ is not initialized, the EDN has yet to connected to CSRNG */ + if (!c->genbits_ready) { + qemu_irq req_sts; + req_sts = qdev_get_gpio_in_named(DEVICE(s), TYPE_OT_EDN "-req_sts", 0); + c->genbits_ready = ot_csnrg_connect_hw_app(c->device, c->appid, req_sts, + &ot_edn_fill_bits, s); + g_assert(c->genbits_ready); + } +} + static bool ot_edn_update_genbits_ready(OtEDNState *s) { OtEDNCSRNG *c = &s->rng; @@ -504,56 +609,82 @@ static bool ot_edn_update_genbits_ready(OtEDNState *s) return accept_entropy; } -static int ot_edn_push_csrng_request(OtEDNState *s) +static OtCSRNGCmdStatus +ot_edn_push_csrng_request(OtEDNState *s, bool auto_mode, uint32_t length) { + ot_edn_connect_csrng(s); + OtEDNCSRNG *c = &s->rng; - /* if the IRQ is not initialized, the EDN has yet to connected to CSRNG */ - if (!c->genbits_ready) { - qemu_irq req_sts; - req_sts = qdev_get_gpio_in_named(DEVICE(s), TYPE_OT_EDN "-req_sts", 0); - c->genbits_ready = ot_csnrg_connect_hw_app(c->device, c->appid, req_sts, - &ot_edn_fill_bits, s); - g_assert(c->genbits_ready); - } - s->regs[R_SW_CMD_STS] |= R_SW_CMD_STS_CMD_ACK_MASK; - int res = ot_csrng_push_command(c->device, c->appid, c->buffer); - if (res) { - xtrace_ot_edn_error(c->appid, "CSRNG rejected command"); - /* do not expect any delayed completion */ - memset(c->buffer, 0, sizeof(*c->buffer)); + OtCSRNGCmdStatus res = CSRNG_STATUS_INVALID_ACMD; + + for (unsigned cix = 0; cix < length; cix++) { + trace_ot_edn_push_csrng_command(c->appid, auto_mode ? "auto" : "boot", + c->buffer[cix]); + res = ot_csrng_push_command(c->device, c->appid, c->buffer[cix]); + if (res != CSRNG_STATUS_SUCCESS) { + trace_ot_edn_push_csrng_error(c->appid, (int)res); + ot_edn_change_state(s, EDN_REJECT_CSRNG_ENTROPY); + s->regs[R_RECOV_ALERT_STS] |= R_RECOV_ALERT_STS_CSRNG_ACK_ERR_MASK; + /* do not expect any delayed completion */ + memset(c->buffer, 0, sizeof(*c->buffer)); + ot_edn_update_alerts(s); + break; + } } return res; } -static void ot_edn_send_boot_req(OtEDNState *s, unsigned reg) +static bool ot_edn_check_command_ready(OtEDNState *s) { - OtEDNCSRNG *c = &s->rng; - + const OtEDNCSRNG *c = &s->rng; uint32_t command = FIELD_EX32(c->buffer[0], OT_CSNRG_CMD, ACMD); if (command != OT_CSRNG_CMD_NONE) { xtrace_ot_edn_error(c->appid, "Another command is already scheduled"); + s->regs[R_ERR_CODE] |= R_ERR_CODE_EDN_MAIN_SM_ERR_MASK; ot_edn_change_state(s, EDN_ERROR); + return false; + } + + return true; +} + +static void ot_edn_send_boot_req(OtEDNState *s, unsigned reg) +{ + OtEDNCSRNG *c = &s->rng; + + if (!ot_edn_check_command_ready(s)) { return; } c->buffer[0u] = s->regs[reg]; - command = FIELD_EX32(c->buffer[0], OT_CSNRG_CMD, ACMD); + uint32_t command = FIELD_EX32(c->buffer[0], OT_CSNRG_CMD, ACMD); + uint32_t clen = FIELD_EX32(command, OT_CSNRG_CMD, CLEN); + if (clen) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %u: boot command CLEN is non-zero\n", __func__, + c->appid); + /* + * the HW does not consider this case as an error and resume execution, + * which causes the CSRNG to stall + */ + } if (command == OT_CSRNG_CMD_GENERATE) { c->rem_packet_count = FIELD_EX32(c->buffer[0], OT_CSNRG_CMD, GLEN); xtrace_ot_edn_dinfo(c->appid, "Boot generation w/ packets", c->rem_packet_count); ot_edn_update_genbits_ready(s); - ot_edn_change_state(s, EDN_BOOT_CAPT_GEN_CNT); + ot_edn_change_state(s, EDN_BOOT_LOAD_GEN); for (unsigned epix = 0; epix < ARRAY_SIZE(s->endpoints); epix++) { s->endpoints[epix].gen_count = 0; } } - if (ot_edn_push_csrng_request(s)) { - xtrace_ot_edn_error(c->appid, "Cannot push command"); - ot_edn_change_state(s, EDN_ERROR); + + c->hw_cmd_type = (uint8_t)FIELD_EX32(command, OT_CSNRG_CMD, ACMD); + c->hw_cmd_status = ot_edn_push_csrng_request(s, false, 1u); + if (c->hw_cmd_status) { return; } @@ -563,6 +694,7 @@ static void ot_edn_send_boot_req(OtEDNState *s, unsigned reg) */ switch (command) { case OT_CSRNG_CMD_INSTANTIATE: + c->no_fips = false; ot_edn_change_state(s, EDN_BOOT_INS_ACK_WAIT); break; case OT_CSRNG_CMD_GENERATE: @@ -573,187 +705,144 @@ static void ot_edn_send_boot_req(OtEDNState *s, unsigned reg) } } -static void ot_edn_try_auto_instantiate(OtEDNState *s) +static void ot_edn_send_auto_reseed_cmd(OtEDNState *s) { OtEDNCSRNG *c = &s->rng; - if (ot_fifo32_is_empty(&c->sw_cmd_fifo)) { - /* instantiate command not yet loaded into the SW_CMD_REQ */ - xtrace_ot_edn_xinfo(c->appid, "no SW cmd in FIFO", 0); + if (!ot_edn_check_command_ready(s)) { return; } - uint32_t command = ot_fifo32_peek(&c->sw_cmd_fifo); - uint32_t length = FIELD_EX32(command, OT_CSNRG_CMD, CLEN) + 1u; - if (ot_fifo32_num_used(&c->sw_cmd_fifo) < length) { - /* instantiate command not fully loaded into the SW_CMD_REQ */ - xtrace_ot_edn_xinfo(c->appid, "SW cmd FIFO incomplete", 0); - return; - } - - uint32_t num = length; - const uint32_t *cmd = ot_fifo32_pop_buf(&c->sw_cmd_fifo, num, &num); - g_assert(num == length); - memcpy(c->buffer, cmd, length * sizeof(uint32_t)); - - if (ot_edn_push_csrng_request(s)) { - xtrace_ot_edn_error(c->appid, "Cannot execute command"); - ot_edn_change_state(s, EDN_ERROR); - return; - } - - ot_edn_change_state(s, EDN_AUTO_FIRST_ACK_WAIT); -} - -static void ot_edn_send_reseed_cmd(OtEDNState *s) -{ - OtEDNCSRNG *c = &s->rng; + bool fatal_error = false; + uint32_t command; + uint32_t length; if (ot_fifo32_is_empty(&c->cmd_reseed_fifo)) { s->regs[R_ERR_CODE] |= R_ERR_CODE_SFIFO_RESCMD_ERR_MASK | R_ERR_CODE_FIFO_READ_ERR_MASK; - s->regs[R_INTR_STATE] |= INTR_EDN_FATAL_ERR_BIT_MASK; - ot_edn_update_irqs(s); - ot_edn_update_alerts(s); - return; + fatal_error = true; + command = (uint32_t)OT_CSRNG_CMD_NONE; + length = 1u; /* always push the command */ + } else { + command = ot_fifo32_peek(&c->cmd_reseed_fifo); + length = FIELD_EX32(command, OT_CSNRG_CMD, CLEN) + 1u; + if (ot_fifo32_num_used(&c->cmd_reseed_fifo) < length) { + s->regs[R_ERR_CODE] |= R_ERR_CODE_SFIFO_RESCMD_ERR_MASK | + R_ERR_CODE_FIFO_READ_ERR_MASK; + fatal_error = true; + } + uint32_t num = length; + const uint32_t *cmd; + cmd = ot_fifo32_peek_buf(&c->cmd_reseed_fifo, num, &length); + if (num != length) { + xtrace_ot_edn_error(c->appid, "incoherent reseed FIFO length"); + } + memcpy(c->buffer, cmd, length * sizeof(uint32_t)); } - uint32_t command = ot_fifo32_peek(&c->cmd_reseed_fifo); - uint32_t length = FIELD_EX32(command, OT_CSNRG_CMD, CLEN) + 1u; - if (ot_fifo32_num_used(&c->cmd_reseed_fifo) < length) { - s->regs[R_ERR_CODE] |= - R_ERR_CODE_SFIFO_RESCMD_ERR_MASK | R_ERR_CODE_FIFO_READ_ERR_MASK; - s->regs[R_INTR_STATE] |= INTR_EDN_FATAL_ERR_BIT_MASK; - ot_edn_update_irqs(s); - ot_edn_update_alerts(s); + if (fatal_error) { + ot_edn_change_state(s, EDN_ERROR); return; } ot_edn_change_state(s, EDN_AUTO_SEND_RESEED_CMD); - uint32_t num = length; - const uint32_t *cmd = ot_fifo32_peek_buf(&c->cmd_reseed_fifo, num, &num); - g_assert(num == length); - memcpy(c->buffer, cmd, length * sizeof(uint32_t)); - - if (ot_edn_push_csrng_request(s)) { - xtrace_ot_edn_error(c->appid, "Cannot execute command"); - ot_edn_change_state(s, EDN_ERROR); + c->hw_cmd_type = (uint8_t)FIELD_EX32(command, OT_CSNRG_CMD, ACMD); + c->hw_cmd_status = ot_edn_push_csrng_request(s, true, length); + if (c->hw_cmd_status) { return; } + c->no_fips = false; ot_edn_change_state(s, EDN_AUTO_ACK_WAIT); } -static void ot_edn_send_generate_cmd(OtEDNState *s) +static void ot_edn_send_auto_generate_cmd(OtEDNState *s) { OtEDNCSRNG *c = &s->rng; - if (ot_fifo32_is_empty(&c->cmd_gen_fifo)) { - s->regs[R_ERR_CODE] |= - R_ERR_CODE_SFIFO_GENCMD_ERR_MASK | R_ERR_CODE_FIFO_READ_ERR_MASK; - s->regs[R_INTR_STATE] |= INTR_EDN_FATAL_ERR_BIT_MASK; - ot_edn_update_irqs(s); - ot_edn_update_alerts(s); + if (!ot_edn_check_command_ready(s)) { return; } - uint32_t command = ot_fifo32_peek(&c->cmd_gen_fifo); - xtrace_ot_edn_xinfo(c->appid, "COMMAND", command); - uint32_t length = FIELD_EX32(command, OT_CSNRG_CMD, CLEN) + 1u; - if (ot_fifo32_num_used(&c->cmd_gen_fifo) < length) { + bool fatal_error = false; + uint32_t command; + uint32_t length; + + if (ot_fifo32_is_empty(&c->cmd_gen_fifo)) { s->regs[R_ERR_CODE] |= R_ERR_CODE_SFIFO_GENCMD_ERR_MASK | R_ERR_CODE_FIFO_READ_ERR_MASK; - s->regs[R_INTR_STATE] |= INTR_EDN_FATAL_ERR_BIT_MASK; - ot_edn_update_irqs(s); - ot_edn_update_alerts(s); + fatal_error = true; + command = (uint32_t)OT_CSRNG_CMD_NONE; + length = 1u; /* always push the command */ + } else { + command = ot_fifo32_peek(&c->cmd_gen_fifo); + length = FIELD_EX32(command, OT_CSNRG_CMD, CLEN) + 1u; + if (ot_fifo32_num_used(&c->cmd_gen_fifo) < length) { + s->regs[R_ERR_CODE] |= R_ERR_CODE_SFIFO_GENCMD_ERR_MASK | + R_ERR_CODE_FIFO_READ_ERR_MASK; + fatal_error = true; + } + uint32_t num = length; + const uint32_t *cmd = + ot_fifo32_peek_buf(&c->cmd_gen_fifo, num, &length); + if (num != length) { + xtrace_ot_edn_error(c->appid, "incoherent generate FIFO length"); + } + memcpy(c->buffer, cmd, length * sizeof(uint32_t)); + c->rem_packet_count = FIELD_EX32(c->buffer[0], OT_CSNRG_CMD, GLEN); + xtrace_ot_edn_dinfo(c->appid, "Generate cmd w/ packets", + c->rem_packet_count); + } + + if (fatal_error) { + ot_edn_change_state(s, EDN_ERROR); return; } - uint32_t num = length; - const uint32_t *cmd = ot_fifo32_peek_buf(&c->cmd_gen_fifo, num, &num); - g_assert(num == length); - memcpy(c->buffer, cmd, length * sizeof(uint32_t)); - c->rem_packet_count = FIELD_EX32(c->buffer[0], OT_CSNRG_CMD, GLEN); - xtrace_ot_edn_dinfo(c->appid, "Generate cmd w/ packets", - c->rem_packet_count); - ot_edn_update_genbits_ready(s); + xtrace_ot_edn_xinfo(c->appid, "COMMAND", c->buffer[0]); - ot_edn_change_state(s, EDN_AUTO_SEND_GEN_CMD); + ot_edn_update_genbits_ready(s); + ot_edn_change_state(s, EDN_AUTO_SEND_RESEED_CMD); for (unsigned epix = 0; epix < ARRAY_SIZE(s->endpoints); epix++) { s->endpoints[epix].gen_count = 0; } - if (ot_edn_push_csrng_request(s)) { - xtrace_ot_edn_error(c->appid, "Cannot execute command"); - ot_edn_change_state(s, EDN_ERROR); + + c->hw_cmd_type = (uint8_t)FIELD_EX32(command, OT_CSNRG_CMD, ACMD); + c->hw_cmd_status = ot_edn_push_csrng_request(s, true, length); + if (c->hw_cmd_status) { return; } - if (s->reseed_counter) { - s->reseed_counter -= 1u; + if (s->max_reqs_cnt) { + s->max_reqs_cnt -= 1u; } ot_edn_change_state(s, EDN_AUTO_ACK_WAIT); } -static void ot_edn_send_uninstanciate_cmd(OtEDNState *s) +static void ot_edn_send_boot_uninstanciate_cmd(OtEDNState *s) { OtEDNCSRNG *c = &s->rng; - memset(c->buffer, 0, sizeof(c->buffer)); - c->buffer[0u] = - FIELD_DP32(0, OT_CSNRG_CMD, ACMD, OT_CSRNG_CMD_UNINSTANTIATE); + g_assert(s->state == EDN_BOOT_LOAD_UNI); - if (ot_edn_push_csrng_request(s)) { - xtrace_ot_edn_error(c->appid, "Cannot execute command"); - ot_edn_change_state(s, EDN_ERROR); + if (!ot_edn_check_command_ready(s)) { return; } - /* TODO: what is the actual state of uninstantiating from boot mode? */ - ot_edn_change_state(s, EDN_AUTO_ACK_WAIT); -} - -static void ot_edn_try_sw_request(OtEDNState *s) -{ - OtEDNCSRNG *c = &s->rng; + c->buffer[0u] = + FIELD_DP32(0, OT_CSNRG_CMD, ACMD, OT_CSRNG_CMD_UNINSTANTIATE); - uint32_t command = ot_fifo32_peek(&c->sw_cmd_fifo); - uint32_t length = FIELD_EX32(command, OT_CSNRG_CMD, CLEN) + 1u; - if (ot_fifo32_num_used(&c->sw_cmd_fifo) != length) { - /* command not yet complete */ + c->hw_cmd_type = (uint8_t)OT_CSRNG_CMD_UNINSTANTIATE; + c->hw_cmd_status = ot_edn_push_csrng_request(s, false, 1u); + if (c->hw_cmd_status) { return; } - g_assert(s->state == EDN_SW_PORT_MODE); - - uint32_t num = length; - const uint32_t *cmd = ot_fifo32_peek_buf(&c->sw_cmd_fifo, num, &num); - memcpy(c->buffer, cmd, length * sizeof(uint32_t)); - ot_fifo32_reset(&c->sw_cmd_fifo); - - s->sw_cmd_ready = false; - - command = FIELD_EX32(c->buffer[0], OT_CSNRG_CMD, ACMD); - - if (command == OT_CSRNG_CMD_GENERATE) { - c->rem_packet_count = FIELD_EX32(c->buffer[0], OT_CSNRG_CMD, GLEN); - xtrace_ot_edn_dinfo(c->appid, "SW generation w/ packets", - c->rem_packet_count); - ot_edn_update_genbits_ready(s); - for (unsigned epix = 0; epix < ARRAY_SIZE(s->endpoints); epix++) { - s->endpoints[epix].gen_count = 0; - } - } - - if (ot_edn_push_csrng_request(s)) { - xtrace_ot_edn_error(c->appid, "Cannot execute command"); - ot_edn_change_state(s, EDN_ERROR); - s->sw_cmd_ready = true; - return; - } + ot_edn_change_state(s, EDN_BOOT_UNI_ACK_WAIT); } static void ot_edn_handle_disable(OtEDNState *s) @@ -785,87 +874,232 @@ static void ot_edn_handle_disable(OtEDNState *s) /* signal CSRNG that EDN is no longer ready to receive entropy */ ot_edn_update_genbits_ready(s); - switch (s->state) { - case EDN_BOOT_GEN_ACK_WAIT: - /* no longer expect a generate ack */ - ot_edn_change_state(s, EDN_BOOT_DONE); - break; - case EDN_AUTO_ACK_WAIT: - /* no longer expect a generate ack */ - ot_edn_change_state(s, EDN_IDLE); - break; - default: - break; - } + /* disconnect */ + qemu_irq rdy; + rdy = ot_csnrg_connect_hw_app(c->device, c->appid, NULL, NULL, NULL); + g_assert(!rdy); - ot_edn_send_uninstanciate_cmd(s); + c->genbits_ready = NULL; } -static void ot_edn_complete_sw_req(OtEDNState *s) +static void ot_edn_clean_up(OtEDNState *s, bool discard_requests) { - s->sw_cmd_ready = true; - s->regs[R_INTR_STATE] |= INTR_EDN_CMD_REQ_DONE_BIT_MASK; + OtEDNCSRNG *c = &s->rng; + + trace_ot_edn_clean_up(c->appid, discard_requests); + + c->instantiated = false; + s->sw_cmd_ready = false; + c->hw_cmd_status = CSRNG_STATUS_SUCCESS; + c->sw_cmd_status = CSRNG_STATUS_SUCCESS; + c->hw_ack = false; + c->sw_ack = false; + s->recov_alert_sts = 0u; + s->max_reqs_cnt = 0; + memset(c->buffer, 0, sizeof(*c->buffer)); + ot_fifo32_reset(&c->bits_fifo); ot_edn_update_irqs(s); + ot_edn_update_alerts(s); + + if (discard_requests) { + /* clear all pending end point requests */ + while (QSIMPLEQ_FIRST(&s->ep_requests)) { + QSIMPLEQ_REMOVE_HEAD(&s->ep_requests, request); + } + } + + for (unsigned epix = 0; epix < ARRAY_SIZE(s->endpoints); epix++) { + ot_fifo32_reset(&s->endpoints[epix].fifo); + s->endpoints[epix].fips = false; + } + + bool accept_entropy = ot_edn_update_genbits_ready(s); + g_assert(!accept_entropy); + c->genbits_ready = NULL; } -static void ot_edn_dispatch(OtEDNState *s) +static bool ot_edn_update_mode(OtEDNState *s) { + /* + * CTRL may have disabled EDN, while the EDN was in an active state. + * If disablement has been requested, now is time to handle it, if not + * already done or in a fatal error state. + */ + if (!ot_edn_is_enabled(s)) { + if (s->state != EDN_IDLE) { + ot_edn_handle_disable(s); + ot_edn_clean_up(s, true); + if (s->state != EDN_ERROR) { + ot_edn_change_state(s, EDN_IDLE); + } + } + return true; + } + + /* EDN is enabled */ + OtEDNCSRNG *c = &s->rng; - if (ot_edn_is_boot_req_mode(s)) { - xtrace_ot_edn_dinfo(c->appid, "Dispatch in boot mode", - c->rem_packet_count); - s->reseed_counter = s->regs[R_MAX_NUM_REQS_BETWEEN_RESEEDS]; - ot_edn_change_state(s, EDN_IDLE); - return; + if (s->state == EDN_IDLE) { + if (ot_edn_is_boot_req_mode(s)) { + trace_ot_edn_enable(c->appid, "boot mode"); + ot_edn_change_state(s, EDN_BOOT_LOAD_INS); + ot_edn_send_boot_req(s, R_BOOT_INS_CMD); + } else if (ot_edn_is_auto_req_mode(s)) { + trace_ot_edn_enable(c->appid, "auto mode"); + s->sw_cmd_ready = true; + ot_edn_change_state(s, EDN_AUTO_LOAD_INS); + } else { + trace_ot_edn_enable(c->appid, "sw mode"); + s->sw_cmd_ready = true; + ot_edn_reset_replay_fifos(s); + ot_edn_change_state(s, EDN_SW_PORT_MODE); + } + return true; } - if (ot_edn_is_sw_port_mode(s)) { - xtrace_ot_edn_dinfo(c->appid, "Dispatch in sw port mode", 0); - ot_edn_complete_sw_req(s); - return; + if (s->state == EDN_BOOT_DONE) { + trace_ot_edn_enable(c->appid, "boot uninstantiate"); + ot_edn_change_state(s, EDN_BOOT_LOAD_UNI); + ot_edn_send_boot_uninstanciate_cmd(s); + return true; } - xtrace_ot_edn_dinfo(c->appid, "Dispatch in auto mode", c->rem_packet_count); - if (s->reseed_counter == 0) { - ot_edn_change_state(s, EDN_AUTO_CAPT_RESEED_CNT); - ot_edn_send_reseed_cmd(s); - s->reseed_counter = s->regs[R_MAX_NUM_REQS_BETWEEN_RESEEDS]; - } else { - ot_edn_change_state(s, EDN_AUTO_CAPT_GEN_CNT); - ot_edn_send_generate_cmd(s); + return s->state == EDN_SW_PORT_MODE; +} + +static void ot_edn_handle_ctrl(OtEDNState *s, uint32_t val32) +{ + OtEDNCSRNG *c = &s->rng; + + bool enabled = + FIELD_EX32(s->regs[R_CTRL], CTRL, EDN_ENABLE) == OT_MULTIBITBOOL4_TRUE; + + s->regs[R_CTRL] = val32; + +#define CHECK_MULTIBOOT(_s_, _r_, _b_) \ + ot_edn_check_multibitboot((_s_), FIELD_EX32(val32, _r_, _b_), \ + ALERT_STATUS_BIT(_b_)); + bool enable = CHECK_MULTIBOOT(s, CTRL, EDN_ENABLE); + bool boot_req_mode = CHECK_MULTIBOOT(s, CTRL, BOOT_REQ_MODE); + bool auto_req_mode = CHECK_MULTIBOOT(s, CTRL, AUTO_REQ_MODE); + bool cmd_fifo_rst = CHECK_MULTIBOOT(s, CTRL, CMD_FIFO_RST); + bool disabling = !enable && enabled; + + trace_ot_edn_ctrl_in_state(c->appid, STATE_NAME(s->state), s->state, enable, + boot_req_mode, auto_req_mode, cmd_fifo_rst, + disabling); + + if ((FIELD_EX32(s->regs[R_CTRL], CTRL, CMD_FIFO_RST) == + OT_MULTIBITBOOL4_TRUE) || + disabling) { + ot_edn_reset_replay_fifos(s); + } + + if (!ot_edn_update_mode(s)) { + trace_ot_edn_delay_mode_change(c->appid, STATE_NAME(s->state), val32); } } -static void ot_edn_clean_up(OtEDNState *s, bool discard_requests) +static void ot_edn_complete_sw_req(OtEDNState *s, OtCSRNGCmdStatus cmd_status) { OtEDNCSRNG *c = &s->rng; - c->instantiated = false; - s->sw_cmd_ready = false; - s->rng.last_cmd_status = CSRNG_STATUS_SUCCESS; - s->reseed_counter = 0; - memset(c->buffer, 0, sizeof(*c->buffer)); - ot_fifo32_reset(&c->bits_fifo); - ot_fifo32_reset(&c->sw_cmd_fifo); + c->sw_cmd_status = cmd_status; + c->sw_ack = true; + s->sw_cmd_ready = cmd_status == CSRNG_STATUS_SUCCESS; + s->regs[R_INTR_STATE] |= INTR_EDN_CMD_REQ_DONE_MASK; + ot_edn_update_irqs(s); - ot_edn_update_alerts(s); +} - if (discard_requests) { - /* clear all pending end point requests */ - while (QSIMPLEQ_FIRST(&s->ep_requests)) { - QSIMPLEQ_REMOVE_HEAD(&s->ep_requests, request); +static void ot_edn_handle_sw_cmd_req(OtEDNState *s, uint32_t value) +{ + OtEDNCSRNG *c = &s->rng; + + if (!ot_edn_is_sw_cmd_mode(s)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: %u: ignore SW REQ in %s\n", + __func__, c->appid, STATE_NAME(s->state)); + return; + } + + ot_edn_connect_csrng(s); + + c->sw_ack = false; + + trace_ot_edn_push_csrng_command(c->appid, "sw", value); + OtCSRNGCmdStatus res = ot_csrng_push_command(c->device, c->appid, value); + if (res != CSRNG_STATUS_SUCCESS) { + xtrace_ot_edn_error(c->appid, "CSRNG rejected command"); + s->sw_cmd_ready = false; + s->regs[R_RECOV_ALERT_STS] |= R_RECOV_ALERT_STS_CSRNG_ACK_ERR_MASK; + ot_edn_change_state(s, EDN_REJECT_CSRNG_ENTROPY); + ot_edn_complete_sw_req(s, res); + ot_edn_update_alerts(s); + return; + } + + if (s->state == EDN_SW_PORT_MODE) { + if (s->sw_cmd_ready) { + /* + * first word for this command sequence: + * 1. value contains the actual command + * 2. flag SW command as not ready till the command is completed + */ + s->sw_cmd_ready = false; + uint32_t command = FIELD_EX32(value, OT_CSNRG_CMD, ACMD); + switch (command) { + case OT_CSRNG_CMD_INSTANTIATE: + case OT_CSRNG_CMD_RESEED: + c->no_fips = false; + break; + case OT_CSRNG_CMD_GENERATE: + c->rem_packet_count = FIELD_EX32(value, OT_CSNRG_CMD, GLEN); + xtrace_ot_edn_dinfo(c->appid, "SW generation w/ packets", + c->rem_packet_count); + ot_edn_update_genbits_ready(s); + for (unsigned epix = 0; epix < ARRAY_SIZE(s->endpoints); + epix++) { + s->endpoints[epix].gen_count = 0; + } + break; + default: + break; + } } } - for (unsigned epix = 0; epix < ARRAY_SIZE(s->endpoints); epix++) { - ot_fifo32_reset(&s->endpoints[epix].fifo); - s->endpoints[epix].fips = false; + if (s->state == EDN_AUTO_LOAD_INS) { + ot_edn_change_state(s, EDN_AUTO_FIRST_ACK_WAIT); } - if (c->genbits_ready) { - qemu_set_irq(c->genbits_ready, 0); +} + +static void ot_edn_auto_dispatch(OtEDNState *s) +{ + const OtEDNCSRNG *c = &s->rng; + + bool auto_req_mode = ot_edn_is_auto_req_mode(s); + trace_ot_edn_auto_dispatch(c->appid, auto_req_mode, s->max_reqs_cnt); + + ot_edn_update_irqs(s); + + if (!auto_req_mode) { + ot_edn_change_state(s, EDN_IDLE); + ot_edn_reset_replay_fifos(s); + ot_edn_update_mode(s); + return; + } + + if (s->state == EDN_AUTO_DISPATCH) { + if (s->max_reqs_cnt == 0) { + ot_edn_change_state(s, EDN_AUTO_CAPT_RESEED_CNT); + ot_edn_send_auto_reseed_cmd(s); + s->max_reqs_cnt = s->regs[R_MAX_NUM_REQS_BETWEEN_RESEEDS]; + } else { + ot_edn_change_state(s, EDN_AUTO_CAPT_GEN_CNT); + ot_edn_send_auto_generate_cmd(s); + } } - ot_edn_change_state(s, EDN_IDLE); } static void ot_edn_fill_bits(void *opaque, const uint32_t *bits, bool fips) @@ -880,8 +1114,8 @@ static void ot_edn_fill_bits(void *opaque, const uint32_t *bits, bool fips) break; default: xtrace_ot_edn_error(c->appid, "unexpected state"); + s->regs[R_ERR_CODE] |= R_ERR_CODE_EDN_MAIN_SM_ERR_MASK; ot_edn_change_state(s, EDN_ERROR); - qemu_system_shutdown_request_with_code(SHUTDOWN_CAUSE_GUEST_PANIC, 1); break; } @@ -896,7 +1130,7 @@ static void ot_edn_fill_bits(void *opaque, const uint32_t *bits, bool fips) xtrace_ot_edn_error(c->appid, "entropy input fifo overflow"); s->regs[R_ERR_CODE] |= R_ERR_CODE_SFIFO_GENCMD_ERR_MASK | R_ERR_CODE_FIFO_WRITE_ERR_MASK; - s->regs[R_INTR_STATE] |= INTR_EDN_FATAL_ERR_BIT_MASK; + s->regs[R_INTR_STATE] |= INTR_EDN_FATAL_ERR_MASK; ot_edn_update_irqs(s); ot_edn_update_alerts(s); return; @@ -996,76 +1230,76 @@ static void ot_edn_csrng_ack_irq(void *opaque, int n, int level) trace_ot_edn_csrng_ack(c->appid, STATE_NAME(s->state), level); - OtCsrngCmd last_cmd = ot_edn_get_last_csrng_command(s); /* * cleaning up the first world would be enough, clearing the whole buffer * help debugging */ memset(c->buffer, 0, sizeof(*c->buffer)); - c->last_cmd_status = - level != 0 ? CSRNG_STATUS_INVALID_ACMD : CSRNG_STATUS_SUCCESS; + OtCSRNGCmdStatus cmd_status; - if (level) { - xtrace_ot_edn_error(c->appid, "last command failed"); - ot_edn_change_state(s, EDN_ERROR); - /* TODO: better error handling is required (IRQ signalling, ...)*/ + /* NOLINTNEXTLINE */ + switch (level) { + case CSRNG_STATUS_SUCCESS: + case CSRNG_STATUS_INVALID_ACMD: + case CSRNG_STATUS_INVALID_GEN_CMD: + case CSRNG_STATUS_INVALID_CMD_SEQ: + case CSRNG_STATUS_RESEED_CNT_EXCEEDED: + cmd_status = (OtCSRNGCmdStatus)level; + break; + default: + qemu_log("%s: unexpected CSRNG ack value: %d\n", __func__, level); g_assert_not_reached(); return; } - /* success */ - switch (last_cmd) { - case OT_CSRNG_CMD_INSTANTIATE: - c->instantiated = true; - break; - case OT_CSRNG_CMD_UNINSTANTIATE: - if (ot_edn_is_sw_port_mode(s)) { - ot_edn_complete_sw_req(s); + if (cmd_status != CSRNG_STATUS_SUCCESS) { + trace_ot_edn_push_csrng_error(c->appid, level); + if (s->state != EDN_ERROR) { + ot_edn_change_state(s, EDN_REJECT_CSRNG_ENTROPY); } -#ifdef EDN_DISCARD_PENDING_REQUEST_ON_DISABLE - ot_edn_clean_up(s, true); -#else - ot_edn_clean_up(s, false); -#endif - return; - default: - break; } switch (s->state) { case EDN_BOOT_INS_ACK_WAIT: ot_edn_change_state(s, EDN_BOOT_LOAD_GEN); ot_edn_send_boot_req(s, R_BOOT_GEN_CMD); + c->hw_cmd_status = cmd_status; break; case EDN_BOOT_GEN_ACK_WAIT: - /* todo: boot pulse/done only activated once the generation is over? */ ot_edn_change_state(s, EDN_BOOT_PULSE); ot_edn_change_state(s, EDN_BOOT_DONE); + c->hw_cmd_status = cmd_status; + ot_edn_update_mode(s); + break; + case EDN_BOOT_UNI_ACK_WAIT: + ot_edn_reset_replay_fifos(s); + ot_edn_change_state(s, EDN_IDLE); + c->hw_cmd_status = cmd_status; + ot_edn_update_mode(s); break; case EDN_AUTO_FIRST_ACK_WAIT: ot_edn_change_state(s, EDN_AUTO_DISPATCH); - ot_edn_dispatch(s); + ot_edn_complete_sw_req(s, cmd_status); + ot_edn_auto_dispatch(s); break; case EDN_AUTO_ACK_WAIT: ot_edn_change_state(s, EDN_AUTO_DISPATCH); - ot_edn_dispatch(s); + c->hw_cmd_status = cmd_status; + ot_edn_auto_dispatch(s); break; case EDN_SW_PORT_MODE: - ot_edn_dispatch(s); + ot_edn_complete_sw_req(s, cmd_status); break; default: - trace_ot_edn_invalid_state(c->appid, __func__, STATE_NAME(s->state), - s->state); - s->regs[R_ERR_CODE] |= R_ERR_CODE_EDN_ACK_SM_ERR_MASK; - ot_edn_update_alerts(s); - g_assert_not_reached(); + break; } } static uint64_t ot_edn_regs_read(void *opaque, hwaddr addr, unsigned size) { OtEDNState *s = opaque; + OtEDNCSRNG *c = &s->rng; (void)size; uint32_t val32; @@ -1084,15 +1318,22 @@ static uint64_t ot_edn_regs_read(void *opaque, hwaddr addr, unsigned size) case R_ERR_CODE_TEST: val32 = s->regs[reg]; break; - case R_SW_CMD_STS: { - uint32_t rdy = (uint32_t)ot_edn_is_cmd_rdy(s, false); - uint32_t reg_rdy = (uint32_t)ot_edn_is_cmd_rdy(s, true); - val32 = s->regs[R_SW_CMD_STS]; - val32 = FIELD_DP32(val32, SW_CMD_STS, CMD_STS, s->rng.last_cmd_status); - val32 = FIELD_DP32(val32, SW_CMD_STS, CMD_RDY, rdy); - val32 = FIELD_DP32(val32, SW_CMD_STS, CMD_REG_RDY, reg_rdy); + case R_HW_CMD_STS: + val32 = FIELD_DP32(0u, HW_CMD_STS, BOOT_MODE, ot_edn_is_boot_mode(s)); + val32 = + FIELD_DP32(val32, HW_CMD_STS, AUTO_MODE, ot_edn_is_auto_mode(s)); + val32 = + FIELD_DP32(val32, HW_CMD_STS, CMD_TYPE, (uint32_t)c->hw_cmd_type); + val32 = FIELD_DP32(val32, HW_CMD_STS, CMD_ACK, c->hw_ack); + val32 = FIELD_DP32(val32, HW_CMD_STS, CMD_STS, c->hw_cmd_status); + break; + case R_SW_CMD_STS: + val32 = + FIELD_DP32(0u, SW_CMD_STS, CMD_REG_RDY, ot_edn_is_cmd_reg_rdy(s)); + val32 = FIELD_DP32(val32, SW_CMD_STS, CMD_RDY, ot_edn_is_cmd_rdy(s)); + val32 = FIELD_DP32(val32, SW_CMD_STS, CMD_ACK, c->sw_ack); + val32 = FIELD_DP32(val32, SW_CMD_STS, CMD_STS, c->sw_cmd_status); break; - } case R_MAIN_SM_STATE: switch (s->state) { case EDN_IDLE ... EDN_ERROR: @@ -1127,10 +1368,6 @@ static uint64_t ot_edn_regs_read(void *opaque, hwaddr addr, unsigned size) return (uint64_t)val32; }; -#define CHECK_MULTIBOOT(_s_, _r_, _b_) \ - ot_edn_check_multibitboot((_s_), FIELD_EX32(s->regs[R_##_r_], _r_, _b_), \ - ALERT_STATUS_BIT(_b_)); - static void ot_edn_regs_write(void *opaque, hwaddr addr, uint64_t val64, unsigned size) { @@ -1170,76 +1407,20 @@ static void ot_edn_regs_write(void *opaque, hwaddr addr, uint64_t val64, s->regs[reg] &= val32; break; case R_CTRL: - if (s->regs[R_REGWEN]) { - val32 &= CTRL_MASK; - s->regs[reg] = val32; - CHECK_MULTIBOOT(s, CTRL, EDN_ENABLE); - CHECK_MULTIBOOT(s, CTRL, BOOT_REQ_MODE); - CHECK_MULTIBOOT(s, CTRL, AUTO_REQ_MODE); - CHECK_MULTIBOOT(s, CTRL, CMD_FIFO_RST); - if (FIELD_EX32(s->regs[reg], CTRL, CMD_FIFO_RST) == - OT_MULTIBITBOOL4_TRUE) { - ot_fifo32_reset(&s->rng.cmd_gen_fifo); - ot_fifo32_reset(&s->rng.cmd_reseed_fifo); - } - trace_ot_edn_ctrl_in_state(c->appid, STATE_NAME(s->state), - s->state); - if (s->state == EDN_IDLE) { - if (ot_edn_is_enabled(s)) { - if (ot_edn_is_boot_req_mode(s)) { - trace_ot_edn_enable(c->appid, "boot mode"); - ot_edn_change_state(s, EDN_BOOT_LOAD_INS); - ot_edn_send_boot_req(s, R_BOOT_INS_CMD); - } else if (ot_edn_is_auto_req_mode(s)) { - trace_ot_edn_enable(c->appid, "auto mode"); - ot_edn_change_state(s, EDN_AUTO_LOAD_INS); - ot_edn_try_auto_instantiate(s); - } else { - trace_ot_edn_enable(c->appid, "sw mode"); - ot_fifo32_reset(&c->sw_cmd_fifo); - s->sw_cmd_ready = true; - ot_edn_change_state(s, EDN_SW_PORT_MODE); - } - } - } else if (ot_edn_is_disabled(s)) { - OtCsrngCmd last_cmd = ot_edn_get_last_csrng_command(s); - /* do not pile up uninstanciation requests */ - if (last_cmd != OT_CSRNG_CMD_UNINSTANTIATE) { - trace_ot_edn_enable(c->appid, "disabling"); - ot_edn_handle_disable(s); - } - } - } else { + if (!s->regs[R_REGWEN]) { qemu_log_mask(LOG_GUEST_ERROR, "Cannot change CTRL, REGWEN disabled"); + break; } + val32 &= CTRL_MASK; + ot_edn_handle_ctrl(s, val32); break; case R_BOOT_INS_CMD: case R_BOOT_GEN_CMD: s->regs[reg] = val32; break; case R_SW_CMD_REQ: - s->regs[R_SW_CMD_STS] &= ~R_SW_CMD_STS_CMD_ACK_MASK; - /* ignore all sw commands in auto req mode once instantiated */ - if (ot_edn_is_auto_req_mode(s) && c->instantiated) { - xtrace_ot_edn_dinfo(c->appid, "ignore SW REQ", c->appid); - break; - } - if (!ot_fifo32_is_full(&c->sw_cmd_fifo)) { - ot_fifo32_push(&c->sw_cmd_fifo, val32); - if (s->state == EDN_AUTO_LOAD_INS) { - ot_edn_try_auto_instantiate(s); - break; - } - if (ot_edn_is_sw_port_mode(s)) { - ot_edn_try_sw_request(s); - break; - } - } else { - s->regs[R_ERR_CODE] |= R_ERR_CODE_FIFO_WRITE_ERR_MASK; - ot_edn_update_alerts(s); - xtrace_ot_edn_error(c->appid, "sw fifo full"); - } + ot_edn_handle_sw_cmd_req(s, val32); break; case R_RESEED_CMD: if (ot_fifo32_is_full(&c->cmd_reseed_fifo)) { @@ -1260,15 +1441,24 @@ static void ot_edn_regs_write(void *opaque, hwaddr addr, uint64_t val64, break; case R_MAX_NUM_REQS_BETWEEN_RESEEDS: s->regs[reg] = val32; - s->reseed_counter = val32; + s->max_reqs_cnt = val32; break; case R_RECOV_ALERT_STS: val32 &= RECOV_ALERT_STS_MASK; - s->regs[reg] = val32; + s->regs[reg] &= val32; /* rw0c */ + s->recov_alert_sts &= val32; + ot_edn_update_alerts(s); break; case R_ERR_CODE_TEST: val32 &= R_ERR_CODE_TEST_VAL_MASK; s->regs[reg] = val32; + if ((1u << val32) & ERR_CODE_ACTIVE_MASK) { + if (s->state != EDN_ERROR) { + s->regs[R_ERR_CODE] |= 1u << val32; + ot_edn_change_state(s, EDN_ERROR); + } + } + ot_edn_update_irqs(s); ot_edn_update_alerts(s); break; case R_SW_CMD_STS: @@ -1300,12 +1490,17 @@ static const MemoryRegionOps ot_edn_regs_ops = { .impl.max_access_size = 4u, }; -static void ot_edn_reset(DeviceState *dev) +static void ot_edn_reset_enter(Object *obj, ResetType type) { - OtEDNState *s = OT_EDN(dev); + OtEDNClass *k = OT_EDN_GET_CLASS(obj); + OtEDNState *s = OT_EDN(obj); OtEDNCSRNG *c = &s->rng; - trace_ot_edn_reset(s->rng.appid); + trace_ot_edn_reset(s->rng.appid, "enter"); + + if (k->parent_phases.enter) { + k->parent_phases.enter(obj, type); + } memset(s->regs, 0, REGS_SIZE); s->regs[R_REGWEN] = 0x1u; @@ -1314,9 +1509,9 @@ static void ot_edn_reset(DeviceState *dev) s->regs[R_BOOT_GEN_CMD] = 0xfff003u; ot_edn_clean_up(s, true); + ot_edn_change_state(s, EDN_IDLE); + - /* do not reset connection info since reset order is not known */ - (void)c->genbits_ready; ot_fifo32_reset(&c->cmd_gen_fifo); ot_fifo32_reset(&c->cmd_reseed_fifo); @@ -1347,7 +1542,6 @@ static void ot_edn_init(Object *obj) s->ep_bh = qemu_bh_new(&ot_edn_handle_ep_request, s); ot_fifo32_create(&c->bits_fifo, OT_CSRNG_PACKET_WORD_COUNT * 2u); - ot_fifo32_create(&c->sw_cmd_fifo, OT_CSRNG_CMD_WORD_MAX); ot_fifo32_create(&c->cmd_gen_fifo, OT_CSRNG_CMD_WORD_MAX); ot_fifo32_create(&c->cmd_reseed_fifo, OT_CSRNG_CMD_WORD_MAX); @@ -1364,9 +1558,13 @@ static void ot_edn_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); (void)data; - device_class_set_legacy_reset(dc, &ot_edn_reset); device_class_set_props(dc, ot_edn_properties); set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + ResettableClass *rc = RESETTABLE_CLASS(klass); + OtEDNClass *uc = OT_EDN_CLASS(klass); + resettable_class_set_parent_phases(rc, &ot_edn_reset_enter, NULL, NULL, + &uc->parent_phases); } static const TypeInfo ot_edn_info = { @@ -1374,6 +1572,7 @@ static const TypeInfo ot_edn_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OtEDNState), .instance_init = &ot_edn_init, + .class_size = sizeof(OtEDNClass), .class_init = &ot_edn_class_init, }; diff --git a/hw/opentitan/ot_entropy_src.c b/hw/opentitan/ot_entropy_src.c index 76be8b20768b9..34201bb562d41 100644 --- a/hw/opentitan/ot_entropy_src.c +++ b/hw/opentitan/ot_entropy_src.c @@ -2,6 +2,7 @@ * QEMU OpenTitan Entropy Source device * * Copyright (c) 2023-2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -79,10 +80,12 @@ REG32(MODULE_ENABLE, 0x20u) FIELD(MODULE_ENABLE, MODULE_ENABLE, 0u, 4u) REG32(CONF, 0x24u) FIELD(CONF, FIPS_ENABLE, 0u, 4u) - FIELD(CONF, ENTROPY_DATA_REG_ENABLE, 4u, 4u) - FIELD(CONF, THRESHOLD_SCOPE, 12u, 4u) - FIELD(CONF, RNG_BIT_ENABLE, 20u, 4u) - FIELD(CONF, RNG_BIT_SEL, 24u, 2u) + 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) @@ -149,11 +152,11 @@ REG32(FW_OV_RD_FIFO_OVERFLOW, 0xbcu) REG32(FW_OV_RD_DATA, 0xc0u) REG32(FW_OV_WR_DATA, 0xc4u) REG32(OBSERVE_FIFO_THRESH, 0xc8u) - FIELD(OBSERVE_FIFO_THRESH, VAL, 0u, 7u) + FIELD(OBSERVE_FIFO_THRESH, VAL, 0u, 6u) REG32(OBSERVE_FIFO_DEPTH, 0xccu) - FIELD(OBSERVE_FIFO_DEPTH, VAL, 0u, 7u) + FIELD(OBSERVE_FIFO_DEPTH, VAL, 0u, 6u) REG32(DEBUG_STATUS, 0xd0u) - FIELD(DEBUG_STATUS, ENTROPY_FIFO_DEPTH, 0u, 3u) + 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) @@ -177,10 +180,14 @@ REG32(RECOV_ALERT_STS, 0xd4u) 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_OBSERVE_ERR, 1u, 1u) - FIELD(ERR_CODE, SFIFO_ESFINAL_ERR, 2u, 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) @@ -209,9 +216,9 @@ REG32(MAIN_SM_STATE, 0xe0u) #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_ENTROPY_DATA_REG_ENABLE_MASK | \ - R_CONF_THRESHOLD_SCOPE_MASK | R_CONF_RNG_BIT_ENABLE_MASK | \ - R_CONF_RNG_BIT_SEL_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 \ @@ -232,14 +239,17 @@ REG32(MAIN_SM_STATE, 0xe0u) 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_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_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) + (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 | \ @@ -325,8 +335,17 @@ static const char *REG_NAMES[REGS_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 */ -#define OT_ENTROPY_SRC_BOOT_DELAY_NS 2000000u /* 2 ms */ +/* + * 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, @@ -377,7 +396,6 @@ struct OtEntropySrcState { OtFifo32 final_fifo; /* output FIFO */ hash_state sha3_state; /* libtomcrypt hash state */ OtEntropySrcFsmState state; - unsigned gennum; 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 */ @@ -411,29 +429,29 @@ static const uint16_t OtEDNFsmStateCode[] = { [ENTROPY_SRC_ERROR] = 0b100111101, }; -#define STATE_NAME_ENTRY(_st_) [_st_] = stringify(_st_) +#define STATE_NAME_ENTRY(_st_) [ENTROPY_SRC_##_st_] = stringify(_st_) static const char *STATE_NAMES[] = { - STATE_NAME_ENTRY(ENTROPY_SRC_IDLE), - STATE_NAME_ENTRY(ENTROPY_SRC_BOOT_HT_RUNNING), - STATE_NAME_ENTRY(ENTROPY_SRC_BOOT_POST_HT_CHK), - STATE_NAME_ENTRY(ENTROPY_SRC_BOOT_PHASE_DONE), - STATE_NAME_ENTRY(ENTROPY_SRC_STARTUP_HT_START), - STATE_NAME_ENTRY(ENTROPY_SRC_STARTUP_PHASE1), - STATE_NAME_ENTRY(ENTROPY_SRC_STARTUP_PASS1), - STATE_NAME_ENTRY(ENTROPY_SRC_STARTUP_FAIL1), - STATE_NAME_ENTRY(ENTROPY_SRC_CONT_HT_START), - STATE_NAME_ENTRY(ENTROPY_SRC_CONT_HT_RUNNING), - STATE_NAME_ENTRY(ENTROPY_SRC_FW_INSERT_START), - STATE_NAME_ENTRY(ENTROPY_SRC_FW_INSERT_MSG), - STATE_NAME_ENTRY(ENTROPY_SRC_SHA3_MSGDONE), - STATE_NAME_ENTRY(ENTROPY_SRC_SHA3_PREP), - STATE_NAME_ENTRY(ENTROPY_SRC_SHA3_PROCESS), - STATE_NAME_ENTRY(ENTROPY_SRC_SHA3_VALID), - STATE_NAME_ENTRY(ENTROPY_SRC_SHA3_DONE), - STATE_NAME_ENTRY(ENTROPY_SRC_SHA3_QUIESCE), - STATE_NAME_ENTRY(ENTROPY_SRC_ALERT_STATE), - STATE_NAME_ENTRY(ENTROPY_SRC_ALERT_HANG), - STATE_NAME_ENTRY(ENTROPY_SRC_ERROR), + 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_) \ @@ -447,36 +465,22 @@ static const char *STATE_NAMES[] = { #define xtrace_ot_entropy_src_show_buffer(_msg_, _buf_, _len_) \ ot_entropy_src_show_buffer(__func__, __LINE__, _msg_, _buf_, _len_) -static bool ot_entropy_src_is_module_enabled(OtEntropySrcState *s); -static bool ot_entropy_src_is_hw_route(OtEntropySrcState *s); -static bool ot_entropy_src_is_fips_capable(OtEntropySrcState *s); +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_reset(DeviceState *dev); static void ot_entropy_src_update_alerts(OtEntropySrcState *s); static void ot_entropy_src_update_filler(OtEntropySrcState *s); -static int ot_entropy_src_get_generation(OtRandomSrcIf *dev) -{ - OtEntropySrcState *s = OT_ENTROPY_SRC(dev); - - return ot_entropy_src_is_module_enabled(s) ? (int)s->gennum : 0; -} - -static int ot_entropy_src_get_random(OtRandomSrcIf *dev, int genid, - uint64_t random[OT_RANDOM_SRC_DWORD_COUNT], - bool *fips) +static int ot_entropy_src_get_random( + OtRandomSrcIf *dev, uint64_t random[OT_RANDOM_SRC_DWORD_COUNT], bool *fips) { OtEntropySrcState *s = OT_ENTROPY_SRC(dev); if (!ot_entropy_src_is_module_enabled(s)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: entropy_src is down\n", __func__); - return -2; - } - - if (genid != (int)s->gennum) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: entropy_src gennum mismatch req:%d cur:%u\n", - __func__, genid, s->gennum); - return -2; + return -1; } bool fips_compliant; @@ -500,18 +504,19 @@ static int ot_entropy_src_get_random(OtRandomSrcIf *dev, int genid, case ENTROPY_SRC_STARTUP_PHASE1: case ENTROPY_SRC_STARTUP_PASS1: case ENTROPY_SRC_STARTUP_FAIL1: { - int wait_ns; + int64_t wait_ns; if (timer_pending(s->scheduler)) { - wait_ns = 1; - } else { /* computed delay fits into a 31-bit value */ - wait_ns = (int)(timer_expire_time_ns(s->scheduler) - - qemu_clock_get_ns(OT_VIRTUAL_CLOCK)); + wait_ns = ((int64_t)timer_expire_time_ns(s->scheduler)) - + qemu_clock_get_ns(OT_VIRTUAL_CLOCK); + wait_ns = MAX(wait_ns, OT_ENTROPY_SRC_WAIT_DELAY_NS); + } else { + wait_ns = OT_ENTROPY_SRC_WAIT_DELAY_NS; } trace_ot_entropy_src_init_ongoing(STATE_NAME(s->state), s->state, - wait_ns); + (int)wait_ns); /* not ready */ - return wait_ns; + return (int)wait_ns; } case ENTROPY_SRC_IDLE: qemu_log_mask(LOG_GUEST_ERROR, "%s: module is not enabled\n", __func__); @@ -535,7 +540,7 @@ static int ot_entropy_src_get_random(OtRandomSrcIf *dev, int genid, 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 1; + return OT_ENTROPY_SRC_WAIT_DELAY_NS; } uint32_t *randu32 = (uint32_t *)random; @@ -545,8 +550,17 @@ static int ot_entropy_src_get_random(OtRandomSrcIf *dev, int genid, randu32[pos++] = ot_fifo32_pop(&s->final_fifo); } + bool fips_capable = ot_entropy_src_is_fips_capable(s); + /* note: fips compliancy is only simulated here for now */ - *fips = fips_compliant && ot_entropy_src_is_fips_capable(s); + *fips = fips_compliant && fips_capable; + + trace_ot_entropy_src_get_random_fips( + STATE_NAME(s->state), ot_entropy_src_is_fips_enabled(s), + REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_ROUTE), + REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_TYPE), + REG_MB4_IS_FALSE(s, CONF, RNG_BIT_ENABLE), fips_capable, fips_compliant, + *fips); if (ot_fifo32_num_used(&s->final_fifo) < ES_WORD_COUNT) { ot_entropy_src_update_filler(s); @@ -587,17 +601,17 @@ static void ot_entropy_src_show_buffer( } } -static bool ot_entropy_src_is_module_enabled(OtEntropySrcState *s) +static bool ot_entropy_src_is_module_enabled(const OtEntropySrcState *s) { return REG_MB4_IS_TRUE(s, MODULE_ENABLE, MODULE_ENABLE); } -static bool ot_entropy_src_is_module_disabled(OtEntropySrcState *s) +static bool ot_entropy_src_is_module_disabled(const OtEntropySrcState *s) { return REG_MB4_IS_FALSE(s, MODULE_ENABLE, MODULE_ENABLE); } -static bool ot_entropy_src_is_fips_enabled(OtEntropySrcState *s) +static bool ot_entropy_src_is_fips_enabled(const OtEntropySrcState *s) { return REG_MB4_IS_TRUE(s, CONF, FIPS_ENABLE); } @@ -610,54 +624,48 @@ static void ot_entropy_src_update_irqs(OtEntropySrcState *s) } } -static bool ot_entropy_src_is_final_fifo_slot_available(OtEntropySrcState *s) +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(OtEntropySrcState *s) +static bool ot_entropy_src_is_hw_route(const OtEntropySrcState *s) { return REG_MB4_IS_FALSE(s, ENTROPY_CONTROL, ES_ROUTE); } -static bool ot_entropy_src_is_fw_route(OtEntropySrcState *s) +static bool ot_entropy_src_is_fw_route(const OtEntropySrcState *s) { return REG_MB4_IS_TRUE(s, ENTROPY_CONTROL, ES_ROUTE); } -static bool ot_entropy_src_is_bypass_mode(OtEntropySrcState *s) +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, ENTROPY_CONTROL, ES_TYPE)); } -static bool ot_entropy_src_is_fw_ov_mode(OtEntropySrcState *s) +static bool ot_entropy_src_is_fw_ov_mode(const OtEntropySrcState *s) { return REG_MB4_IS_TRUE(s, FW_OV_CONTROL, FW_OV_MODE); } -static bool ot_entropy_src_is_fw_ov_entropy_insert(OtEntropySrcState *s) +static bool ot_entropy_src_is_fw_ov_entropy_insert(const OtEntropySrcState *s) { return REG_MB4_IS_TRUE(s, FW_OV_CONTROL, FW_OV_ENTROPY_INSERT); } -static bool ot_entropy_src_is_fips_capable(OtEntropySrcState *s) +static bool ot_entropy_src_is_fips_capable(const OtEntropySrcState *s) { - bool fips_capable = - ot_entropy_src_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); - trace_ot_entropy_src_is_fips_capable( - ot_entropy_src_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); - return fips_capable; + return ot_entropy_src_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(OtEntropySrcState *s) +static unsigned ot_alert_get_alert_fail_count(const OtEntropySrcState *s) { unsigned count; @@ -699,8 +707,11 @@ static void ot_entropy_src_change_state_line( break; } - trace_ot_entropy_src_change_state(line, STATE_NAME(old_state), old_state, - STATE_NAME(s->state), s->state); + 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_ERROR) { s->regs[R_ERR_CODE] |= R_ERR_CODE_ES_MAIN_SM_ERR_MASK; @@ -748,7 +759,7 @@ static bool ot_entropy_src_check_multibitboot( return false; } -static bool ot_entropy_src_can_consume_entropy(OtEntropySrcState *s) +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) && @@ -785,7 +796,7 @@ static void ot_entropy_src_update_filler(OtEntropySrcState *s) } } -static bool ot_entropy_src_can_condition_entropy(OtEntropySrcState *s) +static bool ot_entropy_src_can_condition_entropy(const OtEntropySrcState *s) { if (!ot_fifo32_is_full(&s->precon_fifo)) { /* room in preconditioner packer */ @@ -799,7 +810,7 @@ static bool ot_entropy_src_can_condition_entropy(OtEntropySrcState *s) return false; } -static bool ot_entropy_src_can_bypass_entropy(OtEntropySrcState *s) +static bool ot_entropy_src_can_bypass_entropy(const OtEntropySrcState *s) { if (!ot_fifo32_is_full(&s->bypass_fifo)) { /* room in bypass packer */ @@ -847,7 +858,7 @@ ot_entropy_src_push_entropy_to_conditioner(OtEntropySrcState *s, uint32_t word) return true; } -static bool ot_entropy_src_can_hash(OtEntropySrcState *s) +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)))); @@ -1147,6 +1158,7 @@ ot_entropy_src_regs_read(void *opaque, hwaddr addr, unsigned size) 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: @@ -1313,15 +1325,11 @@ static void ot_entropy_src_regs_write(void *opaque, hwaddr addr, uint64_t val64, s->regs[reg] = val32; CHECK_MULTIBOOT(s, MODULE_ENABLE, MODULE_ENABLE); if (ot_entropy_src_is_module_disabled(s)) { - /* change state in disable mode can discard an error state */ - ot_entropy_src_change_state(s, ENTROPY_SRC_IDLE); /* reset takes care of cancelling the scheduler timer */ ot_entropy_src_reset(DEVICE(s)); break; } if ((old ^ s->regs[reg]) && ot_entropy_src_is_module_enabled(s)) { - s->gennum += 1; - trace_ot_entropy_src_update_generation(s->gennum); if (ot_entropy_src_is_fips_enabled(s)) { /* start up phase */ ot_entropy_src_change_state(s, @@ -1557,7 +1565,7 @@ static void ot_entropy_src_reset(DeviceState *dev) s->regs[R_REGWEN] = 0x1u; s->regs[R_REV] = 0x10303u; s->regs[R_MODULE_ENABLE] = 0x9u; - s->regs[R_CONF] = 0x909099u; + s->regs[R_CONF] = 0x2649999u; s->regs[R_ENTROPY_CONTROL] = 0x99u; s->regs[R_HEALTH_TEST_WINDOWS] = 0x600200u; s->regs[R_REPCNT_THRESHOLDS] = 0xffffffffu; @@ -1572,7 +1580,7 @@ static void ot_entropy_src_reset(DeviceState *dev) 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] = 0x20u; + s->regs[R_OBSERVE_FIFO_THRESH] = 0x10u; s->regs[R_DEBUG_STATUS] = 0x10000u; ot_fifo32_reset(&s->input_fifo); @@ -1581,10 +1589,11 @@ static void ot_entropy_src_reset(DeviceState *dev) ot_fifo32_reset(&s->observe_fifo); ot_fifo32_reset(&s->swread_fifo); ot_fifo32_reset(&s->final_fifo); - /* note: s->gennum should not be updated on reset */ + 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 < PARAM_NUM_ALERTS; ix++) { @@ -1596,8 +1605,6 @@ static void ot_entropy_src_reset(DeviceState *dev) const OtOTPEntropyCfg *entropy_cfg = oc->get_entropy_cfg(s->otp_ctrl); g_assert(entropy_cfg); - s->obs_fifo_en = false; - ot_entropy_src_change_state(s, ENTROPY_SRC_IDLE); } @@ -1637,7 +1644,6 @@ static void ot_entropy_src_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); OtRandomSrcIfClass *rdc = OT_RANDOM_SRC_IF_CLASS(klass); - rdc->get_random_generation = &ot_entropy_src_get_generation; rdc->get_random_values = &ot_entropy_src_get_random; } diff --git a/hw/opentitan/ot_ibex_wrapper.c b/hw/opentitan/ot_ibex_wrapper.c index a2dabfa070cf0..793ff1aa3842b 100644 --- a/hw/opentitan/ot_ibex_wrapper.c +++ b/hw/opentitan/ot_ibex_wrapper.c @@ -2,6 +2,7 @@ * QEMU OpenTitan Ibex wrapper device * * Copyright (c) 2023 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Loïc Lefort @@ -26,10 +27,11 @@ */ #include "qemu/osdep.h" +#include "hw/opentitan/ot_common.h" #include "hw/opentitan/ot_ibex_wrapper.h" -OBJECT_DEFINE_ABSTRACT_TYPE(OtIbexWrapperState, ot_ibex_wrapper, - OT_IBEX_WRAPPER, SYS_BUS_DEVICE) +OT_OBJECT_DEFINE_ABSTRACT_TYPE(OtIbexWrapperState, OtIbexWrapperClass, + ot_ibex_wrapper, OT_IBEX_WRAPPER, SYS_BUS_DEVICE) static void ot_ibex_wrapper_class_init(ObjectClass *oc, void *data) {} diff --git a/hw/opentitan/ot_ibex_wrapper_dj.c b/hw/opentitan/ot_ibex_wrapper_dj.c index bff29115d0abd..9324880b34d7b 100644 --- a/hw/opentitan/ot_ibex_wrapper_dj.c +++ b/hw/opentitan/ot_ibex_wrapper_dj.c @@ -2,6 +2,7 @@ * QEMU OpenTitan Darjeeling Ibex wrapper device * * Copyright (c) 2022-2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -1514,11 +1515,16 @@ static const MemoryRegionOps ot_ibex_wrapper_dj_regs_ops = { .impl.max_access_size = 4u, }; -static void ot_ibex_wrapper_dj_reset(DeviceState *dev) +static void ot_ibex_wrapper_dj_reset_enter(Object *obj, ResetType type) { - OtIbexWrapperDjState *s = OT_IBEX_WRAPPER_DJ(dev); + OtIbexWrapperClass *c = OT_IBEX_WRAPPER_DJ_GET_CLASS(obj); + OtIbexWrapperDjState *s = OT_IBEX_WRAPPER_DJ(obj); - trace_ot_ibex_wrapper_reset(s->ot_id); + trace_ot_ibex_wrapper_reset(s->ot_id, "enter"); + + if (c->parent_phases.enter) { + c->parent_phases.enter(obj, type); + } g_assert(s->ot_id); g_assert(s->sys_mem); @@ -1561,7 +1567,23 @@ static void ot_ibex_wrapper_dj_reset(DeviceState *dev) s->cpu_en_bm = s->lc_ignore ? (1u << OT_IBEX_LC_CTRL_CPU_EN) : 0; memset(s->log_engine, 0, sizeof(*s->log_engine)); - s->log_engine->as = ot_common_get_local_address_space(dev); +} + +static void ot_ibex_wrapper_dj_reset_exit(Object *obj, ResetType type) +{ + OtIbexWrapperClass *c = OT_IBEX_WRAPPER_DJ_GET_CLASS(obj); + OtIbexWrapperDjState *s = OT_IBEX_WRAPPER_DJ(obj); + + trace_ot_ibex_wrapper_reset(s->ot_id, "exit"); + + if (c->parent_phases.enter) { + c->parent_phases.enter(obj, type); + } + + s->log_engine->as = ot_common_get_local_address_space(DEVICE(s)); + + /* "Upon reset the data will be invalid with a new EDN request pending." */ + ot_ibex_wrapper_dj_request_entropy(s); } static void ot_ibex_wrapper_dj_realize(DeviceState *dev, Error **errp) @@ -1598,19 +1620,24 @@ static void ot_ibex_wrapper_dj_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); (void)data; - device_class_set_legacy_reset(dc, &ot_ibex_wrapper_dj_reset); dc->realize = &ot_ibex_wrapper_dj_realize; device_class_set_props(dc, ot_ibex_wrapper_dj_properties); set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + ResettableClass *rc = RESETTABLE_CLASS(klass); + OtIbexWrapperClass *ic = OT_IBEX_WRAPPER_CLASS(klass); + resettable_class_set_parent_phases(rc, &ot_ibex_wrapper_dj_reset_enter, + NULL, &ot_ibex_wrapper_dj_reset_exit, + &ic->parent_phases); } static const TypeInfo ot_ibex_wrapper_dj_info = { .name = TYPE_OT_IBEX_WRAPPER_DJ, - .parent = TYPE_SYS_BUS_DEVICE, + .parent = TYPE_OT_IBEX_WRAPPER, .instance_size = sizeof(OtIbexWrapperDjState), .instance_init = &ot_ibex_wrapper_dj_init, .class_init = &ot_ibex_wrapper_dj_class_init, - .class_size = sizeof(OtIbexWrapperStateClass), + .class_size = sizeof(OtIbexWrapperClass), }; static void ot_ibex_wrapper_dj_register_types(void) diff --git a/hw/opentitan/ot_ibex_wrapper_eg.c b/hw/opentitan/ot_ibex_wrapper_eg.c index f1e709fd7ce80..0501197d10e58 100644 --- a/hw/opentitan/ot_ibex_wrapper_eg.c +++ b/hw/opentitan/ot_ibex_wrapper_eg.c @@ -2,6 +2,7 @@ * QEMU OpenTitan EarlGrey Ibex wrapper device * * Copyright (c) 2022-2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -966,11 +967,16 @@ static const MemoryRegionOps ot_ibex_wrapper_eg_regs_ops = { .impl.max_access_size = 4u, }; -static void ot_ibex_wrapper_eg_reset(DeviceState *dev) +static void ot_ibex_wrapper_eg_reset_enter(Object *obj, ResetType type) { - OtIbexWrapperEgState *s = OT_IBEX_WRAPPER_EG(dev); + OtIbexWrapperClass *c = OT_IBEX_WRAPPER_EG_GET_CLASS(obj); + OtIbexWrapperEgState *s = OT_IBEX_WRAPPER_EG(obj); + + trace_ot_ibex_wrapper_reset(s->ot_id, "enter"); - trace_ot_ibex_wrapper_reset(s->ot_id); + if (c->parent_phases.enter) { + c->parent_phases.enter(obj, type); + } g_assert(s->ot_id); g_assert(s->edn); @@ -1003,9 +1009,24 @@ static void ot_ibex_wrapper_eg_reset(DeviceState *dev) s->cpu_en_bm = 1u << OT_IBEX_LC_CTRL_CPU_EN; memset(s->log_engine, 0, sizeof(*s->log_engine)); - s->log_engine->as = ot_common_get_local_address_space(dev); } +static void ot_ibex_wrapper_eg_reset_exit(Object *obj, ResetType type) +{ + OtIbexWrapperClass *c = OT_IBEX_WRAPPER_EG_GET_CLASS(obj); + OtIbexWrapperEgState *s = OT_IBEX_WRAPPER_EG(obj); + + trace_ot_ibex_wrapper_reset(s->ot_id, "exit"); + + if (c->parent_phases.enter) { + c->parent_phases.enter(obj, type); + } + + s->log_engine->as = ot_common_get_local_address_space(DEVICE(s)); + + /* "Upon reset the data will be invalid with a new EDN request pending." */ + ot_ibex_wrapper_eg_request_entropy(s); +} static void ot_ibex_wrapper_eg_init(Object *obj) { @@ -1032,18 +1053,23 @@ static void ot_ibex_wrapper_eg_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); (void)data; - device_class_set_legacy_reset(dc, &ot_ibex_wrapper_eg_reset); device_class_set_props(dc, ot_ibex_wrapper_eg_properties); set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + ResettableClass *rc = RESETTABLE_CLASS(klass); + OtIbexWrapperClass *ic = OT_IBEX_WRAPPER_CLASS(klass); + resettable_class_set_parent_phases(rc, &ot_ibex_wrapper_eg_reset_enter, + NULL, &ot_ibex_wrapper_eg_reset_exit, + &ic->parent_phases); } static const TypeInfo ot_ibex_wrapper_eg_info = { .name = TYPE_OT_IBEX_WRAPPER_EG, - .parent = TYPE_SYS_BUS_DEVICE, + .parent = TYPE_OT_IBEX_WRAPPER, .instance_size = sizeof(OtIbexWrapperEgState), .instance_init = &ot_ibex_wrapper_eg_init, .class_init = &ot_ibex_wrapper_eg_class_init, - .class_size = sizeof(OtIbexWrapperStateClass), + .class_size = sizeof(OtIbexWrapperClass), }; static void ot_ibex_wrapper_eg_register_types(void) diff --git a/hw/opentitan/ot_otbn.c b/hw/opentitan/ot_otbn.c index cf699cfd2c624..7a63b3b5bd8df 100644 --- a/hw/opentitan/ot_otbn.c +++ b/hw/opentitan/ot_otbn.c @@ -165,7 +165,8 @@ struct OtOTBNState { enum OtOTBNCommand last_cmd; OtOTBNRandom rnds[OT_OTBN_RND_COUNT]; - char *logfile; + char *log_file; + bool log_asm; }; static void ot_otbn_request_entropy(OtOTBNRandom *rnd); @@ -327,6 +328,7 @@ static void ot_otbn_fill_entropy(void *opaque, uint32_t bits, bool fips) break; } ot_fifo32_reset(&rnd->packer); + rnd->no_fips = false; if (res) { trace_ot_otbn_error("cannot push entropy"); } @@ -590,7 +592,8 @@ static Property ot_otbn_properties[] = { DEFINE_PROP_UINT8("edn-u-ep", OtOTBNState, rnds[OT_OTBN_URND].ep, UINT8_MAX), DEFINE_PROP_UINT8("edn-r-ep", OtOTBNState, rnds[OT_OTBN_RND].ep, UINT8_MAX), - DEFINE_PROP_STRING("logfile", OtOTBNState, logfile), + DEFINE_PROP_STRING("logfile", OtOTBNState, log_file), + DEFINE_PROP_BOOL("logasm", OtOTBNState, log_asm, false), DEFINE_PROP_END_OF_LIST(), }; @@ -645,7 +648,11 @@ static void ot_otbn_reset(DeviceState *dev) ot_fifo32_reset(&rnd->packer); } - ot_otbn_proxy_start(s->proxy, false, s->logfile); + if (!s->log_file) { + s->log_asm = false; + } + + ot_otbn_proxy_start(s->proxy, false, s->log_file, s->log_asm); } diff --git a/hw/opentitan/ot_sensor.c b/hw/opentitan/ot_sensor_eg.c similarity index 53% rename from hw/opentitan/ot_sensor.c rename to hw/opentitan/ot_sensor_eg.c index e56e973f4661e..5332c3859b5e6 100644 --- a/hw/opentitan/ot_sensor.c +++ b/hw/opentitan/ot_sensor_eg.c @@ -1,7 +1,7 @@ /* - * QEMU OpenTitan Sensor controller device + * QEMU OpenTitan Sensor controller device for EarlGrey * - * Copyright (c) 2023-2024 Rivos, Inc. + * Copyright (c) 2023-2025 Rivos, Inc. * * Author(s): * Emmanuel Blot @@ -32,7 +32,7 @@ #include "qemu/log.h" #include "qemu/typedefs.h" #include "hw/opentitan/ot_alert.h" -#include "hw/opentitan/ot_sensor.h" +#include "hw/opentitan/ot_sensor_eg.h" #include "hw/qdev-properties.h" #include "hw/registerfields.h" #include "hw/riscv/ibex_common.h" @@ -40,7 +40,10 @@ #include "hw/sysbus.h" #include "trace.h" -#define NUM_ALERTS 2u +#define NUM_ALERTS 2u +#define NUM_IO_RAILS 2u + +#define NUM_ALERT_SENSOR_COUNT 11u /* clang-format off */ REG32(INTR_STATE, 0x0u) @@ -65,7 +68,19 @@ REG32(ALERT_TRIG, 0x14u) FIELD(ALERT_TRIG, VAL_8, 8u, 1u) FIELD(ALERT_TRIG, VAL_9, 9u, 1u) FIELD(ALERT_TRIG, VAL_10, 10u, 1u) -REG32(FATAL_ALERT_EN, 0x18u) +REG32(ALERT_EN_0, 0x18u) + SHARED_FIELD(ALERT_EN_VAL, 0u, 4u) +REG32(ALERT_EN_1, 0x1cu) +REG32(ALERT_EN_2, 0x20u) +REG32(ALERT_EN_3, 0x24u) +REG32(ALERT_EN_4, 0x28u) +REG32(ALERT_EN_5, 0x2cu) +REG32(ALERT_EN_6, 0x30u) +REG32(ALERT_EN_7, 0x34u) +REG32(ALERT_EN_8, 0x38u) +REG32(ALERT_EN_9, 0x3cu) +REG32(ALERT_EN_10, 0x40u) +REG32(FATAL_ALERT_EN, 0x44u) FIELD(FATAL_ALERT_EN, VAL_0, 0u, 1u) FIELD(FATAL_ALERT_EN, VAL_1, 1u, 1u) FIELD(FATAL_ALERT_EN, VAL_2, 2u, 1u) @@ -77,7 +92,7 @@ REG32(FATAL_ALERT_EN, 0x18u) FIELD(FATAL_ALERT_EN, VAL_8, 8u, 1u) FIELD(FATAL_ALERT_EN, VAL_9, 9u, 1u) FIELD(FATAL_ALERT_EN, VAL_10, 10u, 1u) -REG32(RECOV_ALERT, 0x1cu) +REG32(RECOV_ALERT, 0x48u) FIELD(RECOV_ALERT, VAL_0, 0u, 1u) FIELD(RECOV_ALERT, VAL_1, 1u, 1u) FIELD(RECOV_ALERT, VAL_2, 2u, 1u) @@ -89,7 +104,7 @@ REG32(RECOV_ALERT, 0x1cu) FIELD(RECOV_ALERT, VAL_8, 8u, 1u) FIELD(RECOV_ALERT, VAL_9, 9u, 1u) FIELD(RECOV_ALERT, VAL_10, 10u, 1u) -REG32(FATAL_ALERT, 0x20u) +REG32(FATAL_ALERT, 0x4cu) FIELD(FATAL_ALERT, VAL_0, 0u, 1u) FIELD(FATAL_ALERT, VAL_1, 1u, 1u) FIELD(FATAL_ALERT, VAL_2, 2u, 1u) @@ -102,36 +117,76 @@ REG32(FATAL_ALERT, 0x20u) FIELD(FATAL_ALERT, VAL_9, 9u, 1u) FIELD(FATAL_ALERT, VAL_10, 10u, 1u) FIELD(FATAL_ALERT, VAL_11, 11u, 1u) -REG32(STATUS, 0x24u) +REG32(STATUS, 0x50u) FIELD(STATUS, AST_INIT_DONE, 0u, 1u) FIELD(STATUS, IO_POK, 1u, 2u) +REG32(MANUAL_PAD_ATTR_REGWEN_0, 0x54u) + SHARED_FIELD(MANUAL_PAD_ATTR_REGWEN_EN, 0u, 1u) +REG32(MANUAL_PAD_ATTR_REGWEN_1, 0x58u) +REG32(MANUAL_PAD_ATTR_REGWEN_2, 0x5cu) +REG32(MANUAL_PAD_ATTR_REGWEN_3, 0x60u) +REG32(MANUAL_PAD_ATTR_0, 0x64u) + SHARED_FIELD(MANUAL_PAD_ATTR_PULL_EN, 2u, 1u) + SHARED_FIELD(MANUAL_PAD_ATTR_PULL_SELECT, 3u, 1u) + SHARED_FIELD(MANUAL_PAD_ATTR_INPUT_DISABLE, 7u, 1u) +REG32(MANUAL_PAD_ATTR_1, 0x68u) +REG32(MANUAL_PAD_ATTR_2, 0x6cu) +REG32(MANUAL_PAD_ATTR_3, 0x70u) /* clang-format on */ -#define PARAM_NUM_IO_RAILS 2 - #define INTR_MASK (INTR_IO_STATUS_CHANGE_MASK | INTR_INIT_STATUS_CHANGE_MASK) #define ALERT_TEST_MASK \ (R_ALERT_TEST_RECOV_ALERT_MASK | R_ALERT_TEST_FATAL_ALERT_MASK) +#define ALERT_SENSOR_MASK ((1u << NUM_ALERT_SENSOR_COUNT) - 1u) +#define MANUAL_PAD_ATTR_MASK \ + (MANUAL_PAD_ATTR_PULL_EN_MASK | MANUAL_PAD_ATTR_PULL_SELECT_MASK | \ + MANUAL_PAD_ATTR_INPUT_DISABLE_MASK) #define R32_OFF(_r_) ((_r_) / sizeof(uint32_t)) -#define R_LAST_REG (R_STATUS) +#define R_LAST_REG (R_MANUAL_PAD_ATTR_3) #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 REG_NAME_ENTRY(_reg_) [R_##_reg_] = stringify(_reg_) +/* clang-format off */ 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(CFG_REGWEN), REG_NAME_ENTRY(ALERT_TRIG), - REG_NAME_ENTRY(FATAL_ALERT_EN), REG_NAME_ENTRY(RECOV_ALERT), - REG_NAME_ENTRY(FATAL_ALERT), REG_NAME_ENTRY(STATUS), + REG_NAME_ENTRY(INTR_STATE), + REG_NAME_ENTRY(INTR_ENABLE), + REG_NAME_ENTRY(INTR_TEST), + REG_NAME_ENTRY(ALERT_TEST), + REG_NAME_ENTRY(CFG_REGWEN), + REG_NAME_ENTRY(ALERT_TRIG), + REG_NAME_ENTRY(ALERT_EN_0), + REG_NAME_ENTRY(ALERT_EN_1), + REG_NAME_ENTRY(ALERT_EN_2), + REG_NAME_ENTRY(ALERT_EN_3), + REG_NAME_ENTRY(ALERT_EN_4), + REG_NAME_ENTRY(ALERT_EN_5), + REG_NAME_ENTRY(ALERT_EN_6), + REG_NAME_ENTRY(ALERT_EN_7), + REG_NAME_ENTRY(ALERT_EN_8), + REG_NAME_ENTRY(ALERT_EN_9), + REG_NAME_ENTRY(ALERT_EN_10), + REG_NAME_ENTRY(FATAL_ALERT_EN), + REG_NAME_ENTRY(RECOV_ALERT), + REG_NAME_ENTRY(FATAL_ALERT), + REG_NAME_ENTRY(STATUS), + REG_NAME_ENTRY(MANUAL_PAD_ATTR_REGWEN_0), + REG_NAME_ENTRY(MANUAL_PAD_ATTR_REGWEN_1), + REG_NAME_ENTRY(MANUAL_PAD_ATTR_REGWEN_2), + REG_NAME_ENTRY(MANUAL_PAD_ATTR_REGWEN_3), + REG_NAME_ENTRY(MANUAL_PAD_ATTR_0), + REG_NAME_ENTRY(MANUAL_PAD_ATTR_1), + REG_NAME_ENTRY(MANUAL_PAD_ATTR_2), + REG_NAME_ENTRY(MANUAL_PAD_ATTR_3), }; +/* clang-format on */ #undef REG_NAME_ENTRY -struct OtSensorState { +struct OtSensorEgState { SysBusDevice parent_obj; MemoryRegion mmio; @@ -141,7 +196,7 @@ struct OtSensorState { uint32_t *regs; }; -static void ot_sensor_update_irqs(OtSensorState *s) +static void ot_sensor_eg_update_irqs(OtSensorEgState *s) { uint32_t levels = s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE]; @@ -151,7 +206,7 @@ static void ot_sensor_update_irqs(OtSensorState *s) } } -static void ot_sensor_update_alerts(OtSensorState *s) +static void ot_sensor_eg_update_alerts(OtSensorEgState *s) { uint32_t level = s->regs[R_ALERT_TEST]; @@ -160,9 +215,9 @@ static void ot_sensor_update_alerts(OtSensorState *s) } } -static uint64_t ot_sensor_regs_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t ot_sensor_eg_regs_read(void *opaque, hwaddr addr, unsigned size) { - OtSensorState *s = opaque; + OtSensorEgState *s = opaque; (void)size; uint32_t val32; @@ -173,9 +228,12 @@ static uint64_t ot_sensor_regs_read(void *opaque, hwaddr addr, unsigned size) case R_INTR_ENABLE: case R_CFG_REGWEN: case R_ALERT_TRIG: + case R_ALERT_EN_0 ... R_ALERT_EN_10: case R_FATAL_ALERT_EN: case R_RECOV_ALERT: case R_FATAL_ALERT: + case R_MANUAL_PAD_ATTR_REGWEN_0 ... R_MANUAL_PAD_ATTR_REGWEN_3: + case R_MANUAL_PAD_ATTR_0 ... R_MANUAL_PAD_ATTR_3: val32 = s->regs[reg]; break; case R_STATUS: @@ -205,10 +263,10 @@ static uint64_t ot_sensor_regs_read(void *opaque, hwaddr addr, unsigned size) return (uint64_t)val32; }; -static void ot_sensor_regs_write(void *opaque, hwaddr addr, uint64_t val64, - unsigned size) +static void ot_sensor_eg_regs_write(void *opaque, hwaddr addr, uint64_t val64, + unsigned size) { - OtSensorState *s = opaque; + OtSensorEgState *s = opaque; (void)size; uint32_t val32 = (uint32_t)val64; @@ -221,28 +279,72 @@ static void ot_sensor_regs_write(void *opaque, hwaddr addr, uint64_t val64, case R_INTR_STATE: val32 &= INTR_MASK; s->regs[R_INTR_STATE] &= ~val32; /* RW1C */ - ot_sensor_update_irqs(s); + ot_sensor_eg_update_irqs(s); break; case R_INTR_ENABLE: val32 &= INTR_MASK; s->regs[R_INTR_ENABLE] = val32; - ot_sensor_update_irqs(s); + ot_sensor_eg_update_irqs(s); break; case R_INTR_TEST: val32 &= INTR_MASK; s->regs[R_INTR_STATE] |= val32; - ot_sensor_update_irqs(s); + ot_sensor_eg_update_irqs(s); break; case R_ALERT_TEST: val32 &= ALERT_TEST_MASK; s->regs[reg] = val32; - ot_sensor_update_alerts(s); + ot_sensor_eg_update_alerts(s); + s->regs[reg] = 0u; + ot_sensor_eg_update_alerts(s); break; case R_CFG_REGWEN: + val32 &= R_CFG_REGWEN_EN_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; case R_ALERT_TRIG: + val32 &= ALERT_SENSOR_MASK; + s->regs[reg] = val32; + qemu_log_mask(LOG_UNIMP, + "Unimplemented register 0x%02" HWADDR_PRIx " (%s)\n", + addr, REG_NAME(reg)); + break; + case R_ALERT_EN_0 ... R_ALERT_EN_10: + if (!s->regs[R_CFG_REGWEN]) { + qemu_log_mask(LOG_GUEST_ERROR, + "Cannot change %s, CFG_REGWEN disabled", + REG_NAME(reg)); + break; + } + val32 &= ALERT_EN_VAL_MASK; + s->regs[reg] = val32; + qemu_log_mask(LOG_UNIMP, + "Unimplemented register 0x%02" HWADDR_PRIx " (%s)\n", + addr, REG_NAME(reg)); + break; case R_FATAL_ALERT_EN: + if (!s->regs[R_CFG_REGWEN]) { + qemu_log_mask(LOG_GUEST_ERROR, + "Cannot change %s, CFG_REGWEN disabled", + REG_NAME(reg)); + break; + } + val32 &= ALERT_SENSOR_MASK; + s->regs[reg] = val32; + qemu_log_mask(LOG_UNIMP, + "Unimplemented register 0x%02" HWADDR_PRIx " (%s)\n", + addr, REG_NAME(reg)); + break; case R_RECOV_ALERT: + val32 &= ALERT_SENSOR_MASK; + s->regs[reg] = val32; + qemu_log_mask(LOG_UNIMP, + "Unimplemented register 0x%02" HWADDR_PRIx " (%s)\n", + addr, REG_NAME(reg)); + break; case R_FATAL_ALERT: + val32 &= ALERT_SENSOR_MASK; + s->regs[reg] = val32; qemu_log_mask(LOG_UNIMP, "Unimplemented register 0x%02" HWADDR_PRIx " (%s)\n", addr, REG_NAME(reg)); @@ -252,6 +354,23 @@ static void ot_sensor_regs_write(void *opaque, hwaddr addr, uint64_t val64, "%s: R/O register 0x%02" HWADDR_PRIx " (%s)\n", __func__, addr, REG_NAME(reg)); break; + case R_MANUAL_PAD_ATTR_REGWEN_0 ... R_MANUAL_PAD_ATTR_REGWEN_3: + val32 &= MANUAL_PAD_ATTR_REGWEN_EN_MASK; + s->regs[reg] &= val32; /* RW0C */ + break; + case R_MANUAL_PAD_ATTR_0 ... R_MANUAL_PAD_ATTR_3: + if (!s->regs[reg - R_MANUAL_PAD_ATTR_0 + R_MANUAL_PAD_ATTR_REGWEN_0]) { + qemu_log_mask(LOG_GUEST_ERROR, "Cannot change %s, %s disabled", + REG_NAME(reg), + REG_NAME(reg - R_MANUAL_PAD_ATTR_0 + + R_MANUAL_PAD_ATTR_REGWEN_0)); + } + break; + val32 &= MANUAL_PAD_ATTR_MASK; + qemu_log_mask(LOG_UNIMP, + "Unimplemented register 0x%02" HWADDR_PRIx " (%s)\n", + addr, REG_NAME(reg)); + break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr); @@ -259,36 +378,43 @@ static void ot_sensor_regs_write(void *opaque, hwaddr addr, uint64_t val64, } }; -static Property ot_sensor_properties[] = { +static Property ot_sensor_eg_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static const MemoryRegionOps ot_sensor_regs_ops = { - .read = &ot_sensor_regs_read, - .write = &ot_sensor_regs_write, +static const MemoryRegionOps ot_sensor_eg_regs_ops = { + .read = &ot_sensor_eg_regs_read, + .write = &ot_sensor_eg_regs_write, .endianness = DEVICE_NATIVE_ENDIAN, .impl.min_access_size = 4u, .impl.max_access_size = 4u, }; -static void ot_sensor_reset(DeviceState *dev) +static void ot_sensor_eg_reset(DeviceState *dev) { - OtSensorState *s = OT_SENSOR(dev); + OtSensorEgState *s = OT_SENSOR_EG(dev); memset(s->regs, 0, REGS_SIZE); s->regs[R_CFG_REGWEN] = 0x1u; + for (unsigned rix = R_ALERT_EN_0; rix <= R_ALERT_EN_10; rix++) { + s->regs[rix] = 0x6u; + } + for (unsigned rix = R_MANUAL_PAD_ATTR_REGWEN_0; + rix <= R_MANUAL_PAD_ATTR_REGWEN_3; rix++) { + s->regs[rix] = 0x1u; + } - ot_sensor_update_irqs(s); - ot_sensor_update_alerts(s); + ot_sensor_eg_update_irqs(s); + ot_sensor_eg_update_alerts(s); } -static void ot_sensor_init(Object *obj) +static void ot_sensor_eg_init(Object *obj) { - OtSensorState *s = OT_SENSOR(obj); + OtSensorEgState *s = OT_SENSOR_EG(obj); - memory_region_init_io(&s->mmio, obj, &ot_sensor_regs_ops, s, TYPE_OT_SENSOR, - REGS_SIZE); + memory_region_init_io(&s->mmio, obj, &ot_sensor_eg_regs_ops, s, + TYPE_OT_SENSOR_EG, REGS_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); s->regs = g_new0(uint32_t, REGS_COUNT); @@ -300,27 +426,27 @@ static void ot_sensor_init(Object *obj) } } -static void ot_sensor_class_init(ObjectClass *klass, void *data) +static void ot_sensor_eg_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); (void)data; - device_class_set_legacy_reset(dc, &ot_sensor_reset); - device_class_set_props(dc, ot_sensor_properties); + device_class_set_legacy_reset(dc, &ot_sensor_eg_reset); + device_class_set_props(dc, ot_sensor_eg_properties); set_bit(DEVICE_CATEGORY_MISC, dc->categories); } -static const TypeInfo ot_sensor_info = { - .name = TYPE_OT_SENSOR, +static const TypeInfo ot_sensor_eg_info = { + .name = TYPE_OT_SENSOR_EG, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(OtSensorState), - .instance_init = &ot_sensor_init, - .class_init = &ot_sensor_class_init, + .instance_size = sizeof(OtSensorEgState), + .instance_init = &ot_sensor_eg_init, + .class_init = &ot_sensor_eg_class_init, }; -static void ot_sensor_register_types(void) +static void ot_sensor_eg_register_types(void) { - type_register_static(&ot_sensor_info); + type_register_static(&ot_sensor_eg_info); } -type_init(ot_sensor_register_types); +type_init(ot_sensor_eg_register_types); diff --git a/hw/opentitan/otbn/otbn/src/csrs.rs b/hw/opentitan/otbn/otbn/src/csrs.rs index 3c932f06a915a..8593e66d21ee4 100644 --- a/hw/opentitan/otbn/otbn/src/csrs.rs +++ b/hw/opentitan/otbn/otbn/src/csrs.rs @@ -16,7 +16,6 @@ use super::random; use super::{CSR, WSR}; use crate::{ExceptionCause, CSRNG, PRNG}; - #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[repr(u32)] #[allow(non_camel_case_types)] @@ -406,7 +405,7 @@ impl CSRSet { key_s0_h: CSRWideGeneric::default(), key_s1_l: CSRWideGeneric::default(), key_s1_h: CSRWideGeneric::default(), - shared_flags: SharedFlags::default() + shared_flags: SharedFlags::default(), }; csrs.fg0.plug(&csrs.shared_flags, FlagMode::Fg0); csrs.fg1.plug(&csrs.shared_flags, FlagMode::Fg1); diff --git a/hw/opentitan/otbn/otbn/src/otbn.rs b/hw/opentitan/otbn/otbn/src/otbn.rs index 914afd25cd65a..5eb383450d819 100644 --- a/hw/opentitan/otbn/otbn/src/otbn.rs +++ b/hw/opentitan/otbn/otbn/src/otbn.rs @@ -110,6 +110,7 @@ pub struct Executer { syncurnd: Arc, on_complete: Option>, log_file: Option>, + log_asm: bool, } impl Executer { @@ -123,6 +124,7 @@ impl Executer { rnd: Arc, on_complete: Option>, log_name: Option, + log_asm: bool, ) -> Self { let log_file: Option>; if let Some(logname) = log_name { @@ -143,6 +145,7 @@ impl Executer { syncurnd, on_complete, log_file, + log_asm, } } @@ -156,6 +159,7 @@ impl Executer { rnd: Arc, on_complete: Option>, log_name: Option, + log_asm: bool, ) { Self::new( channel, @@ -166,6 +170,7 @@ impl Executer { rnd, on_complete, log_name, + log_asm, ) .enter(); } @@ -316,32 +321,34 @@ impl Executer { loop { // Debug/traces - if let Some(log_file) = &mut self.log_file { - // Output current instruction disassembly to log - if let Some(insn_bits) = executor.imem.read_mem(executor.hart_state.pc) { - let mut outputter = insn_disasm::InstructionStringOutputter { - insn_pc: executor.hart_state.pc, - }; - if let Some(inst) = insn_decode::decoder(&mut outputter, insn_bits) { - writeln!( - log_file, - "{:04x}: {:08x} {}", - executor.hart_state.pc, insn_bits, inst - ) - .expect("Log file write failed"); + if self.log_asm { + if let Some(log_file) = &mut self.log_file { + // Output current instruction disassembly to log + if let Some(insn_bits) = executor.imem.read_mem(executor.hart_state.pc) { + let mut outputter = insn_disasm::InstructionStringOutputter { + insn_pc: executor.hart_state.pc, + }; + if let Some(inst) = insn_decode::decoder(&mut outputter, insn_bits) { + writeln!( + log_file, + "{:04x}: {:08x} {}", + executor.hart_state.pc, insn_bits, inst + ) + .expect("Log file write failed"); + } else { + let base = (insn_bits >> 2) & 0b11111; + let funct3 = (insn_bits >> 12) & 0b111; + writeln!( + log_file, + "Unable to decode instruction @ {:x}: {:x} [{:03b}..{:05b}]", + executor.hart_state.pc, insn_bits, funct3, base + ) + .expect("Log file write failed"); + } } else { - let base = (insn_bits >> 2) & 0b11111; - let funct3 = (insn_bits >> 12) & 0b111; - writeln!( - log_file, - "Unable to decode instruction @ {:x}: {:x} [{:03b}..{:05b}]", - executor.hart_state.pc, insn_bits, funct3, base - ) - .expect("Log file write failed"); + writeln!(log_file, "Could not read PC {:08x}", executor.hart_state.pc) + .expect("Log file write failed"); } - } else { - writeln!(log_file, "Could not read PC {:08x}", executor.hart_state.pc) - .expect("Log file write failed"); } } @@ -405,8 +412,10 @@ impl Executer { self.registers.insn_count.fetch_add(1, Ordering::Relaxed); - if let Some(log_file) = &mut self.log_file { - Executer::log_changes(executor.hart_state, log_file); + if self.log_asm { + if let Some(log_file) = &mut self.log_file { + Executer::log_changes(executor.hart_state, log_file); + } } } } diff --git a/hw/opentitan/otbn/otbn/src/proxy.rs b/hw/opentitan/otbn/otbn/src/proxy.rs index 3e27359e0d7c4..5789f39661f6c 100644 --- a/hw/opentitan/otbn/otbn/src/proxy.rs +++ b/hw/opentitan/otbn/otbn/src/proxy.rs @@ -97,8 +97,11 @@ impl Proxy { } /// Register a callback for requesting entropy from EDN - pub fn register_entropy_req_cb(&mut self, urnd_entropy_req: Box, - rnd_entropy_req: Box) { + pub fn register_entropy_req_cb( + &mut self, + urnd_entropy_req: Box, + rnd_entropy_req: Box, + ) { self.syncurnd.register_entropy_req_cb(urnd_entropy_req); self.rnd.register_entropy_req_cb(rnd_entropy_req); } @@ -109,7 +112,7 @@ impl Proxy { } /// Kick off the core executer, and create the communication channels - pub fn start(&mut self, test_mode: bool, log_name: Option<&str>) { + pub fn start(&mut self, test_mode: bool, log_name: Option<&str>, log_asm: bool) { if self.core_id.is_some() { // already started, only reset // hartstate is not reset, as it is done after each execution @@ -152,6 +155,7 @@ impl Proxy { rnd, on_complete, log_name, + log_asm, ) }) .unwrap(), @@ -382,13 +386,18 @@ impl comm::Callback for CCallback { #[no_mangle] pub extern "C" fn ot_otbn_proxy_new( - urnd_entropy_req: CCallbackFunc, urnd_opaque: CCallbackArg, - rnd_entropy_req: CCallbackFunc, rnd_opaque: CCallbackArg, - on_complete: CCallbackFunc, on_comp_opaque: CCallbackArg, + urnd_entropy_req: CCallbackFunc, + urnd_opaque: CCallbackArg, + rnd_entropy_req: CCallbackFunc, + rnd_opaque: CCallbackArg, + on_complete: CCallbackFunc, + on_comp_opaque: CCallbackArg, ) -> Box { let mut proxy = Box::new(Proxy::new()); - proxy.register_entropy_req_cb(Box::new(CCallback::new(urnd_entropy_req, urnd_opaque)), - Box::new(CCallback::new(rnd_entropy_req, rnd_opaque))); + proxy.register_entropy_req_cb( + Box::new(CCallback::new(urnd_entropy_req, urnd_opaque)), + Box::new(CCallback::new(rnd_entropy_req, rnd_opaque)), + ); proxy.register_signal_cb(Box::new(CCallback::new(on_complete, on_comp_opaque))); proxy } @@ -398,14 +407,15 @@ pub extern "C" fn ot_otbn_proxy_new( pub unsafe extern "C" fn ot_otbn_proxy_start( proxy: Option<&mut Proxy>, test_mode: bool, - logname: *const c_char, + log_name: *const c_char, + log_asm: bool, ) { - let log_name: Option<&str> = if !logname.is_null() { - Some(CStr::from_ptr(logname).to_str().unwrap()) + let log_name: Option<&str> = if !log_name.is_null() { + Some(CStr::from_ptr(log_name).to_str().unwrap()) } else { None }; - proxy.unwrap().start(test_mode, log_name); + proxy.unwrap().start(test_mode, log_name, log_asm); } #[no_mangle] diff --git a/hw/opentitan/otbn/otbn/src/random.rs b/hw/opentitan/otbn/otbn/src/random.rs index e506e7d519be3..71c290ae842c9 100644 --- a/hw/opentitan/otbn/otbn/src/random.rs +++ b/hw/opentitan/otbn/otbn/src/random.rs @@ -16,7 +16,7 @@ pub struct RndCache { value: u256, available: bool, fips: bool, - repeat: bool + repeat: bool, } pub struct Rnd { @@ -117,7 +117,6 @@ impl CSRNG for Rnd { } } - #[derive(Default)] pub struct Urnd { xoshiro: Xoshiro256PlusPlus, @@ -147,7 +146,6 @@ impl Urnd { } } - pub struct SyncUrnd { urnd: Arc>, sync: Mutex, @@ -213,4 +211,3 @@ impl SyncUrnd { self.wait.notify_one(); } } - diff --git a/hw/opentitan/trace-events b/hw/opentitan/trace-events index db083211d5ff3..f26e003119e1c 100644 --- a/hw/opentitan/trace-events +++ b/hw/opentitan/trace-events @@ -12,6 +12,7 @@ ot_aes_io_read_out(uint32_t addr, const char * regname, uint32_t val, uint32_t p ot_aes_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_aes_request_entropy(void) "" ot_aes_reseed(const char *reason) "%s" +ot_aes_reseed_rate(unsigned rate) "%u" ot_aes_schedule(void) "" # ot_alert.c @@ -62,34 +63,36 @@ ot_common_configure_device_uint(const char *objid, const char *key, uint64_t val ot_csrng_change_state(int line, const char *old, int nold, const char *new, int nnew) "@ %d [%s:%d] -> [%s:%d]" ot_csrng_command_scheduler(unsigned slot, const char *action) "#%u: %s" ot_csrng_complete_command(unsigned slot, const char *kind, const char *cmd, unsigned acmd, int res) "#%u (%s) acmd: %s(%u): %d" -ot_csrng_connection(unsigned slot) "#%u" +ot_csrng_connection(unsigned slot, bool newc) "#%u new:%u" ot_csrng_defer_generation(unsigned slot) "#%u instanciation not yet completed" +ot_csrng_disconnection(unsigned slot, bool explicit) "#%u explicit:%u" ot_csrng_end_of_gen(unsigned slot, unsigned rempack) "#%u rem %u" ot_csrng_entropy_injecter(unsigned slot, const char *action) "#%u: %s" ot_csrng_entropy_rejected(unsigned slot, const char *reason, int res) "#%u: %s (%d)" ot_csrng_error(const char *func, int line, const char *err) "%s:%d %s" -ot_csrng_expedite_uninstantiation(unsigned slot) "#%u" ot_csrng_fill_entropy(unsigned slot, bool fips) "#%u fips %u" ot_csrng_generate(unsigned slot, unsigned count) "#%u %u packets to generate" ot_csrng_hwapp_need_entropy(unsigned slot, const char *msg) "#%u: %s" ot_csrng_hwapp_ready(unsigned slot, bool ready, unsigned rem) "#%u: %u rem %u" ot_csrng_info(const char *func, int line, const char *msg, uint32_t value) "%s:%d %s: 0x%08x" -ot_csrng_instantiate(unsigned slot, bool on) "#%u: %u" +ot_csrng_instantiate(unsigned slot) "#%u" ot_csrng_invalid_state(const char *func, const char *state, int st) "%s [%s:%d]" ot_csrng_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_csrng_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_csrng_irqs(uint32_t active, uint32_t mask, uint32_t eff) "act:0x%08x msk:0x%08x eff:0x%08x" ot_csrng_push_command(unsigned slot, const char *cmd, unsigned acmd, char code, unsigned len) "#%u: %s(%u) %clen: %u" ot_csrng_read_state_db(unsigned slot, unsigned pos, uint32_t val) "#%u [%u] = 0x%08x" -ot_csrng_request_entropy(unsigned slot, int gen) "#%u gen %d" -ot_csrng_retry_es_init(unsigned retry_count) "rescheduling initial ES request: %u to go" +ot_csrng_reject_command(unsigned slot, uint32_t command, int res) "#%u: cmd: 0x%08x res: %d" +ot_csrng_request_entropy(unsigned slot) "#%u" ot_csrng_reset(void) "" +ot_csrng_retry_es_init(unsigned retry_count) "rescheduling initial ES request: %u to go" ot_csrng_schedule(unsigned slot, const char *kind) "#%u: %s" ot_csrng_scheduling_command(unsigned slot) "#%u" ot_csrng_show_buffer(const char *func, int line, unsigned appid, const char *msg, const char *hexstr) "%s:%u #%u %s: %s" ot_csrng_show_command(const char *msg, unsigned slot, const char *cmd, unsigned acmd) "%s slot #%u, acmd: %s(%u)" ot_csrng_swapp_fill(unsigned count) "%u to go" ot_csrng_try_schedule_genbits(unsigned slot, bool ready, bool queued, unsigned rem) "? #%u rdy:%u q:%u rem:%u" +ot_csrng_uninstantiate(unsigned slot, bool explicit) "#%u explicit:%u" # ot_dev_proxy.c @@ -131,10 +134,13 @@ ot_dma_transfer(const char *id, const char *dir, const char *asname, uint64_t ad # ot_edn.c +ot_edn_auto_dispatch(unsigned appid, bool auto_, unsigned max_reqs_cnt) "a#%u auto:%u max_reqs_cnt:%u" +ot_edn_clean_up(unsigned appid, bool discard) "a#%u discard:%u" ot_edn_change_state(unsigned appid, int line, const char *old, int nold, const char *new, int nnew) "a#%u @ %d [%s:%d] -> [%s:%d]" ot_edn_connect_endpoint(unsigned appid, unsigned epid) "a#%u:e#%u" ot_edn_csrng_ack(unsigned appid, const char *state, int level) "a#%u %s %d" -ot_edn_ctrl_in_state(unsigned appid, const char *state, int nstate) "a#%u [%s:%d]" +ot_edn_ctrl_in_state(unsigned appid, const char *state, int nstate, bool en, bool boot, bool auto_, bool clr, bool dis) "a#%u [%s:%d] en:%u boot:%u auto:%u clr:%u dis:%u" +ot_edn_delay_mode_change(unsigned appid, const char *state, uint32_t ctrl) "a#%u %s ctrl:0x%08x" ot_edn_dinfo(unsigned appid, const char *func, int line, const char *msg, uint32_t value) "a#%u %s:%d %s %u" ot_edn_enable(unsigned appid, const char *msg) "a#%u: %s" ot_edn_ep_fifo(unsigned appid, const char *msg, unsigned remwslot) "a#%u %s rem:%u" @@ -146,9 +152,12 @@ ot_edn_handle_ep_request(unsigned appid, unsigned epid) "a#%u:e#%u" ot_edn_invalid_state(unsigned appid, const char *func, const char *state, int st) "a#%u %s [%s:%d]" ot_edn_io_read_out(unsigned appid, uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "a#%u addr=0x%02x (%s), val=0x%x, pc=0x%x" ot_edn_io_write(unsigned appid, uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "a#%u addr=0x%02x (%s), val=0x%x, pc=0x%x" -ot_edn_irqs(unsigned appid, uint32_t active, uint32_t mask, uint32_t eff) "#%u act:0x%08x msk:0x%08x eff:0x%08x" +ot_edn_irqs(unsigned appid, uint32_t active, uint32_t mask, uint32_t eff) "a#%u act:0x%08x msk:0x%08x eff:0x%08x" +ot_edn_push_csrng_command(unsigned appid, const char *mode, uint32_t value) "a#%u (%s) cmd:0x%08x" +ot_edn_push_csrng_error(unsigned appid, int res) "a#%u res:%d" ot_edn_request_entropy(unsigned appid, unsigned epid) "a#%u:e#%u" -ot_edn_reset(unsigned appid) "a#%u" +ot_edn_reset(unsigned appid, const char *phase) "a#%u %s" +ot_edn_reset_replay_fifos(unsigned appid) "a#%u" ot_edn_schedule(unsigned appid, const char *cause) "a#%u %s" ot_edn_update_genbits_ready(unsigned appid, unsigned rem, unsigned fslot, bool accept) "a#%u rem packet %u, free slot %u, accept? %u" ot_edn_xinfo(unsigned appid, const char *func, int line, const char *msg, uint32_t value) "a#%u %s:%d %s 0x%08x" @@ -160,18 +169,17 @@ ot_entropy_src_change_state(int line, const char *old, int nold, const char *new 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_is_fips_capable(bool en, bool es_route, bool es_type, bool rng_bit_en, bool res) "en:%u rt:%u tp:%u !rb:%u => %u" 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_update_generation(unsigned gennum) "%u" # ot_flash.c @@ -246,7 +254,7 @@ ot_ibex_wrapper_io_read_out(const char *id, uint32_t addr, const char * regname, ot_ibex_wrapper_io_write(const char *id, uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%08x, pc=0x%x" ot_ibex_wrapper_map(const char *id, unsigned slot, uint32_t src, uint32_t dst, uint32_t size, const char *name, uint32_t offset) "%s: region %u from 0x%08x to 0x%08x on 0x%x bytes (%s), off 0x%x" ot_ibex_wrapper_request_entropy(const char *id, bool again) "%s: %u" -ot_ibex_wrapper_reset(const char *id) "%s" +ot_ibex_wrapper_reset(const char *id, const char *phase) "%s: %s" ot_ibex_wrapper_unmap(const char *id, unsigned slot) "%s: region %u" ot_ibex_wrapper_update_exec(const char *id, uint32_t bm, bool esc_rx, bool cpu_en) "%s: 0x%x %u-> CPU enable %u" diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index dc815d82f6648..8d369e6298305 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -46,7 +46,6 @@ config OT_DARJEELING select OT_PWRMGR select OT_RSTMGR select OT_ROM_CTRL - select OT_SENSOR select OT_SOC_PROXY select OT_SPI_DEVICE select OT_SPI_HOST @@ -87,7 +86,7 @@ config OT_EARLGREY select OT_PWRMGR select OT_ROM_CTRL select OT_RSTMGR - select OT_SENSOR + select OT_SENSOR_EG select OT_SPI_DEVICE select OT_SPI_HOST select OT_SRAM_CTRL diff --git a/hw/riscv/ot_darjeeling.c b/hw/riscv/ot_darjeeling.c index db373bc7b0107..d8f99216c21e9 100644 --- a/hw/riscv/ot_darjeeling.c +++ b/hw/riscv/ot_darjeeling.c @@ -62,7 +62,6 @@ #include "hw/opentitan/ot_pwrmgr.h" #include "hw/opentitan/ot_rom_ctrl.h" #include "hw/opentitan/ot_rstmgr.h" -#include "hw/opentitan/ot_sensor.h" #include "hw/opentitan/ot_soc_proxy.h" #include "hw/opentitan/ot_spi_device.h" #include "hw/opentitan/ot_spi_host.h" @@ -1032,16 +1031,6 @@ static const IbexDeviceDef ot_dj_soc_devices[] = { IBEX_DEV_UINT_PROP("pclk", OT_DJ_PERIPHERAL_CLK_HZ) ), }, - [OT_DJ_SOC_DEV_SENSOR_CTRL] = { - .type = TYPE_OT_SENSOR, - .memmap = MEMMAPENTRIES( - { .base = 0x30020000u } - ), - .gpio = IBEXGPIOCONNDEFS( - OT_DJ_SOC_GPIO_SYSBUS_IRQ(0, PLIC, 81), - OT_DJ_SOC_GPIO_SYSBUS_IRQ(1, PLIC, 82) - ) - }, [OT_DJ_SOC_DEV_I2C0] = { .type = TYPE_OT_I2C_DJ, .memmap = MEMMAPENTRIES( diff --git a/hw/riscv/ot_earlgrey.c b/hw/riscv/ot_earlgrey.c index a9035944bda5d..8faba62f75422 100644 --- a/hw/riscv/ot_earlgrey.c +++ b/hw/riscv/ot_earlgrey.c @@ -25,6 +25,8 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qemu/typedefs.h" #include "qapi/error.h" #include "qapi/qmp/qlist.h" #include "qom/object.h" @@ -35,7 +37,6 @@ #include "hw/jtag/tap_ctrl.h" #include "hw/jtag/tap_ctrl_rbb.h" #include "hw/misc/pulp_rv_dm.h" -#include "hw/misc/unimp.h" #include "hw/opentitan/ot_aes.h" #include "hw/opentitan/ot_alert.h" #include "hw/opentitan/ot_aon_timer.h" @@ -59,7 +60,7 @@ #include "hw/opentitan/ot_pwrmgr.h" #include "hw/opentitan/ot_rom_ctrl.h" #include "hw/opentitan/ot_rstmgr.h" -#include "hw/opentitan/ot_sensor.h" +#include "hw/opentitan/ot_sensor_eg.h" #include "hw/opentitan/ot_spi_device.h" #include "hw/opentitan/ot_spi_host.h" #include "hw/opentitan/ot_sram_ctrl.h" @@ -183,10 +184,16 @@ enum OtEGBoardDevice { #define OT_EG_CORE_CLK_HZ 24000000u /* EarlGrey/CW310 Peripheral clock is 6 MHz */ #define OT_EG_PERIPHERAL_CLK_HZ ((OT_EG_CORE_CLK_HZ) / 4u) - /* EarlGrey/CW310 AON clock is 250 kHz */ #define OT_EG_AON_CLK_HZ 250000u +/* Verilator Core clock is 500 kHz */ +#define OT_EG_VERILATOR_CORE_CLK_HZ 500000u +/* Verilator Peripheral clock is 125 kHz */ +#define OT_EG_VERILATOR_PERIPHERAL_CLK_HZ ((OT_EG_VERILATOR_CORE_CLK_HZ) / 4u) +/* Verilator AON clock is 125 kHz */ +#define OT_EG_VERILATOR_AON_CLK_HZ OT_EG_VERILATOR_PERIPHERAL_CLK_HZ + static const uint8_t ot_eg_pmp_cfgs[] = { /* clang-format off */ IBEX_PMP_CFG(0, IBEX_PMP_MODE_OFF, 0, 0, 0), @@ -524,7 +531,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { IBEX_DEV_STRING_PROP("ot_id", "i2c0"), IBEX_DEV_UINT_PROP("size", 0x80u), IBEX_DEV_UINT_PROP("irq-count", 15u), - IBEX_DEV_UINT_PROP("alert-count", 1u) + IBEX_DEV_UINT_PROP("alert-count", 1u), + IBEX_DEV_BOOL_PROP("warn-once", true) ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_ALERT(0, 6) @@ -540,7 +548,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { IBEX_DEV_STRING_PROP("ot_id", "i2c1"), IBEX_DEV_UINT_PROP("size", 0x80u), IBEX_DEV_UINT_PROP("irq-count", 15u), - IBEX_DEV_UINT_PROP("alert-count", 1u) + IBEX_DEV_UINT_PROP("alert-count", 1u), + IBEX_DEV_BOOL_PROP("warn-once", true) ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_ALERT(0, 7) @@ -556,7 +565,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { IBEX_DEV_STRING_PROP("ot_id", "i2c2"), IBEX_DEV_UINT_PROP("size", 0x80u), IBEX_DEV_UINT_PROP("irq-count", 15u), - IBEX_DEV_UINT_PROP("alert-count", 1u) + IBEX_DEV_UINT_PROP("alert-count", 1u), + IBEX_DEV_BOOL_PROP("warn-once", true) ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_ALERT(0, 8) @@ -572,7 +582,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { IBEX_DEV_STRING_PROP("ot_id", "pattgen"), IBEX_DEV_UINT_PROP("size", 0x40u), IBEX_DEV_UINT_PROP("irq-count", 2u), - IBEX_DEV_UINT_PROP("alert-count", 1u) + IBEX_DEV_UINT_PROP("alert-count", 1u), + IBEX_DEV_BOOL_PROP("warn-once", true) ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_ALERT(0, 9) @@ -639,9 +650,6 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { OT_EG_SOC_DEVLINK("otp_ctrl", OTP_CTRL), OT_EG_SOC_DEVLINK("kmac", KMAC) ), - .prop = IBEXDEVICEPROPDEFS( - IBEX_DEV_UINT_PROP("edn-ep", 4u) - ), .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_UINT_PROP("silicon_creator_id", 0x4001u), IBEX_DEV_UINT_PROP("product_id", 0x0002u), @@ -732,7 +740,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { IBEX_DEV_STRING_PROP("ot_id", "usbdev"), IBEX_DEV_UINT_PROP("size", 0x1000u), IBEX_DEV_UINT_PROP("irq-count", 18u), - IBEX_DEV_UINT_PROP("alert-count", 1u) + IBEX_DEV_UINT_PROP("alert-count", 1u), + IBEX_DEV_BOOL_PROP("warn-once", true) ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_ALERT(0, 21) @@ -793,7 +802,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { IBEX_DEV_STRING_PROP("ot_id", "sysrst_ctrl"), IBEX_DEV_UINT_PROP("size", 0x100u), IBEX_DEV_UINT_PROP("irq-count", 1u), - IBEX_DEV_UINT_PROP("alert-count", 1u) + IBEX_DEV_UINT_PROP("alert-count", 1u), + IBEX_DEV_BOOL_PROP("warn-once", true) ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_ALERT(0, 27) @@ -809,7 +819,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { IBEX_DEV_STRING_PROP("ot_id", "adc_ctrl"), IBEX_DEV_UINT_PROP("size", 0x80u), IBEX_DEV_UINT_PROP("irq-count", 1u), - IBEX_DEV_UINT_PROP("alert-count", 1u) + IBEX_DEV_UINT_PROP("alert-count", 1u), + IBEX_DEV_BOOL_PROP("warn-once", true) ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_ALERT(0, 28) @@ -824,7 +835,8 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { .prop = IBEXDEVICEPROPDEFS( IBEX_DEV_STRING_PROP("ot_id", "pwm"), IBEX_DEV_UINT_PROP("size", 0x80u), - IBEX_DEV_UINT_PROP("alert-count", 1u) + IBEX_DEV_UINT_PROP("alert-count", 1u), + IBEX_DEV_BOOL_PROP("warn-once", true) ), .gpio = IBEXGPIOCONNDEFS( OT_EG_SOC_GPIO_ALERT(0, 29) @@ -864,7 +876,7 @@ static const IbexDeviceDef ot_eg_soc_devices[] = { ), }, [OT_EG_SOC_DEV_SENSOR_CTRL] = { - .type = TYPE_OT_SENSOR, + .type = TYPE_OT_SENSOR_EG, .memmap = MEMMAPENTRIES( { .base = 0x40490000u } ), @@ -1212,6 +1224,7 @@ struct OtEGMachineState { bool no_epmp_cfg; bool ignore_elf_entry; + bool verilator; }; struct OtEGMachineClass { @@ -1392,6 +1405,59 @@ static void ot_eg_soc_reset_exit(Object *obj, ResetType type) resettable_release_reset(OBJECT(s->devices[OT_EG_SOC_DEV_ROM_CTRL]), type); } +static void +ot_earlgrey_update_device_clocks(DeviceState **devices, size_t count) +{ + for (unsigned ix = 0; ix < (unsigned)count; ix++) { + DeviceState *dev = devices[ix]; + if (!dev) { + continue; + } + Error *errp = NULL; + uint64_t pclk = object_property_get_uint(OBJECT(dev), "pclk", &errp); + if (errp) { + error_free(errp); + continue; + } + switch (pclk) { + case 0: + /* PCLK property exists, but is not used, skip it */ + continue; + case OT_EG_CORE_CLK_HZ: + pclk = OT_EG_VERILATOR_CORE_CLK_HZ; + break; + case OT_EG_PERIPHERAL_CLK_HZ: + pclk = OT_EG_VERILATOR_PERIPHERAL_CLK_HZ; + break; + case OT_EG_AON_CLK_HZ: + pclk = OT_EG_VERILATOR_AON_CLK_HZ; + break; + default: + warn_report("%s: OT device %s has invalid pclk value: %" PRIu64, + __func__, object_get_typename(OBJECT(dev)), pclk); + continue; + } + + if (!object_property_set_uint(OBJECT(dev), "pclk", pclk, &errp)) { + error_propagate(&error_fatal, errp); + g_assert_not_reached(); + } + } +} + +static void +ot_earlgrey_configure_verilator_devices(DeviceState **devices, BusState *bus, + const IbexDeviceDef *defs, size_t count) +{ + ibex_link_devices(devices, defs, count); + ibex_define_device_props(devices, defs, count); + ibex_identify_devices(devices, OT_COMMON_DEV_ID, "soc", false, count); + ot_common_configure_device_opts(devices, count); + ot_earlgrey_update_device_clocks(devices, count); + ibex_realize_devices(devices, bus, defs, count); + ibex_connect_devices(devices, defs, count); +} + static void ot_eg_soc_realize(DeviceState *dev, Error **errp) { OtEGSoCState *s = RISCV_OT_EG_SOC(dev); @@ -1399,9 +1465,19 @@ static void ot_eg_soc_realize(DeviceState *dev, Error **errp) /* Link, define properties and realize devices, then connect GPIOs */ BusState *bus = sysbus_get_default(); - ot_common_configure_devices_with_id(s->devices, bus, "soc", false, - ot_eg_soc_devices, - ARRAY_SIZE(ot_eg_soc_devices)); + bool verilator_mode; + + verilator_mode = + object_property_get_bool(qdev_get_machine(), "verilator", NULL); + if (!verilator_mode) { + ot_common_configure_devices_with_id(s->devices, bus, "soc", false, + ot_eg_soc_devices, + ARRAY_SIZE(ot_eg_soc_devices)); + } else { + ot_earlgrey_configure_verilator_devices(s->devices, bus, + ot_eg_soc_devices, + ARRAY_SIZE(ot_eg_soc_devices)); + } MemoryRegion *mrs[] = { get_system_memory(), NULL, NULL, NULL }; ibex_map_devices(s->devices, mrs, ot_eg_soc_devices, @@ -1619,6 +1695,22 @@ ot_eg_machine_set_ignore_elf_entry(Object *obj, bool value, Error **errp) s->ignore_elf_entry = value; } +static bool ot_eg_machine_get_verilator(Object *obj, Error **errp) +{ + OtEGMachineState *s = RISCV_OT_EG_MACHINE(obj); + (void)errp; + + return s->verilator; +} + +static void ot_eg_machine_set_verilator(Object *obj, bool value, Error **errp) +{ + OtEGMachineState *s = RISCV_OT_EG_MACHINE(obj); + (void)errp; + + s->verilator = value; +} + static ResettableState *ot_eg_get_reset_state(Object *obj) { OtEGMachineState *s = RISCV_OT_EG_MACHINE(obj); @@ -1664,6 +1756,9 @@ static void ot_eg_machine_instance_init(Object *obj) &ot_eg_machine_set_ignore_elf_entry); object_property_set_description(obj, "ignore-elf-entry", "Do not set vCPU PC with ELF entry point"); + object_property_add_bool(obj, "verilator", &ot_eg_machine_get_verilator, + &ot_eg_machine_set_verilator); + object_property_set_description(obj, "verilator", "Use Verilator clocks"); } static void ot_eg_machine_init(MachineState *state) diff --git a/include/hw/opentitan/ot_common.h b/include/hw/opentitan/ot_common.h index a339db3be4547..0961088bafdc7 100644 --- a/include/hw/opentitan/ot_common.h +++ b/include/hw/opentitan/ot_common.h @@ -323,4 +323,31 @@ void ot_common_configure_devices_with_id( DeviceState **devices, BusState *bus, const char *id_value, bool id_prepend, const IbexDeviceDef *defs, size_t count); +void ot_common_configure_device_opts(DeviceState **devices, unsigned count); + +/* ------------------------------------------------------------------------ */ +/* OBJECT macros */ +/* ------------------------------------------------------------------------ */ + +/* + * OBJECT_DEFINE_TYPE_EXTENDED with explicit class name + */ +#define OT_OBJECT_DEFINE_TYPE_EXTENDED(ModuleObjName, ModuleClassName, \ + module_obj_name, MODULE_OBJ_NAME, \ + PARENT_MODULE_OBJ_NAME, ABSTRACT, ...) \ + DO_OBJECT_DEFINE_TYPE_EXTENDED(ModuleObjName, module_obj_name, \ + MODULE_OBJ_NAME, PARENT_MODULE_OBJ_NAME, \ + ABSTRACT, sizeof(ModuleClassName), \ + __VA_ARGS__) + +/* + * OBJECT_DEFINE_ABSTRACT_TYPE with explicit class name + */ +#define OT_OBJECT_DEFINE_ABSTRACT_TYPE(ModuleObjName, ModuleClassName, \ + module_obj_name, MODULE_OBJ_NAME, \ + PARENT_MODULE_OBJ_NAME) \ + OT_OBJECT_DEFINE_TYPE_EXTENDED(ModuleObjName, ModuleClassName, \ + module_obj_name, MODULE_OBJ_NAME, \ + PARENT_MODULE_OBJ_NAME, true, { NULL }) + #endif /* HW_OPENTITAN_OT_COMMON_H */ diff --git a/include/hw/opentitan/ot_csrng.h b/include/hw/opentitan/ot_csrng.h index c6f437bc5a6a6..5e609f773f466 100644 --- a/include/hw/opentitan/ot_csrng.h +++ b/include/hw/opentitan/ot_csrng.h @@ -2,6 +2,7 @@ * QEMU OpenTitan Cryptographically Secure Random Number Generator * * Copyright (c) 2023-2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -54,7 +55,16 @@ typedef enum { OT_CSRNG_CMD_GENERATE = 3, OT_CSRNG_CMD_UPDATE = 4, OT_CSRNG_CMD_UNINSTANTIATE = 5, -} OtCsrngCmd; +} OtCSRNGCmd; + +typedef enum { + CSRNG_STATUS_SUCCESS, + CSRNG_STATUS_INVALID_ACMD, + CSRNG_STATUS_INVALID_GEN_CMD, + CSRNG_STATUS_INVALID_CMD_SEQ, + CSRNG_STATUS_RESEED_CNT_EXCEEDED, + CSRNG_STATUS_COUNT, +} OtCSRNGCmdStatus; /* clang-format off */ REG32(OT_CSNRG_CMD, 0) @@ -80,22 +90,24 @@ typedef void (*ot_csrng_genbit_filler_fn)(void *opaque, const uint32_t *bits, bool fips); /** - * Connect a HW application to the CSRNG device. + * Connect or disconnect a HW application to the CSRNG device. * * @s the CSRNG device * @app_id the HW application unique identifier * @req_sts the IRQ to signal once a command is completed. The IRQ level signal * the completion status of the command: 0 indicates a sucessful - * completion, non-zero a failed one. - * @fn the filler function to call with one or more entropy packet, when a - * generate command is called. - * @opaque a opaque pointer to forward to the filler function + * completion, non-zero a failed one. Ignored if filler_fn is NULL. + * @filler_fn the filler function to call with one or more entropy packet, when + * a generate command is called. If filler_fn is NULL, the HW + * application is disconnected. + * @opaque a opaque pointer to forward to the filler_fn function * @return an IRQ line that signals whether the HW application is ready to * receive entropy, i.e. genbits_ready */ -qemu_irq ot_csnrg_connect_hw_app(OtCSRNGState *s, unsigned app_id, - qemu_irq req_sts, ot_csrng_genbit_filler_fn fn, - void *opaque); +qemu_irq +ot_csnrg_connect_hw_app(OtCSRNGState *s, unsigned app_id, qemu_irq req_sts, + ot_csrng_genbit_filler_fn filler_fn, void *opaque); + /** * Request a generated entropy block. @@ -116,11 +128,11 @@ int ot_csrng_request_entropy(OtCSRNGState *s, unsigned app_id); * @s the CSRNG device * @app_id the HW application unique identifier, as provided with the connect * command - * @command the command to execute (with any payload) - * @return 0 on success, -1 otherwise. If non-zero, the req_sts is not + * @word a command or payload chunk + * @return CSRNG_STATUS_SUCCESS on success. If failure, the req_sts is not * signalled for this command. */ -int ot_csrng_push_command(OtCSRNGState *s, unsigned app_id, - const uint32_t *command); +OtCSRNGCmdStatus ot_csrng_push_command(OtCSRNGState *s, unsigned app_id, + uint32_t word); #endif /* HW_OPENTITAN_OT_CSRNG_H */ diff --git a/include/hw/opentitan/ot_edn.h b/include/hw/opentitan/ot_edn.h index 7027efd4ff2a0..679ca01ca993c 100644 --- a/include/hw/opentitan/ot_edn.h +++ b/include/hw/opentitan/ot_edn.h @@ -2,6 +2,7 @@ * QEMU OpenTitan Entropy Distribution Network device * * Copyright (c) 2023-2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -31,7 +32,7 @@ #include "qom/object.h" #define TYPE_OT_EDN "ot-edn" -OBJECT_DECLARE_SIMPLE_TYPE(OtEDNState, OT_EDN) +OBJECT_DECLARE_TYPE(OtEDNState, OtEDNClass, OT_EDN) /* * Function called by the EDN instance whenever entropy has been requested diff --git a/include/hw/opentitan/ot_fifo32.h b/include/hw/opentitan/ot_fifo32.h index 18eb3705b39ef..f0f961715376a 100644 --- a/include/hw/opentitan/ot_fifo32.h +++ b/include/hw/opentitan/ot_fifo32.h @@ -62,7 +62,7 @@ static inline uint32_t ot_fifo32_pop(OtFifo32 *fifo) return ret; } -static inline uint32_t ot_fifo32_peek(OtFifo32 *fifo) +static inline uint32_t ot_fifo32_peek(const OtFifo32 *fifo) { g_assert(fifo->num > 0); @@ -86,7 +86,7 @@ ot_fifo32_pop_buf(OtFifo32 *fifo, uint32_t max, uint32_t *num) } static inline const uint32_t * -ot_fifo32_peek_buf(OtFifo32 *fifo, uint32_t max, uint32_t *num) +ot_fifo32_peek_buf(const OtFifo32 *fifo, uint32_t max, uint32_t *num) { uint32_t *ret; @@ -110,22 +110,22 @@ static inline void ot_fifo32_reset(OtFifo32 *fifo) fifo->head = 0u; } -static inline bool ot_fifo32_is_empty(OtFifo32 *fifo) +static inline bool ot_fifo32_is_empty(const OtFifo32 *fifo) { return (fifo->num == 0u); } -static inline bool ot_fifo32_is_full(OtFifo32 *fifo) +static inline bool ot_fifo32_is_full(const OtFifo32 *fifo) { return (fifo->num == fifo->capacity); } -static inline uint32_t ot_fifo32_num_free(OtFifo32 *fifo) +static inline uint32_t ot_fifo32_num_free(const OtFifo32 *fifo) { return fifo->capacity - fifo->num; } -static inline uint32_t ot_fifo32_num_used(OtFifo32 *fifo) +static inline uint32_t ot_fifo32_num_used(const OtFifo32 *fifo) { return fifo->num; } diff --git a/include/hw/opentitan/ot_ibex_wrapper.h b/include/hw/opentitan/ot_ibex_wrapper.h index baf862448d6d4..aa4c5a4f187b6 100644 --- a/include/hw/opentitan/ot_ibex_wrapper.h +++ b/include/hw/opentitan/ot_ibex_wrapper.h @@ -2,6 +2,7 @@ * QEMU OpenTitan Ibex Wrapper device * * Copyright (c) 2022-2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -30,18 +31,19 @@ #define HW_OPENTITAN_OT_IBEX_WRAPPER_H #include "qom/object.h" +#include "hw/resettable.h" #include "hw/sysbus.h" #define TYPE_OT_IBEX_WRAPPER "ot-ibex_wrapper" -OBJECT_DECLARE_TYPE(OtIbexWrapperState, OtIbexWrapperStateClass, - OT_IBEX_WRAPPER) +OBJECT_DECLARE_TYPE(OtIbexWrapperState, OtIbexWrapperClass, OT_IBEX_WRAPPER) struct OtIbexWrapperState { SysBusDevice parent_obj; }; -struct OtIbexWrapperStateClass { +struct OtIbexWrapperClass { SysBusDeviceClass parent_class; + ResettablePhases parent_phases; }; #define OT_IBEX_WRAPPER_CPU_EN TYPE_OT_IBEX_WRAPPER "-cpu-en" diff --git a/include/hw/opentitan/ot_ibex_wrapper_dj.h b/include/hw/opentitan/ot_ibex_wrapper_dj.h index 76069c1468730..8544e52eb6cb3 100644 --- a/include/hw/opentitan/ot_ibex_wrapper_dj.h +++ b/include/hw/opentitan/ot_ibex_wrapper_dj.h @@ -2,6 +2,7 @@ * QEMU OpenTitan Darjeeling Ibex Wrapper device * * Copyright (c) 2022-2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -32,7 +33,7 @@ #include "hw/opentitan/ot_ibex_wrapper.h" #define TYPE_OT_IBEX_WRAPPER_DJ "ot-ibex_wrapper-dj" -OBJECT_DECLARE_TYPE(OtIbexWrapperDjState, OtIbexWrapperStateClass, +OBJECT_DECLARE_TYPE(OtIbexWrapperDjState, OtIbexWrapperClass, OT_IBEX_WRAPPER_DJ) #endif /* HW_OPENTITAN_OT_IBEX_WRAPPER_DJ_H */ diff --git a/include/hw/opentitan/ot_ibex_wrapper_eg.h b/include/hw/opentitan/ot_ibex_wrapper_eg.h index 9bc3c03ee0762..b65179d2badae 100644 --- a/include/hw/opentitan/ot_ibex_wrapper_eg.h +++ b/include/hw/opentitan/ot_ibex_wrapper_eg.h @@ -2,6 +2,7 @@ * QEMU OpenTitan EarlGrey Ibex Wrapper device * * Copyright (c) 2022-2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. * * Author(s): * Emmanuel Blot @@ -33,7 +34,7 @@ #include "hw/opentitan/ot_ibex_wrapper.h" #define TYPE_OT_IBEX_WRAPPER_EG "ot-ibex_wrapper-eg" -OBJECT_DECLARE_TYPE(OtIbexWrapperEgState, OtIbexWrapperStateClass, +OBJECT_DECLARE_TYPE(OtIbexWrapperEgState, OtIbexWrapperClass, OT_IBEX_WRAPPER_EG) #endif /* HW_OPENTITAN_OT_IBEX_WRAPPER_EG_H */ diff --git a/include/hw/opentitan/ot_random_src.h b/include/hw/opentitan/ot_random_src.h index a7ceee1608eaa..606ef74091dea 100644 --- a/include/hw/opentitan/ot_random_src.h +++ b/include/hw/opentitan/ot_random_src.h @@ -1,7 +1,9 @@ /* * QEMU OpenTitan Random Source interface * - * Copyright (c) 2023 Rivos, Inc. + * Copyright (c) 2023-2024 Rivos, Inc. + * Copyright (c) 2025 lowRISC contributors. + * * * Author(s): * Emmanuel Blot @@ -48,39 +50,20 @@ typedef struct OtRandomSrcIf OtRandomSrcIf; struct OtRandomSrcIfClass { InterfaceClass parent_class; - /* - * Tell whether the random source is available, i.e. whether the random - * source module has been enabled. - * - * @dev the random source instance - * @return 0 if the random_src is disabled, otherwise: - * * a positive, monotonic increase generation number which indicates the - * number of time the random_src has been cycled (enabled from a - * disable state). This generation identifier should be passed on any - * subsequent #get_random_values request, or - * * a negative number, which indicates that the random source is enabled, - * but the generation number should be simply ignored. - */ - int (*get_random_generation)(OtRandomSrcIf *dev); - /* * Fill up a buffer with random values * * @dev the random source instance - * @genid the generation identifier, from #get_random_generation * @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, - * >=1 if the source is initializing, if >1, indicates the hint on - * how many ns to wait before retrying, + * >=1 if the random source is still initializing or not enough + * entropy is available to fill the output buffer; + * if >1, indicates a hint on how many ns to wait before retrying, * -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, - * -2 if the generation ID does not match and execution cannot - * process any further, 1 if the random source is still - * initializing or not enough entropy is available to fill the - * output buffer. */ - int (*get_random_values)(OtRandomSrcIf *dev, int genid, + int (*get_random_values)(OtRandomSrcIf *dev, uint64_t random[OT_RANDOM_SRC_DWORD_COUNT], bool *fips); }; diff --git a/include/hw/opentitan/ot_sensor.h b/include/hw/opentitan/ot_sensor_eg.h similarity index 79% rename from include/hw/opentitan/ot_sensor.h rename to include/hw/opentitan/ot_sensor_eg.h index b8bd230868f95..b57895c0ecb90 100644 --- a/include/hw/opentitan/ot_sensor.h +++ b/include/hw/opentitan/ot_sensor_eg.h @@ -1,7 +1,7 @@ /* - * QEMU OpenTitan Sensor controller device + * QEMU OpenTitan Sensor controller device for EarlGrey * - * Copyright (c) 2023 Rivos, Inc. + * Copyright (c) 2023-2025 Rivos, Inc. * * Author(s): * Emmanuel Blot @@ -25,12 +25,12 @@ * THE SOFTWARE. */ -#ifndef HW_OPENTITAN_OT_SENSOR_H -#define HW_OPENTITAN_OT_SENSOR_H +#ifndef HW_OPENTITAN_OT_SENSOR_EG_H +#define HW_OPENTITAN_OT_SENSOR_EG_H #include "qom/object.h" -#define TYPE_OT_SENSOR "ot-sensor" -OBJECT_DECLARE_SIMPLE_TYPE(OtSensorState, OT_SENSOR) +#define TYPE_OT_SENSOR_EG "ot-sensor-eg" +OBJECT_DECLARE_SIMPLE_TYPE(OtSensorEgState, OT_SENSOR_EG) -#endif /* HW_OPENTITAN_OT_SENSOR_H */ +#endif /* HW_OPENTITAN_OT_SENSOR_EG_H */ diff --git a/include/hw/opentitan/otbn/otbnproxy.h b/include/hw/opentitan/otbn/otbnproxy.h index 1d19513f944b3..b54e79bd3f1b6 100644 --- a/include/hw/opentitan/otbn/otbnproxy.h +++ b/include/hw/opentitan/otbn/otbnproxy.h @@ -51,11 +51,7 @@ enum OtOTBNStatus { OT_OTBN_STATUS_LOCKED = 0xFF, }; -enum OtOTBNRandomSource { - OT_OTBN_URND, - OT_OTBN_RND, - OT_OTBN_RND_COUNT -}; +enum OtOTBNRandomSource { OT_OTBN_URND, OT_OTBN_RND, OT_OTBN_RND_COUNT }; #define OT_OTBN_IMEM_SIZE (8U << 10U) #define OT_OTBN_DMEM_SIZE (3U << 10U) @@ -64,17 +60,16 @@ enum OtOTBNRandomSource { #define OT_OTBN_RANDOM_WORD_COUNT \ ((OT_OTBN_RANDOM_BIT_WIDTH) / (8u * sizeof(uint32_t))) -extern OTBNProxy ot_otbn_proxy_new(ot_otbn_fetch_entropy_fn urnd_req_entropy, - void *urnd_opaque, - ot_otbn_fetch_entropy_fn rnd_req_entropy, - void *rnd_opaque, - ot_otbn_signal_completion_fn signal, - void *on_comp_opaque); +extern OTBNProxy +ot_otbn_proxy_new(ot_otbn_fetch_entropy_fn urnd_req_entropy, void *urnd_opaque, + ot_otbn_fetch_entropy_fn rnd_req_entropy, void *rnd_opaque, + ot_otbn_signal_completion_fn signal, void *on_comp_opaque); extern void ot_otbn_proxy_start(OTBNProxy proxy, bool test_mode, - const char *logname); + const char *logname, bool log_asm); extern void ot_otbn_proxy_terminate(OTBNProxy proxy); extern int ot_otbn_proxy_push_entropy(OTBNProxy proxy, uint32_t rndix, - const uint8_t *seed, uint32_t len, bool fips); + const uint8_t *seed, uint32_t len, + bool fips); extern int ot_otbn_proxy_execute(OTBNProxy proxy, bool dumpstate); extern int ot_otbn_proxy_wipe_memory(OTBNProxy proxy, bool doi); extern bool ot_otbn_proxy_acknowledge_execution(OTBNProxy proxy); diff --git a/python/qemu/ot/eflash/gen.py b/python/qemu/ot/eflash/gen.py index 71d81324c58a8..5ee3f80f097f1 100644 --- a/python/qemu/ot/eflash/gen.py +++ b/python/qemu/ot/eflash/gen.py @@ -301,7 +301,7 @@ def store_rom_ext(self, bank: int, dfp: BinaryIO, elif elfpath and not no_header: self._log.warning('Discarding ELF as input binary file is invalid') elfpath = None - if elfpath and not no_header: + if elfpath and isfile(dfp.name) and not no_header: elftime = stat(elfpath).st_mtime bintime = stat(dfp.name).st_mtime if bintime < elftime: diff --git a/python/qemu/ot/pyot/executer.py b/python/qemu/ot/pyot/executer.py index 5a96c9c03eb30..dec35553e62d3 100644 --- a/python/qemu/ot/pyot/executer.py +++ b/python/qemu/ot/pyot/executer.py @@ -273,6 +273,8 @@ def _build_qemu_fw_args(self, args: Namespace) \ -> tuple[str, Optional[str], list[str], Optional[str]]: rom_exec = bool(args.rom_exec) roms = args.rom or [] + if isinstance(roms, str): + roms = [roms] multi_rom = (len(roms) + int(rom_exec)) > 1 # generate pre-application ROM option fw_args: list[str] = []