Line 80... |
Line 80... |
#endif
|
#endif
|
/**@}*/
|
/**@}*/
|
|
|
|
|
// Prototypes
|
// Prototypes
|
|
void __attribute__((naked)) goto_user_mode(void);
|
void sim_irq_trigger(uint32_t sel);
|
void sim_irq_trigger(uint32_t sel);
|
void global_trap_handler(void);
|
void global_trap_handler(void);
|
void xirq_trap_handler0(void);
|
void xirq_trap_handler0(void);
|
void xirq_trap_handler1(void);
|
void xirq_trap_handler1(void);
|
void test_ok(void);
|
void test_ok(void);
|
Line 99... |
Line 100... |
/// Global number of available HPMs
|
/// Global number of available HPMs
|
uint32_t num_hpm_cnts_global = 0;
|
uint32_t num_hpm_cnts_global = 0;
|
/// XIRQ trap handler acknowledge
|
/// XIRQ trap handler acknowledge
|
uint32_t xirq_trap_handler_ack = 0;
|
uint32_t xirq_trap_handler_ack = 0;
|
|
|
|
/// Variable to test store accesses
|
|
volatile uint32_t store_access_addr[2];
|
|
|
/// Variable to test atomic accesses
|
/// Variable to test atomic accesses
|
uint32_t atomic_access_addr;
|
volatile uint32_t atomic_access_addr;
|
|
|
|
/// Variable to test PMP
|
|
volatile uint32_t pmp_access_addr;
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* High-level CPU/processor test program.
|
* High-level CPU/processor test program.
|
*
|
*
|
Line 160... |
Line 167... |
else {
|
else {
|
PRINT_STANDARD("no\n");
|
PRINT_STANDARD("no\n");
|
}
|
}
|
|
|
|
|
// reset performance counter
|
// reset (performance) counters
|
// neorv32_cpu_csr_write(CSR_MCYCLEH, 0); -> done in crt0.S
|
// neorv32_cpu_csr_write(CSR_MCYCLEH, 0); -> done in crt0.S
|
// neorv32_cpu_csr_write(CSR_MCYCLE, 0); -> done in crt0.S
|
// neorv32_cpu_csr_write(CSR_MCYCLE, 0); -> done in crt0.S
|
// neorv32_cpu_csr_write(CSR_MINSTRETH, 0); -> done in crt0.S
|
// neorv32_cpu_csr_write(CSR_MINSTRETH, 0); -> done in crt0.S
|
// neorv32_cpu_csr_write(CSR_MINSTRET, 0); -> done in crt0.S
|
// neorv32_cpu_csr_write(CSR_MINSTRET, 0); -> done in crt0.S
|
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, 0); // enable performance counter auto increment (ALL counters)
|
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, 0); // enable performance counter auto increment (ALL counters)
|
Line 175... |
Line 182... |
neorv32_mtime_set_time(0);
|
neorv32_mtime_set_time(0);
|
|
|
|
|
// fancy intro
|
// fancy intro
|
// -----------------------------------------------
|
// -----------------------------------------------
|
// logo
|
// show ASCII logo
|
neorv32_rte_print_logo();
|
neorv32_rte_print_logo();
|
|
|
// show project credits
|
// show project credits
|
neorv32_rte_print_credits();
|
neorv32_rte_print_credits();
|
|
|
// show full HW config report
|
// show full hardware configuration report
|
neorv32_rte_print_hw_config();
|
neorv32_rte_print_hw_config();
|
|
|
|
|
// configure RTE
|
// configure RTE
|
// -----------------------------------------------
|
// -----------------------------------------------
|
Line 221... |
Line 228... |
// Run CPU and SoC tests
|
// Run CPU and SoC tests
|
// **********************************************************************************************
|
// **********************************************************************************************
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
|
// Test fence instructions (just make sure CPU does not crash)
|
|
// ----------------------------------------------------------
|
|
asm volatile ("fence");
|
|
asm volatile ("fence.i");
|
|
|
|
|
|
// ----------------------------------------------------------
|
// Test performance counter: setup as many events and counter as feasible
|
// Test performance counter: setup as many events and counter as feasible
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] Setup HPM events: ", cnt_test);
|
PRINT_STANDARD("[%i] Setup HPM events: ", cnt_test);
|
|
|
Line 360... |
Line 374... |
// do not allow user-level code to access cycle[h] CSRs
|
// do not allow user-level code to access cycle[h] CSRs
|
tmp_a = neorv32_cpu_csr_read(CSR_MCOUNTEREN);
|
tmp_a = neorv32_cpu_csr_read(CSR_MCOUNTEREN);
|
tmp_a &= ~(1<<CSR_MCOUNTEREN_CY); // clear access right
|
tmp_a &= ~(1<<CSR_MCOUNTEREN_CY); // clear access right
|
neorv32_cpu_csr_write(CSR_MCOUNTEREN, tmp_a);
|
neorv32_cpu_csr_write(CSR_MCOUNTEREN, tmp_a);
|
|
|
neorv32_cpu_csr_write(CSR_CYCLE, 1); // make sure CSR is != 0 for this test
|
neorv32_cpu_csr_write(CSR_CYCLEH, 1); // make sure CSR is != 0 for this test
|
|
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
neorv32_cpu_goto_user_mode();
|
goto_user_mode();
|
{
|
{
|
// access to cycle CSR is no longer allowed
|
// access to cycle CSR is no longer allowed
|
asm volatile (" mv %[result], zero \n" // initialize with zero
|
asm volatile (" li %[result], 0xcc11aa22 \n" // initialize
|
" rdcycle %[result] " // read CSR_CYCLE, is not allowed and should not alter [result]
|
" rdcycleh %[result] " // read CSR_CYCLE, is not allowed and should not alter [result]
|
: [result] "=r" (tmp_a) : );
|
: [result] "=r" (tmp_a) : );
|
}
|
}
|
|
|
if (tmp_a != 0) {
|
|
PRINT_CRITICAL("%c[1m<SECURITY FAILURE> %c[0m\n", 27, 27);
|
|
}
|
|
|
|
// make sure there was an illegal instruction trap
|
// make sure there was an illegal instruction trap
|
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) && (tmp_a == 0)) {
|
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) &&
|
|
(tmp_a == 0xcc11aa22)) { // destination register not altered
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
Line 398... |
Line 409... |
PRINT_STANDARD("[%i] MRET in U-mode: ", cnt_test);
|
PRINT_STANDARD("[%i] MRET in U-mode: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
neorv32_cpu_goto_user_mode();
|
goto_user_mode();
|
{
|
{
|
asm volatile ("mret");
|
asm volatile ("mret");
|
}
|
}
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) {
|
Line 415... |
Line 426... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// External memory interface test
|
// External memory interface test
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] External memory access (@ 0x%x): ", cnt_test, (uint32_t)EXT_MEM_BASE);
|
PRINT_STANDARD("[%i] Ext. memory access (@ 0x%x): ", cnt_test, (uint32_t)EXT_MEM_BASE);
|
|
|
if (NEORV32_SYSINFO.SOC & (1 << SYSINFO_SOC_MEM_EXT)) {
|
if (NEORV32_SYSINFO.SOC & (1 << SYSINFO_SOC_MEM_EXT)) {
|
cnt_test++;
|
cnt_test++;
|
|
|
// create test program in RAM
|
// create test program in RAM
|
Line 454... |
Line 465... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Illegal CSR access (CSR not implemented)
|
// Illegal CSR access (CSR not implemented)
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] Non-existent CSR access: ", cnt_test);
|
PRINT_STANDARD("[%i] Non-existent CSR: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
tmp_a = neorv32_cpu_csr_read(0xfff); // CSR 0xfff not implemented
|
tmp_a = neorv32_cpu_csr_read(0xfff); // CSR 0xfff not implemented
|
|
|
Line 472... |
Line 483... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Write-access to read-only CSR
|
// Write-access to read-only CSR
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] Read-only CSR write access: ", cnt_test);
|
PRINT_STANDARD("[%i] Read-only CSR write: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
neorv32_cpu_csr_write(CSR_TIME, 0); // time CSR is read-only
|
neorv32_cpu_csr_write(CSR_TIME, 0); // time CSR is read-only
|
|
|
Line 510... |
Line 521... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Unaligned instruction address
|
// Unaligned instruction address
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] I_ALIGN (instr. alignment) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] I_ALIGN (instr. align) EXC: ", cnt_test);
|
|
|
// skip if C-mode is implemented
|
// skip if C-mode is implemented
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C)) == 0) {
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C)) == 0) {
|
|
|
cnt_test++;
|
cnt_test++;
|
Line 612... |
Line 623... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Breakpoint instruction
|
// Breakpoint instruction
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] BREAK (break instr.) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] BREAK EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
asm volatile("EBREAK");
|
asm volatile("EBREAK");
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_BREAKPOINT) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_BREAKPOINT) {
|
Line 629... |
Line 640... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Unaligned load address
|
// Unaligned load address
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] L_ALIGN (load addr alignment) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] L_ALIGN (load align) EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
// load from unaligned address
|
// load from unaligned address
|
neorv32_cpu_load_unsigned_word(ADDR_UNALIGNED_1);
|
asm volatile ("li %[da], 0xcafe1230 \n" // initialize destination register with known value
|
|
"lw %[da], 0(%[ad]) " // must not update destination register to to exception
|
|
: [da] "=r" (tmp_b) : [ad] "r" (ADDR_UNALIGNED_1));
|
|
|
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_MISALIGNED) &&
|
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_MISALIGNED) &&
|
(neorv32_cpu_csr_read(CSR_MTVAL) == ADDR_UNALIGNED_1)) {
|
(neorv32_cpu_csr_read(CSR_MTVAL) == ADDR_UNALIGNED_1) &&
|
|
(tmp_b == 0xcafe1230)) { // make sure dest. reg is not updated
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
Line 648... |
Line 662... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Load access fault
|
// Load access fault
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] L_ACC (load bus access) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] L_ACC (load access) EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
tmp_a = (1 << BUSKEEPER_ERR_FLAG) | (1 << BUSKEEPER_ERR_TYPE);
|
tmp_a = (1 << BUSKEEPER_ERR_FLAG) | (1 << BUSKEEPER_ERR_TYPE);
|
|
|
// load from unreachable aligned address
|
// load from unreachable aligned address
|
neorv32_cpu_load_unsigned_word(ADDR_UNREACHABLE);
|
asm volatile ("li %[da], 0xcafe1230 \n" // initialize destination register with known value
|
|
"lw %[da], 0(%[ad]) " // must not update destination register to to exception
|
|
: [da] "=r" (tmp_b) : [ad] "r" (ADDR_UNREACHABLE));
|
|
|
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) && // load bus access error exception
|
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) && // load bus access error exception
|
|
(neorv32_cpu_csr_read(CSR_MTVAL) == ADDR_UNREACHABLE) &&
|
|
(tmp_b == 0xcafe1230) && // make sure dest. reg is not updated
|
(NEORV32_BUSKEEPER.CTRL = tmp_a)) { // buskeeper: error flag + timeout error
|
(NEORV32_BUSKEEPER.CTRL = tmp_a)) { // buskeeper: error flag + timeout error
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
Line 669... |
Line 687... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Unaligned store address
|
// Unaligned store address
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] S_ALIGN (store addr alignment) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] S_ALIGN (store align) EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
|
// initialize test variable
|
|
store_access_addr[0] = 0x11223344;
|
|
store_access_addr[1] = 0x55667788;
|
|
tmp_a = (uint32_t)(&store_access_addr[0]);
|
|
tmp_a += 2; // make word-unaligned
|
|
|
// store to unaligned address
|
// store to unaligned address
|
neorv32_cpu_store_unsigned_word(ADDR_UNALIGNED_2, 0);
|
neorv32_cpu_store_unsigned_word(tmp_a, 0);
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_MISALIGNED) {
|
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_MISALIGNED) &&
|
|
(neorv32_cpu_csr_read(CSR_MTVAL) == tmp_a) &&
|
|
(store_access_addr[0] == 0x11223344) &&
|
|
(store_access_addr[1] == 0x55667788)) { // make sure memory was not altered
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
}
|
}
|
Line 687... |
Line 714... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Store access fault
|
// Store access fault
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] S_ACC (store bus access) EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] S_ACC (store access) EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
tmp_a = (1 << BUSKEEPER_ERR_FLAG) | (0 << BUSKEEPER_ERR_TYPE);
|
tmp_a = (1 << BUSKEEPER_ERR_FLAG) | (0 << BUSKEEPER_ERR_TYPE);
|
|
|
// store to unreachable aligned address
|
// store to unreachable aligned address
|
neorv32_cpu_store_unsigned_word(ADDR_READONLY, 0);
|
neorv32_cpu_store_unsigned_word(ADDR_READONLY, 0);
|
|
|
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) && // store bus access error exception
|
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) && // store bus access error exception
|
|
(neorv32_cpu_csr_read(CSR_MTVAL) == ADDR_READONLY) &&
|
(NEORV32_BUSKEEPER.CTRL == tmp_a)) { // buskeeper: error flag + device error
|
(NEORV32_BUSKEEPER.CTRL == tmp_a)) { // buskeeper: error flag + device error
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
test_fail();
|
test_fail();
|
Line 708... |
Line 736... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Environment call from M-mode
|
// Environment call from M-mode
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] ENVCALL (ecall instr.) from M-mode EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] ENVCALL M-mode EXC: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
|
|
asm volatile("ECALL");
|
asm volatile("ecall");
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MENV_CALL) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MENV_CALL) {
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
Line 725... |
Line 753... |
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Environment call from U-mode
|
// Environment call from U-mode
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] ENVCALL (ecall instr.) from U-mode EXC: ", cnt_test);
|
PRINT_STANDARD("[%i] ENVCALL U-mode EXC: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
neorv32_cpu_goto_user_mode();
|
goto_user_mode();
|
{
|
{
|
asm volatile("ECALL");
|
asm volatile("ecall");
|
}
|
}
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_UENV_CALL) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_UENV_CALL) {
|
test_ok();
|
test_ok();
|
}
|
}
|
Line 1406... |
Line 1434... |
//PRINT_STANDARD("[%i] FIRQ13..15: ", cnt_test);
|
//PRINT_STANDARD("[%i] FIRQ13..15: ", cnt_test);
|
//PRINT_STANDARD("skipped (n.a.)\n");
|
//PRINT_STANDARD("skipped (n.a.)\n");
|
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test WFI ("sleep") instructions, wakeup via MTIME
|
// Test WFI ("sleep") instruction (executed in user mode), wakeup via MTIME
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
PRINT_STANDARD("[%i] WFI (sleep instruction, wake-up via MTIME): ", cnt_test);
|
PRINT_STANDARD("[%i] WFI (sleep instruction, wake-up via MTIME): ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
Line 1419... |
Line 1447... |
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + 500);
|
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + 500);
|
|
|
// enable mtime interrupt
|
// enable mtime interrupt
|
neorv32_cpu_irq_enable(CSR_MIE_MTIE);
|
neorv32_cpu_irq_enable(CSR_MIE_MTIE);
|
|
|
// put CPU into sleep mode
|
// clear mstatus.TW to allow execution of WFI also in user-mode
|
|
neorv32_cpu_csr_write(CSR_MSTATUS, neorv32_cpu_csr_read(CSR_MSTATUS) & ~(1<<CSR_MSTATUS_TW));
|
|
|
|
// put CPU into sleep mode (from user mode)
|
|
goto_user_mode();
|
|
{
|
asm volatile ("wfi");
|
asm volatile ("wfi");
|
|
}
|
|
|
// no more mtime interrupts
|
// no more mtime interrupts
|
neorv32_cpu_irq_disable(CSR_MIE_MTIE);
|
neorv32_cpu_irq_disable(CSR_MIE_MTIE);
|
neorv32_mtime_set_timecmp(-1);
|
neorv32_mtime_set_timecmp(-1);
|
|
|
Line 1443... |
Line 1477... |
PRINT_STANDARD("[%i] Invalid CSR access (mstatus) from user mode: ", cnt_test);
|
PRINT_STANDARD("[%i] Invalid CSR access (mstatus) from user mode: ", cnt_test);
|
|
|
cnt_test++;
|
cnt_test++;
|
|
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
neorv32_cpu_goto_user_mode();
|
goto_user_mode();
|
{
|
{
|
// access to misa not allowed for user-level programs
|
// access to misa not allowed for user-level programs
|
tmp_a = neorv32_cpu_csr_read(CSR_MISA);
|
tmp_a = neorv32_cpu_csr_read(CSR_MISA);
|
}
|
}
|
|
|
Line 1486... |
Line 1520... |
|
|
|
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
// Test physical memory protection
|
// Test physical memory protection
|
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
PRINT_STANDARD("[%i] PMP - Physical memory protection: ", cnt_test);
|
PRINT_STANDARD("[%i] PMP:\n", cnt_test);
|
|
|
// check if PMP is implemented
|
// check if PMP is implemented (two regions are required for these tests)
|
if (neorv32_cpu_pmp_get_num_regions() != 0) {
|
if (neorv32_cpu_pmp_get_num_regions() > 1) {
|
|
|
// Create PMP protected region
|
// Create PMP protected region
|
// ---------------------------------------------
|
// ---------------------------------------------
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
cnt_test++;
|
cnt_test++;
|
|
|
// find out minimal region size (granularity)
|
tmp_a = (uint32_t)(&pmp_access_addr); // base address of protected region
|
tmp_b = neorv32_cpu_pmp_get_granularity();
|
tmp_b = PMP_TOR << PMPCFG_A_LSB; // enable region, but absolutely no access rights
|
|
|
tmp_a = NEORV32_SYSINFO.DSPACE_BASE; // base address of protected region
|
|
PRINT_STANDARD("Creating protected page (NAPOT, [!X,!W,!R], %u bytes) @ 0x%x: ", tmp_b, tmp_a);
|
|
|
|
// configure
|
// configure
|
int pmp_return = neorv32_cpu_pmp_configure_region(0, tmp_a, tmp_b, PMPCFG_MODE_NAPOT << PMPCFG_A_LSB); // NAPOT, NO read/write/execute permissions
|
int pmp_res = 0;
|
|
PRINT_STANDARD("Setup region 0 OFF [ -, -, -] @ 0x%x\n", tmp_a);
|
if ((pmp_return == 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) {
|
pmp_res += neorv32_cpu_pmp_configure_region(0, tmp_a, 0);
|
|
PRINT_STANDARD("Setup region 1 TOR [!X,!W,!R] @ 0x%x ", tmp_a+4);
|
|
pmp_res += neorv32_cpu_pmp_configure_region(1, tmp_a+4, tmp_b);
|
|
if ((pmp_res == 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) {
|
test_ok();
|
test_ok();
|
}
|
}
|
else {
|
else {
|
if (neorv32_cpu_csr_read(CSR_PMPCFG0) & 0x80) {
|
|
PRINT_CRITICAL("%c[1m<Entry LOCKED!> %c[0m\n", 27, 27);
|
|
}
|
|
test_fail();
|
test_fail();
|
}
|
}
|
|
|
|
|
// ------ EXECUTE: should fail ------
|
// ------ EXECUTE: should fail ------
|
PRINT_STANDARD("[%i] PMP: U-mode execute: ", cnt_test);
|
PRINT_STANDARD("[%i] PMP: U-mode execute: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
|
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
neorv32_cpu_goto_user_mode();
|
goto_user_mode();
|
{
|
{
|
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); // call address to execute -> should fail
|
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); // call address to execute -> should fail
|
}
|
}
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ACCESS) {
|
// switch back to machine mode (if not already)
|
asm volatile ("ecall"); // switch back to machine mode (if not already)
|
asm volatile ("ecall");
|
test_ok();
|
|
|
test_fail();
|
|
}
|
}
|
else {
|
else {
|
// switch back to machine mode (if not already)
|
asm volatile ("ecall"); // switch back to machine mode (if not already)
|
asm volatile ("ecall");
|
test_fail();
|
|
|
test_ok();
|
|
}
|
}
|
|
|
|
|
// ------ LOAD: should fail ------
|
// ------ LOAD: should fail ------
|
PRINT_STANDARD("[%i] PMP: U-mode read: ", cnt_test);
|
PRINT_STANDARD("[%i] PMP: U-mode read: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
|
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
neorv32_cpu_goto_user_mode();
|
goto_user_mode();
|
tmp_b = 0;
|
|
{
|
{
|
tmp_b = neorv32_cpu_load_unsigned_word(tmp_a); // load access -> should fail
|
asm volatile ("li %[da], 0xcafe0000 \n" // initialize destination register with known value
|
}
|
"lw %[da], 0(%[ad]) " // must not update destination register to to exception
|
|
: [da] "=r" (tmp_b) : [ad] "r" (tmp_a));
|
if (tmp_b != 0) {
|
|
PRINT_CRITICAL("%c[1m<SECURITY FAILURE> %c[0m\n", 27, 27);
|
|
}
|
}
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) {
|
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) &&
|
|
(tmp_b == 0xcafe0000)) { // destination register not altered
|
// switch back to machine mode (if not already)
|
// switch back to machine mode (if not already)
|
asm volatile ("ecall");
|
asm volatile ("ecall");
|
|
|
test_ok();
|
test_ok();
|
}
|
}
|
Line 1577... |
Line 1602... |
PRINT_STANDARD("[%i] PMP: U-mode write: ", cnt_test);
|
PRINT_STANDARD("[%i] PMP: U-mode write: ", cnt_test);
|
cnt_test++;
|
cnt_test++;
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
|
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
|
neorv32_cpu_goto_user_mode();
|
goto_user_mode();
|
{
|
{
|
neorv32_cpu_store_unsigned_word(tmp_a, 0); // store access -> should fail
|
neorv32_cpu_store_unsigned_word(tmp_a, 0); // store access -> should fail
|
}
|
}
|
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) {
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) {
|
Line 1772... |
Line 1797... |
|
|
return (int)cnt_fail; // return error counter for after-main handler
|
return (int)cnt_fail; // return error counter for after-main handler
|
}
|
}
|
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Switch from privilege mode MACHINE to privilege mode USER.
|
|
*
|
|
* @warning This function requires the U extension to be implemented.
|
|
**************************************************************************/
|
|
void __attribute__((naked)) goto_user_mode(void) {
|
|
|
|
// make sure to use NO registers in here! -> naked
|
|
|
|
asm volatile ("csrw mepc, ra \n" // move return address to mepc so we can return using "mret". also, we can now use ra as temp register
|
|
"li ra, %[input_imm] \n" // bit mask to clear the two MPP bits
|
|
"csrrc zero, mstatus, ra \n" // clear MPP bits -> MPP=u-mode
|
|
"mret \n" // return and switch to user mode
|
|
: : [input_imm] "i" ((1<<CSR_MSTATUS_MPP_H) | (1<<CSR_MSTATUS_MPP_L)));
|
|
}
|
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Simulation-based function to trigger CPU interrupts (MSI, MEI, FIRQ4..7).
|
* Simulation-based function to trigger CPU interrupts (MSI, MEI).
|
*
|
*
|
* @param[in] sel IRQ select mask (bit positions according to #NEORV32_CSR_MIE_enum).
|
* @param[in] sel IRQ select mask (bit positions according to #NEORV32_CSR_MIE_enum).
|
**************************************************************************/
|
**************************************************************************/
|
void sim_irq_trigger(uint32_t sel) {
|
void sim_irq_trigger(uint32_t sel) {
|
|
|
Line 1791... |
Line 1834... |
* Trap handler for ALL exceptions/interrupts.
|
* Trap handler for ALL exceptions/interrupts.
|
**************************************************************************/
|
**************************************************************************/
|
void global_trap_handler(void) {
|
void global_trap_handler(void) {
|
|
|
// clear all pending FIRQs
|
// clear all pending FIRQs
|
neorv32_cpu_csr_write(CSR_MIP, -1);
|
neorv32_cpu_csr_write(CSR_MIP, 0);
|
|
|
// hack: always come back in MACHINE MODE
|
// hack: always come back in MACHINE MODE
|
register uint32_t mask = (1<<CSR_MSTATUS_MPP_H) | (1<<CSR_MSTATUS_MPP_L);
|
register uint32_t mask = (1<<CSR_MSTATUS_MPP_H) | (1<<CSR_MSTATUS_MPP_L);
|
asm volatile ("csrrs zero, mstatus, %[input_j]" : : [input_j] "r" (mask));
|
asm volatile ("csrrs zero, mstatus, %[input_j]" : : [input_j] "r" (mask));
|
}
|
}
|
Line 1842... |
Line 1885... |
/**********************************************************************//**
|
/**********************************************************************//**
|
* "after-main" handler that is executed after the application's
|
* "after-main" handler that is executed after the application's
|
* main function returns (called by crt0.S start-up code): Output minimal
|
* main function returns (called by crt0.S start-up code): Output minimal
|
* test report to physical UART
|
* test report to physical UART
|
**************************************************************************/
|
**************************************************************************/
|
int __neorv32_crt0_after_main(int32_t return_code) {
|
void __neorv32_crt0_after_main(int32_t return_code) {
|
|
|
// make sure sim mode is disabled and UARTs are actually enabled
|
// make sure sim mode is disabled and UARTs are actually enabled
|
NEORV32_UART0.CTRL |= (1 << UART_CTRL_EN);
|
NEORV32_UART0.CTRL |= (1 << UART_CTRL_EN);
|
NEORV32_UART0.CTRL &= ~(1 << UART_CTRL_SIM_MODE);
|
NEORV32_UART0.CTRL &= ~(1 << UART_CTRL_SIM_MODE);
|
NEORV32_UART1.CTRL = NEORV32_UART0.CTRL;
|
NEORV32_UART1.CTRL = NEORV32_UART0.CTRL;
|
|
|
// minimal result report
|
// minimal result report
|
PRINT_CRITICAL("%u/%u\n", (uint32_t)return_code, (uint32_t)cnt_test);
|
PRINT_CRITICAL("%u/%u\n", (uint32_t)return_code, (uint32_t)cnt_test);
|
|
|
return 0;
|
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|