Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions hw/top_chip/dv/top_chip_sim_cfg.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,20 @@
run_opts: ["+ChipMemDRAM_image_file={run_dir}/entropy_src_smoketest_cheri.vmem",
"+ChipMemROM_image_file={run_dir}/bootrom_scrambled.vmem"]
}
{
name: kmac_rom_app_test
uvm_test_seq: top_chip_dv_base_vseq
sw_images: ["kmac_smoketest_vanilla:5" "bootrom:5"]
run_opts: ["+ChipMemDRAM_image_file={run_dir}/kmac_smoketest_vanilla.vmem",
"+ChipMemROM_image_file={run_dir}/bootrom_scrambled.vmem"]
}
{
name: kmac_rom_app_test_cheri
uvm_test_seq: top_chip_dv_base_vseq
sw_images: ["kmac_smoketest_cheri:5" "bootrom:5"]
run_opts: ["+ChipMemDRAM_image_file={run_dir}/kmac_smoketest_cheri.vmem",
"+ChipMemROM_image_file={run_dir}/bootrom_scrambled.vmem"]
}
]

// List of regressions.
Expand Down Expand Up @@ -402,6 +416,8 @@
"pwrmgr_smoke_cheri",
"entropy_src_smoke",
"entropy_src_smoke_cheri",
"kmac_rom_app_test",
"kmac_rom_app_test_cheri",
]
}
{
Expand Down Expand Up @@ -521,5 +537,12 @@
"entropy_src_smoke_cheri"
]
}
{
name: kmac
tests: [
"kmac_rom_app_test",
"kmac_rom_app_test_cheri"
]
}
]
}
16 changes: 16 additions & 0 deletions sw/device/lib/hal/rom_ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,26 @@
#include "hal/rom_ctrl.h"
#include "hal/mmio.h"
#include "hal/mocha.h"
#include <stddef.h>
#include <stdint.h>

/* Read a 32 bit data word from ROM memory */
uint32_t read_rom(rom_t rom, uint32_t rel_addr)
{
return DEV_READ(rom + rel_addr);
}

rom_ctrl_fatal_alert_cause rom_ctrl_fatal_alert_cause_read(rom_ctrl_t rom_ctrl)
{
return VOLATILE_READ(rom_ctrl->fatal_alert_cause);
}

uint32_t rom_ctrl_digest_read(rom_ctrl_t rom_ctrl, size_t index)
{
return VOLATILE_READ(rom_ctrl->digest[index]);
}

uint32_t rom_ctrl_exp_digest_read(rom_ctrl_t rom_ctrl, size_t index)
{
return VOLATILE_READ(rom_ctrl->exp_digest[index]);
}
18 changes: 13 additions & 5 deletions sw/device/lib/hal/rom_ctrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,23 @@

#pragma once

#include "autogen/rom_ctrl.h"
#include "builtin.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>


#define ROM_CTRL_REG (0x0)
#define FATAL_ALERT_CAUSE (0x4)

typedef void *rom_ctrl_t;
typedef void *rom_t;

uint32_t read_rom(rom_t rom, uint32_t rel_addr);

/* Reasons a fatal alert was raised: a failure in the ROM checker, or a bus
* integrity error. The bits are sticky and cannot be cleared once set. */
rom_ctrl_fatal_alert_cause rom_ctrl_fatal_alert_cause_read(rom_ctrl_t rom_ctrl);

/* One word of the digest computed by KMAC over the boot ROM contents. */
uint32_t rom_ctrl_digest_read(rom_ctrl_t rom_ctrl, size_t index);

/* One word of the expected digest, stored in the top words of the boot ROM
* image. rom_ctrl compares this against the digest KMAC computed. */
uint32_t rom_ctrl_exp_digest_read(rom_ctrl_t rom_ctrl, size_t index);
1 change: 1 addition & 0 deletions sw/device/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mocha_add_test(NAME gpio_reg_access_test SOURCES gpio/reg_access_test.c LIBRARIE
mocha_add_test(NAME gpio_smoketest SOURCES gpio/smoketest.c LIBRARIES ${LIBS} SKIP_VERILATOR SKIP_FPGA)
mocha_add_test(NAME i2c_temperature_sensor_test SOURCES i2c/temperature_sensor_test.c LIBRARIES ${LIBS})
mocha_add_test(NAME i2c_host_tx_rx_test SOURCES i2c/host_tx_rx_test.c LIBRARIES ${LIBS} SKIP_VERILATOR SKIP_FPGA)
mocha_add_test(NAME kmac_smoketest SOURCES kmac/smoketest.c LIBRARIES ${LIBS})
mocha_add_test(NAME mailbox_smoketest SOURCES mailbox/smoketest.c LIBRARIES ${LIBS})
mocha_add_test(NAME plic_smoketest SOURCES plic/smoketest.c LIBRARIES ${LIBS})
mocha_add_test(NAME pwrmgr_smoketest SOURCES pwrmgr/smoketest.c LIBRARIES ${LIBS})
Expand Down
69 changes: 69 additions & 0 deletions sw/device/tests/kmac/smoketest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright lowRISC contributors (COSMIC project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

/* Connectivity smoke test for the KMAC block.
*
* Software cannot reach KMAC directly in Mocha: its register interface is tied
* off at the top level. Its only live connection is to rom_ctrl, which uses it
* to hash the boot ROM at power-on.
*
* The hash is produced twice. At build time scramble_image.py hashes the ROM
* image and stores the result in the top 8 words of that image. At power-on
* rom_ctrl reads the ROM back, sends everything below those 8 words to KMAC,
* and gets a freshly computed hash in return. rom_ctrl holds the stored copy in
* exp_digest and the computed one in digest, and only lets the CPU start if the
* two match. Mocha never bypasses that check, because lc_dft_en_i is hardwired
* off; upstream OpenTitan does bypass it in TEST and RMA. Running at all
* therefore already means the hashes agreed.
*
* That also limits what this test can find. If the hashes had disagreed, or if
* rom_ctrl had reported a fault, the CPU would never have started and this code
* would never run. The simulation would simply time out. So the checks below
* only ever see the case where everything already worked.
*
* What they can find is a fault in reading the registers back out. rom_ctrl
* compares the values it stored, so if storing them were broken the chip would
* not boot at all. But if only the read path is wrong, say the wrong address or
* the words in the wrong order, the chip boots normally while software sees the
* wrong values. Comparing the two registers here catches that.
*/

#include "builtin.h"
#include "hal/mocha.h"
#include "hal/rom_ctrl.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

static bool rom_digest_test(rom_ctrl_t rom_ctrl)
{
uint32_t any_bit_set = 0;
uint32_t any_bit_clear = 0;

for (size_t i = 0; i < ARRAY_LEN(rom_ctrl->digest); i++) {
uint32_t digest = rom_ctrl_digest_read(rom_ctrl, i);

// Check that all the digests match the expected
if (digest != rom_ctrl_exp_digest_read(rom_ctrl, i)) {
return false;
}

// Check if the digest was all 0s or all 1s
any_bit_set |= digest;
any_bit_clear |= ~digest;
}

return any_bit_set != 0 && any_bit_clear != 0;
}

bool test_main()
{
rom_ctrl_t rom_ctrl = mocha_system_rom_ctrl();

if (rom_ctrl_fatal_alert_cause_read(rom_ctrl) != rom_ctrl_fatal_alert_cause_none) {
return false;
}

return rom_digest_test(rom_ctrl);
}
Loading