| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #include "sw/device/lib/base/mmio.h" |
| #include "sw/device/lib/dif/dif_hmac.h" |
| #include "sw/device/lib/dif/dif_rv_plic.h" |
| #include "sw/device/lib/runtime/irq.h" |
| #include "sw/device/lib/runtime/log.h" |
| #include "sw/device/lib/testing/hmac_testutils.h" |
| #include "sw/device/lib/testing/rv_plic_testutils.h" |
| #include "sw/device/lib/testing/test_framework/check.h" |
| #include "sw/device/lib/testing/test_framework/ottf_main.h" |
| |
| #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" |
| #include "sw/device/lib/testing/autogen/isr_testutils.h" |
| |
| static plic_isr_ctx_t plic_ctx = { |
| .hart_id = kTopEarlgreyPlicTargetIbex0, |
| }; |
| |
| static top_earlgrey_plic_peripheral_t peripheral_serviced; |
| static dif_hmac_irq_t irq_serviced; |
| static hmac_isr_ctx_t hmac_ctx = { |
| .plic_hmac_start_irq_id = kTopEarlgreyPlicIrqIdHmacHmacDone, |
| .is_only_irq = false, |
| }; |
| |
| OTTF_DEFINE_TEST_CONFIG(); |
| |
| static const dif_hmac_transaction_t kHmacTransactionConfig = { |
| .digest_endianness = kDifHmacEndiannessLittle, |
| .message_endianness = kDifHmacEndiannessLittle, |
| }; |
| |
| /** |
| * External ISR. |
| * |
| * Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt |
| * line to the CPU, which results in a call to this OTTF ISR. This ISR |
| * overrides the default OTTF implementation. |
| */ |
| void ottf_external_isr(void) { |
| isr_testutils_hmac_isr(plic_ctx, hmac_ctx, &peripheral_serviced, |
| &irq_serviced); |
| } |
| |
| /** |
| * Enables interrupts required by this test. |
| */ |
| static void irqs_init(void) { |
| mmio_region_t base_addr = |
| mmio_region_from_addr(TOP_EARLGREY_RV_PLIC_BASE_ADDR); |
| CHECK_DIF_OK(dif_rv_plic_init(base_addr, plic_ctx.rv_plic)); |
| |
| // Enable interrupts in HMAC IP. |
| CHECK_DIF_OK(dif_hmac_irq_set_enabled(hmac_ctx.hmac, kDifHmacIrqHmacDone, |
| kDifToggleEnabled)); |
| CHECK_DIF_OK(dif_hmac_irq_set_enabled(hmac_ctx.hmac, kDifHmacIrqFifoEmpty, |
| kDifToggleEnabled)); |
| |
| // Enable interrupts in PLIC. |
| rv_plic_testutils_irq_range_enable(plic_ctx.rv_plic, plic_ctx.hart_id, |
| kTopEarlgreyPlicIrqIdHmacHmacDone, |
| kTopEarlgreyPlicIrqIdHmacFifoEmpty); |
| // Enable interrupts in Ibex. |
| irq_external_ctrl(true); |
| irq_global_ctrl(true); |
| } |
| |
| bool test_main(void) { |
| dif_hmac_t hmac; |
| dif_rv_plic_t plic; |
| plic_ctx.rv_plic = &plic; |
| hmac_ctx.hmac = &hmac; |
| |
| mmio_region_t base_addr = mmio_region_from_addr(TOP_EARLGREY_HMAC_BASE_ADDR); |
| CHECK_DIF_OK(dif_hmac_init(base_addr, &hmac)); |
| |
| irqs_init(); |
| |
| // Expect the fifo empty irq after pushing data. |
| hmac_ctx.expected_irq = kDifHmacIrqFifoEmpty; |
| irq_serviced = UINT32_MAX; |
| // Use HMAC in SHA256 mode to generate a 256bit key from `kHmacRefLongKey`. |
| CHECK_DIF_OK( |
| dif_hmac_mode_sha256_start(hmac_ctx.hmac, kHmacTransactionConfig)); |
| hmac_testutils_push_message(hmac_ctx.hmac, (char *)kHmacRefLongKey, |
| sizeof(kHmacRefLongKey)); |
| hmac_testutils_check_message_length(hmac_ctx.hmac, |
| sizeof(kHmacRefLongKey) * 8); |
| |
| // If the irq has't fired yet, wait for the `fifoEmpty` interrupt . |
| if (irq_serviced != hmac_ctx.expected_irq) { |
| wait_for_interrupt(); |
| } |
| CHECK(irq_serviced == hmac_ctx.expected_irq); |
| |
| // Expect the done irq after processing data. |
| hmac_ctx.expected_irq = kDifHmacIrqHmacDone; |
| irq_serviced = UINT32_MAX; |
| |
| CHECK_DIF_OK(dif_hmac_process(hmac_ctx.hmac)); |
| dif_hmac_digest_t key_digest; |
| hmac_testutils_finish_polled(hmac_ctx.hmac, &key_digest); |
| CHECK_ARRAYS_EQ(key_digest.digest, kHmacRefExpectedLongKeyDigest.digest, |
| ARRAYSIZE(key_digest.digest)); |
| |
| CHECK(irq_serviced == hmac_ctx.expected_irq); |
| |
| // Generate HMAC final digest, using the resulted SHA256 digest over the |
| // `kHmacRefLongKey`. |
| CHECK_DIF_OK(dif_hmac_mode_hmac_start( |
| hmac_ctx.hmac, (uint8_t *)&key_digest.digest[0], kHmacTransactionConfig)); |
| hmac_testutils_push_message(hmac_ctx.hmac, kHmacRefData, |
| sizeof(kHmacRefData)); |
| hmac_testutils_check_message_length(hmac_ctx.hmac, sizeof(kHmacRefData) * 8); |
| CHECK_DIF_OK(dif_hmac_process(hmac_ctx.hmac)); |
| LOG_INFO("Waiting for HMAC pooling to finish"); |
| hmac_testutils_finish_and_check_polled(hmac_ctx.hmac, |
| &kHmacRefExpectedDigest); |
| return true; |
| } |