blob: ac1523566bc306eb3c293d36de6f6b54884b237c [file] [log] [blame]
// 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/memory.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_aes.h"
#include "sw/device/lib/dif/dif_alert_handler.h"
#include "sw/device/lib/dif/dif_entropy_src.h"
#include "sw/device/lib/dif/dif_keymgr.h"
#include "sw/device/lib/dif/dif_kmac.h"
#include "sw/device/lib/dif/dif_otbn.h"
#include "sw/device/lib/dif/dif_otp_ctrl.h"
#include "sw/device/lib/dif/dif_pwrmgr.h"
#include "sw/device/lib/dif/dif_rv_core_ibex.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/aes_testutils.h"
#include "sw/device/lib/testing/alert_handler_testutils.h"
#include "sw/device/lib/testing/entropy_testutils.h"
#include "sw/device/lib/testing/keymgr_testutils.h"
#include "sw/device/lib/testing/otp_ctrl_testutils.h"
#include "sw/device/lib/testing/pwrmgr_testutils.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"
#include "sw/device/tests/otbn_randomness_impl.h"
#include "alert_handler_regs.h" // Generated.
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
static dif_aes_t aes;
static dif_csrng_t csrng;
static dif_edn_t edn0;
static dif_edn_t edn1;
static dif_entropy_src_t entropy_src;
static dif_kmac_t kmac;
static dif_keymgr_t kmgr;
static dif_otbn_t otbn;
static dif_otp_ctrl_t otp;
static dif_pwrmgr_t pwrmgr;
static dif_rv_core_ibex_t ibex;
static dif_alert_handler_t alert_handler;
static dif_rv_core_ibex_fpga_info_t fpga_info;
enum {
kFpgaLoop = 5,
};
OTTF_DEFINE_TEST_CONFIG();
/**
* Trigger an reseed operation.
*
* @param aes Aes dif handle.
*/
static void aes_test(const dif_aes_t *aes) {
LOG_INFO("%s", __func__);
dif_aes_transaction_t transaction = {
.operation = kDifAesOperationEncrypt,
.mode = kDifAesModeEcb,
.key_len = kDifAesKey128,
.key_provider = kDifAesKeySideload,
.mask_reseeding = kDifAesReseedPerBlock,
.manual_operation = kDifAesManualOperationManual,
.reseed_on_key_change = false,
.ctrl_aux_lock = false,
};
CHECK_DIF_OK(dif_aes_start(aes, &transaction, /*key=*/NULL, /*iv=*/NULL));
CHECK_DIF_OK(dif_aes_trigger(aes, kDifAesTriggerPrngReseed));
}
/**
* Configure the kmac to use entropy from edn to request entropy.
*/
static void kmac_test(dif_kmac_t *kmac) {
dif_kmac_operation_state_t kmac_operation_state;
LOG_INFO("%s", __func__);
dif_kmac_config_t config = (dif_kmac_config_t){
.entropy_mode = kDifKmacEntropyModeEdn,
.entropy_fast_process = kDifToggleDisabled,
};
CHECK_DIF_OK(dif_kmac_configure(kmac, config));
}
/**
* Configure the opt to request entropy from the edn.
*/
static void otp_ctrl_test(const dif_otp_ctrl_t *otp) {
LOG_INFO("%s", __func__);
// For security reasons, the LFSR is periodically reseeded with entropy coming
// from EDN. Setting the integrity period to a small value will make the
// otp_ctrl to fetch entropy from EDN.
dif_otp_ctrl_config_t config = {
.check_timeout = 100000,
.integrity_period_mask = 0x4,
.consistency_period_mask = 0x3ffffff,
};
CHECK_DIF_OK(dif_otp_ctrl_configure(otp, config));
otp_ctrl_testutils_wait_for_dai(otp);
}
/**
* Configure the reseed interval to a short period and
* advance to the `kDifKeymgrStateInitialized` to request entropy from the edn.
*/
static void keymgr_test(const dif_keymgr_t *kmgr) {
/**
* Key manager can only be tested once per boot.
*/
static bool tested = false;
if (!tested) {
LOG_INFO("%s", __func__);
dif_keymgr_config_t config = {.entropy_reseed_interval = 4};
CHECK_DIF_OK(dif_keymgr_configure(kmgr, config));
CHECK_DIF_OK(dif_keymgr_advance_state(kmgr, NULL));
tested = true;
}
}
/**
* Read 4 words of rnd data to request entropy from the edn.
*/
static void ibex_test(const dif_rv_core_ibex_t *ibex) {
LOG_INFO("%s", __func__);
for (size_t i = 0; i < 4; i++) {
uint32_t rnd;
CHECK_DIF_OK(dif_rv_core_ibex_read_rnd_data(ibex, &rnd));
}
}
/**
* Configure the `alert_handler`to escalate up to phase 0.
*/
static void alert_handler_configure(const dif_alert_handler_t *alert_handler) {
LOG_INFO("%s", __func__);
dif_alert_handler_local_alert_t loc_alerts[] = {
kDifAlertHandlerLocalAlertAlertPingFail};
dif_alert_handler_class_t loc_alert_classes[] = {kDifAlertHandlerClassB};
dif_alert_handler_escalation_phase_t esc_phases[] = {
{.phase = kDifAlertHandlerClassStatePhase0,
.signal = 0,
.duration_cycles = 2000}};
dif_alert_handler_class_config_t class_config = {
.auto_lock_accumulation_counter = kDifToggleDisabled,
.accumulator_threshold = 0,
.irq_deadline_cycles = 10000,
.escalation_phases = esc_phases,
.escalation_phases_len = ARRAYSIZE(esc_phases),
.crashdump_escalation_phase = kDifAlertHandlerClassStatePhase1,
};
dif_alert_handler_class_config_t class_configs[] = {class_config,
class_config};
dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA,
kDifAlertHandlerClassB};
dif_alert_handler_config_t config = {
.alerts = NULL,
.alert_classes = NULL,
.alerts_len = 0,
.local_alerts = loc_alerts,
.local_alert_classes = loc_alert_classes,
.local_alerts_len = ARRAYSIZE(loc_alerts),
.classes = classes,
.class_configs = class_configs,
.classes_len = ARRAYSIZE(class_configs),
.ping_timeout = 10,
};
alert_handler_testutils_configure_all(alert_handler, config,
kDifToggleEnabled);
}
/**
* Trigger fault in the pwrmgr in order to escalate the alert handler.
*/
static void alert_handler_test(const dif_pwrmgr_t *pwrmgr) {
LOG_INFO("%s", __func__);
dif_pwrmgr_alert_t alert = kDifPwrmgrAlertFatalFault;
CHECK_DIF_OK(dif_pwrmgr_alert_force(pwrmgr, alert));
}
void test_initialize(void) {
CHECK_DIF_OK(dif_entropy_src_init(
mmio_region_from_addr(TOP_EARLGREY_ENTROPY_SRC_BASE_ADDR), &entropy_src));
CHECK_DIF_OK(dif_csrng_init(
mmio_region_from_addr(TOP_EARLGREY_CSRNG_BASE_ADDR), &csrng));
CHECK_DIF_OK(
dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR), &edn0));
CHECK_DIF_OK(
dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN1_BASE_ADDR), &edn1));
CHECK_DIF_OK(dif_rv_core_ibex_init(
mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &ibex));
CHECK_DIF_OK(dif_pwrmgr_init(
mmio_region_from_addr(TOP_EARLGREY_PWRMGR_AON_BASE_ADDR), &pwrmgr));
CHECK_DIF_OK(dif_keymgr_init(
mmio_region_from_addr(TOP_EARLGREY_KEYMGR_BASE_ADDR), &kmgr));
CHECK_DIF_OK(
dif_otbn_init(mmio_region_from_addr(TOP_EARLGREY_OTBN_BASE_ADDR), &otbn));
CHECK_DIF_OK(dif_otp_ctrl_init(
mmio_region_from_addr(TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR), &otp));
CHECK_DIF_OK(
dif_aes_init(mmio_region_from_addr(TOP_EARLGREY_AES_BASE_ADDR), &aes));
CHECK_DIF_OK(
dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac));
CHECK_DIF_OK(dif_alert_handler_init(
mmio_region_from_addr(TOP_EARLGREY_ALERT_HANDLER_BASE_ADDR),
&alert_handler));
}
/**
* TODO: Run the test entropy src end reqs in continuous mode
* (https://github.com/lowRISC/opentitan/issues/13393)
*/
bool test_main() {
test_initialize();
alert_handler_configure(&alert_handler);
entropy_testutils_auto_mode_init();
// ensure health tests are actually running
entropy_testutils_wait_for_state(&entropy_src,
kDifEntropySrcMainFsmStateContHTRunning);
CHECK_DIF_OK(dif_rv_core_ibex_read_fpga_info(&ibex, &fpga_info));
uint32_t loop = (fpga_info != 0) ? kFpgaLoop : 1;
for (size_t i = 0; i < loop; ++i) {
LOG_INFO("Entropy src test %d/%d", i, loop);
alert_handler_test(&pwrmgr);
aes_test(&aes);
otbn_randomness_test_start(&otbn);
keymgr_test(&kmgr);
otp_ctrl_test(&otp);
kmac_test(&kmac);
ibex_test(&ibex);
AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusIdle, /*value=*/true,
/*timeout_usec=*/100000);
CHECK(otbn_randomness_test_end(&otbn, /*skip_otbn_done_check=*/false));
keymgr_testutils_wait_for_operation_done(&kmgr);
keymgr_testutils_check_state(&kmgr, kDifKeymgrStateInitialized);
entropy_testutils_error_check(&entropy_src, &csrng, &edn0, &edn1);
}
return true;
}