[test] Add rom_e2e_static_critical test
This commit also updates the test point to include a negative sec_mmio
test.
Fixes #14502
Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/sw/device/silicon_creator/rom/data/rom_testplan.hjson b/sw/device/silicon_creator/rom/data/rom_testplan.hjson
index 9d700f9..ccc2b03 100644
--- a/sw/device/silicon_creator/rom/data/rom_testplan.hjson
+++ b/sw/device/silicon_creator/rom/data/rom_testplan.hjson
@@ -1105,6 +1105,7 @@
- Don't specify any usage constraints to be able to compute the actual hash in the second stage.
- Verify that `sec_mmio_ctx` is valid using `sec_mmio_check_values()` and
`sec_mmio_check_counters()`.
+ - Verify that a failed sec_mmio check triggers an illegal instruction exception.
'''
tags: ["rom", "verilator", "dv", "fpga", "silicon"]
stage: V2
diff --git a/sw/device/silicon_creator/rom/e2e/BUILD b/sw/device/silicon_creator/rom/e2e/BUILD
index ed55cce..f5607d6 100644
--- a/sw/device/silicon_creator/rom/e2e/BUILD
+++ b/sw/device/silicon_creator/rom/e2e/BUILD
@@ -65,6 +65,30 @@
],
)
+opentitan_functest(
+ name = "rom_e2e_static_critical",
+ srcs = ["rom_e2e_static_critical_test.c"],
+ cw310 = cw310_params(
+ bitstream = "//hw/bitstream:rom",
+ ),
+ manifest = "//sw/device/silicon_creator/rom_ext:manifest_standard",
+ signed = True,
+ targets = [
+ "cw310",
+ "verilator",
+ ],
+ verilator = verilator_params(
+ timeout = "eternal",
+ rom = "//sw/device/silicon_creator/rom",
+ ),
+ deps = [
+ "//sw/device/lib/dif:hmac",
+ "//sw/device/lib/testing:hmac_testutils",
+ "//sw/device/lib/testing/test_framework:ottf_main",
+ "//sw/device/silicon_creator/lib/base:sec_mmio",
+ ],
+)
+
# Same as `:e2e_bootup_success`, but the Dev OTP image is spliced into the
# bitstream before it's sent to the CW310 FPGA.
opentitan_functest(
diff --git a/sw/device/silicon_creator/rom/e2e/rom_e2e_static_critical_test.c b/sw/device/silicon_creator/rom/e2e/rom_e2e_static_critical_test.c
new file mode 100644
index 0000000..9261252
--- /dev/null
+++ b/sw/device/silicon_creator/rom/e2e/rom_e2e_static_critical_test.c
@@ -0,0 +1,136 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include <stdbool.h>
+
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/dif/dif_hmac.h"
+#include "sw/device/lib/runtime/ibex.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/hmac_testutils.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/boot_measurements.h"
+#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
+#include "sw/device/silicon_creator/lib/manifest_def.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+
+OTTF_DEFINE_TEST_CONFIG();
+
+#define RUN_TEST(test_) \
+ LOG_INFO("Starting test " #test_ "..."); \
+ test_(); \
+ LOG_INFO("Finished test " #test_ ": ok.");
+
+#define CHECK_WORD_ALIGNED(addr_) \
+ CHECK((uintptr_t)addr_ % sizeof(uint32_t) == 0, \
+ #addr_ " must be word aligned");
+
+void boot_measurements_test(void) {
+ CHECK(kManifest.usage_constraints.selector_bits == 0,
+ "Selector bits must be 0");
+ const volatile char *manifest_start = (const volatile char *)&kManifest;
+ const char *manifest_end = (const char *)manifest_start + sizeof(manifest_t);
+ const volatile char *signed_region_start =
+ manifest_start + sizeof(sigverify_rsa_buffer_t);
+ const char *signed_region_end =
+ (const char *)manifest_start + kManifest.length;
+ size_t manifest_signed_region_size = manifest_end - signed_region_start;
+ size_t signed_region_size = signed_region_end - signed_region_start;
+ dif_hmac_t hmac;
+
+ CHECK_WORD_ALIGNED(manifest_start);
+ CHECK_WORD_ALIGNED(manifest_end);
+ CHECK_WORD_ALIGNED(signed_region_start);
+ CHECK_WORD_ALIGNED(signed_region_end);
+ CHECK_WORD_ALIGNED(manifest_signed_region_size);
+ CHECK_WORD_ALIGNED(signed_region_size);
+
+ CHECK_DIF_OK(
+ dif_hmac_init(mmio_region_from_addr(TOP_EARLGREY_HMAC_BASE_ADDR), &hmac));
+ CHECK_DIF_OK(dif_hmac_mode_sha256_start(
+ &hmac, (dif_hmac_transaction_t){
+ .digest_endianness = kDifHmacEndiannessLittle,
+ .message_endianness = kDifHmacEndiannessLittle,
+ }));
+
+ // Copy the part of the manifest that's in the signed region to
+ // memory before pushing to hmac since it's volatile.
+ // Note: this array is larger than `manifest_signed_region_size` since VLAs
+ // are optional in C11.
+ char manifest_signed_region[sizeof(manifest_t)];
+ for (size_t i = 0; i < manifest_signed_region_size; ++i) {
+ manifest_signed_region[i] =
+ *((const volatile char *)signed_region_start + i);
+ }
+ hmac_testutils_push_message(&hmac, manifest_signed_region,
+ manifest_signed_region_size);
+ // Rest of the image
+ hmac_testutils_push_message(&hmac, manifest_end,
+ signed_region_size - manifest_signed_region_size);
+
+ CHECK_DIF_OK(dif_hmac_process(&hmac));
+ dif_hmac_digest_t act_digest;
+ hmac_testutils_finish_polled(&hmac, &act_digest);
+
+ CHECK_ARRAYS_EQ(boot_measurements.rom_ext.data, act_digest.digest,
+ ARRAYSIZE(act_digest.digest));
+}
+
+void sec_mmio_pos_test(void) {
+ enum {
+ kRndOffset = 13,
+ kRomCheckValue = 6,
+ };
+
+ sec_mmio_check_values(kRndOffset);
+ sec_mmio_check_counters(kRomCheckValue + 1);
+}
+
+static volatile bool exception_expected = false;
+static volatile bool exception_observed = false;
+
+// Redeclaration of the addressable symbol in `sec_mmio_neg_test()` to be used
+// in `ottf_exception_handler()`.
+extern const char kSecMmioNegTestReturn[];
+
+void ottf_exception_handler(void) {
+ CHECK(exception_expected == true);
+ CHECK(exception_observed == false);
+ exception_expected = false;
+ // The frame address is the address of the stack location that holds the
+ // `mepc`, since the OTTF exception handler entry code saves the `mepc` to
+ // the top of the stack before transferring control flow to the exception
+ // handler function (which is overridden here). See the `handler_exception`
+ // subroutine in `sw/device/lib/testing/testing/ottf_isrs.S` for more details.
+ uintptr_t *mepc_stack_addr = (uintptr_t *)OT_FRAME_ADDR();
+ ibex_exc_t exception = ibex_mcause_read();
+ switch (exception) {
+ case kIbexExcIllegalInstrFault:
+ LOG_INFO("Observed illegal instruction fault");
+ exception_observed = true;
+ *mepc_stack_addr = (uintptr_t)kSecMmioNegTestReturn;
+ break;
+ default:
+ LOG_FATAL("Unexpected exception id = 0x%x", exception);
+ abort();
+ }
+}
+
+void sec_mmio_neg_test(void) {
+ exception_expected = true;
+ sec_mmio_check_counters(0);
+ CHECK(false, "Should not be here");
+
+ OT_ADDRESSABLE_LABEL(kSecMmioNegTestReturn);
+ CHECK(exception_observed == true);
+}
+
+bool test_main(void) {
+ RUN_TEST(boot_measurements_test);
+ RUN_TEST(sec_mmio_pos_test);
+ RUN_TEST(sec_mmio_neg_test);
+ return true;
+}