Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update OpenTitan EDN registers and SW_CMD_STS behavior #85

Merged
merged 2 commits into from
Dec 9, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 36 additions & 19 deletions hw/opentitan/ot_edn.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,21 @@ REG32(BOOT_INS_CMD, 0x18u)
REG32(BOOT_GEN_CMD, 0x1cu)
REG32(SW_CMD_REQ, 0x20u)
REG32(SW_CMD_STS, 0x24u)
FIELD(SW_CMD_STS, CMD_RDY, 0u, 1u)
FIELD(SW_CMD_STS, CMD_STS, 1u, 1u)
REG32(RESEED_CMD, 0x28u)
REG32(GENERATE_CMD, 0x2cu)
REG32(MAX_NUM_REQS_BETWEEN_RESEEDS, 0x30u)
REG32(RECOV_ALERT_STS, 0x34u)
FIELD(SW_CMD_STS, CMD_REG_RDY, 0u, 1u)
FIELD(SW_CMD_STS, CMD_RDY, 1u, 1u)
FIELD(SW_CMD_STS, CMD_ACK, 2u, 1u)
FIELD(SW_CMD_STS, CMD_STS, 3u, 3u)
REG32(HW_CMD_STS, 0x28u)
REG32(RESEED_CMD, 0x2cu)
REG32(GENERATE_CMD, 0x30u)
REG32(MAX_NUM_REQS_BETWEEN_RESEEDS, 0x34u)
REG32(RECOV_ALERT_STS, 0x38u)
FIELD(RECOV_ALERT_STS, EDN_ENABLE_FIELD_ALERT, 0u, 1u)
FIELD(RECOV_ALERT_STS, BOOT_REQ_MODE_FIELD_ALERT, 1u, 1u)
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)
REG32(ERR_CODE, 0x38u)
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)
Expand All @@ -93,9 +96,9 @@ REG32(ERR_CODE, 0x38u)
FIELD(ERR_CODE, FIFO_WRITE_ERR, 28u, 1u)
FIELD(ERR_CODE, FIFO_READ_ERR, 29u, 1u)
FIELD(ERR_CODE, FIFO_STATE_ERR, 30u, 1u)
REG32(ERR_CODE_TEST, 0x3cu)
REG32(ERR_CODE_TEST, 0x40u)
FIELD(ERR_CODE_TEST, VAL, 0u, 5u)
REG32(MAIN_SM_STATE, 0x40u)
REG32(MAIN_SM_STATE, 0x44u)
FIELD(MAIN_SM_STATE, VAL, 0u, 9u)
/* clang-format on */

Expand Down Expand Up @@ -194,8 +197,17 @@ typedef enum {
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 */
Expand Down Expand Up @@ -231,7 +243,6 @@ struct OtEDNState {
uint32_t *regs;

unsigned reseed_counter; /* track remaining requests before reseeding */
bool last_cmd_failed; /* status of the last CSRNG command */
bool sw_cmd_ready; /* ready to receive command in SW port mode */
OtEDNFsmState state; /* Main FSM state */
OtEDNCSRNG rng;
Expand Down Expand Up @@ -437,12 +448,12 @@ static OtCsrngCmd ot_edn_get_last_csrng_command(OtEDNState *s)
}
}

static bool ot_edn_is_cmd_rdy(OtEDNState *s)
static bool ot_edn_is_cmd_rdy(OtEDNState *s, bool check_fifo)
{
if (!ot_edn_is_enabled(s)) {
return false;
}
if (ot_fifo32_is_full(&s->rng.sw_cmd_fifo)) {
if (check_fifo && ot_fifo32_is_full(&s->rng.sw_cmd_fifo)) {
return false;
}
switch (s->state) {
Expand Down Expand Up @@ -505,6 +516,7 @@ static int ot_edn_push_csrng_request(OtEDNState *s)
&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");
Expand Down Expand Up @@ -831,7 +843,7 @@ static void ot_edn_clean_up(OtEDNState *s, bool discard_requests)

c->instantiated = false;
s->sw_cmd_ready = false;
s->last_cmd_failed = 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);
Expand Down Expand Up @@ -991,7 +1003,8 @@ static void ot_edn_csrng_ack_irq(void *opaque, int n, int level)
*/
memset(c->buffer, 0, sizeof(*c->buffer));

s->last_cmd_failed = level != 0;
c->last_cmd_status =
level != 0 ? CSRNG_STATUS_INVALID_ACMD : CSRNG_STATUS_SUCCESS;

if (level) {
xtrace_ot_edn_error(c->appid, "last command failed");
Expand Down Expand Up @@ -1071,12 +1084,15 @@ 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:
val32 =
FIELD_DP32(0, SW_CMD_STS, CMD_STS, (uint32_t)s->last_cmd_failed);
val32 = FIELD_DP32(val32, SW_CMD_STS, CMD_RDY,
(uint32_t)ot_edn_is_cmd_rdy(s));
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);
break;
}
case R_MAIN_SM_STATE:
switch (s->state) {
case EDN_IDLE ... EDN_ERROR:
Expand Down Expand Up @@ -1202,6 +1218,7 @@ static void ot_edn_regs_write(void *opaque, hwaddr addr, uint64_t val64,
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);
Expand Down
Loading