From ee982c7588cb10196f0f11d096ffb929e3913ef5 Mon Sep 17 00:00:00 2001 From: Kip Macsai-Goren Date: Sun, 30 Jan 2022 23:08:02 +0000 Subject: [PATCH] converted library to header file for RISCV test compliance --- .../rv32i_m/privilege/src/WALLY-MMU-SV32.S | 2 +- .../rv32i_m/privilege/src/WALLY-PMA.S | 2 +- .../rv32i_m/privilege/src/WALLY-PMP.S | 4 +- .../rv32i_m/privilege/src/WALLY-TEST-LIB-32.S | 607 ----------------- .../rv32i_m/privilege/src/WALLY-TEST-LIB-32.h | 607 +++++++++++++++++ .../rv64i_m/privilege/src/WALLY-MMU-SV39.S | 2 +- .../rv64i_m/privilege/src/WALLY-MMU-SV48.S | 2 +- .../rv64i_m/privilege/src/WALLY-PMA.S | 2 +- .../rv64i_m/privilege/src/WALLY-PMP.S | 2 +- .../rv64i_m/privilege/src/WALLY-TEST-LIB-64.S | 624 ------------------ .../rv64i_m/privilege/src/WALLY-TEST-LIB-64.h | 624 ++++++++++++++++++ 11 files changed, 1239 insertions(+), 1239 deletions(-) delete mode 100644 tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.S create mode 100644 tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h delete mode 100644 tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.S create mode 100644 tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-MMU-SV32.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-MMU-SV32.S index 57e4943f..91681f81 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-MMU-SV32.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-MMU-SV32.S @@ -21,7 +21,7 @@ // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /////////////////////////////////////////// -#include "WALLY-TEST-LIB-32.S" +#include "WALLY-TEST-LIB-32.h" // Test library includes and handler for each type of test, a trap handler, imperas compliance instructions // Ideally this should mean that a test can be written by simply adding .8byte statements as below. diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-PMA.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-PMA.S index c9db410f..80d6d504 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-PMA.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-PMA.S @@ -34,7 +34,7 @@ #define PLIC_BASE 0x0C000000 #define PLIC_RANGE 0x03FFFFFF -#include "WALLY-TEST-LIB-32.S" +#include "WALLY-TEST-LIB-32.h" // Test library includes and handler for each type of test, a trap handler, imperas compliance instructions // Ideally this should mean that a test can be written by simply adding .4byte statements as below. diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-PMP.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-PMP.S index 193da763..887bfd97 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-PMP.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-PMP.S @@ -21,7 +21,7 @@ // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /////////////////////////////////////////// -#include "WALLY-TEST-LIB-32.S" +#include "WALLY-TEST-LIB-32.h" // Test library includes and handler for each type of test, a trap handler, imperas compliance instructions // Ideally this should mean that a test can be written by simply adding .4byte statements as below. @@ -45,7 +45,7 @@ # Test 12.3.2.2.1 Config: Write known values and set PMP config according to table 12.4 in the *** riscv book, copied below # write pmpaddr regs - # | Reg | pmpaddr | pmpcfg | L | A | X | W | R | Comments | + # | Reg | pmpaddr | pmpcfg | L | A | X | W | R | Comments | .4byte 0x0, 0x0FFFFFFF, write_pmpaddr_0 # | 0 | 0x0FFFFFFF | 1F | 0 | NAPOT | 0 | 1 | 1 | I/O 00000000-7FFFFFFF RW | .4byte 0x1, 0x20040000, write_pmpaddr_0 # | 1 | 0x20040000 | 00 | 0 | OFF | 0 | 0 | 0 | | .4byte 0x2, 0x2004003F, write_pmpaddr_0 # | 2 | 0x2004003F | 09 | 0 | TOR | 0 | 0 | 1 | 80100000-801000FF R | diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.S deleted file mode 100644 index 8166e76b..00000000 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.S +++ /dev/null @@ -1,607 +0,0 @@ -/////////////////////////////////////////// -// -// WALLY-TEST-LIB-32.S -// -// Author: Kip Macsai-Goren -// -// Created 2021-07-20 -// -// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, -// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -/////////////////////////////////////////// - -#include "model_test.h" -#include "arch_test.h" -RVTEST_ISA("RV32I") - -.section .text.init -.globl rvtest_entry_point -rvtest_entry_point: -RVMODEL_BOOT -RVTEST_CODE_BEGIN - - # --------------------------------------------------------------------------------------------- - # Initialization Overview: - # - # Initialize x6 as a virtual pointer to the test results - # Initialize x16 as a physical pointer to the test results - # Set up stack pointer (sp = x2) - # Set up the exception Handler, keeping the original handler in x4. - # - # --------------------------------------------------------------------------------------------- - - # address for test results - la x6, test_1_res - la x16, test_1_res # x16 reserved for the physical address equivalent of x6 to be used in trap handlers - # any time either is used, both must be updated. - - # address for stack - la sp, top_of_stack - - # trap handler setup - la x1, machine_trap_handler - csrrw x4, mtvec, x1 # x4 reserved for "default" trap handler address that needs to be restored before halting this test. - li a0, 0 - li a1, 0 - li a2, 0 # reset trap handler inputs to zero - - # go to first test! - j test_setup - - - # --------------------------------------------------------------------------------------------- - # General traps Handler - # - # Handles traps by branching to different behaviors based on mcause. - # - # Note that allowing the exception handler to change mode for a program is a huge security - # hole, but this is an expedient way of writing tests that need different modes - # - # input parameters: - # - # a0 (x10): - # 0: halt program with no failures - # 1: halt program with failure in x11 = a1 - # 2: go to machine mode - # 3: go to supervisor mode - # 4: go to user mode - # others: do nothing - # - # a1 (x11): - # VPN for return address after changing privilege mode. - # This should be the base VPN with no offset. - # 0x0 : defaults to next instruction on the same page the trap was called on. - # - # a2 (x12): - # Pagetype of the current address VPN before changing privilge mode - # Used so that we can know how many bits of the adress are the offset. - # Ignored if a1 == 0x0 - # 0: Kilopage - # 1: Megapage - # - # -------------------------------------------------------------------------------------------- - - -machine_trap_handler: - # The processor is always in machine mode when a trap takes us here - # save registers on stack before using - sw x1, -4(sp) - sw x5, -8(sp) - - # Record trap - csrr x1, mcause # record the mcause - sw x1, 0(x16) - addi x6, x6, 4 - addi x16, x16, 4 # update pointers for logging results - - # Respond to trap based on cause - # All interrupts should return after being logged - li x5, 0x8000000000000000 # if msb is set, it is an interrupt - and x5, x5, x1 - bnez x5, trapreturn # return from interrupt - # Other trap handling is specified in the vector Table - slli x1, x1, 2 # multiply cause by 4 to get offset in vector Table - la x5, trap_handler_vector_table - add x5, x5, x1 # compute address of vector in Table - lw x5, 0(x5) # fectch address of handler from vector Table - jr x5 # and jump to the handler - -segfault: - lw x5, -8(sp) # restore registers from stack before faulting - lw x1, -4(sp) - j terminate_test # halt program. - -trapreturn: - # look at the instruction to figure out whether to add 2 or 4 bytes to PC, or go to address specified in a1 - csrr x1, mepc # get the mepc - addi x1, x1, 4 # *** should be 2 for compressed instructions, see note. - - -# ****** KMG: the following is no longer as easy to determine. mepc gets the virtual address of the trapped instruction, -# ******** but in the handler, we work in M mode with physical addresses -# This means the address in mepc is suddenly pointing somewhere else. -# to get this to work, We could either retranslate the vaddr back into a paddr (probably on the scale of difficult to intractible) -# or we could come up with some other ingenious way to stay in M mode and see if the instruction was compressed. - -# lw x5, 0(x1) # read the faulting instruction -# li x1, 3 # check bottom 2 bits of instruction to see if compressed -# and x5, x5, x1 # mask the other bits -# beq x5, x1, trapreturn_uncompressed # if 11, the instruction is return_uncompressed - -# trapreturn_compressed: -# csrr x1, mepc # get the mepc again -# addi x1, x1, 2 # add 2 to find the next instruction -# j trapreturn_specified # and return - -# trapreturn_uncompressed: -# csrr x1, mepc # get the mepc again -# addi x1, x1, 4 # add 4 to find the next instruction - -trapreturn_specified: - # reset the necessary pointers and registers (x1, x5, x6, and the return address going to mepc) - # so that when we return to a new virtual address, they're all in the right spot as well. - - beqz a1, trapreturn_finished # either update values, of go to default return address. - - la x5, trap_return_pagetype_table - slli a2, a2, 2 - add x5, x5, a2 - lw a2, 0(x5) # a2 = number of offset bits in current page type - - li x5, 1 - sll x5, x5, a2 - addi x5, x5, -1 # x5 = mask bits for offset into current pagetype - - # reset the top of the stack, x1 - lw x7, -4(sp) - and x7, x5, x7 # x7 = offset for x1 - add x7, x7, a1 # x7 = new address for x1 - sw x7, -4(sp) - - # reset the second spot in the stack, x5 - lw x7, -8(sp) - and x7, x5, x7 # x7 = offset for x5 - add x7, x7, a1 # x7 = new address for x5 - sw x7, -8(sp) - - # reset x6, the pointer for the virtual address of the output of the tests - and x7, x5, x6 # x7 = offset for x6 - add x6, x7, a1 # x6 = new address for the result pointer - - # set return address, stored temporarily in x1, to the next instruction, but in the new virtual page. - and x1, x5, x1 # x1 = offset for the return address - add x1, x1, a1 # x1 = new return address. - - li a1, 0 - li a2, 0 # reset trapreturn inputs to the trap handler - -trapreturn_finished: - csrw mepc, x1 # update the mepc with address of next instruction - lw x5, -8(sp) # restore registers from stack before returning - lw x1, -4(sp) - mret # return from trap - -ecallhandler: - # Check input parameter a0. encoding above. - # *** ASSUMES: that this trap is being handled in machine mode. in other words, that nothing odd has been written to the medeleg or mideleg csrs. - li x5, 2 # case 2: change to machine mode - beq a0, x5, ecallhandler_changetomachinemode - li x5, 3 # case 3: change to supervisor mode - beq a0, x5, ecallhandler_changetosupervisormode - li x5, 4 # case 4: change to user mode - beq a0, x5, ecallhandler_changetousermode - # unsupported ecalls should segfault - j segfault - -ecallhandler_changetomachinemode: - # Force mstatus.MPP (bits 12:11) to 11 to enter machine mode after mret - li x1, 0b1100000000000 - csrs mstatus, x1 - j trapreturn - -ecallhandler_changetosupervisormode: - # Force mstatus.MPP (bits 12:11) to 01 to enter supervisor mode after mret - li x1, 0b1100000000000 - csrc mstatus, x1 - li x1, 0b0100000000000 - csrs mstatus, x1 - j trapreturn - -ecallhandler_changetousermode: - # Force mstatus.MPP (bits 12:11) to 00 to enter user mode after mret - li x1, 0b1100000000000 - csrc mstatus, x1 - j trapreturn - -instrfault: - lw x1, -4(sp) # load return address int x1 (the address after the jal into faulting page) - j trapreturn_finished # puts x1 into mepc, restores stack and returns to program (outside of faulting page) - -accessfault: - # *** What do I have to do here? - j trapreturn - # Table of trap behavior - # lists what to do on each exception (not interrupts) - # unexpected exceptions should cause segfaults for easy detection - # Expected exceptions should increment the EPC to the next instruction and return - - .align 2 # aligns this data table to an 4 byte boundary -trap_handler_vector_table: - .4byte segfault # 0: instruction address misaligned - .4byte instrfault # 1: instruction access fault - .4byte segfault # 2: illegal instruction - .4byte segfault # 3: breakpoint - .4byte segfault # 4: load address misaligned - .4byte accessfault # 5: load access fault - .4byte segfault # 6: store address misaligned - .4byte accessfault # 7: store access fault - .4byte ecallhandler # 8: ecall from U-mode - .4byte ecallhandler # 9: ecall from S-mode - .4byte segfault # 10: reserved - .4byte ecallhandler # 11: ecall from M-mode - .4byte instrfault # 12: instruction page fault - .4byte trapreturn # 13: load page fault - .4byte segfault # 14: reserved - .4byte trapreturn # 15: store page fault - -.align 2 -trap_return_pagetype_table: - .4byte 0xC # 0: kilopage has 12 offset bits - .4byte 0x16 # 1: megapage has 22 offset bits - - # --------------------------------------------------------------------------------------------- - # Test Handler - # - # This test handler works in a similar wy to the trap handler. It takes in a few things by reading from a table in memory - # (see test_cases) and performing certain behavior based on them. - # - # Input parameters: - # - # x28: - # Address input for the test taking place (think address to read/write, new address to return to, etc...) - # - # x29: - # Value input for the test taking place (think value to write, any other extra info needed) - # - # x30: - # Test type input that determines which kind of test will take place. Encoding for this input is in the table/case statements below - # - # ------------------------------------------------------------------------------------------------------------------------------------ - -test_setup: - la x5, test_cases - -test_loop: - lw x28, 0(x5) # fetch test case address - lw x29, 4(x5) # fetch test case value - lw x30, 8(x5) # fetch test case flag - addi x5, x5, 12 # set x5 to next test case - - # x5 has the symbol for a test's location in the assembly - li x7, 0x3FFFFF - and x30, x30, x7 # This program is always on at least a megapage, so this masks out the megapage offset. - auipc x7, 0x0 - srli x7, x7, 22 - slli x7, x7, 22 # zero out the bottom 22 bits so the megapage offset of the symbol can be placed there - or x30, x7, x30 # x30 = virtual address of the symbol for this type of test. - - jr x30 - -# Test Name : Description : Fault output value : Normal output values -# ----------------------:---------------------------------------:------------------------:------------------------------------------------------ -# write32_test : Write 32 bits to address : 0xf : None -# write16_test : Write 16 bits to address : 0xf : None -# write08_test : Write 8 bits to address : 0xf : None -# read32_test : Read 32 bits from address : 0xd, 0xbad : readvalue in hex -# read16_test : Read 16 bits from address : 0xd, 0xbad : readvalue in hex -# read08_test : Read 8 bits from address : 0xd, 0xbad : readvalue in hex -# executable_test : test executable at address : 0xc, 0xbad : leading 12 bits of the li instr written to address. In general this is 0x111. (be sure to also write a return instruction) -# terminate_test : terminate tests : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 -# goto_baremetal : satp.MODE = bare metal : None : None -# goto_sv32 : satp.MODE = sv32 : None : None -# write_mxr_sum : write sstatus.[19:18] = MXR, SUM bits : None : None -# goto_m_mode : go to mahcine mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 -# goto_s_mode : go to supervisor mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 -# goto_u_mode : go to user mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 -# write_pmpcfg_x : Write one of the pmpcfg csr's : mstatuses?, 0xD : readback of pmpcfg value -# write_pmpaddr_x : Write one of the pmpaddr csr's : None : readback of pmpaddr value - - -write32_test: - # address to write in x28, word value in x29 - sw x29, 0(x28) - j test_loop # go to next test case - -write16_test: - # address to write in x28, halfword value in x29 - sh x29, 0(x28) - j test_loop # go to next test case - -write08_test: - # address to write in x28, value in x29 - sb x29, 0(x28) - j test_loop # go to next test case - -read32_test: - # address to read in x28, expected 32 bit value in x29 (unused, but there for your perusal). - li x7, 0xBAD # bad value that will be overwritten on good reads. - lw x7, 0(x28) - sw x7, 0(x6) - addi x6, x6, 4 - addi x16, x16, 4 - j test_loop # go to next test case - -read16_test: - # address to read in x28, expected 16 bit value in x29 (unused, but there for your perusal). - li x7, 0xBAD # bad value that will be overwritten on good reads. - lh x7, 0(x28) - sw x7, 0(x6) - addi x6, x6, 4 - addi x16, x16, 4 - j test_loop # go to next test case - -read08_test: - # address to read in x28, expected 8 bit value in x29 (unused, but there for your perusal). - li x7, 0xBAD # bad value that will be overwritten on good reads. - lb x7, 0(x28) - sw x7, 0(x6) - addi x6, x6, 4 - addi x16, x16, 4 - j test_loop # go to next test case - - -goto_s_mode: - li a0, 3 # Trap handler behavior (go to machine mode) - mv a1, x28 # return VPN - mv a2, x29 # return page types - ecall # writes mcause to the output. - # now in S mode - j test_loop - -goto_m_mode: - li a0, 2 # Trap handler behavior (go to machine mode) - mv a1, x28 # return VPN - mv a2, x29 # return page types - ecall # writes mcause to the output. - j test_loop - -goto_u_mode: - li a0, 4 # Trap handler behavior (go to user mode) - mv a1, x28 # return VPN - mv a2, x29 # return page types - ecall # writes mcause to the output. - j test_loop - -goto_baremetal: - # Turn translation off - li x7, 0 # satp.MODE value for bare metal (0) - slli x7, x7, 31 - li x28, 0x8000D # Base Pagetable physical page number, satp.PPN field. - add x7, x7, x28 - csrw satp, x7 - sfence.vma x0, x0 # *** flushes global pte's as well. Be careful - j test_loop # go to next test case - -goto_sv32: - li x7, 1 # satp.MODE value for Sv39 (1) - slli x7, x7, 31 - li x28, 0x8000D # Base Pagetable physical page number, satp.PPN field. - add x7, x7, x28 - csrw satp, x7 - sfence.vma x0, x0 # *** flushes global pte's as well. Be careful - j test_loop # go to next test case - -write_mxr_sum: - # writes sstatus.[mxr, sum] with the (assumed to be) 2 bit value in x29. also assumes we're in S. M mode - li x30, 0xC0000 # mask bits for MXR, SUM - not x7, x29 - slli x7, x7, 18 - and x7, x7, x30 - slli x29, x29, 18 - csrc sstatus, x7 - csrs sstatus, x29 - j test_loop - -write_pmpcfg_0: - # writes the value in x29 to the pmpcfg register specified in x28. - li x7, 0x0 - bne x7, x28, write_pmpcfg_1 - csrw pmpcfg0, x29 - csrr x30, pmpcfg0 -write_pmpcfg_1: - li x7, 0x1 - bne x7, x28, write_pmpcfg_2 - csrw pmpcfg1, x29 - csrr x30, pmpcfg1 -write_pmpcfg_2: - li x7, 0x2 - bne x7, x28, write_pmpcfg_3 - csrw pmpcfg2, x29 - csrr x30, pmpcfg2 -write_pmpcfg_3: - li x7, 0x3 - bne x7, x28, write_pmpcfg_end - csrw pmpcfg3, x29 - csrr x30, pmpcfg3 -write_pmpcfg_end: - sw x30, 0(x6) - addi x6, x6, 4 - addi x16, x16, 4 - j test_loop - -write_pmpaddr_0: - # writes the value in x29 to the pmpaddr register specified in x28. - # then writes the final value of pmpaddrX to the output. - li x7, 0x0 - bne x7, x28, write_pmpaddr_1 - csrw pmpaddr0, x29 - csrr x30, pmpaddr0 - j write_pmpaddr_end -write_pmpaddr_1: - li x7, 0x1 - bne x7, x28, write_pmpaddr_2 - csrw pmpaddr1, x29 - csrr x30, pmpaddr1 - j write_pmpaddr_end -write_pmpaddr_2: - li x7, 0x2 - bne x7, x28, write_pmpaddr_3 - csrw pmpaddr2, x29 - csrr x30, pmpaddr2 - j write_pmpaddr_end -write_pmpaddr_3: - li x7, 0x3 - bne x7, x28, write_pmpaddr_4 - csrw pmpaddr3, x29 - csrr x30, pmpaddr3 - j write_pmpaddr_end -write_pmpaddr_4: - li x7, 0x4 - bne x7, x28, write_pmpaddr_5 - csrw pmpaddr4, x29 - csrr x30, pmpaddr4 - j write_pmpaddr_end -write_pmpaddr_5: - li x7, 0x5 - bne x7, x28, write_pmpaddr_6 - csrw pmpaddr5, x29 - csrr x30, pmpaddr5 - j write_pmpaddr_end -write_pmpaddr_6: - li x7, 0x6 - bne x7, x28, write_pmpaddr_7 - csrw pmpaddr6, x29 - csrr x30, pmpaddr6 - j write_pmpaddr_end -write_pmpaddr_7: - li x7, 0x7 - bne x7, x28, write_pmpaddr_8 - csrw pmpaddr7, x29 - csrr x30, pmpaddr7 - j write_pmpaddr_end -write_pmpaddr_8: - li x7, 0x8 - bne x7, x28, write_pmpaddr_9 - csrw pmpaddr8, x29 - csrr x30, pmpaddr8 - j write_pmpaddr_end -write_pmpaddr_9: - li x7, 0x9 - bne x7, x28, write_pmpaddr_10 - csrw pmpaddr9, x29 - csrr x30, pmpaddr9 - j write_pmpaddr_end -write_pmpaddr_10: - li x7, 0xA - bne x7, x28, write_pmpaddr_11 - csrw pmpaddr10, x29 - csrr x30, pmpaddr10 - j write_pmpaddr_end -write_pmpaddr_11: - li x7, 0xB - bne x7, x28, write_pmpaddr_12 - csrw pmpaddr11, x29 - csrr x30, pmpaddr11 - j write_pmpaddr_end -write_pmpaddr_12: - li x7, 0xC - bne x7, x28, write_pmpaddr_13 - csrw pmpaddr12, x29 - csrr x30, pmpaddr12 - j write_pmpaddr_end -write_pmpaddr_13: - li x7, 0xD - bne x7, x28, write_pmpaddr_14 - csrw pmpaddr13, x29 - csrr x30, pmpaddr13 - j write_pmpaddr_end -write_pmpaddr_14: - li x7, 0xE - bne x7, x28, write_pmpaddr_15 - csrw pmpaddr14, x29 - csrr x30, pmpaddr14 - j write_pmpaddr_end -write_pmpaddr_15: - li x7, 0xF - bne x7, x28, write_pmpaddr_end - csrw pmpaddr15, x29 - csrr x30, pmpaddr15 - j write_pmpaddr_end -write_pmpaddr_end: - sw x30, 0(x6) - addi x6, x6, 4 - addi x16, x16, 4 - j test_loop - -executable_test: - # Execute the code at the address in x28, returning the value in x7. - # Assumes the code modifies x7, to become the value stored in x29 for this test. - fence.i # forces cache and main memory to sync so execution code written by the program can run. - li x7, 0xBAD - jalr x28 - sw x7, 0(x6) - addi x6, x6, 4 - addi x16, x16, 4 - j test_loop - - - -terminate_test: - - li a0, 2 # Trap handler behavior (go to machine mode) - ecall # writes mcause to the output. - csrw mtvec, x4 # restore original trap handler to halt program - - -RVTEST_CODE_END -RVMODEL_HALT - -RVTEST_DATA_BEGIN -.align 4 -rvtest_data: -.word 0xbabecafe -RVTEST_DATA_END - -.align 2 # align stack to 4 byte boundary -bottom_of_stack: - .fill 1024, 4, 0xdeadbeef -top_of_stack: - - - -RVMODEL_DATA_BEGIN - -// next lines through test cases copied over from old framework -test_1_res: - .fill 1024, 4, 0xdeadbeef - -RVMODEL_DATA_END - -#ifdef rvtest_mtrap_routine - -mtrap_sigptr: - .fill 64*(XLEN/32),4,0xdeadbeef - -#endif - -#ifdef rvtest_gpr_save - -gpr_save: - .fill 32*(XLEN/32),4,0xdeadbeef - -#endif - -.align 2 -test_cases: - diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h new file mode 100644 index 00000000..31bd1194 --- /dev/null +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h @@ -0,0 +1,607 @@ +/////////////////////////////////////////// +// +// WALLY-TEST-LIB-32.S +// +// Author: Kip Macsai-Goren +// +// Created 2021-07-20 +// +// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/////////////////////////////////////////// + +#include "model_test.h" +#include "arch_test.h" +RVTEST_ISA("RV32I") + +.section .text.init +.globl rvtest_entry_point +rvtest_entry_point: +RVMODEL_BOOT +RVTEST_CODE_BEGIN + + // --------------------------------------------------------------------------------------------- + // Initialization Overview: + // + // Initialize x6 as a virtual pointer to the test results + // Initialize x16 as a physical pointer to the test results + // Set up stack pointer (sp = x2) + // Set up the exception Handler, keeping the original handler in x4. + // + // --------------------------------------------------------------------------------------------- + + // address for test results + la x6, test_1_res + la x16, test_1_res // x16 reserved for the physical address equivalent of x6 to be used in trap handlers + // any time either is used, both must be updated. + + // address for stack + la sp, top_of_stack + + // trap handler setup + la x1, machine_trap_handler + csrrw x4, mtvec, x1 // x4 reserved for "default" trap handler address that needs to be restored before halting this test. + li a0, 0 + li a1, 0 + li a2, 0 // reset trap handler inputs to zero + + // go to first test! + j test_setup + + + // --------------------------------------------------------------------------------------------- + // General traps Handler + // + // Handles traps by branching to different behaviors based on mcause. + // + // Note that allowing the exception handler to change mode for a program is a huge security + // hole, but this is an expedient way of writing tests that need different modes + // + // input parameters: + // + // a0 (x10): + // 0: halt program with no failures + // 1: halt program with failure in x11 = a1 + // 2: go to machine mode + // 3: go to supervisor mode + // 4: go to user mode + // others: do nothing + // + // a1 (x11): + // VPN for return address after changing privilege mode. + // This should be the base VPN with no offset. + // 0x0 : defaults to next instruction on the same page the trap was called on. + // + // a2 (x12): + // Pagetype of the current address VPN before changing privilge mode + // Used so that we can know how many bits of the adress are the offset. + // Ignored if a1 == 0x0 + // 0: Kilopage + // 1: Megapage + // + // -------------------------------------------------------------------------------------------- + + +machine_trap_handler: + // The processor is always in machine mode when a trap takes us here + // save registers on stack before using + sw x1, -4(sp) + sw x5, -8(sp) + + // Record trap + csrr x1, mcause // record the mcause + sw x1, 0(x16) + addi x6, x6, 4 + addi x16, x16, 4 // update pointers for logging results + + // Respond to trap based on cause + // All interrupts should return after being logged + li x5, 0x8000000000000000 // if msb is set, it is an interrupt + and x5, x5, x1 + bnez x5, trapreturn // return from interrupt + // Other trap handling is specified in the vector Table + slli x1, x1, 2 // multiply cause by 4 to get offset in vector Table + la x5, trap_handler_vector_table + add x5, x5, x1 // compute address of vector in Table + lw x5, 0(x5) // fectch address of handler from vector Table + jr x5 // and jump to the handler + +segfault: + lw x5, -8(sp) // restore registers from stack before faulting + lw x1, -4(sp) + j terminate_test // halt program. + +trapreturn: + // look at the instruction to figure out whether to add 2 or 4 bytes to PC, or go to address specified in a1 + csrr x1, mepc // get the mepc + addi x1, x1, 4 // *** should be 2 for compressed instructions, see note. + + +// ****** KMG: the following is no longer as easy to determine. mepc gets the virtual address of the trapped instruction, +// ******** but in the handler, we work in M mode with physical addresses +// This means the address in mepc is suddenly pointing somewhere else. +// to get this to work, We could either retranslate the vaddr back into a paddr (probably on the scale of difficult to intractible) +// or we could come up with some other ingenious way to stay in M mode and see if the instruction was compressed. + +// lw x5, 0(x1) // read the faulting instruction +// li x1, 3 // check bottom 2 bits of instruction to see if compressed +// and x5, x5, x1 // mask the other bits +// beq x5, x1, trapreturn_uncompressed // if 11, the instruction is return_uncompressed + +// trapreturn_compressed: +// csrr x1, mepc // get the mepc again +// addi x1, x1, 2 // add 2 to find the next instruction +// j trapreturn_specified // and return + +// trapreturn_uncompressed: +// csrr x1, mepc // get the mepc again +// addi x1, x1, 4 // add 4 to find the next instruction + +trapreturn_specified: + // reset the necessary pointers and registers (x1, x5, x6, and the return address going to mepc) + // so that when we return to a new virtual address, they're all in the right spot as well. + + beqz a1, trapreturn_finished // either update values, of go to default return address. + + la x5, trap_return_pagetype_table + slli a2, a2, 2 + add x5, x5, a2 + lw a2, 0(x5) // a2 = number of offset bits in current page type + + li x5, 1 + sll x5, x5, a2 + addi x5, x5, -1 // x5 = mask bits for offset into current pagetype + + // reset the top of the stack, x1 + lw x7, -4(sp) + and x7, x5, x7 // x7 = offset for x1 + add x7, x7, a1 // x7 = new address for x1 + sw x7, -4(sp) + + // reset the second spot in the stack, x5 + lw x7, -8(sp) + and x7, x5, x7 // x7 = offset for x5 + add x7, x7, a1 // x7 = new address for x5 + sw x7, -8(sp) + + // reset x6, the pointer for the virtual address of the output of the tests + and x7, x5, x6 // x7 = offset for x6 + add x6, x7, a1 // x6 = new address for the result pointer + + // set return address, stored temporarily in x1, to the next instruction, but in the new virtual page. + and x1, x5, x1 // x1 = offset for the return address + add x1, x1, a1 // x1 = new return address. + + li a1, 0 + li a2, 0 // reset trapreturn inputs to the trap handler + +trapreturn_finished: + csrw mepc, x1 // update the mepc with address of next instruction + lw x5, -8(sp) // restore registers from stack before returning + lw x1, -4(sp) + mret // return from trap + +ecallhandler: + // Check input parameter a0. encoding above. + // *** ASSUMES: that this trap is being handled in machine mode. in other words, that nothing odd has been written to the medeleg or mideleg csrs. + li x5, 2 // case 2: change to machine mode + beq a0, x5, ecallhandler_changetomachinemode + li x5, 3 // case 3: change to supervisor mode + beq a0, x5, ecallhandler_changetosupervisormode + li x5, 4 // case 4: change to user mode + beq a0, x5, ecallhandler_changetousermode + // unsupported ecalls should segfault + j segfault + +ecallhandler_changetomachinemode: + // Force mstatus.MPP (bits 12:11) to 11 to enter machine mode after mret + li x1, 0b1100000000000 + csrs mstatus, x1 + j trapreturn + +ecallhandler_changetosupervisormode: + // Force mstatus.MPP (bits 12:11) to 01 to enter supervisor mode after mret + li x1, 0b1100000000000 + csrc mstatus, x1 + li x1, 0b0100000000000 + csrs mstatus, x1 + j trapreturn + +ecallhandler_changetousermode: + // Force mstatus.MPP (bits 12:11) to 00 to enter user mode after mret + li x1, 0b1100000000000 + csrc mstatus, x1 + j trapreturn + +instrfault: + lw x1, -4(sp) // load return address int x1 (the address after the jal into faulting page) + j trapreturn_finished // puts x1 into mepc, restores stack and returns to program (outside of faulting page) + +accessfault: + // *** What do I have to do here? + j trapreturn + // Table of trap behavior + // lists what to do on each exception (not interrupts) + // unexpected exceptions should cause segfaults for easy detection + // Expected exceptions should increment the EPC to the next instruction and return + + .align 2 // aligns this data table to an 4 byte boundary +trap_handler_vector_table: + .4byte segfault // 0: instruction address misaligned + .4byte instrfault // 1: instruction access fault + .4byte segfault // 2: illegal instruction + .4byte segfault // 3: breakpoint + .4byte segfault // 4: load address misaligned + .4byte accessfault // 5: load access fault + .4byte segfault // 6: store address misaligned + .4byte accessfault // 7: store access fault + .4byte ecallhandler // 8: ecall from U-mode + .4byte ecallhandler // 9: ecall from S-mode + .4byte segfault // 10: reserved + .4byte ecallhandler // 11: ecall from M-mode + .4byte instrfault // 12: instruction page fault + .4byte trapreturn // 13: load page fault + .4byte segfault // 14: reserved + .4byte trapreturn // 15: store page fault + +.align 2 +trap_return_pagetype_table: + .4byte 0xC // 0: kilopage has 12 offset bits + .4byte 0x16 // 1: megapage has 22 offset bits + + // --------------------------------------------------------------------------------------------- + // Test Handler + // + // This test handler works in a similar wy to the trap handler. It takes in a few things by reading from a table in memory + // (see test_cases) and performing certain behavior based on them. + // + // Input parameters: + // + // x28: + // Address input for the test taking place (think address to read/write, new address to return to, etc...) + // + // x29: + // Value input for the test taking place (think value to write, any other extra info needed) + // + // x30: + // Test type input that determines which kind of test will take place. Encoding for this input is in the table/case statements below + // + // ------------------------------------------------------------------------------------------------------------------------------------ + +test_setup: + la x5, test_cases + +test_loop: + lw x28, 0(x5) // fetch test case address + lw x29, 4(x5) // fetch test case value + lw x30, 8(x5) // fetch test case flag + addi x5, x5, 12 // set x5 to next test case + + // x5 has the symbol for a test's location in the assembly + li x7, 0x3FFFFF + and x30, x30, x7 // This program is always on at least a megapage, so this masks out the megapage offset. + auipc x7, 0x0 + srli x7, x7, 22 + slli x7, x7, 22 // zero out the bottom 22 bits so the megapage offset of the symbol can be placed there + or x30, x7, x30 // x30 = virtual address of the symbol for this type of test. + + jr x30 + +// Test Name : Description : Fault output value : Normal output values +// ----------------------:---------------------------------------:------------------------:------------------------------------------------------ +// write32_test : Write 32 bits to address : 0xf : None +// write16_test : Write 16 bits to address : 0xf : None +// write08_test : Write 8 bits to address : 0xf : None +// read32_test : Read 32 bits from address : 0xd, 0xbad : readvalue in hex +// read16_test : Read 16 bits from address : 0xd, 0xbad : readvalue in hex +// read08_test : Read 8 bits from address : 0xd, 0xbad : readvalue in hex +// executable_test : test executable at address : 0xc, 0xbad : leading 12 bits of the li instr written to address. In general this is 0x111. (be sure to also write a return instruction) +// terminate_test : terminate tests : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 +// goto_baremetal : satp.MODE = bare metal : None : None +// goto_sv32 : satp.MODE = sv32 : None : None +// write_mxr_sum : write sstatus.[19:18] = MXR, SUM bits : None : None +// goto_m_mode : go to mahcine mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 +// goto_s_mode : go to supervisor mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 +// goto_u_mode : go to user mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 +// write_pmpcfg_x : Write one of the pmpcfg csr's : mstatuses?, 0xD : readback of pmpcfg value +// write_pmpaddr_x : Write one of the pmpaddr csr's : None : readback of pmpaddr value + + +write32_test: + // address to write in x28, word value in x29 + sw x29, 0(x28) + j test_loop // go to next test case + +write16_test: + // address to write in x28, halfword value in x29 + sh x29, 0(x28) + j test_loop // go to next test case + +write08_test: + // address to write in x28, value in x29 + sb x29, 0(x28) + j test_loop // go to next test case + +read32_test: + // address to read in x28, expected 32 bit value in x29 (unused, but there for your perusal). + li x7, 0xBAD // bad value that will be overwritten on good reads. + lw x7, 0(x28) + sw x7, 0(x6) + addi x6, x6, 4 + addi x16, x16, 4 + j test_loop // go to next test case + +read16_test: + // address to read in x28, expected 16 bit value in x29 (unused, but there for your perusal). + li x7, 0xBAD // bad value that will be overwritten on good reads. + lh x7, 0(x28) + sw x7, 0(x6) + addi x6, x6, 4 + addi x16, x16, 4 + j test_loop // go to next test case + +read08_test: + // address to read in x28, expected 8 bit value in x29 (unused, but there for your perusal). + li x7, 0xBAD // bad value that will be overwritten on good reads. + lb x7, 0(x28) + sw x7, 0(x6) + addi x6, x6, 4 + addi x16, x16, 4 + j test_loop // go to next test case + + +goto_s_mode: + li a0, 3 // Trap handler behavior (go to machine mode) + mv a1, x28 // return VPN + mv a2, x29 // return page types + ecall // writes mcause to the output. + // now in S mode + j test_loop + +goto_m_mode: + li a0, 2 // Trap handler behavior (go to machine mode) + mv a1, x28 // return VPN + mv a2, x29 // return page types + ecall // writes mcause to the output. + j test_loop + +goto_u_mode: + li a0, 4 // Trap handler behavior (go to user mode) + mv a1, x28 // return VPN + mv a2, x29 // return page types + ecall // writes mcause to the output. + j test_loop + +goto_baremetal: + // Turn translation off + li x7, 0 // satp.MODE value for bare metal (0) + slli x7, x7, 31 + li x28, 0x8000D // Base Pagetable physical page number, satp.PPN field. + add x7, x7, x28 + csrw satp, x7 + sfence.vma x0, x0 // *** flushes global pte's as well. Be careful + j test_loop // go to next test case + +goto_sv32: + li x7, 1 // satp.MODE value for Sv39 (1) + slli x7, x7, 31 + li x28, 0x8000D // Base Pagetable physical page number, satp.PPN field. + add x7, x7, x28 + csrw satp, x7 + sfence.vma x0, x0 // *** flushes global pte's as well. Be careful + j test_loop // go to next test case + +write_mxr_sum: + // writes sstatus.[mxr, sum] with the (assumed to be) 2 bit value in x29. also assumes we're in S. M mode + li x30, 0xC0000 // mask bits for MXR, SUM + not x7, x29 + slli x7, x7, 18 + and x7, x7, x30 + slli x29, x29, 18 + csrc sstatus, x7 + csrs sstatus, x29 + j test_loop + +write_pmpcfg_0: + // writes the value in x29 to the pmpcfg register specified in x28. + li x7, 0x0 + bne x7, x28, write_pmpcfg_1 + csrw pmpcfg0, x29 + csrr x30, pmpcfg0 +write_pmpcfg_1: + li x7, 0x1 + bne x7, x28, write_pmpcfg_2 + csrw pmpcfg1, x29 + csrr x30, pmpcfg1 +write_pmpcfg_2: + li x7, 0x2 + bne x7, x28, write_pmpcfg_3 + csrw pmpcfg2, x29 + csrr x30, pmpcfg2 +write_pmpcfg_3: + li x7, 0x3 + bne x7, x28, write_pmpcfg_end + csrw pmpcfg3, x29 + csrr x30, pmpcfg3 +write_pmpcfg_end: + sw x30, 0(x6) + addi x6, x6, 4 + addi x16, x16, 4 + j test_loop + +write_pmpaddr_0: + // writes the value in x29 to the pmpaddr register specified in x28. + // then writes the final value of pmpaddrX to the output. + li x7, 0x0 + bne x7, x28, write_pmpaddr_1 + csrw pmpaddr0, x29 + csrr x30, pmpaddr0 + j write_pmpaddr_end +write_pmpaddr_1: + li x7, 0x1 + bne x7, x28, write_pmpaddr_2 + csrw pmpaddr1, x29 + csrr x30, pmpaddr1 + j write_pmpaddr_end +write_pmpaddr_2: + li x7, 0x2 + bne x7, x28, write_pmpaddr_3 + csrw pmpaddr2, x29 + csrr x30, pmpaddr2 + j write_pmpaddr_end +write_pmpaddr_3: + li x7, 0x3 + bne x7, x28, write_pmpaddr_4 + csrw pmpaddr3, x29 + csrr x30, pmpaddr3 + j write_pmpaddr_end +write_pmpaddr_4: + li x7, 0x4 + bne x7, x28, write_pmpaddr_5 + csrw pmpaddr4, x29 + csrr x30, pmpaddr4 + j write_pmpaddr_end +write_pmpaddr_5: + li x7, 0x5 + bne x7, x28, write_pmpaddr_6 + csrw pmpaddr5, x29 + csrr x30, pmpaddr5 + j write_pmpaddr_end +write_pmpaddr_6: + li x7, 0x6 + bne x7, x28, write_pmpaddr_7 + csrw pmpaddr6, x29 + csrr x30, pmpaddr6 + j write_pmpaddr_end +write_pmpaddr_7: + li x7, 0x7 + bne x7, x28, write_pmpaddr_8 + csrw pmpaddr7, x29 + csrr x30, pmpaddr7 + j write_pmpaddr_end +write_pmpaddr_8: + li x7, 0x8 + bne x7, x28, write_pmpaddr_9 + csrw pmpaddr8, x29 + csrr x30, pmpaddr8 + j write_pmpaddr_end +write_pmpaddr_9: + li x7, 0x9 + bne x7, x28, write_pmpaddr_10 + csrw pmpaddr9, x29 + csrr x30, pmpaddr9 + j write_pmpaddr_end +write_pmpaddr_10: + li x7, 0xA + bne x7, x28, write_pmpaddr_11 + csrw pmpaddr10, x29 + csrr x30, pmpaddr10 + j write_pmpaddr_end +write_pmpaddr_11: + li x7, 0xB + bne x7, x28, write_pmpaddr_12 + csrw pmpaddr11, x29 + csrr x30, pmpaddr11 + j write_pmpaddr_end +write_pmpaddr_12: + li x7, 0xC + bne x7, x28, write_pmpaddr_13 + csrw pmpaddr12, x29 + csrr x30, pmpaddr12 + j write_pmpaddr_end +write_pmpaddr_13: + li x7, 0xD + bne x7, x28, write_pmpaddr_14 + csrw pmpaddr13, x29 + csrr x30, pmpaddr13 + j write_pmpaddr_end +write_pmpaddr_14: + li x7, 0xE + bne x7, x28, write_pmpaddr_15 + csrw pmpaddr14, x29 + csrr x30, pmpaddr14 + j write_pmpaddr_end +write_pmpaddr_15: + li x7, 0xF + bne x7, x28, write_pmpaddr_end + csrw pmpaddr15, x29 + csrr x30, pmpaddr15 + j write_pmpaddr_end +write_pmpaddr_end: + sw x30, 0(x6) + addi x6, x6, 4 + addi x16, x16, 4 + j test_loop + +executable_test: + // Execute the code at the address in x28, returning the value in x7. + // Assumes the code modifies x7, to become the value stored in x29 for this test. + fence.i // forces cache and main memory to sync so execution code written by the program can run. + li x7, 0xBAD + jalr x28 + sw x7, 0(x6) + addi x6, x6, 4 + addi x16, x16, 4 + j test_loop + + + +terminate_test: + + li a0, 2 // Trap handler behavior (go to machine mode) + ecall // writes mcause to the output. + csrw mtvec, x4 // restore original trap handler to halt program + + +RVTEST_CODE_END +RVMODEL_HALT + +RVTEST_DATA_BEGIN +.align 4 +rvtest_data: +.word 0xbabecafe +RVTEST_DATA_END + +.align 2 // align stack to 4 byte boundary +bottom_of_stack: + .fill 1024, 4, 0xdeadbeef +top_of_stack: + + + +RVMODEL_DATA_BEGIN + +// next lines through test cases copied over from old framework +test_1_res: + .fill 1024, 4, 0xdeadbeef + +RVMODEL_DATA_END + +#ifdef rvtest_mtrap_routine + +mtrap_sigptr: + .fill 64*(XLEN/32),4,0xdeadbeef + +#endif + +#ifdef rvtest_gpr_save + +gpr_save: + .fill 32*(XLEN/32),4,0xdeadbeef + +#endif + +.align 2 +test_cases: + diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-MMU-SV39.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-MMU-SV39.S index 56de42c9..39ca0a25 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-MMU-SV39.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-MMU-SV39.S @@ -21,7 +21,7 @@ // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /////////////////////////////////////////// -#include "WALLY-TEST-LIB-64.S" +#include "WALLY-TEST-LIB-64.h" // Test library includes and handler for each type of test, a trap handler, imperas compliance instructions // Ideally this should mean that a test can be written by simply adding .8byte statements as below. diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-MMU-SV48.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-MMU-SV48.S index db21370c..260a40fe 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-MMU-SV48.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-MMU-SV48.S @@ -21,7 +21,7 @@ // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /////////////////////////////////////////// -#include "WALLY-TEST-LIB-64.S" +#include "WALLY-TEST-LIB-64.h" // Test library includes and handler for each type of test, a trap handler, imperas compliance instructions // Ideally this should mean that a test can be written by simply adding .8byte statements as below. diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-PMA.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-PMA.S index af14ce75..a4a50a3d 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-PMA.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-PMA.S @@ -34,7 +34,7 @@ #define PLIC_BASE 0x0C000000 #define PLIC_RANGE 0x03FFFFFF -#include "WALLY-TEST-LIB-64.S" +#include "WALLY-TEST-LIB-64.h" // Test library includes and handler for each type of test, a trap handler, imperas compliance instructions // Ideally this should mean that a test can be written by simply adding .8byte statements as below. diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-PMP.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-PMP.S index 16bb3a2d..226c9398 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-PMP.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-PMP.S @@ -21,7 +21,7 @@ // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /////////////////////////////////////////// -#include "WALLY-TEST-LIB-64.S" +#include "WALLY-TEST-LIB-64.h" // Test library includes and handler for each type of test, a trap handler, imperas compliance instructions // Ideally this should mean that a test can be written by simply adding .8byte statements as below. diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.S deleted file mode 100644 index 1d0cc969..00000000 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.S +++ /dev/null @@ -1,624 +0,0 @@ -/////////////////////////////////////////// -// -// WALLY-TEST-LIB-64.S -// -// Author: Kip Macsai-Goren -// -// Created 2021-07-19 -// -// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, -// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -/////////////////////////////////////////// - -#include "model_test.h" -#include "arch_test.h" -RVTEST_ISA("RV64I") - -.section .text.init -.globl rvtest_entry_point -rvtest_entry_point: -RVMODEL_BOOT -RVTEST_CODE_BEGIN - - # --------------------------------------------------------------------------------------------- - # Initialization Overview: - # - # Initialize x6 as a virtual pointer to the test results - # Initialize x16 as a physical pointer to the test results - # Set up stack pointer (sp = x2) - # Set up the exception Handler, keeping the original handler in x4. - # - # --------------------------------------------------------------------------------------------- - - # address for test results - la x6, test_1_res - la x16, test_1_res # x16 reserved for the physical address equivalent of x6 to be used in trap handlers - # any time either is used, both must be updated. - - # address for stack - la sp, top_of_stack - - # trap handler setup - la x1, machine_trap_handler - csrrw x4, mtvec, x1 # x4 reserved for "default" trap handler address that needs to be restored before halting this test. - li a0, 0 - li a1, 0 - li a2, 0 # reset trap handler inputs to zero - - # go to first test! - j test_setup - - - # --------------------------------------------------------------------------------------------- - # General traps Handler - # - # Handles traps by branching to different behaviors based on mcause. - # - # Note that allowing the exception handler to change mode for a program is a huge security - # hole, but this is an expedient way of writing tests that need different modes - # - # input parameters: - # - # a0 (x10): - # 0: halt program with no failures - # 1: halt program with failure in x11 = a1 - # 2: go to machine mode - # 3: go to supervisor mode - # 4: go to user mode - # others: do nothing - # - # a1 (x11): - # VPN for return address after changing privilege mode. - # This should be the base VPN with no offset. - # 0x0 : defaults to next instruction on the same page the trap was called on. - # - # a2 (x12): - # Pagetype of the current address VPN before changing privilge mode - # Used so that we can know how many bits of the adress are the offset. - # Ignored if a1 == 0x0 - # 0: Kilopage - # 1: Megapage - # 2: Gigapage - # 3: Terapage - # - # -------------------------------------------------------------------------------------------- - - -machine_trap_handler: - # The processor is always in machine mode when a trap takes us here - # save registers on stack before using - sd x1, -8(sp) - sd x5, -16(sp) - - # Record trap - csrr x1, mcause # record the mcause - sd x1, 0(x16) - addi x6, x6, 8 - addi x16, x16, 8 # update pointers for logging results - - # Respond to trap based on cause - # All interrupts should return after being logged - li x5, 0x8000000000000000 # if msb is set, it is an interrupt - and x5, x5, x1 - bnez x5, trapreturn # return from interrupt - # Other trap handling is specified in the vector Table - slli x1, x1, 3 # multiply cause by 8 to get offset in vector Table - la x5, trap_handler_vector_table - add x5, x5, x1 # compute address of vector in Table - ld x5, 0(x5) # fectch address of handler from vector Table - jr x5 # and jump to the handler - -segfault: - ld x5, -16(sp) # restore registers from stack before faulting - ld x1, -8(sp) - j terminate_test # halt program. - -trapreturn: - # look at the instruction to figure out whether to add 2 or 4 bytes to PC, or go to address specified in a1 - csrr x1, mepc # get the mepc - addi x1, x1, 4 # *** should be 2 for compressed instructions, see note. - - -# ****** KMG: the following is no longer as easy to determine. mepc gets the virtual address of the trapped instruction, -# ******** but in the handler, we work in M mode with physical addresses -# This means the address in mepc is suddenly pointing somewhere else. -# to get this to work, We could either retranslate the vaddr back into a paddr (probably on the scale of difficult to intractible) -# or we could come up with some other ingenious way to stay in M mode and see if the instruction was compressed. - -# lw x5, 0(x1) # read the faulting instruction -# li x1, 3 # check bottom 2 bits of instruction to see if compressed -# and x5, x5, x1 # mask the other bits -# beq x5, x1, trapreturn_uncompressed # if 11, the instruction is return_uncompressed - -# trapreturn_compressed: -# csrr x1, mepc # get the mepc again -# addi x1, x1, 2 # add 2 to find the next instruction -# j trapreturn_specified # and return - -# trapreturn_uncompressed: -# csrr x1, mepc # get the mepc again -# addi x1, x1, 4 # add 4 to find the next instruction - -trapreturn_specified: - # reset the necessary pointers and registers (x1, x5, x6, and the return address going to mepc) - # so that when we return to a new virtual address, they're all in the right spot as well. - - beqz a1, trapreturn_finished # either update values, of go to default return address. - - la x5, trap_return_pagetype_table - slli a2, a2, 3 - add x5, x5, a2 - ld a2, 0(x5) # a2 = number of offset bits in current page type - - li x5, 1 - sll x5, x5, a2 - addi x5, x5, -1 # x5 = mask bits for offset into current pagetype - - # reset the top of the stack, x1 - ld x7, -8(sp) - and x7, x5, x7 # x7 = offset for x1 - add x7, x7, a1 # x7 = new address for x1 - sd x7, -8(sp) - - # reset the second spot in the stack, x5 - ld x7, -16(sp) - and x7, x5, x7 # x7 = offset for x5 - add x7, x7, a1 # x7 = new address for x5 - sd x7, -16(sp) - - # reset x6, the pointer for the virtual address of the output of the tests - and x7, x5, x6 # x7 = offset for x6 - add x6, x7, a1 # x6 = new address for the result pointer - - # set return address, stored temporarily in x1, to the next instruction, but in the new virtual page. - and x1, x5, x1 # x1 = offset for the return address - add x1, x1, a1 # x1 = new return address. - - li a1, 0 - li a2, 0 # reset trapreturn inputs to the trap handler - -trapreturn_finished: - csrw mepc, x1 # update the mepc with address of next instruction - ld x5, -16(sp) # restore registers from stack before returning - ld x1, -8(sp) - mret # return from trap - -ecallhandler: - # Check input parameter a0. encoding above. - # *** ASSUMES: that this trap is being handled in machine mode. in other words, that nothing odd has been written to the medeleg or mideleg csrs. - li x5, 2 # case 2: change to machine mode - beq a0, x5, ecallhandler_changetomachinemode - li x5, 3 # case 3: change to supervisor mode - beq a0, x5, ecallhandler_changetosupervisormode - li x5, 4 # case 4: change to user mode - beq a0, x5, ecallhandler_changetousermode - # unsupported ecalls should segfault - j segfault - -ecallhandler_changetomachinemode: - # Force mstatus.MPP (bits 12:11) to 11 to enter machine mode after mret - li x1, 0b1100000000000 - csrs mstatus, x1 - j trapreturn - -ecallhandler_changetosupervisormode: - # Force mstatus.MPP (bits 12:11) to 01 to enter supervisor mode after mret - li x1, 0b1100000000000 - csrc mstatus, x1 - li x1, 0b0100000000000 - csrs mstatus, x1 - j trapreturn - -ecallhandler_changetousermode: - # Force mstatus.MPP (bits 12:11) to 00 to enter user mode after mret - li x1, 0b1100000000000 - csrc mstatus, x1 - j trapreturn - -instrfault: - ld x1, -8(sp) # load return address int x1 (the address AFTER the jal into faulting page) - j trapreturn_finished # puts x1 into mepc, restores stack and returns to program (outside of faulting page) - -accessfault: - # *** What do I have to do here? - j trapreturn - - # Table of trap behavior - # lists what to do on each exception (not interrupts) - # unexpected exceptions should cause segfaults for easy detection - # Expected exceptions should increment the EPC to the next instruction and return - - .align 3 # aligns this data table to an 8 byte boundary -trap_handler_vector_table: - .8byte segfault # 0: instruction address misaligned - .8byte instrfault # 1: instruction access fault - .8byte segfault # 2: illegal instruction - .8byte segfault # 3: breakpoint - .8byte segfault # 4: load address misaligned - .8byte accessfault # 5: load access fault - .8byte segfault # 6: store address misaligned - .8byte accessfault # 7: store access fault - .8byte ecallhandler # 8: ecall from U-mode - .8byte ecallhandler # 9: ecall from S-mode - .8byte segfault # 10: reserved - .8byte ecallhandler # 11: ecall from M-mode - .8byte instrfault # 12: instruction page fault - .8byte trapreturn # 13: load page fault - .8byte segfault # 14: reserved - .8byte trapreturn # 15: store page fault - -.align 3 -trap_return_pagetype_table: - .8byte 0xC # 0: kilopage has 12 offset bits - .8byte 0x15 # 1: megapage has 21 offset bits - .8byte 0x1E # 2: gigapage has 30 offset bits - .8byte 0x27 # 3: terapage has 39 offset bits - - # --------------------------------------------------------------------------------------------- - # Test Handler - # - # This test handler works in a similar wy to the trap handler. It takes in a few things by reading from a table in memory - # (see test_cases) and performing certain behavior based on them. - # - # Input parameters: - # - # x28: - # Address input for the test taking place (think address to read/write, new address to return to, etc...) - # - # x29: - # Value input for the test taking place (think value to write, any other extra info needed) - # - # x30: - # Test type input that determines which kind of test will take place. Encoding for this input is in the table/case statements below - # - # ------------------------------------------------------------------------------------------------------------------------------------ - -test_setup: - la x5, test_cases - -test_loop: - ld x28, 0(x5) # fetch test case address - ld x29, 8(x5) # fetch test case value - ld x30, 16(x5) # fetch test case flag - addi x5, x5, 24 # set x5 to next test case - - # x5 has the symbol for a test's location in the assembly - li x7, 0x1FFFFF - and x30, x30, x7 # This program is always on at least a megapage, so this masks out the megapage offset. - auipc x7, 0x0 - srli x7, x7, 21 - slli x7, x7, 21 # zero out the bottom 21 bits so the megapage offset of the symbol can be placed there - or x30, x7, x30 # x30 = virtual address of the symbol for this type of test. - - jr x30 - -# Test Name : Description : Fault output value : Normal output values -# ----------------------:-------------------------------------------:------------------------:------------------------------------------------------ -# write64_test : Write 64 bits to address : 0xf : None -# write32_test : Write 32 bits to address : 0xf : None -# write16_test : Write 16 bits to address : 0xf : None -# write08_test : Write 8 bits to address : 0xf : None -# read64_test : Read 64 bits from address : 0xd, 0xbad : readvalue in hex -# read32_test : Read 32 bitsfrom address : 0xd, 0xbad : readvalue in hex -# read16_test : Read 16 bitsfrom address : 0xd, 0xbad : readvalue in hex -# read08_test : Read 8 bitsfrom address : 0xd, 0xbad : readvalue in hex -# executable_test : test executable on virtual page : 0xc, 0xbad : value of x7 modified by exectuion code (usually 0x111) -# terminate_test : terminate tests : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 -# goto_baremetal : satp.MODE = bare metal : None : None -# goto_sv39 : satp.MODE = sv39 : None : None -# goto_sv48 : satp.MODE = sv48 : None : None -# write_mxr_sum : write sstatus.[19:18] = MXR, SUM bits : None : None -# goto_m_mode : go to mahcine mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 -# goto_s_mode : go to supervisor mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 -# goto_u_mode : go to user mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 -# write_pmpcfg_x : Write one of the pmpcfg csr's : mstatuses?, 0xD : readback of pmpcfg value -# write_pmpaddr_x : Write one of the pmpaddr csr's : None : readback of pmpaddr value - - -write64_test: - # address to write in x28, double value in x29 - sd x29, 0(x28) - j test_loop # go to next test case - -write32_test: - # address to write in x28, word value in x29 - sw x29, 0(x28) - j test_loop # go to next test case - -write16_test: - # address to write in x28, halfword value in x29 - sh x29, 0(x28) - j test_loop # go to next test case - -write08_test: - # address to write in x28, value in x29 - sb x29, 0(x28) - j test_loop # go to next test case - -read64_test: - # address to read in x28, expected 64 bit value in x29 (unused, but there for your perusal). - li x7, 0xBAD # bad value that will be overwritten on good reads. - ld x7, 0(x28) - sd x7, 0(x6) - addi x6, x6, 8 - addi x16, x16, 8 - j test_loop # go to next test case - -read32_test: - # address to read in x28, expected 32 bit value in x29 (unused, but there for your perusal). - li x7, 0xBAD # bad value that will be overwritten on good reads. - lw x7, 0(x28) - sd x7, 0(x6) - addi x6, x6, 8 - addi x16, x16, 8 - j test_loop # go to next test case - -read16_test: - # address to read in x28, expected 16 bit value in x29 (unused, but there for your perusal). - li x7, 0xBAD # bad value that will be overwritten on good reads. - lh x7, 0(x28) - sd x7, 0(x6) - addi x6, x6, 8 - addi x16, x16, 8 - j test_loop # go to next test case - -read08_test: - # address to read in x28, expected 8 bit value in x29 (unused, but there for your perusal). - li x7, 0xBAD # bad value that will be overwritten on good reads. - lb x7, 0(x28) - sd x7, 0(x6) - addi x6, x6, 8 - addi x16, x16, 8 - j test_loop # go to next test case - -goto_s_mode: - # return to address in x28, - li a0, 3 # Trap handler behavior (go to supervisor mode) - mv a1, x28 # return VPN - mv a2, x29 # return page types - ecall # writes mcause to the output. - # now in S mode - j test_loop - -goto_m_mode: - li a0, 2 # Trap handler behavior (go to machine mode) - mv a1, x28 # return VPN - mv a2, x29 # return page types - ecall # writes mcause to the output. - j test_loop - -goto_u_mode: - li a0, 4 # Trap handler behavior (go to user mode) - mv a1, x28 # return VPN - mv a2, x29 # return page types - ecall # writes mcause to the output. - j test_loop - -goto_baremetal: - # Turn translation off - li x7, 0 # satp.MODE value for bare metal (0) - slli x7, x7, 60 - li x28, 0x8000D # Base Pagetable physical page number, satp.PPN field. - add x7, x7, x28 - csrw satp, x7 - sfence.vma x0, x0 # *** flushes global pte's as well - j test_loop # go to next test case - -goto_sv39: - li x7, 8 # satp.MODE value for Sv39 (8) - slli x7, x7, 60 - li x28, 0x8000D # Base Pagetable physical page number, satp.PPN field. - add x7, x7, x28 - csrw satp, x7 - sfence.vma x0, x0 # *** flushes global pte's as well - j test_loop # go to next test case - -goto_sv48: - li x7, 9 # satp.MODE value for Sv48 - slli x7, x7, 60 - li x28, 0x8000D # Base Pagetable physical page number, satp.PPN field. - add x7, x7, x28 - csrw satp, x7 - sfence.vma x0, x0 # *** flushes global pte's as well - j test_loop # go to next test case - -write_mxr_sum: - # writes sstatus.[mxr, sum] with the (assumed to be) 2 bit value in x29. also assumes we're in S. M mode - li x30, 0xC0000 # mask bits for MXR, SUM - not x7, x29 - slli x7, x7, 18 - and x7, x7, x30 - slli x29, x29, 18 - csrc sstatus, x7 - csrs sstatus, x29 - j test_loop - -write_pmpcfg_0: - # writes the value in x29 to the pmpcfg register specified in x28. - # then writes the final value of pmpcfgX to the output. - li x7, 0x0 - bne x7, x28, write_pmpcfg_2 - csrw pmpcfg0, x29 - csrr x30, pmpcfg0 -write_pmpcfg_2: - li x7, 0x2 - bne x7, x28, write_pmpcfg_end - csrw pmpcfg2, x29 - csrr x30, pmpcfg2 # I would use csrrw but we need the value AFTER the csr has been written -write_pmpcfg_end: - sd x30, 0(x6) - addi x6, x6, 8 - addi x16, x16, 8 - j test_loop - -write_pmpaddr_0: - # writes the value in x29 to the pmpaddr register specified in x28. - # then writes the final value of pmpaddrX to the output. - li x7, 0x0 - bne x7, x28, write_pmpaddr_1 - csrw pmpaddr0, x29 - csrr x30, pmpaddr0 - j write_pmpaddr_end -write_pmpaddr_1: - li x7, 0x1 - bne x7, x28, write_pmpaddr_2 - csrw pmpaddr1, x29 - csrr x30, pmpaddr1 - j write_pmpaddr_end -write_pmpaddr_2: - li x7, 0x2 - bne x7, x28, write_pmpaddr_3 - csrw pmpaddr2, x29 - csrr x30, pmpaddr2 - j write_pmpaddr_end -write_pmpaddr_3: - li x7, 0x3 - bne x7, x28, write_pmpaddr_4 - csrw pmpaddr3, x29 - csrr x30, pmpaddr3 - j write_pmpaddr_end -write_pmpaddr_4: - li x7, 0x4 - bne x7, x28, write_pmpaddr_5 - csrw pmpaddr4, x29 - csrr x30, pmpaddr4 - j write_pmpaddr_end -write_pmpaddr_5: - li x7, 0x5 - bne x7, x28, write_pmpaddr_6 - csrw pmpaddr5, x29 - csrr x30, pmpaddr5 - j write_pmpaddr_end -write_pmpaddr_6: - li x7, 0x6 - bne x7, x28, write_pmpaddr_7 - csrw pmpaddr6, x29 - csrr x30, pmpaddr6 - j write_pmpaddr_end -write_pmpaddr_7: - li x7, 0x7 - bne x7, x28, write_pmpaddr_8 - csrw pmpaddr7, x29 - csrr x30, pmpaddr7 - j write_pmpaddr_end -write_pmpaddr_8: - li x7, 0x8 - bne x7, x28, write_pmpaddr_9 - csrw pmpaddr8, x29 - csrr x30, pmpaddr8 - j write_pmpaddr_end -write_pmpaddr_9: - li x7, 0x9 - bne x7, x28, write_pmpaddr_10 - csrw pmpaddr9, x29 - csrr x30, pmpaddr9 - j write_pmpaddr_end -write_pmpaddr_10: - li x7, 0xA - bne x7, x28, write_pmpaddr_11 - csrw pmpaddr10, x29 - csrr x30, pmpaddr10 - j write_pmpaddr_end -write_pmpaddr_11: - li x7, 0xB - bne x7, x28, write_pmpaddr_12 - csrw pmpaddr11, x29 - csrr x30, pmpaddr11 - j write_pmpaddr_end -write_pmpaddr_12: - li x7, 0xC - bne x7, x28, write_pmpaddr_13 - csrw pmpaddr12, x29 - csrr x30, pmpaddr12 - j write_pmpaddr_end -write_pmpaddr_13: - li x7, 0xD - bne x7, x28, write_pmpaddr_14 - csrw pmpaddr13, x29 - csrr x30, pmpaddr13 - j write_pmpaddr_end -write_pmpaddr_14: - li x7, 0xE - bne x7, x28, write_pmpaddr_15 - csrw pmpaddr14, x29 - csrr x30, pmpaddr14 - j write_pmpaddr_end -write_pmpaddr_15: - li x7, 0xF - bne x7, x28, write_pmpaddr_end - csrw pmpaddr15, x29 - csrr x30, pmpaddr15 - j write_pmpaddr_end -write_pmpaddr_end: - sd x30, 0(x6) - addi x6, x6, 8 - addi x16, x16, 8 - j test_loop - -executable_test: - # Execute the code at the address in x28, returning the value in x7. - # Assumes the code modifies x7, to become the value stored in x29 for this test. - fence.i # forces cache and main memory to sync so execution code written by the program can run. - li x7, 0xBAD - jalr x28 - sd x7, 0(x6) - addi x6, x6, 8 - addi x16, x16, 8 - j test_loop - -terminate_test: - - li a0, 2 # Trap handler behavior (go to machine mode) - ecall # writes mcause to the output. - csrw mtvec, x4 # restore original trap handler to halt program - -RVTEST_CODE_END -RVMODEL_HALT - -RVTEST_DATA_BEGIN -.align 4 -rvtest_data: -.word 0xbabecafe -RVTEST_DATA_END - -.align 3 # align stack to 8 byte boundary -bottom_of_stack: - .fill 1024, 4, 0xdeadbeef -top_of_stack: - - -RVMODEL_DATA_BEGIN - -test_1_res: - .fill 1024, 4, 0xdeadbeef - -RVMODEL_DATA_END - -#ifdef rvtest_mtrap_routine - -mtrap_sigptr: - .fill 64*(XLEN/32),4,0xdeadbeef - -#endif - -#ifdef rvtest_gpr_save - -gpr_save: - .fill 32*(XLEN/32),4,0xdeadbeef - -#endif - -.align 3 -test_cases: - diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h new file mode 100644 index 00000000..5e946618 --- /dev/null +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h @@ -0,0 +1,624 @@ +/////////////////////////////////////////// +// +// WALLY-TEST-LIB-64.S +// +// Author: Kip Macsai-Goren +// +// Created 2021-07-19 +// +// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/////////////////////////////////////////// + +#include "model_test.h" +#include "arch_test.h" +RVTEST_ISA("RV64I") + +.section .text.init +.globl rvtest_entry_point +rvtest_entry_point: +RVMODEL_BOOT +RVTEST_CODE_BEGIN + + // --------------------------------------------------------------------------------------------- + // Initialization Overview: + // + // Initialize x6 as a virtual pointer to the test results + // Initialize x16 as a physical pointer to the test results + // Set up stack pointer (sp = x2) + // Set up the exception Handler, keeping the original handler in x4. + // + // --------------------------------------------------------------------------------------------- + + // address for test results + la x6, test_1_res + la x16, test_1_res // x16 reserved for the physical address equivalent of x6 to be used in trap handlers + // any time either is used, both must be updated. + + // address for stack + la sp, top_of_stack + + // trap handler setup + la x1, machine_trap_handler + csrrw x4, mtvec, x1 // x4 reserved for "default" trap handler address that needs to be restored before halting this test. + li a0, 0 + li a1, 0 + li a2, 0 // reset trap handler inputs to zero + + // go to first test! + j test_setup + + + // --------------------------------------------------------------------------------------------- + // General traps Handler + // + // Handles traps by branching to different behaviors based on mcause. + // + // Note that allowing the exception handler to change mode for a program is a huge security + // hole, but this is an expedient way of writing tests that need different modes + // + // input parameters: + // + // a0 (x10): + // 0: halt program with no failures + // 1: halt program with failure in x11 = a1 + // 2: go to machine mode + // 3: go to supervisor mode + // 4: go to user mode + // others: do nothing + // + // a1 (x11): + // VPN for return address after changing privilege mode. + // This should be the base VPN with no offset. + // 0x0 : defaults to next instruction on the same page the trap was called on. + // + // a2 (x12): + // Pagetype of the current address VPN before changing privilge mode + // Used so that we can know how many bits of the adress are the offset. + // Ignored if a1 == 0x0 + // 0: Kilopage + // 1: Megapage + // 2: Gigapage + // 3: Terapage + // + // -------------------------------------------------------------------------------------------- + + +machine_trap_handler: + // The processor is always in machine mode when a trap takes us here + // save registers on stack before using + sd x1, -8(sp) + sd x5, -16(sp) + + // Record trap + csrr x1, mcause // record the mcause + sd x1, 0(x16) + addi x6, x6, 8 + addi x16, x16, 8 // update pointers for logging results + + // Respond to trap based on cause + // All interrupts should return after being logged + li x5, 0x8000000000000000 // if msb is set, it is an interrupt + and x5, x5, x1 + bnez x5, trapreturn // return from interrupt + // Other trap handling is specified in the vector Table + slli x1, x1, 3 // multiply cause by 8 to get offset in vector Table + la x5, trap_handler_vector_table + add x5, x5, x1 // compute address of vector in Table + ld x5, 0(x5) // fectch address of handler from vector Table + jr x5 // and jump to the handler + +segfault: + ld x5, -16(sp) // restore registers from stack before faulting + ld x1, -8(sp) + j terminate_test // halt program. + +trapreturn: + // look at the instruction to figure out whether to add 2 or 4 bytes to PC, or go to address specified in a1 + csrr x1, mepc // get the mepc + addi x1, x1, 4 // *** should be 2 for compressed instructions, see note. + + +// ****** KMG: the following is no longer as easy to determine. mepc gets the virtual address of the trapped instruction, +// ******** but in the handler, we work in M mode with physical addresses +// This means the address in mepc is suddenly pointing somewhere else. +// to get this to work, We could either retranslate the vaddr back into a paddr (probably on the scale of difficult to intractible) +// or we could come up with some other ingenious way to stay in M mode and see if the instruction was compressed. + +// lw x5, 0(x1) // read the faulting instruction +// li x1, 3 // check bottom 2 bits of instruction to see if compressed +// and x5, x5, x1 // mask the other bits +// beq x5, x1, trapreturn_uncompressed // if 11, the instruction is return_uncompressed + +// trapreturn_compressed: +// csrr x1, mepc // get the mepc again +// addi x1, x1, 2 // add 2 to find the next instruction +// j trapreturn_specified // and return + +// trapreturn_uncompressed: +// csrr x1, mepc // get the mepc again +// addi x1, x1, 4 // add 4 to find the next instruction + +trapreturn_specified: + // reset the necessary pointers and registers (x1, x5, x6, and the return address going to mepc) + // so that when we return to a new virtual address, they're all in the right spot as well. + + beqz a1, trapreturn_finished // either update values, of go to default return address. + + la x5, trap_return_pagetype_table + slli a2, a2, 3 + add x5, x5, a2 + ld a2, 0(x5) // a2 = number of offset bits in current page type + + li x5, 1 + sll x5, x5, a2 + addi x5, x5, -1 // x5 = mask bits for offset into current pagetype + + // reset the top of the stack, x1 + ld x7, -8(sp) + and x7, x5, x7 // x7 = offset for x1 + add x7, x7, a1 // x7 = new address for x1 + sd x7, -8(sp) + + // reset the second spot in the stack, x5 + ld x7, -16(sp) + and x7, x5, x7 // x7 = offset for x5 + add x7, x7, a1 // x7 = new address for x5 + sd x7, -16(sp) + + // reset x6, the pointer for the virtual address of the output of the tests + and x7, x5, x6 // x7 = offset for x6 + add x6, x7, a1 // x6 = new address for the result pointer + + // set return address, stored temporarily in x1, to the next instruction, but in the new virtual page. + and x1, x5, x1 // x1 = offset for the return address + add x1, x1, a1 // x1 = new return address. + + li a1, 0 + li a2, 0 // reset trapreturn inputs to the trap handler + +trapreturn_finished: + csrw mepc, x1 // update the mepc with address of next instruction + ld x5, -16(sp) // restore registers from stack before returning + ld x1, -8(sp) + mret // return from trap + +ecallhandler: + // Check input parameter a0. encoding above. + // *** ASSUMES: that this trap is being handled in machine mode. in other words, that nothing odd has been written to the medeleg or mideleg csrs. + li x5, 2 // case 2: change to machine mode + beq a0, x5, ecallhandler_changetomachinemode + li x5, 3 // case 3: change to supervisor mode + beq a0, x5, ecallhandler_changetosupervisormode + li x5, 4 // case 4: change to user mode + beq a0, x5, ecallhandler_changetousermode + // unsupported ecalls should segfault + j segfault + +ecallhandler_changetomachinemode: + // Force mstatus.MPP (bits 12:11) to 11 to enter machine mode after mret + li x1, 0b1100000000000 + csrs mstatus, x1 + j trapreturn + +ecallhandler_changetosupervisormode: + // Force mstatus.MPP (bits 12:11) to 01 to enter supervisor mode after mret + li x1, 0b1100000000000 + csrc mstatus, x1 + li x1, 0b0100000000000 + csrs mstatus, x1 + j trapreturn + +ecallhandler_changetousermode: + // Force mstatus.MPP (bits 12:11) to 00 to enter user mode after mret + li x1, 0b1100000000000 + csrc mstatus, x1 + j trapreturn + +instrfault: + ld x1, -8(sp) // load return address int x1 (the address AFTER the jal into faulting page) + j trapreturn_finished // puts x1 into mepc, restores stack and returns to program (outside of faulting page) + +accessfault: + // *** What do I have to do here? + j trapreturn + + // Table of trap behavior + // lists what to do on each exception (not interrupts) + // unexpected exceptions should cause segfaults for easy detection + // Expected exceptions should increment the EPC to the next instruction and return + + .align 3 // aligns this data table to an 8 byte boundary +trap_handler_vector_table: + .8byte segfault // 0: instruction address misaligned + .8byte instrfault // 1: instruction access fault + .8byte segfault // 2: illegal instruction + .8byte segfault // 3: breakpoint + .8byte segfault // 4: load address misaligned + .8byte accessfault // 5: load access fault + .8byte segfault // 6: store address misaligned + .8byte accessfault // 7: store access fault + .8byte ecallhandler // 8: ecall from U-mode + .8byte ecallhandler // 9: ecall from S-mode + .8byte segfault // 10: reserved + .8byte ecallhandler // 11: ecall from M-mode + .8byte instrfault // 12: instruction page fault + .8byte trapreturn // 13: load page fault + .8byte segfault // 14: reserved + .8byte trapreturn // 15: store page fault + +.align 3 +trap_return_pagetype_table: + .8byte 0xC // 0: kilopage has 12 offset bits + .8byte 0x15 // 1: megapage has 21 offset bits + .8byte 0x1E // 2: gigapage has 30 offset bits + .8byte 0x27 // 3: terapage has 39 offset bits + + // --------------------------------------------------------------------------------------------- + // Test Handler + // + // This test handler works in a similar wy to the trap handler. It takes in a few things by reading from a table in memory + // (see test_cases) and performing certain behavior based on them. + // + // Input parameters: + // + // x28: + // Address input for the test taking place (think address to read/write, new address to return to, etc...) + // + // x29: + // Value input for the test taking place (think value to write, any other extra info needed) + // + // x30: + // Test type input that determines which kind of test will take place. Encoding for this input is in the table/case statements below + // + // ------------------------------------------------------------------------------------------------------------------------------------ + +test_setup: + la x5, test_cases + +test_loop: + ld x28, 0(x5) // fetch test case address + ld x29, 8(x5) // fetch test case value + ld x30, 16(x5) // fetch test case flag + addi x5, x5, 24 // set x5 to next test case + + // x5 has the symbol for a test's location in the assembly + li x7, 0x1FFFFF + and x30, x30, x7 // This program is always on at least a megapage, so this masks out the megapage offset. + auipc x7, 0x0 + srli x7, x7, 21 + slli x7, x7, 21 // zero out the bottom 21 bits so the megapage offset of the symbol can be placed there + or x30, x7, x30 // x30 = virtual address of the symbol for this type of test. + + jr x30 + +// Test Name : Description : Fault output value : Normal output values +// ----------------------:-------------------------------------------:------------------------:------------------------------------------------------ +// write64_test : Write 64 bits to address : 0xf : None +// write32_test : Write 32 bits to address : 0xf : None +// write16_test : Write 16 bits to address : 0xf : None +// write08_test : Write 8 bits to address : 0xf : None +// read64_test : Read 64 bits from address : 0xd, 0xbad : readvalue in hex +// read32_test : Read 32 bitsfrom address : 0xd, 0xbad : readvalue in hex +// read16_test : Read 16 bitsfrom address : 0xd, 0xbad : readvalue in hex +// read08_test : Read 8 bitsfrom address : 0xd, 0xbad : readvalue in hex +// executable_test : test executable on virtual page : 0xc, 0xbad : value of x7 modified by exectuion code (usually 0x111) +// terminate_test : terminate tests : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 +// goto_baremetal : satp.MODE = bare metal : None : None +// goto_sv39 : satp.MODE = sv39 : None : None +// goto_sv48 : satp.MODE = sv48 : None : None +// write_mxr_sum : write sstatus.[19:18] = MXR, SUM bits : None : None +// goto_m_mode : go to mahcine mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 +// goto_s_mode : go to supervisor mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 +// goto_u_mode : go to user mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8 +// write_pmpcfg_x : Write one of the pmpcfg csr's : mstatuses?, 0xD : readback of pmpcfg value +// write_pmpaddr_x : Write one of the pmpaddr csr's : None : readback of pmpaddr value + + +write64_test: + // address to write in x28, double value in x29 + sd x29, 0(x28) + j test_loop // go to next test case + +write32_test: + // address to write in x28, word value in x29 + sw x29, 0(x28) + j test_loop // go to next test case + +write16_test: + // address to write in x28, halfword value in x29 + sh x29, 0(x28) + j test_loop // go to next test case + +write08_test: + // address to write in x28, value in x29 + sb x29, 0(x28) + j test_loop // go to next test case + +read64_test: + // address to read in x28, expected 64 bit value in x29 (unused, but there for your perusal). + li x7, 0xBAD // bad value that will be overwritten on good reads. + ld x7, 0(x28) + sd x7, 0(x6) + addi x6, x6, 8 + addi x16, x16, 8 + j test_loop // go to next test case + +read32_test: + // address to read in x28, expected 32 bit value in x29 (unused, but there for your perusal). + li x7, 0xBAD // bad value that will be overwritten on good reads. + lw x7, 0(x28) + sd x7, 0(x6) + addi x6, x6, 8 + addi x16, x16, 8 + j test_loop // go to next test case + +read16_test: + // address to read in x28, expected 16 bit value in x29 (unused, but there for your perusal). + li x7, 0xBAD // bad value that will be overwritten on good reads. + lh x7, 0(x28) + sd x7, 0(x6) + addi x6, x6, 8 + addi x16, x16, 8 + j test_loop // go to next test case + +read08_test: + // address to read in x28, expected 8 bit value in x29 (unused, but there for your perusal). + li x7, 0xBAD // bad value that will be overwritten on good reads. + lb x7, 0(x28) + sd x7, 0(x6) + addi x6, x6, 8 + addi x16, x16, 8 + j test_loop // go to next test case + +goto_s_mode: + // return to address in x28, + li a0, 3 // Trap handler behavior (go to supervisor mode) + mv a1, x28 // return VPN + mv a2, x29 // return page types + ecall // writes mcause to the output. + // now in S mode + j test_loop + +goto_m_mode: + li a0, 2 // Trap handler behavior (go to machine mode) + mv a1, x28 // return VPN + mv a2, x29 // return page types + ecall // writes mcause to the output. + j test_loop + +goto_u_mode: + li a0, 4 // Trap handler behavior (go to user mode) + mv a1, x28 // return VPN + mv a2, x29 // return page types + ecall // writes mcause to the output. + j test_loop + +goto_baremetal: + // Turn translation off + li x7, 0 // satp.MODE value for bare metal (0) + slli x7, x7, 60 + li x28, 0x8000D // Base Pagetable physical page number, satp.PPN field. + add x7, x7, x28 + csrw satp, x7 + sfence.vma x0, x0 // *** flushes global pte's as well + j test_loop // go to next test case + +goto_sv39: + li x7, 8 // satp.MODE value for Sv39 (8) + slli x7, x7, 60 + li x28, 0x8000D // Base Pagetable physical page number, satp.PPN field. + add x7, x7, x28 + csrw satp, x7 + sfence.vma x0, x0 // *** flushes global pte's as well + j test_loop // go to next test case + +goto_sv48: + li x7, 9 // satp.MODE value for Sv48 + slli x7, x7, 60 + li x28, 0x8000D // Base Pagetable physical page number, satp.PPN field. + add x7, x7, x28 + csrw satp, x7 + sfence.vma x0, x0 // *** flushes global pte's as well + j test_loop // go to next test case + +write_mxr_sum: + // writes sstatus.[mxr, sum] with the (assumed to be) 2 bit value in x29. also assumes we're in S. M mode + li x30, 0xC0000 // mask bits for MXR, SUM + not x7, x29 + slli x7, x7, 18 + and x7, x7, x30 + slli x29, x29, 18 + csrc sstatus, x7 + csrs sstatus, x29 + j test_loop + +write_pmpcfg_0: + // writes the value in x29 to the pmpcfg register specified in x28. + // then writes the final value of pmpcfgX to the output. + li x7, 0x0 + bne x7, x28, write_pmpcfg_2 + csrw pmpcfg0, x29 + csrr x30, pmpcfg0 +write_pmpcfg_2: + li x7, 0x2 + bne x7, x28, write_pmpcfg_end + csrw pmpcfg2, x29 + csrr x30, pmpcfg2 // I would use csrrw but we need the value AFTER the csr has been written +write_pmpcfg_end: + sd x30, 0(x6) + addi x6, x6, 8 + addi x16, x16, 8 + j test_loop + +write_pmpaddr_0: + // writes the value in x29 to the pmpaddr register specified in x28. + // then writes the final value of pmpaddrX to the output. + li x7, 0x0 + bne x7, x28, write_pmpaddr_1 + csrw pmpaddr0, x29 + csrr x30, pmpaddr0 + j write_pmpaddr_end +write_pmpaddr_1: + li x7, 0x1 + bne x7, x28, write_pmpaddr_2 + csrw pmpaddr1, x29 + csrr x30, pmpaddr1 + j write_pmpaddr_end +write_pmpaddr_2: + li x7, 0x2 + bne x7, x28, write_pmpaddr_3 + csrw pmpaddr2, x29 + csrr x30, pmpaddr2 + j write_pmpaddr_end +write_pmpaddr_3: + li x7, 0x3 + bne x7, x28, write_pmpaddr_4 + csrw pmpaddr3, x29 + csrr x30, pmpaddr3 + j write_pmpaddr_end +write_pmpaddr_4: + li x7, 0x4 + bne x7, x28, write_pmpaddr_5 + csrw pmpaddr4, x29 + csrr x30, pmpaddr4 + j write_pmpaddr_end +write_pmpaddr_5: + li x7, 0x5 + bne x7, x28, write_pmpaddr_6 + csrw pmpaddr5, x29 + csrr x30, pmpaddr5 + j write_pmpaddr_end +write_pmpaddr_6: + li x7, 0x6 + bne x7, x28, write_pmpaddr_7 + csrw pmpaddr6, x29 + csrr x30, pmpaddr6 + j write_pmpaddr_end +write_pmpaddr_7: + li x7, 0x7 + bne x7, x28, write_pmpaddr_8 + csrw pmpaddr7, x29 + csrr x30, pmpaddr7 + j write_pmpaddr_end +write_pmpaddr_8: + li x7, 0x8 + bne x7, x28, write_pmpaddr_9 + csrw pmpaddr8, x29 + csrr x30, pmpaddr8 + j write_pmpaddr_end +write_pmpaddr_9: + li x7, 0x9 + bne x7, x28, write_pmpaddr_10 + csrw pmpaddr9, x29 + csrr x30, pmpaddr9 + j write_pmpaddr_end +write_pmpaddr_10: + li x7, 0xA + bne x7, x28, write_pmpaddr_11 + csrw pmpaddr10, x29 + csrr x30, pmpaddr10 + j write_pmpaddr_end +write_pmpaddr_11: + li x7, 0xB + bne x7, x28, write_pmpaddr_12 + csrw pmpaddr11, x29 + csrr x30, pmpaddr11 + j write_pmpaddr_end +write_pmpaddr_12: + li x7, 0xC + bne x7, x28, write_pmpaddr_13 + csrw pmpaddr12, x29 + csrr x30, pmpaddr12 + j write_pmpaddr_end +write_pmpaddr_13: + li x7, 0xD + bne x7, x28, write_pmpaddr_14 + csrw pmpaddr13, x29 + csrr x30, pmpaddr13 + j write_pmpaddr_end +write_pmpaddr_14: + li x7, 0xE + bne x7, x28, write_pmpaddr_15 + csrw pmpaddr14, x29 + csrr x30, pmpaddr14 + j write_pmpaddr_end +write_pmpaddr_15: + li x7, 0xF + bne x7, x28, write_pmpaddr_end + csrw pmpaddr15, x29 + csrr x30, pmpaddr15 + j write_pmpaddr_end +write_pmpaddr_end: + sd x30, 0(x6) + addi x6, x6, 8 + addi x16, x16, 8 + j test_loop + +executable_test: + // Execute the code at the address in x28, returning the value in x7. + // Assumes the code modifies x7, to become the value stored in x29 for this test. + fence.i // forces cache and main memory to sync so execution code written by the program can run. + li x7, 0xBAD + jalr x28 + sd x7, 0(x6) + addi x6, x6, 8 + addi x16, x16, 8 + j test_loop + +terminate_test: + + li a0, 2 // Trap handler behavior (go to machine mode) + ecall // writes mcause to the output. + csrw mtvec, x4 // restore original trap handler to halt program + +RVTEST_CODE_END +RVMODEL_HALT + +RVTEST_DATA_BEGIN +.align 4 +rvtest_data: +.word 0xbabecafe +RVTEST_DATA_END + +.align 3 // align stack to 8 byte boundary +bottom_of_stack: + .fill 1024, 4, 0xdeadbeef +top_of_stack: + + +RVMODEL_DATA_BEGIN + +test_1_res: + .fill 1024, 4, 0xdeadbeef + +RVMODEL_DATA_END + +#ifdef rvtest_mtrap_routine + +mtrap_sigptr: + .fill 64*(XLEN/32),4,0xdeadbeef + +#endif + +#ifdef rvtest_gpr_save + +gpr_save: + .fill 32*(XLEN/32),4,0xdeadbeef + +#endif + +.align 3 +test_cases: +