blob: 888c2fc4ea7721b4b9a6c76fff821d706d3909e2 [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/csr.h"
#include "sw/device/lib/runtime/hart.h"
#include "sw/device/lib/runtime/irq.h"
#include "sw/device/lib/runtime/pmp.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"
#include "sw/device/silicon_creator/lib/epmp_state.h"
/**
* PMP regions that are used for load/store and execution permission violation
* tests.
*
* "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
* "3.6 Physical Memory Protection", "Address Matching":
*
* "If PMP entry i’s A field is set to TOR, the entry matches any address y
* such that pmpaddri−1 <= y < pmpaddri. If PMP entry 0’s A field is set to TOR,
* zero is used for the lower bound, and so it matches any address
* y < pmpaddr0."
*
* To protect an address range that starts above 0 address, the first region
* we can use is 1.
*/
#define PMP_LOAD_REGION_ID 2
#define PMP_LOAD_RANGE_BUFFER_SIZE 1024
#define PMP_LOAD_RANGE_SIZE 512
#define PMP_LOAD_RANGE_BOTTOM_OFFSET 0
#define PMP_LOAD_RANGE_TOP_OFFSET \
(PMP_LOAD_RANGE_BOTTOM_OFFSET + PMP_LOAD_RANGE_SIZE - 1)
// These flags are used in the test routine to verify that a corresponding
// interrupt has elapsed, and has been serviced. These are declared as volatile
// since they are referenced in the ISR routine as well as in the main program
// flow.
static volatile bool pmp_load_exception;
/**
* The buffer that is used for load/store access violation test.
*/
__attribute__((aligned(PMP_LOAD_RANGE_SIZE))) //
static volatile char pmp_load_test_data[PMP_LOAD_RANGE_BUFFER_SIZE];
void ottf_load_store_fault_handler(void) { pmp_load_exception = true; }
static void pmp_configure_load_tor(void) {
uintptr_t load_range_start =
(uintptr_t)&pmp_load_test_data[PMP_LOAD_RANGE_BOTTOM_OFFSET];
// Non-inclusive
uintptr_t load_range_end =
(uintptr_t)&pmp_load_test_data[PMP_LOAD_RANGE_SIZE];
pmp_region_config_t config = {
.lock = kPmpRegionLockLocked,
.permissions = kPmpRegionPermissionsNone,
};
pmp_region_configure_result_t result = pmp_region_configure_tor(
PMP_LOAD_REGION_ID, config, load_range_start, load_range_end);
CHECK(result == kPmpRegionConfigureOk,
"Load configuration failed, error code = %d", result);
}
OTTF_DEFINE_TEST_CONFIG();
bool test_main(void) {
// 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_WRITE(CSR_REG_PMPCFG3, (kEpmpModeNapot | kEpmpPermLockedReadWriteExecute)
<< 24);
CSR_WRITE(CSR_REG_PMPCFG2, 0);
CSR_WRITE(CSR_REG_PMPCFG1, 0);
CSR_WRITE(CSR_REG_PMPCFG0, 0);
pmp_load_exception = false;
char load = pmp_load_test_data[PMP_LOAD_RANGE_BOTTOM_OFFSET];
CHECK(!pmp_load_exception, "Load access violation before PMP configuration");
pmp_configure_load_tor();
pmp_load_exception = false;
load = pmp_load_test_data[PMP_LOAD_RANGE_BOTTOM_OFFSET];
CHECK(pmp_load_exception,
"No load access violation on the bottom of the range load");
pmp_load_exception = false;
load = pmp_load_test_data[PMP_LOAD_RANGE_TOP_OFFSET];
CHECK(pmp_load_exception,
"No load access violation on the top of the range load");
pmp_load_exception = false;
load = pmp_load_test_data[PMP_LOAD_RANGE_TOP_OFFSET + 1];
CHECK(!pmp_load_exception, "Load access violation on top of the range + 1");
(void)load;
return true;
}