blob: ee46939a3b4569968b39d36d257378aa73dc6514 [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 "hw/ip/aes/model/aes_modes.h"
#include "sw/device/lib/base/math.h"
#include "sw/device/lib/base/multibits.h"
#include "sw/device/lib/crypto/drivers/otbn.h"
#include "sw/device/lib/crypto/impl/rsa_3072/rsa_3072_verify.h"
#include "sw/device/lib/dif/dif_adc_ctrl.h"
#include "sw/device/lib/dif/dif_aes.h"
#include "sw/device/lib/dif/dif_csrng.h"
#include "sw/device/lib/dif/dif_csrng_shared.h"
#include "sw/device/lib/dif/dif_edn.h"
#include "sw/device/lib/dif/dif_entropy_src.h"
#include "sw/device/lib/dif/dif_flash_ctrl.h"
#include "sw/device/lib/dif/dif_gpio.h"
#include "sw/device/lib/dif/dif_hmac.h"
#include "sw/device/lib/dif/dif_i2c.h"
#include "sw/device/lib/dif/dif_kmac.h"
#include "sw/device/lib/dif/dif_otbn.h"
#include "sw/device/lib/dif/dif_pattgen.h"
#include "sw/device/lib/dif/dif_pinmux.h"
#include "sw/device/lib/dif/dif_pwm.h"
#include "sw/device/lib/dif/dif_rv_plic.h"
#include "sw/device/lib/dif/dif_spi_device.h"
#include "sw/device/lib/dif/dif_spi_host.h"
#include "sw/device/lib/dif/dif_uart.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/aes_testutils.h"
#include "sw/device/lib/testing/entropy_testutils.h"
#include "sw/device/lib/testing/hmac_testutils.h"
#include "sw/device/lib/testing/i2c_testutils.h"
#include "sw/device/lib/testing/pinmux_testutils.h"
#include "sw/device/lib/testing/spi_device_testutils.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_macros.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"
#include "adc_ctrl_regs.h" // Generated.
#include "aes_regs.h" // Generated.
#include "csrng_regs.h" // Generated.
#include "entropy_src_regs.h" // Generated.
#include "gpio_regs.h" // Generated.
#include "hmac_regs.h" // Generated.
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
#include "i2c_regs.h" // Generated.
#include "kmac_regs.h" // Generated.
#include "pattgen_regs.h" // Generated.
#include "pwm_regs.h" // Generated.
#include "spi_host_regs.h" // Generated.
#include "uart_regs.h" // Generated.
// The autogen rule that creates this header creates it in a directory named
// after the rule, then manipulates the include path in the
// cc_compilation_context to include that directory, so the compiler will find
// the version of this file matching the Bazel rule under test.
#include "rsa_3072_verify_testvectors.h"
OTTF_DEFINE_TEST_CONFIG(.enable_concurrency = true,
.enable_uart_flow_control = true,
.can_clobber_uart = false, );
/**
* Peripheral DIF Handles.
*/
static dif_pinmux_t pinmux;
static dif_gpio_t gpio;
static dif_adc_ctrl_t adc_ctrl;
static dif_entropy_src_t entropy_src;
static dif_csrng_t csrng;
static dif_edn_t edn_0;
static dif_edn_t edn_1;
static dif_aes_t aes;
static dif_hmac_t hmac;
static dif_kmac_t kmac;
static dif_otbn_t otbn;
static dif_i2c_t i2c_0;
static dif_i2c_t i2c_1;
static dif_i2c_t i2c_2;
static dif_spi_device_handle_t spi_device;
static dif_spi_host_t spi_host_0;
static dif_spi_host_t spi_host_1;
static dif_uart_t uart_1;
static dif_uart_t uart_2;
static dif_uart_t uart_3;
static dif_pattgen_t pattgen;
static dif_pwm_t pwm;
static dif_flash_ctrl_state_t flash_ctrl;
static dif_rv_plic_t rv_plic;
static const dif_i2c_t *i2c_handles[] = {&i2c_0, &i2c_1, &i2c_2};
static const dif_uart_t *uart_handles[] = {&uart_1, &uart_2, &uart_3};
static dif_kmac_operation_state_t kmac_operation_state;
static const dif_pattgen_channel_t pattgen_channels[] = {kDifPattgenChannel0,
kDifPattgenChannel1};
static const dif_pwm_channel_t pwm_channels[PWM_PARAM_N_OUTPUTS] = {
kDifPwmChannel0, kDifPwmChannel1, kDifPwmChannel2,
kDifPwmChannel3, kDifPwmChannel4, kDifPwmChannel5,
};
/**
* Test configuration parameters.
*/
enum {
/**
* Test timeout parameter.
*/
kTestTimeoutMicros = 1000, // 1ms
/**
* ADC controller parameters.
*/
kAdcCtrlPowerUpTimeAonCycles = 15, // maximum power-up time
/**
* Entropy Source parameters.
*/
kEntropySrcHealthTestWindowSize = 0x60,
kEntropySrcAdaptiveProportionHealthTestHighThreshold = 0x50,
kEntropySrcAdaptiveProportionHealthTestLowThreshold = 0x10,
/**
* EDN parameters.
*/
kEdn0SeedMaterialNumWords = 0,
kEdn1SeedMaterialNumWords = 12,
kEdn0ReseedInterval = 128,
kEdn1ReseedInterval = 32,
/**
* KMAC parameters.
*/
kKmacEntropyReseedInterval = 1,
kKmacEntropyHashThreshold = 1, // KMAC operations between entropy requests
kKmacEntropyWaitTimer = 0xffff,
kKmacEntropyPrescaler = 0x3ff,
kKmacMessageLength = 200,
kKmacDigestLength = 16,
/**
* I2C parameters.
*/
kI2cSdaRiseFallTimeNs = 10,
kI2cDeviceMask = 0x7f,
kI2c0DeviceAddress0 = 0x11,
kI2c0DeviceAddress1 = 0x22,
kI2c1DeviceAddress0 = 0x33,
kI2c1DeviceAddress1 = 0x44,
kI2c2DeviceAddress0 = 0x55,
kI2c2DeviceAddress1 = 0x66,
kI2c0TargetAddress = 0x01,
kI2c1TargetAddress = 0x02,
kI2c2TargetAddress = 0x03,
/**
* UART parameters.
*/
kUartFifoDepth = 32,
/**
* Pattern Generator parameters.
*/
kPattgenClockDivisor = 0,
kPattgenSeedPatternLowerWord = 0xaaaaaaaa,
kPattgenSeedPatternUpperWord = 0xaaaaaaaa,
kPattgenSeedPatternLength = 64,
kPattgenNumPatternRepetitions = 1024,
/**
* PWM parameters.
*/
kPwmClockDivisor = 1,
kPwmBeatsPerCycle = 2,
kPwmOnBeats = 1,
kPwmPhaseDelayBeats = 0,
/**
* SPI Host parameters.
*/
kSpiHost1Csid = 0xaabbaabb,
kSpiHost1TxDataWord = 0xaaaaaaaa,
};
static uint32_t csrng_reseed_cmd_header;
/**
* These symbols are meant to be backdoor read by the testbench. Due to current
* DV infrastructure limitations, these must be `volatile const` to be accessed
* by the testbench.
*/
static volatile const uint32_t kI2cSclPeriodNs = 1000;
static volatile uint32_t peripheral_clock_period_ns;
/**
* Pinmux pad configurations.
*/
static const pinmux_pad_attributes_t pinmux_pad_attributes[] = {
// Enable pull-ups for spi_host_0 data pins to avoid floating inputs.
{
.pad = kTopEarlgreyDirectPadsSpiHost0Sd0,
.kind = kDifPinmuxPadKindDio,
.flags = kDifPinmuxPadAttrPullResistorEnable |
kDifPinmuxPadAttrPullResistorUp,
},
{
.pad = kTopEarlgreyDirectPadsSpiHost0Sd1,
.kind = kDifPinmuxPadKindDio,
.flags = kDifPinmuxPadAttrPullResistorEnable |
kDifPinmuxPadAttrPullResistorUp,
},
{
.pad = kTopEarlgreyDirectPadsSpiHost0Sd2,
.kind = kDifPinmuxPadKindDio,
.flags = kDifPinmuxPadAttrPullResistorEnable |
kDifPinmuxPadAttrPullResistorUp,
},
{
.pad = kTopEarlgreyDirectPadsSpiHost0Sd3,
.kind = kDifPinmuxPadKindDio,
.flags = kDifPinmuxPadAttrPullResistorEnable |
kDifPinmuxPadAttrPullResistorUp,
},
// Enable pull-ups for spi_host_1 data pins to avoid floating inputs.
{
.pad = kTopEarlgreyMuxedPadsIoa2, // SD0
.kind = kDifPinmuxPadKindMio,
.flags = kDifPinmuxPadAttrPullResistorEnable |
kDifPinmuxPadAttrPullResistorUp,
},
{
.pad = kTopEarlgreyMuxedPadsIor11, // SD1
.kind = kDifPinmuxPadKindMio,
.flags = kDifPinmuxPadAttrPullResistorEnable |
kDifPinmuxPadAttrPullResistorUp,
},
{
.pad = kTopEarlgreyMuxedPadsIor12, // SD2
.kind = kDifPinmuxPadKindMio,
.flags = kDifPinmuxPadAttrPullResistorEnable |
kDifPinmuxPadAttrPullResistorUp,
},
{
.pad = kTopEarlgreyMuxedPadsIor13, // SD3
.kind = kDifPinmuxPadKindMio,
.flags = kDifPinmuxPadAttrPullResistorEnable |
kDifPinmuxPadAttrPullResistorUp,
},
};
/**
* The mask share, used to mask kAesKey.
*/
static const uint8_t kAesKeyShare1[] = {
0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f, 0x8f, 0x9f, 0xaf,
0xbf, 0xcf, 0xdf, 0xef, 0xff, 0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a,
0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa,
};
static const dif_kmac_key_t kKmacKey = {
.share0 = {0x43424140, 0x47464544, 0x4B4A4948, 0x4F4E4D4C, 0x53525150,
0x57565554, 0x5B5A5958, 0x5F5E5D5C},
.share1 = {0},
.length = kDifKmacKeyLen256,
};
static const char *kKmacMessage =
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7";
static const uint32_t kKmacDigest[] = {
0xF71886B5, 0xD5E1921F, 0x558C1B6C, 0x18CDD7DD, 0xCAB4978B, 0x1E83994D,
0x839A69B2, 0xD9E4A27D, 0xFDACFB70, 0xAE3300E5, 0xA2F185A5, 0xC3108570,
0x0888072D, 0x2818BD01, 0x6847FE98, 0x6589FC76};
static rsa_3072_verify_test_vector_t rsa3072_test_vector;
static rsa_3072_int_t rsa3072_encoded_message;
static rsa_3072_constants_t rsa3072_constants;
static const uint8_t kUartMessage[] = {
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
};
static const uint8_t kI2cMessage[] = {
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
};
static void log_entropy_src_alert_failures(void) {
dif_entropy_src_alert_fail_counts_t counts;
CHECK_DIF_OK(dif_entropy_src_get_alert_fail_counts(&entropy_src, &counts));
LOG_INFO("Entropy source health test failure encountered.");
LOG_INFO("Total Fails: %d", counts.total_fails);
for (size_t i = 0; i < kDifEntropySrcTestNumVariants; ++i) {
switch (i) {
case kDifEntropySrcTestRepetitionCount:
LOG_INFO("Fails (Repetition Count): %d", counts.high_fails[i]);
break;
case kDifEntropySrcTestRepetitionCountSymbol:
LOG_INFO("Fails (Repetition Symbol Count): %d", counts.high_fails[i]);
break;
case kDifEntropySrcTestAdaptiveProportion:
LOG_INFO("High Fails (Adaptive Proportion): %d", counts.high_fails[i]);
LOG_INFO("Low Fails (Adaptive Proportion): %d", counts.low_fails[i]);
break;
case kDifEntropySrcTestBucket:
LOG_INFO("Fails (Bucket): %d", counts.high_fails[i]);
break;
case kDifEntropySrcTestMarkov:
LOG_INFO("High Fails (Markov): %d", counts.high_fails[i]);
LOG_INFO("Low Fails (Markov): %d", counts.low_fails[i]);
break;
case kDifEntropySrcTestMailbox:
LOG_INFO("High Fails (Mailbox): %d", counts.high_fails[i]);
LOG_INFO("Low Fails (Mailbox): %d", counts.low_fails[i]);
break;
}
}
}
/**
* External (OTTF) ISR override.
*/
void ottf_external_isr(void) {
// Find which interrupt fired at PLIC by claiming it.
dif_rv_plic_irq_id_t irq_id;
CHECK_DIF_OK(
dif_rv_plic_irq_claim(&rv_plic, kTopEarlgreyPlicTargetIbex0, &irq_id));
top_earlgrey_plic_peripheral_t periph =
top_earlgrey_plic_interrupt_for_peripheral[irq_id];
switch (periph) {
case kTopEarlgreyPlicPeripheralEntropySrc:
log_entropy_src_alert_failures();
CHECK(false);
break;
default:
CHECK(false, "Unexpected IRQ fired with ID: %d", irq_id);
break;
}
}
/**
* Initializes all DIF handles for each peripheral used in this test.
*/
static void init_peripheral_handles(void) {
CHECK_DIF_OK(dif_adc_ctrl_init(
mmio_region_from_addr(TOP_EARLGREY_ADC_CTRL_AON_BASE_ADDR), &adc_ctrl));
CHECK_DIF_OK(
dif_aes_init(mmio_region_from_addr(TOP_EARLGREY_AES_BASE_ADDR), &aes));
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), &edn_0));
CHECK_DIF_OK(
dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN1_BASE_ADDR), &edn_1));
CHECK_DIF_OK(dif_entropy_src_init(
mmio_region_from_addr(TOP_EARLGREY_ENTROPY_SRC_BASE_ADDR), &entropy_src));
CHECK_DIF_OK(
dif_hmac_init(mmio_region_from_addr(TOP_EARLGREY_HMAC_BASE_ADDR), &hmac));
CHECK_DIF_OK(
dif_gpio_init(mmio_region_from_addr(TOP_EARLGREY_GPIO_BASE_ADDR), &gpio));
CHECK_DIF_OK(
dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac));
CHECK_DIF_OK(dif_pinmux_init(
mmio_region_from_addr(TOP_EARLGREY_PINMUX_AON_BASE_ADDR), &pinmux));
// UART 0 is already configured (and used) by the OTTF.
CHECK_DIF_OK(dif_uart_init(
mmio_region_from_addr(TOP_EARLGREY_UART1_BASE_ADDR), &uart_1));
CHECK_DIF_OK(dif_uart_init(
mmio_region_from_addr(TOP_EARLGREY_UART2_BASE_ADDR), &uart_2));
CHECK_DIF_OK(dif_uart_init(
mmio_region_from_addr(TOP_EARLGREY_UART3_BASE_ADDR), &uart_3));
CHECK_DIF_OK(
dif_i2c_init(mmio_region_from_addr(TOP_EARLGREY_I2C0_BASE_ADDR), &i2c_0));
CHECK_DIF_OK(
dif_i2c_init(mmio_region_from_addr(TOP_EARLGREY_I2C1_BASE_ADDR), &i2c_1));
CHECK_DIF_OK(
dif_i2c_init(mmio_region_from_addr(TOP_EARLGREY_I2C2_BASE_ADDR), &i2c_2));
CHECK_DIF_OK(dif_spi_device_init_handle(
mmio_region_from_addr(TOP_EARLGREY_SPI_DEVICE_BASE_ADDR), &spi_device));
CHECK_DIF_OK(dif_spi_host_init(
mmio_region_from_addr(TOP_EARLGREY_SPI_HOST0_BASE_ADDR), &spi_host_0));
CHECK_DIF_OK(dif_spi_host_init(
mmio_region_from_addr(TOP_EARLGREY_SPI_HOST1_BASE_ADDR), &spi_host_1));
CHECK_DIF_OK(
dif_otbn_init(mmio_region_from_addr(TOP_EARLGREY_OTBN_BASE_ADDR), &otbn));
CHECK_DIF_OK(dif_pattgen_init(
mmio_region_from_addr(TOP_EARLGREY_PATTGEN_BASE_ADDR), &pattgen));
CHECK_DIF_OK(dif_pwm_init(
mmio_region_from_addr(TOP_EARLGREY_PWM_AON_BASE_ADDR), &pwm));
CHECK_DIF_OK(dif_flash_ctrl_init_state(
&flash_ctrl,
mmio_region_from_addr(TOP_EARLGREY_FLASH_CTRL_CORE_BASE_ADDR)));
CHECK_DIF_OK(dif_rv_plic_init(
mmio_region_from_addr(TOP_EARLGREY_RV_PLIC_BASE_ADDR), &rv_plic));
}
static void configure_pinmux(void) {
// Configure UART0 (console) and SW strapping pins.
pinmux_testutils_init(&pinmux);
// Configure GPIO max-power period indicator pin on IOA2
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIoa2,
kTopEarlgreyPinmuxOutselGpioGpio0));
// UART1:
// RX on IOA4
// TX on IOA5
CHECK_DIF_OK(dif_pinmux_input_select(&pinmux,
kTopEarlgreyPinmuxPeripheralInUart1Rx,
kTopEarlgreyPinmuxInselIoa4));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIoa4,
kTopEarlgreyPinmuxOutselConstantHighZ));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIoa5,
kTopEarlgreyPinmuxOutselUart1Tx));
// UART2:
// RX on IOB4
// TX on IOB5
CHECK_DIF_OK(dif_pinmux_input_select(&pinmux,
kTopEarlgreyPinmuxPeripheralInUart2Rx,
kTopEarlgreyPinmuxInselIob4));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIob4,
kTopEarlgreyPinmuxOutselConstantHighZ));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIob5,
kTopEarlgreyPinmuxOutselUart2Tx));
// UART3:
// RX on IOA0
// TX on IOA1
CHECK_DIF_OK(dif_pinmux_input_select(&pinmux,
kTopEarlgreyPinmuxPeripheralInUart3Rx,
kTopEarlgreyPinmuxInselIoa0));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIoa0,
kTopEarlgreyPinmuxOutselConstantHighZ));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIoa1,
kTopEarlgreyPinmuxOutselUart3Tx));
// I2C0:
// SDA on IOA7
// SCL on IOA8
CHECK_DIF_OK(dif_pinmux_input_select(&pinmux,
kTopEarlgreyPinmuxPeripheralInI2c0Sda,
kTopEarlgreyPinmuxInselIoa7));
CHECK_DIF_OK(dif_pinmux_input_select(&pinmux,
kTopEarlgreyPinmuxPeripheralInI2c0Scl,
kTopEarlgreyPinmuxInselIoa8));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIoa7,
kTopEarlgreyPinmuxOutselI2c0Sda));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIoa8,
kTopEarlgreyPinmuxOutselI2c0Scl));
// I2C1:
// SDA on IOB9
// SCL on IOB10
CHECK_DIF_OK(dif_pinmux_input_select(&pinmux,
kTopEarlgreyPinmuxPeripheralInI2c1Sda,
kTopEarlgreyPinmuxInselIob9));
CHECK_DIF_OK(dif_pinmux_input_select(&pinmux,
kTopEarlgreyPinmuxPeripheralInI2c1Scl,
kTopEarlgreyPinmuxInselIob10));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIob9,
kTopEarlgreyPinmuxOutselI2c1Sda));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIob10,
kTopEarlgreyPinmuxOutselI2c1Scl));
// I2C2:
// SDA on IOB11
// SCL on IOB12
CHECK_DIF_OK(dif_pinmux_input_select(&pinmux,
kTopEarlgreyPinmuxPeripheralInI2c2Sda,
kTopEarlgreyPinmuxInselIob11));
CHECK_DIF_OK(dif_pinmux_input_select(&pinmux,
kTopEarlgreyPinmuxPeripheralInI2c2Scl,
kTopEarlgreyPinmuxInselIob12));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIob11,
kTopEarlgreyPinmuxOutselI2c2Sda));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIob12,
kTopEarlgreyPinmuxOutselI2c2Scl));
// Enable pull-ups for SPI_HOST_0/1 data pins to avoid floating inputs.
if (kDeviceType == kDeviceSimDV || kDeviceType == kDeviceSimVerilator) {
pinmux_testutils_configure_pads(&pinmux, pinmux_pad_attributes,
ARRAYSIZE(pinmux_pad_attributes));
}
// PATTGEN:
// Channel 0 PDA on IOR0
// Channel 0 PCL on IOR1
// Channel 1 PDA on IOR2
// Channel 1 PCL on IOR3
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIor0,
kTopEarlgreyPinmuxOutselPattgenPda0Tx));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIor1,
kTopEarlgreyPinmuxOutselPattgenPcl0Tx));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIor2,
kTopEarlgreyPinmuxOutselPattgenPda1Tx));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIor3,
kTopEarlgreyPinmuxOutselPattgenPcl1Tx));
// PWM:
// Channel 0 on IOB1
// Channel 1 on IOB2
// Channel 2 on IOR5
// Channel 3 on IOR6
// Channel 4 on IOR7
// Channel 5 on IOR10
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIob1,
kTopEarlgreyPinmuxOutselPwmAonPwm0));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIob2,
kTopEarlgreyPinmuxOutselPwmAonPwm1));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIor5,
kTopEarlgreyPinmuxOutselPwmAonPwm2));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIor6,
kTopEarlgreyPinmuxOutselPwmAonPwm3));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIor7,
kTopEarlgreyPinmuxOutselPwmAonPwm4));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIor10,
kTopEarlgreyPinmuxOutselPwmAonPwm5));
// SPI Host 1:
// CSB on IOB0
// SCK on IOB3
// SD0 on IOA2
// SD1 on IOR11
// SD2 on IOR12
// SD3 on IOR13
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIob0,
kTopEarlgreyPinmuxOutselSpiHost1Csb));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIob3,
kTopEarlgreyPinmuxOutselSpiHost1Sck));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIoa2,
kTopEarlgreyPinmuxOutselSpiHost1Sd0));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIor11,
kTopEarlgreyPinmuxOutselSpiHost1Sd1));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIor12,
kTopEarlgreyPinmuxOutselSpiHost1Sd1));
CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kTopEarlgreyPinmuxMioOutIor13,
kTopEarlgreyPinmuxOutselSpiHost1Sd1));
CHECK_DIF_OK(dif_pinmux_input_select(
&pinmux, kTopEarlgreyPinmuxPeripheralInSpiHost1Sd0,
kTopEarlgreyPinmuxInselIoa2));
CHECK_DIF_OK(dif_pinmux_input_select(
&pinmux, kTopEarlgreyPinmuxPeripheralInSpiHost1Sd1,
kTopEarlgreyPinmuxInselIor11));
CHECK_DIF_OK(dif_pinmux_input_select(
&pinmux, kTopEarlgreyPinmuxPeripheralInSpiHost1Sd2,
kTopEarlgreyPinmuxInselIor12));
CHECK_DIF_OK(dif_pinmux_input_select(
&pinmux, kTopEarlgreyPinmuxPeripheralInSpiHost1Sd3,
kTopEarlgreyPinmuxInselIor13));
}
/**
* Configures adc_ctrl to continuously sample data (applying all filters across
* both channels) in normal power mode, which is the most power intensive
* sampling mode.
*/
static void configure_adc_ctrl_to_continuously_sample(void) {
CHECK_DIF_OK(dif_adc_ctrl_configure(
&adc_ctrl,
(dif_adc_ctrl_config_t){
.mode = kDifAdcCtrlNormalPowerScanMode,
.power_up_time_aon_cycles = kAdcCtrlPowerUpTimeAonCycles,
// Below configurations are unused, so set them to their reset
// values.
.wake_up_time_aon_cycles = ADC_CTRL_ADC_PD_CTL_WAKEUP_TIME_MASK,
.num_low_power_samples = ADC_CTRL_ADC_LP_SAMPLE_CTL_REG_RESVAL,
.num_normal_power_samples = ADC_CTRL_ADC_SAMPLE_CTL_REG_RESVAL,
}));
for (size_t filter = 0; filter < ADC_CTRL_PARAM_NUM_ADC_FILTER; ++filter) {
for (size_t channel = 0; channel < ADC_CTRL_PARAM_NUM_ADC_CHANNEL;
++channel) {
CHECK_DIF_OK(dif_adc_ctrl_configure_filter(
&adc_ctrl, (dif_adc_ctrl_channel_t)channel,
(dif_adc_ctrl_filter_config_t){
.filter = (dif_adc_ctrl_filter_t)filter,
// Set max range.
.min_voltage = 0,
.max_voltage = ADC_CTRL_ADC_CHN0_FILTER_CTL_0_MAX_V_0_MASK,
.in_range = true,
.generate_wakeup_on_match = false,
.generate_irq_on_match = false,
},
kDifToggleEnabled));
}
}
}
static void configure_entropy_complex(void) {
// The (test) ROM enables the entropy complex, and to reconfigure it
// requires temporarily disabling it.
entropy_testutils_stop_all();
// Enable entropy_src interrupts for health-test alert detection.
CHECK_DIF_OK(dif_rv_plic_irq_set_priority(
&rv_plic, kTopEarlgreyPlicIrqIdEntropySrcEsHealthTestFailed, 0x1));
CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
&rv_plic, kTopEarlgreyPlicIrqIdEntropySrcEsHealthTestFailed,
kTopEarlgreyPlicTargetIbex0, kDifToggleEnabled));
CHECK_DIF_OK(dif_entropy_src_irq_set_enabled(
&entropy_src, kDifEntropySrcIrqEsHealthTestFailed, kDifToggleEnabled));
// Configure entropy_src and health tests.
CHECK_DIF_OK(dif_entropy_src_health_test_configure(
&entropy_src, (dif_entropy_src_health_test_config_t){
.test_type = kDifEntropySrcTestRepetitionCount,
.high_threshold = 0xf,
.low_threshold = 0}));
CHECK_DIF_OK(dif_entropy_src_health_test_configure(
&entropy_src, (dif_entropy_src_health_test_config_t){
.test_type = kDifEntropySrcTestRepetitionCountSymbol,
.high_threshold = 0xf,
.low_threshold = 0}));
CHECK_DIF_OK(dif_entropy_src_health_test_configure(
&entropy_src,
(dif_entropy_src_health_test_config_t){
.test_type = kDifEntropySrcTestAdaptiveProportion,
.high_threshold =
kEntropySrcAdaptiveProportionHealthTestHighThreshold,
.low_threshold =
kEntropySrcAdaptiveProportionHealthTestLowThreshold}));
CHECK_DIF_OK(dif_entropy_src_health_test_configure(
&entropy_src, (dif_entropy_src_health_test_config_t){
.test_type = kDifEntropySrcTestBucket,
.high_threshold = 0xff,
.low_threshold = 0}));
CHECK_DIF_OK(dif_entropy_src_health_test_configure(
&entropy_src, (dif_entropy_src_health_test_config_t){
.test_type = kDifEntropySrcTestMarkov,
.high_threshold = 0xff,
.low_threshold = 0}));
CHECK_DIF_OK(dif_entropy_src_fw_override_configure(
&entropy_src,
(dif_entropy_src_fw_override_config_t){
.entropy_insert_enable = false,
.buffer_threshold = ENTROPY_SRC_OBSERVE_FIFO_THRESH_REG_RESVAL,
},
kDifToggleDisabled));
CHECK_DIF_OK(dif_entropy_src_configure(
&entropy_src,
(dif_entropy_src_config_t){
.fips_enable = true,
.route_to_firmware = false,
.bypass_conditioner = false,
.single_bit_mode = kDifEntropySrcSingleBitModeDisabled,
.health_test_threshold_scope = false,
.health_test_window_size = kEntropySrcHealthTestWindowSize,
.alert_threshold = UINT16_MAX},
kDifToggleEnabled));
// Configure CSRNG and create reseed command header for later use during max
// power epoch.
CHECK_DIF_OK(dif_csrng_configure(&csrng));
csrng_reseed_cmd_header = csrng_cmd_header_build(
kCsrngAppCmdReseed, kDifCsrngEntropySrcToggleEnable, /*cmd_len=*/0,
/*generate_len=*/0);
// Configure EDNs in auto mode.
dif_edn_seed_material_t edn_empty_seed = {
.len = kEdn0SeedMaterialNumWords,
};
dif_edn_seed_material_t edn_384_bit_seed = {
.len = kEdn1SeedMaterialNumWords,
.data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
};
dif_edn_auto_params_t edn_auto_params = {
.instantiate_cmd =
{
.cmd = csrng_cmd_header_build(kCsrngAppCmdInstantiate,
kDifCsrngEntropySrcToggleEnable,
/*cmd_len=*/edn_384_bit_seed.len,
/*generate_len=*/0),
.seed_material = edn_384_bit_seed,
},
.reseed_cmd =
{
.cmd = csrng_cmd_header_build(
kCsrngAppCmdReseed, kDifCsrngEntropySrcToggleEnable,
/*cmd_len=*/edn_384_bit_seed.len, /*generate_len=*/0),
.seed_material = edn_384_bit_seed,
},
.generate_cmd =
{
.cmd = csrng_cmd_header_build(kCsrngAppCmdGenerate,
kDifCsrngEntropySrcToggleEnable,
/*cmd_len=*/0,
/*generate_len=*/4096),
.seed_material = edn_empty_seed,
},
.reseed_interval = 0,
};
// EDN0 provides lower-quality entropy. Let one generate command return
// eight 128-bit blocks, and reseed every 128 generates.
edn_auto_params.reseed_interval = kEdn0ReseedInterval;
CHECK_DIF_OK(dif_edn_set_auto_mode(&edn_0, edn_auto_params));
// EDN1 provides higher-quality entropy. Let one generate command return
// eight 128-bit blocks, and reseed every 32 generates.
edn_auto_params.reseed_interval = kEdn1ReseedInterval;
CHECK_DIF_OK(dif_edn_set_auto_mode(&edn_1, edn_auto_params));
CHECK_DIF_OK(dif_edn_configure(&edn_0));
CHECK_DIF_OK(dif_edn_configure(&edn_1));
}
static void configure_aes(void) {
// Prepare and load AES key shares.
uint8_t aes_key_share0[sizeof(kAesModesKey256)];
for (size_t i = 0; i < sizeof(kAesModesKey256); ++i) {
aes_key_share0[i] = kAesModesKey256[i] ^ kAesKeyShare1[i];
}
dif_aes_key_share_t aes_key;
memcpy(aes_key.share0, aes_key_share0, sizeof(aes_key.share0));
memcpy(aes_key.share1, kAesKeyShare1, sizeof(aes_key.share1));
// Prepare and load AES IV.
dif_aes_iv_t aes_iv;
memcpy(aes_iv.iv, kAesModesIvCbc, sizeof(aes_iv.iv));
// Setup AES in automatic, 256-bit SW provided key, CBC encryption mode.
// Additionally, we want to keep the entropy complex busing by constantly
// reseeding PRNGs.
dif_aes_transaction_t aes_transaction_cfg = {
.operation = kDifAesOperationEncrypt,
.mode = kDifAesModeCbc,
.key_len = kDifAesKey256,
.key_provider = kDifAesKeySoftwareProvided,
.mask_reseeding = kDifAesReseedPerBlock,
.manual_operation = kDifAesManualOperationManual,
.reseed_on_key_change = false,
.ctrl_aux_lock = false,
};
// Start the AES operation. Since we are in manual-mode, the encryption will
// not start until plain text data is loaded into the appropriate CSRs, and
// the encryption operation is triggered.
AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusIdle, true,
kTestTimeoutMicros);
CHECK_DIF_OK(dif_aes_start(&aes, &aes_transaction_cfg, &aes_key, &aes_iv));
}
static void configure_hmac(void) {
dif_hmac_transaction_t hmac_transaction_cfg = {
.digest_endianness = kDifHmacEndiannessLittle,
.message_endianness = kDifHmacEndiannessLittle,
};
// Use HMAC in SHA256 mode to generate a 256bit key from `kHmacRefLongKey`.
CHECK_DIF_OK(dif_hmac_mode_sha256_start(&hmac, hmac_transaction_cfg));
hmac_testutils_push_message(&hmac, (char *)kHmacRefLongKey,
sizeof(kHmacRefLongKey));
hmac_testutils_check_message_length(&hmac, sizeof(kHmacRefLongKey) * 8);
CHECK_DIF_OK(dif_hmac_process(&hmac));
dif_hmac_digest_t hmac_key_digest;
hmac_testutils_finish_polled(&hmac, &hmac_key_digest);
// Configure the HMAC in HMAC mode.
CHECK_DIF_OK(dif_hmac_mode_hmac_start(
&hmac, (uint8_t *)&hmac_key_digest.digest[0], hmac_transaction_cfg));
}
static void configure_kmac(void) {
dif_kmac_config_t kmac_cfg = (dif_kmac_config_t){
.entropy_mode = kDifKmacEntropyModeEdn,
.entropy_fast_process = kDifToggleDisabled,
.entropy_hash_threshold = kKmacEntropyHashThreshold,
.entropy_wait_timer = kKmacEntropyWaitTimer,
.entropy_prescaler = kKmacEntropyPrescaler,
.message_big_endian = false,
.output_big_endian = false,
.sideload = false,
.msg_mask = false,
};
CHECK_DIF_OK(dif_kmac_configure(&kmac, kmac_cfg));
}
static void configure_uart(dif_uart_t *uart) {
CHECK_DIF_OK(
dif_uart_configure(uart, (dif_uart_config_t){
.baudrate = kUartBaudrate,
.clk_freq_hz = kClockFreqPeripheralHz,
.parity_enable = kDifToggleEnabled,
.parity = kDifUartParityEven,
.tx_enable = kDifToggleDisabled,
.rx_enable = kDifToggleDisabled,
}));
CHECK_DIF_OK(
dif_uart_loopback_set(uart, kDifUartLoopbackSystem, kDifToggleEnabled));
}
static void configure_i2c(dif_i2c_t *i2c, uint8_t device_addr_0,
uint8_t device_addr_1) {
dif_i2c_config_t config;
CHECK_DIF_OK(dif_i2c_compute_timing(
(dif_i2c_timing_config_t){
.lowest_target_device_speed = kDifI2cSpeedFastPlus,
.clock_period_nanos = peripheral_clock_period_ns,
.sda_rise_nanos = kI2cSdaRiseFallTimeNs,
.sda_fall_nanos = kI2cSdaRiseFallTimeNs,
.scl_period_nanos = kI2cSclPeriodNs},
&config));
CHECK_DIF_OK(dif_i2c_configure(i2c, config));
dif_i2c_id_t id_0 = {.mask = kI2cDeviceMask, .address = device_addr_0};
dif_i2c_id_t id_1 = {.mask = kI2cDeviceMask, .address = device_addr_1};
CHECK_DIF_OK(dif_i2c_set_device_id(i2c, &id_0, &id_1));
CHECK_DIF_OK(dif_i2c_line_loopback_set_enabled(i2c, kDifToggleEnabled));
}
static void configure_spi_host(const dif_spi_host_t *spi_host, bool enable) {
CHECK_DIF_OK(dif_spi_host_configure(
spi_host, (dif_spi_host_config_t){
.spi_clock = kClockFreqHiSpeedPeripheralHz / 2,
.peripheral_clock_freq_hz = kClockFreqHiSpeedPeripheralHz,
.chip_select =
{
.idle = 2,
.trail = 2,
.lead = 2,
},
}));
CHECK_DIF_OK(dif_spi_host_output_set_enabled(spi_host, /*enabled=*/enable));
}
void configure_pattgen(void) {
for (size_t i = 0; i < ARRAYSIZE(pattgen_channels); ++i) {
CHECK_DIF_OK(dif_pattgen_channel_set_enabled(&pattgen, pattgen_channels[i],
kDifToggleDisabled));
CHECK_DIF_OK(dif_pattgen_configure_channel(
&pattgen, pattgen_channels[i],
(dif_pattgen_channel_config_t){
.polarity = kDifPattgenPolarityHigh,
.clock_divisor = kPattgenClockDivisor,
.seed_pattern_lower_word = kPattgenSeedPatternLowerWord,
.seed_pattern_upper_word = kPattgenSeedPatternUpperWord,
.seed_pattern_length = kPattgenSeedPatternLength,
.num_pattern_repetitions = kPattgenNumPatternRepetitions,
}));
}
}
void configure_pwm(void) {
CHECK_DIF_OK(
dif_pwm_configure(&pwm, (dif_pwm_config_t){
.clock_divisor = kPwmClockDivisor,
.beats_per_pulse_cycle = kPwmBeatsPerCycle,
}));
CHECK_DIF_OK(dif_pwm_channel_set_enabled(
&pwm, (1u << PWM_PARAM_N_OUTPUTS) - 1, kDifToggleDisabled));
for (size_t i = 0; i < PWM_PARAM_N_OUTPUTS; ++i) {
CHECK_DIF_OK(
dif_pwm_configure_channel(&pwm, pwm_channels[i],
(dif_pwm_channel_config_t){
.duty_cycle_a = kPwmOnBeats,
.duty_cycle_b = 0, // unused
.phase_delay = kPwmPhaseDelayBeats,
.mode = kDifPwmModeFirmware,
.polarity = kDifPwmPolarityActiveHigh,
.blink_parameter_x = 0, // unused
.blink_parameter_y = 0, // unused
}));
}
}
static void configure_otbn(void) {
rsa3072_test_vector = rsa_3072_verify_tests[0];
// Only one exponent (65537) is currently supported.
CHECK(rsa3072_test_vector.publicKey.e == 65537);
CHECK_STATUS_OK(rsa_3072_encode_sha256(rsa3072_test_vector.msg,
rsa3072_test_vector.msgLen,
&rsa3072_encoded_message));
CHECK_STATUS_OK(rsa_3072_compute_constants(&rsa3072_test_vector.publicKey,
&rsa3072_constants));
}
static void check_crypto_blocks_idle(void) {
// CSRNG
CHECK(mmio_region_get_bit32(csrng.base_addr, CSRNG_SW_CMD_STS_REG_OFFSET,
CSRNG_SW_CMD_STS_CMD_RDY_BIT));
// AES
CHECK(aes_testutils_get_status(&aes, kDifAesStatusIdle));
// HMAC - no status register to check.
// KMAC
dif_kmac_status_t kmac_status;
CHECK_DIF_OK(dif_kmac_get_status(&kmac, &kmac_status));
CHECK(kmac_status.sha3_state == kDifKmacSha3StateAbsorbing);
// OTBN
dif_otbn_status_t otbn_status;
CHECK_DIF_OK(dif_otbn_get_status(&otbn, &otbn_status));
CHECK(otbn_status == kDifOtbnStatusIdle);
}
static void complete_kmac_operations(uint32_t *digest) {
// Poll the status register until in the 'squeeze' state.
CHECK_DIF_OK(dif_kmac_poll_status(&kmac, KMAC_STATUS_SHA3_SQUEEZE_BIT));
// Read both shares of digest from state register and combine using XOR.
uint32_t digest_offset = KMAC_STATE_REG_OFFSET;
for (size_t i = 0; i < kKmacDigestLength; ++i) {
uint32_t share0 = mmio_region_read32(kmac.base_addr, digest_offset);
uint32_t share1 = mmio_region_read32(
kmac.base_addr, digest_offset + kDifKmacStateShareOffset);
digest[i] = share0 ^ share1;
digest_offset += sizeof(uint32_t);
}
kmac_operation_state.offset += kKmacDigestLength;
// Complete KMAC operations and reset operation state.
CHECK_DIF_OK(dif_kmac_end(&kmac, &kmac_operation_state));
}
static void crypto_data_load_task(void *task_parameters) {
LOG_INFO("Loading crypto block FIFOs with data ...");
// Load data into AES block.
dif_aes_data_t aes_plain_text;
memcpy(aes_plain_text.data, kAesModesPlainText, sizeof(aes_plain_text.data));
AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusInputReady, true,
kTestTimeoutMicros);
CHECK_DIF_OK(dif_aes_load_data(&aes, aes_plain_text));
// Load data into HMAC block.
hmac_testutils_push_message(&hmac, kHmacRefData, sizeof(kHmacRefData));
hmac_testutils_check_message_length(&hmac, sizeof(kHmacRefData) * 8);
// Load data into KMAC block.
dif_kmac_customization_string_t kmac_customization_string;
CHECK_DIF_OK(dif_kmac_customization_string_init("My Tagged Application", 21,
&kmac_customization_string));
CHECK_DIF_OK(dif_kmac_mode_kmac_start(
&kmac, &kmac_operation_state, kDifKmacModeKmacLen256, kKmacDigestLength,
&kKmacKey, &kmac_customization_string));
CHECK_DIF_OK(dif_kmac_absorb(&kmac, &kmac_operation_state, kKmacMessage,
kKmacMessageLength, NULL));
// Prepare KMAC for squeeze command (to come later in max power epoch) by
// formatting message for KMAC operation. Note, below code is derived from
// the KMAC DIF: `dif_kmac_sqeeze()`.
CHECK(!kmac_operation_state.squeezing);
if (kmac_operation_state.append_d) {
// The KMAC operation requires that the output length (d) in bits be
// right encoded and appended to the end of the message.
uint32_t kmac_output_length_bits = kmac_operation_state.d * 32;
int len = 1 + (kmac_output_length_bits > 0xFF) +
(kmac_output_length_bits > 0xFFFF) +
(kmac_output_length_bits > 0xFFFFFF);
int shift = (len - 1) * 8;
while (shift >= 8) {
mmio_region_write8(kmac.base_addr, KMAC_MSG_FIFO_REG_OFFSET,
(uint8_t)(kmac_output_length_bits >> shift));
shift -= 8;
}
mmio_region_write8(kmac.base_addr, KMAC_MSG_FIFO_REG_OFFSET,
(uint8_t)kmac_output_length_bits);
mmio_region_write8(kmac.base_addr, KMAC_MSG_FIFO_REG_OFFSET, (uint8_t)len);
}
OTTF_TASK_DELETE_SELF_OR_DIE;
}
static void comms_data_load_task(void *task_parameters) {
LOG_INFO("Loading communication block FIFOs with data ...");
size_t bytes_written;
CHECK(ARRAYSIZE(kUartMessage) == kUartFifoDepth);
CHECK(ARRAYSIZE(kI2cMessage) == I2C_PARAM_FIFO_DEPTH);
// Load data into UART FIFOs.
for (size_t i = 0; i < ARRAYSIZE(uart_handles); ++i) {
bytes_written = 0;
CHECK_DIF_OK(dif_uart_bytes_send(uart_handles[i], kUartMessage,
ARRAYSIZE(kUartMessage), &bytes_written));
CHECK(bytes_written == ARRAYSIZE(kUartMessage));
}
// Load data into I2C FIFOs.
dif_i2c_status_t i2c_status;
for (size_t i = 0; i < ARRAYSIZE(i2c_handles); ++i) {
i2c_testutils_wr(i2c_handles[i], /*addr=*/i, I2C_PARAM_FIFO_DEPTH,
kI2cMessage, /*skip_stop=*/false);
CHECK_DIF_OK(dif_i2c_get_status(i2c_handles[i], &i2c_status));
CHECK(i2c_status.fmt_fifo_full);
}
// Load data into SPI host (1; as 0 is used in passthrough mode) FIFO.
uint32_t spi_host_tx_data[SPI_HOST_PARAM_TX_DEPTH];
for (size_t i = 0; i < SPI_HOST_PARAM_TX_DEPTH; ++i) {
spi_host_tx_data[i] = kSpiHost1TxDataWord;
}
dif_spi_host_segment_t spi_host_tx_segment = {
.type = kDifSpiHostSegmentTypeTx,
.tx = {
.width = kDifSpiHostWidthQuad,
.buf = (void *)&spi_host_tx_data,
.length = ARRAYSIZE(spi_host_tx_data),
}};
CHECK_DIF_OK(dif_spi_host_transaction(&spi_host_1, kSpiHost1Csid,
&spi_host_tx_segment, 1));
OTTF_TASK_DELETE_SELF_OR_DIE;
}
static void max_power_task(void *task_parameters) {
LOG_INFO("Starting the max power task ...");
// ***************************************************************************
// Trigger all chip operations.
//
// Note: We trigger the activations of each operation manually, rather than
// use the DIFs, so that we can maximize the time overlap between all
// operations.
// ***************************************************************************
// Prepare AES, HMAC, and KMAC trigger / process commands.
uint32_t aes_trigger_reg = bitfield_bit32_write(0, kDifAesTriggerStart, true);
uint32_t hmac_cmd_reg =
mmio_region_read32(hmac.base_addr, HMAC_CMD_REG_OFFSET);
hmac_cmd_reg =
bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASH_PROCESS_BIT, true);
uint32_t kmac_cmd_reg =
bitfield_field32_write(0, KMAC_CMD_CMD_FIELD, KMAC_CMD_CMD_VALUE_PROCESS);
// Prepare UART, I2C, SPI host enablement commands (note, all configurations
// between each IP instance should be configured the same).
uint32_t uart_ctrl_reg =
mmio_region_read32(uart_1.base_addr, UART_CTRL_REG_OFFSET);
uart_ctrl_reg = bitfield_bit32_write(uart_ctrl_reg, UART_CTRL_TX_BIT, true);
uart_ctrl_reg = bitfield_bit32_write(uart_ctrl_reg, UART_CTRL_RX_BIT, true);
uint32_t i2c_ctrl_reg =
mmio_region_read32(i2c_0.base_addr, I2C_CTRL_REG_OFFSET);
i2c_ctrl_reg =
bitfield_bit32_write(i2c_ctrl_reg, I2C_CTRL_ENABLEHOST_BIT, true);
uint32_t spi_host_1_ctrl_reg =
mmio_region_read32(spi_host_1.base_addr, SPI_HOST_CONTROL_REG_OFFSET);
spi_host_1_ctrl_reg = bitfield_bit32_write(
spi_host_1_ctrl_reg, SPI_HOST_CONTROL_OUTPUT_EN_BIT, true);
// Prepare pattgen enablement command.
uint32_t pattgen_ctrl_reg =
mmio_region_read32(pattgen.base_addr, PATTGEN_CTRL_REG_OFFSET);
pattgen_ctrl_reg =
bitfield_bit32_write(pattgen_ctrl_reg, PATTGEN_CTRL_ENABLE_CH0_BIT, true);
pattgen_ctrl_reg =
bitfield_bit32_write(pattgen_ctrl_reg, PATTGEN_CTRL_ENABLE_CH1_BIT, true);
// Prepare GPIO register values (for max power indicator).
const uint32_t gpio_on_reg_val = (1u << 16) | 1u;
const uint32_t gpio_off_reg_val = 1u << 16;
check_crypto_blocks_idle();
LOG_INFO("Entering max power epoch ...");
// Enable all PWM channels
mmio_region_write32(pwm.base_addr, PWM_PWM_EN_REG_OFFSET,
(1u << PWM_PARAM_N_OUTPUTS) - 1);
// Enable all UARTs and I2Cs.
mmio_region_write32(uart_1.base_addr, UART_CTRL_REG_OFFSET, uart_ctrl_reg);
mmio_region_write32(uart_2.base_addr, UART_CTRL_REG_OFFSET, uart_ctrl_reg);
mmio_region_write32(uart_3.base_addr, UART_CTRL_REG_OFFSET, uart_ctrl_reg);
mmio_region_write32(i2c_0.base_addr, I2C_CTRL_REG_OFFSET, i2c_ctrl_reg);
mmio_region_write32(i2c_1.base_addr, I2C_CTRL_REG_OFFSET, i2c_ctrl_reg);
mmio_region_write32(i2c_2.base_addr, I2C_CTRL_REG_OFFSET, i2c_ctrl_reg);
// Issue OTBN start command.
CHECK_STATUS_OK(rsa_3072_verify_start(&rsa3072_test_vector.signature,
&rsa3072_test_vector.publicKey,
&rsa3072_constants));
// Enable pattgen.
mmio_region_write32(pattgen.base_addr, PATTGEN_CTRL_REG_OFFSET,
pattgen_ctrl_reg);
// Enable SPI host (1).
mmio_region_write32(spi_host_1.base_addr, SPI_HOST_CONTROL_REG_OFFSET,
spi_host_1_ctrl_reg);
// Request entropy during max power epoch. Since AES is so fast, realistically
// we will only be able to request a single block of entropy.
mmio_region_write32(csrng.base_addr, CSRNG_CMD_REQ_REG_OFFSET,
csrng_reseed_cmd_header);
// Issue HMAC process and KMAC squeeze commands.
mmio_region_write32(hmac.base_addr, HMAC_CMD_REG_OFFSET, hmac_cmd_reg);
kmac_operation_state.squeezing = true;
mmio_region_write32(kmac.base_addr, KMAC_CMD_REG_OFFSET, kmac_cmd_reg);
// Toggle GPIO pin to indicate we are in max power consumption epoch. Note, we
// do this BEFORE triggering the AES, since by the type the new value
// propagates to the pin, the AES will already be active.
mmio_region_write32(gpio.base_addr, GPIO_MASKED_OUT_LOWER_REG_OFFSET,
gpio_on_reg_val);
// Issue AES trigger commands.
mmio_region_write32(aes.base_addr, AES_TRIGGER_REG_OFFSET, aes_trigger_reg);
// Wait for AES to complete encryption, as this is the fastest block.
while (!(mmio_region_read32(aes.base_addr, AES_STATUS_REG_OFFSET) &
(1u << AES_STATUS_OUTPUT_VALID_BIT)))
;
// Toggle GPIO pin to indicate we are out of max power consumption epoch.
mmio_region_write32(gpio.base_addr, GPIO_MASKED_OUT_LOWER_REG_OFFSET,
gpio_off_reg_val);
LOG_INFO("Exited max power epoch.");
// ***************************************************************************
// Check operation results.
// ***************************************************************************
// Check AES operation.
dif_aes_data_t aes_cipher_text;
CHECK_DIF_OK(dif_aes_read_output(&aes, &aes_cipher_text));
CHECK_ARRAYS_EQ((uint8_t *)aes_cipher_text.data, kAesModesCipherTextCbc256,
ARRAYSIZE(aes_cipher_text.data));
// Check HMAC operations.
hmac_testutils_finish_and_check_polled(&hmac, &kHmacRefExpectedDigest);
// Check KMAC operations.
uint32_t kmac_digest[kKmacDigestLength];
complete_kmac_operations(kmac_digest);
CHECK(kKmacDigestLength == ARRAYSIZE(kKmacDigest));
CHECK_ARRAYS_EQ(kmac_digest, kKmacDigest, ARRAYSIZE(kKmacDigest));
// Check OTBN operations.
hardened_bool_t result;
CHECK_STATUS_OK(rsa_3072_verify_finalize(&rsa3072_encoded_message, &result));
CHECK(result == kHardenedBoolTrue);
// Check UART transactions.
uint8_t received_uart_data[kUartFifoDepth];
size_t num_uart_rx_bytes;
for (size_t i = 0; i < ARRAYSIZE(uart_handles); ++i) {
CHECK_DIF_OK(
dif_uart_rx_bytes_available(uart_handles[i], &num_uart_rx_bytes));
// Note, we don't care if all bytes have been transmitted out of the UART by
// the time the fastest processing crypto block (i.e., the AES) has
// completed. Likely, we won't have transmitted all data since the UART is
// quite a bit slower. We just check that what was transmitted is correct.
memset((void *)received_uart_data, 0, kUartFifoDepth);
CHECK_DIF_OK(dif_uart_bytes_receive(uart_handles[i], num_uart_rx_bytes,
received_uart_data, NULL));
CHECK_ARRAYS_EQ(received_uart_data, kUartMessage, num_uart_rx_bytes);
}
OTTF_TASK_DELETE_SELF_OR_DIE;
}
static void check_otp_csr_configs(void) {
dif_flash_ctrl_region_properties_t default_properties;
CHECK_DIF_OK(dif_flash_ctrl_get_default_region_properties(
&flash_ctrl, &default_properties));
CHECK(default_properties.scramble_en == kMultiBitBool4False);
CHECK(default_properties.ecc_en == kMultiBitBool4False);
CHECK(default_properties.high_endurance_en == kMultiBitBool4False);
}
bool test_main(void) {
peripheral_clock_period_ns =
udiv64_slow(1000000000, kClockFreqPeripheralHz, NULL);
// Note: DO NOT change this message string without updating the DV testbench.
LOG_INFO("Computed peripheral clock period.");
// ***************************************************************************
// Initialize and configure all IPs.
// ***************************************************************************
init_peripheral_handles();
configure_pinmux();
// Clear GPIO pin 0 (max power indicator pin).
CHECK_DIF_OK(
dif_gpio_output_set_enabled(&gpio, /*pin=*/0, kDifToggleEnabled));
configure_adc_ctrl_to_continuously_sample();
configure_entropy_complex();
// Note: configuration of OTBN must be done *before* configuration of the
// HMAC, as the cryptolib uses HMAC in SHA256 mode, which will cause HMAC
// computation errors later in this test.
configure_otbn();
configure_aes();
configure_hmac();
configure_kmac();
configure_uart(&uart_1);
configure_uart(&uart_2);
configure_uart(&uart_3);
configure_i2c(&i2c_0, kI2c0DeviceAddress0, kI2c0DeviceAddress1);
configure_i2c(&i2c_1, kI2c1DeviceAddress0, kI2c1DeviceAddress1);
configure_i2c(&i2c_2, kI2c2DeviceAddress0, kI2c2DeviceAddress1);
configure_spi_host(&spi_host_0, /*enable=*/true);
// We don't enable SPI host 1 just yet, as we want to pre-load its FIFO with
// data before enabling it at the last moment, to initiate max power draw.
configure_spi_host(&spi_host_1, /*enable=*/false);
spi_device_testutils_configure_passthrough(&spi_device, /*filters=*/0,
/*upload_write_commands=*/false);
configure_pattgen();
configure_pwm();
LOG_INFO("All IPs configured.");
// ***************************************************************************
// Check OTP configurations propagated to CSRs.
// ***************************************************************************
check_otp_csr_configs();
// ***************************************************************************
// Kick off test tasks.
// ***************************************************************************
CHECK(ottf_task_create(crypto_data_load_task, "CryptoDataLoadTask",
kOttfFreeRtosMinStackSize, 1));
CHECK(ottf_task_create(comms_data_load_task, "CommsDataLoadTask",
kOttfFreeRtosMinStackSize, 1));
CHECK(ottf_task_create(max_power_task, "MaxPowerTask",
kOttfFreeRtosMinStackSize, 1));
// ***************************************************************************
// Yield control flow to the highest priority task in the run queue. Since
// the tasks created above all have a higher priority level than the current
// "test_main" task, and no tasks block, execution will not be returned to the
// current task until the above tasks have been deleted.
// ***************************************************************************
LOG_INFO("Yielding execution to another task.");
ottf_task_yield();
return true;
}