diff --git a/sw/device/lib/dif/BUILD b/sw/device/lib/dif/BUILD index caddd5069c49a5..4b2c8475dfffe3 100644 --- a/sw/device/lib/dif/BUILD +++ b/sw/device/lib/dif/BUILD @@ -206,6 +206,7 @@ cc_library( deps = [ ":base", "//hw/ip/csrng/data:csrng_regs", + "//hw/ip/edn/data:edn_regs", "//sw/device/lib/base:bitfield", "//sw/device/lib/base:macros", "//sw/device/lib/base:memory", diff --git a/sw/device/lib/dif/dif_csrng.c b/sw/device/lib/dif/dif_csrng.c index 7b9e92f4e49e9f..e7b15e6d1e926f 100644 --- a/sw/device/lib/dif/dif_csrng.c +++ b/sw/device/lib/dif/dif_csrng.c @@ -64,7 +64,7 @@ dif_result_t dif_csrng_instantiate( if (csrng == NULL || seed_material == NULL) { return kDifBadArg; } - return csrng_send_app_cmd(csrng->base_addr, CSRNG_CMD_REQ_REG_OFFSET, + return csrng_send_app_cmd(csrng->base_addr, kCsrngAppCmdTypeCsrng, (csrng_app_cmd_t){ .id = kCsrngAppCmdInstantiate, .entropy_src_enable = entropy_src_enable, @@ -77,7 +77,7 @@ dif_result_t dif_csrng_reseed(const dif_csrng_t *csrng, if (csrng == NULL || seed_material == NULL) { return kDifBadArg; } - return csrng_send_app_cmd(csrng->base_addr, CSRNG_CMD_REQ_REG_OFFSET, + return csrng_send_app_cmd(csrng->base_addr, kCsrngAppCmdTypeCsrng, (csrng_app_cmd_t){ .id = kCsrngAppCmdReseed, .seed_material = seed_material, @@ -89,7 +89,7 @@ dif_result_t dif_csrng_update(const dif_csrng_t *csrng, if (csrng == NULL || seed_material == NULL) { return kDifBadArg; } - return csrng_send_app_cmd(csrng->base_addr, CSRNG_CMD_REQ_REG_OFFSET, + return csrng_send_app_cmd(csrng->base_addr, kCsrngAppCmdTypeCsrng, (csrng_app_cmd_t){ .id = kCsrngAppCmdUpdate, .seed_material = seed_material, @@ -104,7 +104,7 @@ dif_result_t dif_csrng_generate_start(const dif_csrng_t *csrng, size_t len) { // Round up the number of 128bit blocks. Aligning with respect to uint32_t. // TODO(#6112): Consider using a canonical reference for alignment operations. const uint32_t num_128bit_blocks = (len + 3) / 4; - return csrng_send_app_cmd(csrng->base_addr, CSRNG_CMD_REQ_REG_OFFSET, + return csrng_send_app_cmd(csrng->base_addr, kCsrngAppCmdTypeCsrng, (csrng_app_cmd_t){ .id = kCsrngAppCmdGenerate, .generate_len = num_128bit_blocks, @@ -131,7 +131,7 @@ dif_result_t dif_csrng_uninstantiate(const dif_csrng_t *csrng) { if (csrng == NULL) { return kDifBadArg; } - return csrng_send_app_cmd(csrng->base_addr, CSRNG_CMD_REQ_REG_OFFSET, + return csrng_send_app_cmd(csrng->base_addr, kCsrngAppCmdTypeCsrng, (csrng_app_cmd_t){ .id = kCsrngAppCmdUninstantiate, }); diff --git a/sw/device/lib/dif/dif_csrng_shared.c b/sw/device/lib/dif/dif_csrng_shared.c index a726956ed5bb86..980c3bcd5d3b46 100644 --- a/sw/device/lib/dif/dif_csrng_shared.c +++ b/sw/device/lib/dif/dif_csrng_shared.c @@ -6,6 +6,9 @@ #include "sw/device/lib/base/multibits.h" +#include "csrng_regs.h" // Generated +#include "edn_regs.h" // Generated + // The application command header is not specified as a register in the // hardware specification, so the fields are mapped here by hand. The // command register also accepts arbitrary 32bit data. @@ -29,8 +32,30 @@ uint32_t csrng_cmd_header_build( return reg; } -dif_result_t csrng_send_app_cmd(mmio_region_t base_addr, ptrdiff_t offset, +dif_result_t csrng_send_app_cmd(mmio_region_t base_addr, + csrng_app_cmd_type_t cmd_type, csrng_app_cmd_t cmd) { + bool ready; + ptrdiff_t offset; + uint32_t reg; + + switch (cmd_type) { + case kCsrngAppCmdTypeCsrng: + offset = CSRNG_CMD_REQ_REG_OFFSET; + break; + case kCsrngAppCmdTypeEdnSw: + offset = EDN_SW_CMD_REQ_REG_OFFSET; + break; + case kCsrngAppCmdTypeEdnGen: + offset = EDN_GENERATE_CMD_REG_OFFSET; + break; + case kCsrngAppCmdTypeEdnRes: + offset = EDN_RESEED_CMD_REG_OFFSET; + break; + default: + return kDifBadArg; + } + // Ensure the `seed_material` array is word-aligned, so it can be loaded to a // CPU register with natively aligned loads. if (cmd.seed_material != NULL && @@ -54,10 +79,26 @@ dif_result_t csrng_send_app_cmd(mmio_region_t base_addr, ptrdiff_t offset, return kDifOutOfRange; } + if (cmd_type == kCsrngAppCmdTypeEdnSw) { + // Wait for the status register to be ready to accept the next command. + do { + reg = mmio_region_read32(base_addr, EDN_SW_CMD_STS_REG_OFFSET); + ready = bitfield_bit32_read(reg, EDN_SW_CMD_STS_CMD_RDY_BIT); + } while (!ready); + } + mmio_region_write32(base_addr, offset, csrng_cmd_header_build(cmd.id, cmd.entropy_src_enable, cmd_len, cmd.generate_len)); for (size_t i = 0; i < cmd_len; ++i) { + // If the command is issued to the SW register of the EDN, the reg ready + // bit needs to be polled before writing each word of additional data. + if (cmd_type == kCsrngAppCmdTypeEdnSw) { + do { + reg = mmio_region_read32(base_addr, EDN_SW_CMD_STS_REG_OFFSET); + ready = bitfield_bit32_read(reg, EDN_SW_CMD_STS_CMD_REG_RDY_BIT); + } while (!ready); + } mmio_region_write32(base_addr, offset, cmd.seed_material->seed_material[i]); } return kDifOk; diff --git a/sw/device/lib/dif/dif_csrng_shared.h b/sw/device/lib/dif/dif_csrng_shared.h index 581efc613b2a4c..2cf6a6c214f262 100644 --- a/sw/device/lib/dif/dif_csrng_shared.h +++ b/sw/device/lib/dif/dif_csrng_shared.h @@ -61,6 +61,31 @@ typedef struct csrng_app_cmd { uint32_t generate_len; } csrng_app_cmd_t; +/** + * This enum type contains all the different command types for + * csrng_send_cmd(). + */ +typedef enum csrng_app_cmd_type { + /** + * Command issued directly to CSRNG. + */ + kCsrngAppCmdTypeCsrng, + /** + * Command issued to CSRNG via the SW_CMD_REQ register of the EDN. + */ + kCsrngAppCmdTypeEdnSw, + /** + * Command issued to CSRNG via the GENERATE_CMD register of the EDN. + * This type of command will be used in the auto mode of the EDN. + */ + kCsrngAppCmdTypeEdnGen, + /** + * Command issued to CSRNG via the RESEED_CMD register of the EDN. + * This type of command will be used in the auto mode of the EDN. + */ + kCsrngAppCmdTypeEdnRes, +} csrng_app_cmd_type_t; + /** * Builds a CSRNG command header. * @@ -87,7 +112,8 @@ uint32_t csrng_cmd_header_build( * Returns the result of the operation. */ OT_WARN_UNUSED_RESULT -dif_result_t csrng_send_app_cmd(mmio_region_t base_addr, ptrdiff_t offset, +dif_result_t csrng_send_app_cmd(mmio_region_t base_addr, + csrng_app_cmd_type_t cmd_type, csrng_app_cmd_t cmd); #endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_CSRNG_SHARED_H_ diff --git a/sw/device/lib/dif/dif_edn.c b/sw/device/lib/dif/dif_edn.c index f91b0ffa3a165f..e3501eb975cf9d 100644 --- a/sw/device/lib/dif/dif_edn.c +++ b/sw/device/lib/dif/dif_edn.c @@ -141,12 +141,13 @@ dif_result_t dif_edn_set_auto_mode(const dif_edn_t *edn, // Wait until CSRNG acknowledges command. ready = false; while (!ready) { - DIF_RETURN_IF_ERROR(dif_edn_get_status(edn, kDifEdnStatusReady, &ready)); + DIF_RETURN_IF_ERROR(dif_edn_get_status(edn, kDifEdnStatusCsrngAck, &ready)); } // Read request acknowledge error and return accordingly. bool ack_err; - DIF_RETURN_IF_ERROR(dif_edn_get_status(edn, kDifEdnStatusCsrngAck, &ack_err)); + DIF_RETURN_IF_ERROR( + dif_edn_get_status(edn, kDifEdnStatusCsrngStatus, &ack_err)); return ack_err ? kDifError : kDifOk; } @@ -158,12 +159,18 @@ dif_result_t dif_edn_get_status(const dif_edn_t *edn, dif_edn_status_t flag, uint32_t bit; switch (flag) { + case kDifEdnStatusRegReady: + bit = EDN_SW_CMD_STS_CMD_REG_RDY_BIT; + break; case kDifEdnStatusReady: bit = EDN_SW_CMD_STS_CMD_RDY_BIT; break; - case kDifEdnStatusCsrngAck: + case kDifEdnStatusCsrngStatus: bit = EDN_SW_CMD_STS_CMD_STS_BIT; break; + case kDifEdnStatusCsrngAck: + bit = EDN_SW_CMD_STS_CMD_ACK_BIT; + break; default: return kDifBadArg; } @@ -280,7 +287,7 @@ dif_result_t dif_edn_instantiate( return kDifBadArg; } return csrng_send_app_cmd( - edn->base_addr, EDN_SW_CMD_REQ_REG_OFFSET, + edn->base_addr, kCsrngAppCmdTypeEdnSw, (csrng_app_cmd_t){ .id = kCsrngAppCmdInstantiate, .entropy_src_enable = @@ -296,7 +303,7 @@ dif_result_t dif_edn_reseed(const dif_edn_t *edn, } dif_csrng_seed_material_t seed_material2; memcpy(&seed_material2, seed_material, sizeof(seed_material2)); - return csrng_send_app_cmd(edn->base_addr, EDN_SW_CMD_REQ_REG_OFFSET, + return csrng_send_app_cmd(edn->base_addr, kCsrngAppCmdTypeEdnSw, (csrng_app_cmd_t){ .id = kCsrngAppCmdReseed, .seed_material = &seed_material2, @@ -310,7 +317,7 @@ dif_result_t dif_edn_update(const dif_edn_t *edn, } dif_csrng_seed_material_t seed_material2; memcpy(&seed_material2, seed_material, sizeof(seed_material2)); - return csrng_send_app_cmd(edn->base_addr, EDN_SW_CMD_REQ_REG_OFFSET, + return csrng_send_app_cmd(edn->base_addr, kCsrngAppCmdTypeEdnSw, (csrng_app_cmd_t){ .id = kCsrngAppCmdUpdate, .seed_material = &seed_material2, @@ -325,7 +332,7 @@ dif_result_t dif_edn_generate_start(const dif_edn_t *edn, size_t len) { // Round up the number of 128bit blocks. Aligning with respect to uint32_t. // TODO(#6112): Consider using a canonical reference for alignment operations. const uint32_t num_128bit_blocks = (len + 3) / 4; - return csrng_send_app_cmd(edn->base_addr, EDN_SW_CMD_REQ_REG_OFFSET, + return csrng_send_app_cmd(edn->base_addr, kCsrngAppCmdTypeEdnSw, (csrng_app_cmd_t){ .id = kCsrngAppCmdGenerate, .generate_len = num_128bit_blocks, @@ -336,7 +343,7 @@ dif_result_t dif_edn_uninstantiate(const dif_edn_t *edn) { if (edn == NULL) { return kDifBadArg; } - return csrng_send_app_cmd(edn->base_addr, EDN_SW_CMD_REQ_REG_OFFSET, + return csrng_send_app_cmd(edn->base_addr, kCsrngAppCmdTypeEdnSw, (csrng_app_cmd_t){ .id = kCsrngAppCmdUninstantiate, }); diff --git a/sw/device/lib/dif/dif_edn.h b/sw/device/lib/dif/dif_edn.h index c697726460d571..3f5a3d3ec405ec 100644 --- a/sw/device/lib/dif/dif_edn.h +++ b/sw/device/lib/dif/dif_edn.h @@ -124,10 +124,18 @@ typedef struct dif_edn_auto_params { * EDN Status flags. */ typedef enum dif_edn_status { + /** + * SW command register is ready to receive the next word of a command. + */ + kDifEdnStatusRegReady, /** * Device is ready to receive a command. */ kDifEdnStatusReady, + /** + * Device has received an error from the CSRNG block. + */ + kDifEdnStatusCsrngStatus, /** * Device has recieved an ACK from the CSRNG block. */ diff --git a/sw/device/lib/dif/dif_edn_unittest.cc b/sw/device/lib/dif/dif_edn_unittest.cc index f20ab9e3fdb8b8..abe50b3b3c6abd 100644 --- a/sw/device/lib/dif/dif_edn_unittest.cc +++ b/sw/device/lib/dif/dif_edn_unittest.cc @@ -153,19 +153,26 @@ TEST_F(SetModeTest, Auto) { {EDN_CTRL_CMD_FIFO_RST_OFFSET, kMultiBitBool4False}, }); - EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, 1); + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_RDY_BIT, true}}); + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 1 | params.instantiate_cmd.seed_material.len << 4 | kMultiBitBool4False << 8); for (size_t i = 0; i < params.instantiate_cmd.seed_material.len; ++i) { + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_REG_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, params.instantiate_cmd.seed_material.data[i]); } - EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, 1); + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_ACK_BIT, true}}); - EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, 1); + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_STS_BIT, false}}); EXPECT_DIF_OK(dif_edn_set_auto_mode(&edn_, params)); } @@ -193,7 +200,19 @@ TEST_F(GetStatusTest, Ok) { EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, { {EDN_SW_CMD_STS_CMD_RDY_BIT, true}, + {EDN_SW_CMD_STS_CMD_REG_RDY_BIT, true}, + {EDN_SW_CMD_STS_CMD_STS_BIT, false}, + {EDN_SW_CMD_STS_CMD_ACK_BIT, false}, + }); + EXPECT_DIF_OK(dif_edn_get_status(&edn_, kDifEdnStatusRegReady, &flag)); + EXPECT_TRUE(flag); + + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + { + {EDN_SW_CMD_STS_CMD_RDY_BIT, true}, + {EDN_SW_CMD_STS_CMD_REG_RDY_BIT, true}, {EDN_SW_CMD_STS_CMD_STS_BIT, false}, + {EDN_SW_CMD_STS_CMD_ACK_BIT, false}, }); EXPECT_DIF_OK(dif_edn_get_status(&edn_, kDifEdnStatusReady, &flag)); EXPECT_TRUE(flag); @@ -201,7 +220,19 @@ TEST_F(GetStatusTest, Ok) { EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, { {EDN_SW_CMD_STS_CMD_RDY_BIT, true}, + {EDN_SW_CMD_STS_CMD_REG_RDY_BIT, true}, {EDN_SW_CMD_STS_CMD_STS_BIT, false}, + {EDN_SW_CMD_STS_CMD_ACK_BIT, false}, + }); + EXPECT_DIF_OK(dif_edn_get_status(&edn_, kDifEdnStatusCsrngStatus, &flag)); + EXPECT_FALSE(flag); + + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + { + {EDN_SW_CMD_STS_CMD_RDY_BIT, true}, + {EDN_SW_CMD_STS_CMD_REG_RDY_BIT, true}, + {EDN_SW_CMD_STS_CMD_STS_BIT, false}, + {EDN_SW_CMD_STS_CMD_ACK_BIT, false}, }); EXPECT_DIF_OK(dif_edn_get_status(&edn_, kDifEdnStatusCsrngAck, &flag)); EXPECT_FALSE(flag); @@ -287,11 +318,15 @@ class CommandTest : public DifEdnTest { }; TEST_F(CommandTest, InstantiateOk) { + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000001 | kMultiBitBool4True << 8); EXPECT_DIF_OK(dif_edn_instantiate(&edn_, kDifEdnEntropySrcToggleDisable, &seed_material_)); + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000001 | kMultiBitBool4False << 8); EXPECT_DIF_OK(dif_edn_instantiate(&edn_, kDifEdnEntropySrcToggleEnable, @@ -299,8 +334,12 @@ TEST_F(CommandTest, InstantiateOk) { seed_material_.data[0] = 0x5a5a5a5a; seed_material_.len = 1; + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000011 | kMultiBitBool4False << 8); + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_REG_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x5a5a5a5a); EXPECT_DIF_OK(dif_edn_instantiate(&edn_, kDifEdnEntropySrcToggleEnable, &seed_material_)); @@ -324,14 +363,20 @@ TEST_F(CommandTest, InstantiateBadArgs) { } TEST_F(CommandTest, ReseedOk) { + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000002 | kMultiBitBool4False << 8); EXPECT_DIF_OK(dif_edn_reseed(&edn_, &seed_material_)); seed_material_.data[0] = 0x5a5a5a5a; seed_material_.len = 1; + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000012 | kMultiBitBool4False << 8); + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_REG_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x5a5a5a5a); EXPECT_DIF_OK(dif_edn_reseed(&edn_, &seed_material_)); } @@ -345,13 +390,19 @@ TEST_F(CommandTest, ReseedBadArgs) { } TEST_F(CommandTest, UpdateOk) { + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000004 | kMultiBitBool4False << 8); EXPECT_DIF_OK(dif_edn_update(&edn_, &seed_material_)); seed_material_.data[0] = 0x5a5a5a5a; seed_material_.len = 1; + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000014 | kMultiBitBool4False << 8); + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_REG_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x5a5a5a5a); EXPECT_DIF_OK(dif_edn_update(&edn_, &seed_material_)); } @@ -362,11 +413,15 @@ TEST_F(CommandTest, UpdateBadArgs) { TEST_F(CommandTest, GenerateOk) { // 512bits = 16 x 32bit = 4 x 128bit blocks + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00004003 | kMultiBitBool4False << 8); EXPECT_DIF_OK(dif_edn_generate_start(&edn_, /*len=*/16)); // 576bits = 18 x 32bit = 5 x 128bit blocks (rounded up) + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00005003 | kMultiBitBool4False << 8); EXPECT_DIF_OK(dif_edn_generate_start(&edn_, /*len=*/18)); @@ -387,6 +442,8 @@ TEST_F(CommandTest, GenerateOutOfRange) { } TEST_F(CommandTest, UninstantiateOk) { + EXPECT_READ32(EDN_SW_CMD_STS_REG_OFFSET, + {{EDN_SW_CMD_STS_CMD_RDY_BIT, true}}); EXPECT_WRITE32(EDN_SW_CMD_REQ_REG_OFFSET, 0x00000005 | kMultiBitBool4False << 8); EXPECT_DIF_OK(dif_edn_uninstantiate(&edn_)); diff --git a/sw/device/lib/testing/csrng_testutils.c b/sw/device/lib/testing/csrng_testutils.c index 02c926c48b8744..34c55a348cb7ff 100644 --- a/sw/device/lib/testing/csrng_testutils.c +++ b/sw/device/lib/testing/csrng_testutils.c @@ -101,7 +101,7 @@ status_t csrng_testutils_kat_reseed( // Reseed CSRNG - use the provided seed material only. TRY(csrng_testutils_cmd_ready_wait(csrng)); TRY(csrng_send_app_cmd( - csrng->base_addr, CSRNG_CMD_REQ_REG_OFFSET, + csrng->base_addr, kCsrngAppCmdTypeCsrng, (csrng_app_cmd_t){ .id = kCsrngAppCmdReseed, .entropy_src_enable = kDifCsrngEntropySrcToggleDisable,