blob: 66f73ff0ac94694edf291117a3c584ecfa6c1751 [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 <stdbool.h>
#include <stdint.h>
#include "sw/device/examples/sram_program/sram_program.h"
#include "sw/device/lib/base/csr.h"
#include "sw/device/lib/base/macros.h"
#include "sw/device/lib/dif/dif_sram_ctrl.h"
#include "sw/device/lib/runtime/ibex.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_isrs.h"
#include "sw/device/lib/testing/test_framework/ottf_macros.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"
#include "sw/device/silicon_creator/lib/epmp_state.h"
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
OTTF_DEFINE_TEST_CONFIG();
static dif_sram_ctrl_t sram_ctrl;
enum {
kSramStart = TOP_EARLGREY_SRAM_CTRL_MAIN_RAM_BASE_ADDR,
kSramEnd = TOP_EARLGREY_SRAM_CTRL_MAIN_RAM_BASE_ADDR +
TOP_EARLGREY_SRAM_CTRL_MAIN_RAM_SIZE_BYTES,
kSramRetStart = TOP_EARLGREY_SRAM_CTRL_RET_AON_RAM_BASE_ADDR,
};
OT_SECTION(".data.sram_function_test")
OT_NOINLINE
static void sram_function_test(void) {
uint32_t pc = 0;
asm("auipc %[pc], 0;" : [pc] "=r"(pc));
LOG_INFO("PC: %p, SRAM: [%p, %p)", pc, kSramStart, kSramEnd);
CHECK(pc >= kSramStart && pc < kSramEnd, "PC is outside the main SRAM");
}
// Redeclaration of the addressable symbol in `sram_ret_neg_test()` to be used
// in `ottf_exception_handler()`.
extern const char kSramRetNegTestReturn[];
void ottf_exception_handler(void) {
// The frame address is the address of the stack location that holds the
// `mepc`, since the OTTF exception handler entry code saves the `mepc` to
// the top of the stack before transferring control flow to the exception
// handler function (which is overridden here). See the `handler_exception`
// subroutine in `sw/device/lib/testing/testing/ottf_isrs.S` for more details.
uintptr_t *mepc_stack_addr = (uintptr_t *)OT_FRAME_ADDR();
ibex_exc_t exception = ibex_mcause_read();
switch (exception) {
case kIbexExcInstrAccessFault:
LOG_INFO("Detected instruction access fault");
*mepc_stack_addr = (uintptr_t)kSramRetNegTestReturn;
break;
default:
LOG_FATAL("Unexpected exception id = 0x%x", exception);
abort();
}
}
static void sram_ret_neg_test(void) {
memset((void *)kSramRetStart, 0, sizeof(uint32_t));
((void (*)(void))kSramRetStart)();
CHECK(false, "Should not be here");
OT_ADDRESSABLE_LABEL(kSramRetNegTestReturn);
}
// See the `bin_to_archive` rule in `opentitan.bzl` for the definition of this
// symbol.
extern const char _sram_program_start[];
static sram_program_entrypoint *sram_main =
(sram_program_entrypoint *)_sram_program_start;
static void sram_program_test(void) {
LOG_INFO("Jumping to the program in SRAM: %p", sram_main);
sram_main();
LOG_INFO("Returned from the program in SRAM");
}
bool test_main(void) {
CHECK_DIF_OK(dif_sram_ctrl_init(
mmio_region_from_addr(TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_BASE_ADDR),
&sram_ctrl));
// Unlock the entire address space for RWX so that we can run this test with
// both rom and test_rom.
CSR_SET_BITS(CSR_REG_PMPADDR15, 0x7fffffff);
CSR_SET_BITS(CSR_REG_PMPCFG3, kEpmpPermLockedReadWriteExecute << 24);
CSR_WRITE(CSR_REG_PMPCFG2, 0);
CSR_WRITE(CSR_REG_PMPCFG1, 0);
CSR_WRITE(CSR_REG_PMPCFG0, 0);
// Note: We can test the negative case only using the retention SRAM since
// execution is unconditionally enabled for the main SRAM in the RMA life
// cycle state.
sram_ret_neg_test();
sram_function_test();
sram_program_test();
return true;
}