Repository: lowRISC/opentitan
Pull request #26878: [sw/cryptolib] Add new ibex driver functions
Author: login: h-filali
Labels: name: CherryPick:earlgrey_1.0.0
description: This PR should be cherry-picked to earlgrey_1.0.0
Created: 2025-04-04T12:45:54Z | Merged: 2025-04-10T09:14:38Z

This PR adds a new ibex driver to cryptolib for gathering randomness from the RND_DATA CSR.
For further information check the individual commits.


Diff:
diff --git a/sw/device/lib/crypto/drivers/BUILD b/sw/device/lib/crypto/drivers/BUILD
index d8a07459457d1..418b06c542913 100644
--- a/sw/device/lib/crypto/drivers/BUILD
+++ b/sw/device/lib/crypto/drivers/BUILD
@@ -186,6 +186,41 @@ cc_library(
     ],
 )
 
+cc_library(
+    name = "ibex",
+    srcs = ["ibex.c"],
+    hdrs = ["ibex.h"],
+    deps = [
+        "//hw/top:rv_core_ibex_c_regs",
+        "//hw/top_earlgrey/sw/autogen:top_earlgrey",
+        "//sw/device/lib/base:abs_mmio",
+        "//sw/device/lib/base:csr",
+        "//sw/device/lib/crypto/impl:status",
+        "//sw/device/silicon_creator/lib/base:sec_mmio",
+    ],
+)
+
+opentitan_test(
+    name = "ibex_test",
+    srcs = ["ibex_test.c"],
+    exec_env = EARLGREY_TEST_ENVS,
+    verilator = verilator_params(
+        timeout = "long",
+    ),
+    deps = [
+        ":ibex",
+        "//hw/top:rv_core_ibex_c_regs",
+        "//hw/top_earlgrey/sw/autogen:top_earlgrey",
+        "//sw/device/lib/base:bitfield",
+        "//sw/device/lib/base:csr",
+        "//sw/device/lib/crypto/impl:status",
+        "//sw/device/lib/runtime:log",
+        "//sw/device/lib/testing/test_framework:check",
+        "//sw/device/lib/testing/test_framework:ottf_main",
+        "//sw/device/silicon_creator/lib/base:sec_mmio",
+    ],
+)
+
 cc_library(
     name = "otbn",
     srcs = ["otbn.c"],
diff --git a/sw/device/lib/crypto/drivers/ibex.c b/sw/device/lib/crypto/drivers/ibex.c
new file mode 100644
index 0000000000000..8caafb4c39450
--- /dev/null
+++ b/sw/device/lib/crypto/drivers/ibex.c
@@ -0,0 +1,37 @@
+// Copyright lowRISC contributors (OpenTitan project).
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/lib/crypto/drivers/ibex.h"
+
+#include "sw/device/lib/base/abs_mmio.h"
+#include "sw/device/lib/base/bitfield.h"
+#include "sw/device/lib/base/csr.h"
+#include "sw/device/lib/crypto/impl/status.h"
+#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+#include "rv_core_ibex_regs.h"
+
+enum {
+  kBase = TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR,
+};
+
+status_t ibex_wait_rnd_valid(void) {
+  while (true) {
+    uint32_t reg = abs_mmio_read32(kBase + RV_CORE_IBEX_RND_STATUS_REG_OFFSET);
+    if (bitfield_bit32_read(reg, RV_CORE_IBEX_RND_STATUS_RND_DATA_VALID_BIT)) {
+      return OTCRYPTO_OK;
+    }
+  }
+}
+
+status_t ibex_rnd_status_read(uint32_t *rnd_status) {
+  *rnd_status = abs_mmio_read32(kBase + RV_CORE_IBEX_RND_STATUS_REG_OFFSET);
+  return OTCRYPTO_OK;
+}
+
+status_t ibex_rnd_data_read(uint32_t *rnd_data) {
+  *rnd_data = abs_mmio_read32(kBase + RV_CORE_IBEX_RND_DATA_REG_OFFSET);
+  return OTCRYPTO_OK;
+}
diff --git a/sw/device/lib/crypto/drivers/ibex.h b/sw/device/lib/crypto/drivers/ibex.h
new file mode 100644
index 0000000000000..d12dc03cfa35f
--- /dev/null
+++ b/sw/device/lib/crypto/drivers/ibex.h
@@ -0,0 +1,42 @@
+// Copyright lowRISC contributors (OpenTitan project).
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+#ifndef OPENTITAN_SW_DEVICE_LIB_CRYPTO_DRIVERS_IBEX_H_
+#define OPENTITAN_SW_DEVICE_LIB_CRYPTO_DRIVERS_IBEX_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sw/device/lib/crypto/impl/status.h"
+
+/**
+ * Wait for random data in the RND_DATA CSR to be valid.
+ *
+ * Returns OTCRYPTO_OK when the random data is valid.
+ *
+ * @return OTCRYPTO_OK.
+ */
+status_t ibex_wait_rnd_valid(void);
+
+/**
+ * Get random data from the EDN0 interface.
+ *
+ * Returns 32 bits of randomness from EDN0.
+ *
+ * @param rnd_data The random data pointer.
+ * @return OTCRYPTO_OK.
+ */
+status_t ibex_rnd_data_read(uint32_t *rnd_data);
+
+/**
+ * Get information on the state of the RND_DATA CSR.
+ *
+ * Returns the status of the randomness interface.
+ *
+ * @param rnd_status The status pointer.
+ * @return OTCRYPTO_OK.
+ */
+status_t ibex_rnd_status_read(uint32_t *rnd_status);
+
+#endif  // OPENTITAN_SW_DEVICE_LIB_CRYPTO_DRIVERS_IBEX_H_
diff --git a/sw/device/lib/crypto/drivers/ibex_test.c b/sw/device/lib/crypto/drivers/ibex_test.c
new file mode 100644
index 0000000000000..815124de1a2d1
--- /dev/null
+++ b/sw/device/lib/crypto/drivers/ibex_test.c
@@ -0,0 +1,46 @@
+// Copyright lowRISC contributors (OpenTitan project).
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+#include "sw/device/lib/crypto/drivers/ibex.h"
+
+#include "sw/device/lib/base/bitfield.h"
+#include "sw/device/lib/base/csr.h"
+#include "sw/device/lib/base/status.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+#include "rv_core_ibex_regs.h"
+
+enum {
+  kBase = TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR,
+};
+
+OTTF_DEFINE_TEST_CONFIG();
+
+static status_t ibex_entropy_test(void) {
+  uint32_t rnd_status;
+  uint32_t rnd_data[2];
+
+  // Read the initial value of the RND_DATA CSR.
+  TRY(ibex_rnd_data_read(rnd_data));
+  // Wait for RND_DATA to be valid again and check if RND_STATUS is as expected.
+  TRY(ibex_wait_rnd_valid());
+  TRY(ibex_rnd_status_read(&rnd_status));
+  TRY_CHECK(bitfield_bit32_read(rnd_status,
+                                RV_CORE_IBEX_RND_STATUS_RND_DATA_VALID_BIT));
+  // Read RND_DATA again and check if it changed.
+  TRY(ibex_rnd_data_read(&rnd_data[1]));
+  TRY_CHECK(rnd_data[0] != rnd_data[1]);
+
+  return OK_STATUS();
+}
+
+bool test_main(void) {
+  status_t result = OK_STATUS();
+  // Test RND_DATA and RND_STATUS CSR access.
+  EXECUTE_TEST(result, ibex_entropy_test);
+  return status_ok(result);
+}


Reviews:
user: login: nasahlpa
body: Thanks @h-filali for implementing this!

A more general question: Is it planned to use this new function only within the cryptolib itself or should this also be accessible to other programs as part of the crypto lib API?

 If the latter, then you would need to add a new API in `sw/device/lib/crypto/include` and add an implementation into `sw/device/lib/crypto/impl` that uses the driver functions in the correct way (`wait_rnd_valid`, `rnd_data_read`) and does some error checking.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T10:24:38Z
user: login: h-filali
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T11:40:06Z
user: login: h-filali
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T11:42:45Z
user: login: nasahlpa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T12:24:29Z
user: login: nasahlpa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T12:24:55Z
user: login: nasahlpa
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T12:29:24Z

Review comments:
diff_hunk: @@ -0,0 +1,37 @@
+// Copyright lowRISC contributors (OpenTitan project).
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/lib/crypto/drivers/ibex.h"
+
+#include "sw/device/lib/base/abs_mmio.h"
+#include "sw/device/lib/base/bitfield.h"
+#include "sw/device/lib/base/csr.h"
+#include "sw/device/lib/crypto/impl/status.h"
+#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+#include "rv_core_ibex_regs.h"
+
+enum {
+  kBase = TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR,
+};
+
+status_t ibex_wait_rnd_valid(void) {
+  while (true) {
+    uint32_t reg = abs_mmio_read32(kBase + RV_CORE_IBEX_RND_STATUS_REG_OFFSET);
+    if (bitfield_bit32_read(reg, RV_CORE_IBEX_RND_STATUS_RND_DATA_VALID_BIT)) {
+      return OTCRYPTO_OK;
+    }
+  }
+}
+
+status_t ibex_rnd_status_read(uint32_t *rnd_status) {
+  *rnd_status = abs_mmio_read32(kBase + RV_CORE_IBEX_RND_STATUS_REG_OFFSET);
+  return OTCRYPTO_OK;
+}
+
+status_t ibex_rnd_data_read(uint32_t *rnd_data) {
+  *rnd_data = abs_mmio_read32(kBase + RV_CORE_IBEX_RND_DATA_REG_OFFSET);
path: sw/device/lib/crypto/drivers/ibex.c
user: login: nasahlpa
body: What happens if we read when `STATUS_RND_DATA_VALID` is not true?
created_at: 2025-04-07T10:20:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,46 @@
+// Copyright lowRISC contributors (OpenTitan project).
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+#include "sw/device/lib/crypto/drivers/ibex.h"
+
+#include "sw/device/lib/base/bitfield.h"
+#include "sw/device/lib/base/csr.h"
+#include "sw/device/lib/base/status.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+#include "rv_core_ibex_regs.h"
+
+enum {
+  kBase = TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR,
+};
+
+OTTF_DEFINE_TEST_CONFIG();
+
+static status_t ibex_entropy_test(void) {
+  uint32_t rnd_status;
+  uint32_t rnd_data[2];
+
+  // Read the initial value of the RND_DATA CSR.
+  TRY(ibex_rnd_data_read(rnd_data));
path: sw/device/lib/crypto/drivers/ibex_test.c
user: login: nasahlpa
body: Don't you first need to call a ibex_wait_rnd_valid()?
created_at: 2025-04-07T10:21:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,37 @@
+// Copyright lowRISC contributors (OpenTitan project).
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/lib/crypto/drivers/ibex.h"
+
+#include "sw/device/lib/base/abs_mmio.h"
+#include "sw/device/lib/base/bitfield.h"
+#include "sw/device/lib/base/csr.h"
+#include "sw/device/lib/crypto/impl/status.h"
+#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+#include "rv_core_ibex_regs.h"
+
+enum {
+  kBase = TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR,
+};
+
+status_t ibex_wait_rnd_valid(void) {
+  while (true) {
+    uint32_t reg = abs_mmio_read32(kBase + RV_CORE_IBEX_RND_STATUS_REG_OFFSET);
+    if (bitfield_bit32_read(reg, RV_CORE_IBEX_RND_STATUS_RND_DATA_VALID_BIT)) {
+      return OTCRYPTO_OK;
+    }
+  }
+}
+
+status_t ibex_rnd_status_read(uint32_t *rnd_status) {
+  *rnd_status = abs_mmio_read32(kBase + RV_CORE_IBEX_RND_STATUS_REG_OFFSET);
+  return OTCRYPTO_OK;
+}
+
+status_t ibex_rnd_data_read(uint32_t *rnd_data) {
+  *rnd_data = abs_mmio_read32(kBase + RV_CORE_IBEX_RND_DATA_REG_OFFSET);
path: sw/device/lib/crypto/drivers/ibex.c
user: login: h-filali
body: Nothing really, this function just returns the value of the the CSR. If the RND data is not valid the corresponding bit will be 0.
created_at: 2025-04-07T11:40:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,46 @@
+// Copyright lowRISC contributors (OpenTitan project).
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+#include "sw/device/lib/crypto/drivers/ibex.h"
+
+#include "sw/device/lib/base/bitfield.h"
+#include "sw/device/lib/base/csr.h"
+#include "sw/device/lib/base/status.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+#include "rv_core_ibex_regs.h"
+
+enum {
+  kBase = TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR,
+};
+
+OTTF_DEFINE_TEST_CONFIG();
+
+static status_t ibex_entropy_test(void) {
+  uint32_t rnd_status;
+  uint32_t rnd_data[2];
+
+  // Read the initial value of the RND_DATA CSR.
+  TRY(ibex_rnd_data_read(rnd_data));
path: sw/device/lib/crypto/drivers/ibex_test.c
user: login: h-filali
body: I could do that. My thought process was that if I read the value this will lead to ibex loading a new value. Be it because a valid one was read or that it is still loading the first value. In any case for the second value we wait for the value to be valid and then we compare and expect the random value to have changed.
created_at: 2025-04-07T11:42:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,37 @@
+// Copyright lowRISC contributors (OpenTitan project).
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/lib/crypto/drivers/ibex.h"
+
+#include "sw/device/lib/base/abs_mmio.h"
+#include "sw/device/lib/base/bitfield.h"
+#include "sw/device/lib/base/csr.h"
+#include "sw/device/lib/crypto/impl/status.h"
+#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+#include "rv_core_ibex_regs.h"
+
+enum {
+  kBase = TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR,
+};
+
+status_t ibex_wait_rnd_valid(void) {
+  while (true) {
+    uint32_t reg = abs_mmio_read32(kBase + RV_CORE_IBEX_RND_STATUS_REG_OFFSET);
+    if (bitfield_bit32_read(reg, RV_CORE_IBEX_RND_STATUS_RND_DATA_VALID_BIT)) {
+      return OTCRYPTO_OK;
+    }
+  }
+}
+
+status_t ibex_rnd_status_read(uint32_t *rnd_status) {
+  *rnd_status = abs_mmio_read32(kBase + RV_CORE_IBEX_RND_STATUS_REG_OFFSET);
+  return OTCRYPTO_OK;
+}
+
+status_t ibex_rnd_data_read(uint32_t *rnd_data) {
+  *rnd_data = abs_mmio_read32(kBase + RV_CORE_IBEX_RND_DATA_REG_OFFSET);
path: sw/device/lib/crypto/drivers/ibex.c
user: login: nasahlpa
body: Alright, thanks for the clarification.
created_at: 2025-04-07T12:24:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,46 @@
+// Copyright lowRISC contributors (OpenTitan project).
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+#include "sw/device/lib/crypto/drivers/ibex.h"
+
+#include "sw/device/lib/base/bitfield.h"
+#include "sw/device/lib/base/csr.h"
+#include "sw/device/lib/base/status.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+#include "rv_core_ibex_regs.h"
+
+enum {
+  kBase = TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR,
+};
+
+OTTF_DEFINE_TEST_CONFIG();
+
+static status_t ibex_entropy_test(void) {
+  uint32_t rnd_status;
+  uint32_t rnd_data[2];
+
+  // Read the initial value of the RND_DATA CSR.
+  TRY(ibex_rnd_data_read(rnd_data));
path: sw/device/lib/crypto/drivers/ibex_test.c
user: login: nasahlpa
body: Ah ok, I see, makes sense.
created_at: 2025-04-07T12:24:55Z
author_association: CONTRIBUTOR

PR comments:
user: login: h-filali
created_at: 2025-04-07T12:03:34Z
body: > Thanks @h-filali for implementing this!
> 
> A more general question: Is it planned to use this new function only within the cryptolib itself or should this also be accessible to other programs as part of the crypto lib API?
> 
> If the latter, then you would need to add a new API in `sw/device/lib/crypto/include` and add an implementation into `sw/device/lib/crypto/impl` that uses the driver functions in the correct way (`wait_rnd_valid`, `rnd_data_read`) and does some error checking.

@nasahlpa thanks for your review. Your comments should all be addressed above.

From what I read this is meant to be a new file in crypt/drivers but I can add a new API as well. As for error checking I'm not sure what checks I should add. I'll add another commit and then we can discuss.
author_association: CONTRIBUTOR
user: login: nasahlpa
created_at: 2025-04-07T12:29:13Z
body: > > Thanks @h-filali for implementing this!
> > A more general question: Is it planned to use this new function only within the cryptolib itself or should this also be accessible to other programs as part of the crypto lib API?
> > If the latter, then you would need to add a new API in `sw/device/lib/crypto/include` and add an implementation into `sw/device/lib/crypto/impl` that uses the driver functions in the correct way (`wait_rnd_valid`, `rnd_data_read`) and does some error checking.
> 
> @nasahlpa thanks for your review. Your comments should all be addressed above.
> 
> From what I read this is meant to be a new file in crypt/drivers but I can add a new API as well. As for error checking I'm not sure what checks I should add. I'll add another commit and then we can discuss.

I see, so for now it is the plan to use this randomness interface within the crypto lib and not to expose it via an API. 
author_association: CONTRIBUTOR
user: login: nasahlpa
created_at: 2025-04-10T09:14:14Z
body: Thanks for your work, @h-filali.

As this PR looks fine for me, I am merging it now.

If there are any suggestions for further improvements or additions, I'd suggest adding them in a separate PR.
author_association: CONTRIBUTOR
user: login: jadephilipoom
created_at: 2025-04-10T09:43:41Z
body: Sorry for the post-merge comment, I'm travelling at the moment. But I'll add that the cryptolib already has a randomness interface that uses the CSRNG directly rather than Ibex's RND register, and I don't think there's a need to add this specifically as a separate function.

As far as I understand, the purpose of RND for cryptolib would be to access randomness for e.g. `memshred` and `random_order_t` from `lib/base` -- is that the intention of this PR? If so, it may make more sense for this code to live in `lib/base` than in cryptolib directly; while cryptolib can and does depend on `lib/base`, `lib/base` libraries should probably not depend on the cryptolib.
author_association: CONTRIBUTOR
user: login: lowrisc-ci[bot]
created_at: 2025-08-15T12:26:15Z
body: Successfully created backport PR for `earlgrey_1.0.0`:
- #27916
author_association: NONE