|  | // 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; | 
|  | } |