Added partially working MMU tests

This commit is contained in:
David Harris 2021-12-29 03:14:16 +00:00
parent 40e0e6a401
commit c3bfa53db0
19 changed files with 9412 additions and 2 deletions

@ -1 +0,0 @@
Subproject commit e1966a2dbb0c861b5bc153235cfd53e590ddc930

1
addins/imperas-riscv-tests Symbolic link
View file

@ -0,0 +1 @@
/opt/riscv/imperas-riscv-tests/

View file

@ -28,6 +28,9 @@
# Description: Makefrag for RV32I architectural tests
rv32i_sc_tests = \
WALLY-MMU-SV32 \
WALLY-PMA \
WALLY-PMP
rv32i_tests = $(addsuffix .elf, $(rv32i_sc_tests))

View file

@ -0,0 +1,972 @@
00000007
00000007
00000007
00000007
00600D64
00600D32
00600D16
00600D08
00600D64
00600D32
00600D16
00600D08
00000007
00000007
00000007
00000005
00000bad
00600D32
00000005
00000bad
00000005
00000bad
00000007
00000007
00000007
00000005
00000bad
00000005
00000bad
00000005
00000bad
00600D08
00000007
00000007
00000007
00000005
00000bad
00600D32
00000005
00000bad
00000005
00000bad
00600D64
00600D32
00600D16
00600D08
00000007
00000005
00000001
00000007
00000005
00000001
00000007
00000005
00000001
00000007
00000005
00000001
00000007
00000005
00000001
00000007
00000005
00000001
0000000b
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff
ffffffff

View file

@ -0,0 +1,158 @@
///////////////////////////////////////////
//
// WALLY-MMU
//
// Author: David_Harris@hmc.edu and Kip Macsai-Goren <kmacsaigoren@g.hmc.edu>
//
// Created 2021-06-15
//
// 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 "WALLY-TEST-LIB-32.S"
// 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.
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.8byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.8byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler in the framework file
#
# ---------------------------------------------------------------------------------------------
# =========== test 12.3.1.1 Page Table Translation ===========
# test 12.3.1.1.1 write page tables / entries to phyiscal memory
# sv32 Page table (See Figure 12.12***):
# Level 1 page table, situated at 0x8000D000
.4byte 0x8000D000, 0x20004CC1, 0x0 # points to level 0 page table A
.4byte 0x8000D004, 0x200000CB, 0x0 # Vaddr 0x400000 Paddr 0x80000000: aligned megapage, W=0, used for execute tests
.4byte 0x8000D008, 0x200054E1, 0x0 # points to level 0 page table B
.4byte 0x8000D00C, 0x000800C7, 0x0 # Vaddr 0xC00000: misaligned megapage
.4byte 0x8000D800, 0x200000CF, 0x0 # Vaddr 0x80000000 Paddr 0x80000000: aligned megapage (program and data memory)
.4byte 0x8000D804, 0x200000DF, 0x0 # Vaddr 0x80400000 Paddr 0x80000000: aligned megapage, U=1 (aliased with program and data memory)
# Level 0 page table A
.4byte 0x80013000, 0x200070D1, 0x0 # Vaddr 0x0000: bad PTE points to level -1 table
.4byte 0x80013004, 0x202000DF, 0x0 # Vaddr 0x1000 Paddr 0x80800000: aligned kilopage, U=1
.4byte 0x80013008, 0x202010D5, 0x0 # Vaddr 0x2000: pad PTE has W but not R
.4byte 0x8001300C, 0x20200817, 0x0 # Vaddr 0x3000: A=0, should cause read fault
.4byte 0x80013010, 0x20200C57, 0x0 # Vaddr 0x4000: D=0, should cause write fault
.4byte 0x80013014, 0x202014C9, 0x0 # Vaddr 0x5000 Paddr 80805000: aligned kilopage, W=R=0
.4byte 0x80013018, 0x0, 0x0 # Vaddr 0x6000: invalid page
# Level 0 page table B
.4byte 0x80015FFC, 0x202004CF, 0x0 # Vaddr 0x00BFF000 Paddr 0x80801000: aligned kilopage
# test 12.3.1.1.2 write values to Paddrs in each page
# each of these values is used for 12.3.1.1.3 and some other tests, specified in the comments.
# when a test is supposed to fault, nothing is written into where it'll be reading/executing since it should fault before getting there.
.4byte 0x800AAAA8, 0xBEEF0055, 0x0 # 12.3.1.1.4 megapage
.4byte 0x800FFAC0, 0xBEEF0033, 0x0 # 12.3.1.3.2
.4byte 0x800E3130, 0xBEEF0077, 0x0 # 12.3.1.3.2
.4byte 0x808017E0, 0xBEEF0099, 0x0 # 12.3.1.1.4 kilopage
.4byte 0x80805EA0, 0xBEEF0440, 0x0 # 12.3.1.3.3
.4byte 0x80803AA0, 0xBEEF0BB0, 0x0 # 12.3.1.3.7
# test 12.3.1.1.3 read values back from Paddrs without translation (this also verifies the previous test)
.4byte 0x0, 0x0, 0x4 # satp.MODE = baremetal / no translation.
.4byte 0x0, 0x0, 0x9 # change to S mode, 0xb written to output
.4byte 0x800AAAA8, 0xBEEF0055, 0x1
.4byte 0x800FFAC0, 0xBEEF0033, 0x1
.4byte 0x800E3130, 0xBEEF0077, 0x1
.4byte 0x808017E0, 0xBEEF0099, 0x1
.4byte 0x80805EA0, 0xBEEF0440, 0x1
.4byte 0x80803AA0, 0xBEEF0BB0, 0x1
# test 12.3.1.1.4 check translation works in sv48, read the same values from previous tests, this time with Vaddrs
.4byte 0x0, 0x0, 0x5 # satp.MODE = sv48, Nothing written to output
.4byte 0x4AAAA8, 0xBEEF0055, 0x1 # megapage at Vaddr 0x400000, Paddr 0x80000000
.4byte 0xBFF7E0, 0xBEEF0099, 0x1 # kilopage at Vaddr 0xBFF000, Paddr 0x80201000
# =========== test 12.3.1.2 page fault tests ===========
# test 12.3.1.2.1 load page fault if upper bits of Vaddr are not the same
# Not tested in rv32/sv32
# test 12.3.1.2.2 load page fault when reading an address where the valid flag is zero
.4byte 0x6000, 0x0, 0x1
# test 12.3.1.2.3 store page fault if PTE has W and ~R flags set
.4byte 0x2000, 0x0, 0x0
# test 12.3.1.2.4 Fault if last level PTE is a pointer
.4byte 0x0200, 0x0, 0x1
# test 12.3.1.2.5 load page fault on misaligned pages
.4byte 0xC00000, 0x0, 0x1 # misaligned megapage
# =========== test 12.3.1.3 PTE Protection flags ===========
// *** 16 July 2021: Execution tests commented out because they rely on some memory that's written in 12.3.1.1.2. this memory is written but stays in the dcache without being synced into memory
// Then the ifu tries to fetch the same address, but it's working with the unsynced memory, NOT the value stored in the dcache
// Until we have some fence instructions or another way of modifying the code implemented, these tests are ignored.
# test 12.3.1.3.1 User flag == 0
# *** reads on pages with U=0 already tested in 12.3.1.1.4
.4byte 0x400000, 0x1, 0x2 # fetch success when U=0, priv=S
.4byte 0x201, 0x11, 0xA # go to U mode, return to megapage VPN at [513] where PTE.U = 1. 0x9 written to output
.4byte 0xBFFC80, 0xBEEF0550, 0x1 # load page fault when U=0, priv=U
.4byte 0x400000, 0x1, 0x2 # instr page fault when U=0, priv=U
# test 12.3.1.3.2 User flag == 1
.4byte 0x804FFAC0, 0xBEEF0033, 0x1 # read success when U=1, priv=U
.4byte 0x200, 0x11, 0x9 # go back to S mode, return to megapage VPN at [512] where PTE.U = 0. 0x8 written to output
.4byte 0x0, 0x3, 0x7 # set sstatus.[MXR, SUM] = 11
.4byte 0x804E3130, 0xBEEF0077, 0x1 # read success when U=1, priv=S, sstatus.SUM=1
.4byte 0x0, 0x400000, 0x10 # push to stack virtual address corresponfding to the PTE about to be changed.
.4byte 0x8000D004, 0x200000DB, 0xF # Edit execution PTE so U=1
.4byte 0x400000, 0x1, 0x2 # instr page fault when U=1, priv=S (with any sstatus.SUM)
.4byte 0x0, 0x2, 0x7 # set sstatus.[MXR, SUM] = 10.
.4byte 0x804FFAC0, 0xBEEF0033, 0x1 # load page fault when U-1, priv=S, sstatus.SUM=0
# test 12.3.1.3.3 Read flag
# *** reads on pages with R=1 already tested in 12.3.1.1.4
.4byte 0x0, 0x1, 0x7 # set sstatus.[MXR, SUM] = 01.
.4byte 0x5EA0, 0xBEEF0440, 0x1 # load page fault when R=0, sstatus.MXR=0
.4byte 0x0, 0x3, 0x7 # set sstatus.[MXR, SUM] = 11.
.4byte 0x5EA0, 0xBEEF0440, 0x1 # read success when R=0, MXR=1, X=1
# test 12.3.1.3.4 Write flag
.4byte 0xBFF290, 0xBEEF0110, 0x0 # write success when W=1
.4byte 0xBFF290, 0xBEEF0110, 0x1 # check write success by reading
.4byte 0x5B78, 0xBEEF0CC0, 0x0 # store page fault when W=0
# test 12.3.1.3.5 eXecute flag
# *** fetches on pages with X = 1 already tested in 12.3.1.3.1
.4byte 0x0, 0x400000, 0x10 # push to stack virtual address corresponfding to the PTE about to be changed.
.4byte 0x8000D004, 0x200000C7, 0xF # Edit execution PTE so U=0, X=0
.4byte 0x400000, 0x0, 0x2 # instr page fault when X=0
# test 12.3.1.3.6 Accessed flag == 0
.4byte 0x3020, 0xBEEF0770, 0x0 # store page fault when A=0
.4byte 0x3808, 0xBEEF0990, 0x1 # load page fault when A=0
# test 12.3.1.3.7 Dirty flag == 0
.4byte 0x4658, 0xBEEF0AA0, 0x0 # store page fault when D=0
.4byte 0x4AA0, 0xBEEF0BB0, 0x1 # read success when D=0
# terminate tests
.4byte 0x0, 0x0, 0x3 # brings us back into machine mode with a final ecall, writing 0x9 to the output.

View file

@ -0,0 +1,82 @@
///////////////////////////////////////////
//
// WALLY-PMA
//
// Author: Kip Macsai-Goren <kmacsaigoren@g.hmc.edu> (Copied heavily from SV48 test).
//
// Created 2021-06-15
//
// 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 "WALLY-TEST-LIB-32.S"
// 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.
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.8byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.8byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler
#
# ---------------------------------------------------------------------------------------------
# =========== test 12.3.2.1 PMAs: Memory Access Size, Type protection test ===========
# Tests memory load, store, and /* *** execute? */ permissions based on table 12.3 in the *** riscv book, copied below
# Test 12.3.2.1.1 check enabled devices
# | Region | Read widths | R | W | X | Cacheable | Idempotent | Atomic |
.8byte 0x1000, 0x0, 0xB # | ROM | Any | YES | NO | YES | YES | NO | NO | # *** Impossible to write? how am I supposed to put a known value in ROM to read out?
.8byte 0x2000000, 0x0, 0xB # | CLINT | Any | YES | YES | NO | NO | NO | NO |
.8byte 0xC000000, 0x0, 0xB # | PLIC | 32-bit | YES | YES | NO | NO | NO | NO |
.8byte 0x10000000, 0x0, 0xB # | UART0 | 8-bit | YES | YES | NO | NO | NO | NO |
.8byte 0x20000000, 0x0, 0xB # | GPIO | 32-bit | YES | YES | NO | NO | NO | NO |
.8byte 0x800F0000, 0x0, 0xB # | DRAM | Any | YES | YES | YES | YES | YES | YES |
# *** the dram one has a little offset so we don't accidentally write over the code of this test.
# Test 12.3.2.1.2 Check Regions with no enabled device fail all
.8byte 0x0000, 0x0, 0xC
.8byte 0x3000, 0x0, 0xC
.8byte 0x4000000, 0x0, 0xC
.8byte 0xE0000000, 0x0, 0xC
.8byte 0x12000000, 0x0, 0xC
.8byte 0xA0000000, 0x0, 0xC
.8byte 0x0, 0x0, 0x3 // terminate tests

View file

@ -0,0 +1,111 @@
///////////////////////////////////////////
//
// WALLY-PMP
//
// Author: Kip Macsai-Goren <kmacsaigoren@g.hmc.edu>
//
// Created 2021-06-15
//
// 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 "WALLY-TEST-LIB-32.S"
// 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.
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.8byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.8byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler in the framework file
#
# ---------------------------------------------------------------------------------------------
# These tests follow the testing plan in Chapter 12 of the riscv-wally textbook *** what is it called and how do I refer to it?
# =========== test 12.3.2.2 PMPs ===========
# 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
.8byte 0x0, 0x0018900C0009001F, 0xD # write pmpcfg0, output 0x0018900C0009001F
.8byte 0x2, 0x1F00000000000000, 0xD # write pmpcfg2, output 0x1F00000000000000
# write pmpaddr regs
# | Reg | pmpaddr | pmpcfg | L | A | X | W | R | Comments |
.8byte 0x0, 0x0FFFFFFF, 0xE # | 0 | 0FFFFFFF | 1F | 0 | NAPOT | 0 | 1 | 1 | I/O 00000000-7FFFFFFF RW |
.8byte 0x1, 0x80100000, 0xE # | 1 | 80100000 | 00 | 0 | OFF | 0 | 0 | 0 | |
.8byte 0x2, 0x801000FF, 0xE # | 2 | 801000FF | 09 | 0 | TOR | 0 | 0 | 1 | 80100000-801000FF R |
.8byte 0x3, 0x80100200, 0xE # | 3 | 80100200 | 00 | 0 | OFF | 0 | 0 | 0 | |
.8byte 0x4, 0x80100210, 0xE # | 4 | 80100210 | 0C | 0 | TOR | 1 | 0 | 0 | 80100200-80100210 X |
.8byte 0x5, 0x80100300, 0xE # | 5 | 80100300 | 90 | 1 | NA4 | 0 | 0 | 0 | 80100300-80100303 locked out |
.8byte 0x6, 0x2004013F, 0xE # | 6 | 2004013F | 18 | 0 | NAPOT | 0 | 0 | 0 | 80100400-801004FF no access |
# Pmpaddr 7-14 are all zeroed out in this test, so they don't need writes.
.8byte 0xF, 0x8FFFFFFF, 0xE # | 15 | 8FFFFFFF | 1F | 0 | NAPOT | 1 | 1 | 1 | Main mem 80000000-FFFFFFFF RWX |
# write known values to memory where W=0. This should be possible since we're in machine mode.
.8byte 0x80100010, 0x600DAA, 0x0 # write to pmpaddr 1-2 range
.8byte 0x80100400, 0x600DBB, 0x0 # write to pmpaddr 6 range
# Write RET to regions where X = 0, 1 in main memory
# *** This is currently impossible due to the fact that writing ret gets put into the datacache but
# The values in datacache never get synced with icache values so when we try to fetch the written ret,
# We get an instr of all 0x0
# It may also be impossible to do the exe tests version from the library since we have no way to guarantee that theyll be
# compiled into in the address range with the right permissions.
# attempt to write to pmpcfg5 after lockout
.8byte 0x0, 0x0018EE0C0009001F, 0xD # instruction ignored, output 0x0018900C0009001F, NOT 0x0018EE0C0009001F
# Test 12.3.2.2.2 Machine mode access
.8byte 0x80100300, 0x0, 0x1 # access fault to region with L=1, R=0
.8byte 0x80100400, 0x0, 0x1 # successful access to region with L=X=W=R=0
# Test 12.3.2.2.3 System mode access
.8byte 0x0, 0x0, 0x9 # go to S mode. 0xb written to output
# test a write followed by a read to each region with R=W=1
.8byte 0x80200000, 0x600D15, 0x0 # Write "good value" to RW range (PMP15)
.8byte 0x80200000, 0x600D15, 0x1 # confirm write with read
# test a write followed by a read on the edges of a read-only range
.8byte 0x800FFFF8, 0x600D02, 0x0 # Write "good value" just below read-only range (PMP2)
.8byte 0x800FFFF8, 0x600D02, 0x1 # confirm write with read
.8byte 0x80100100, 0x600D12, 0x0 # Write "good value" just above read-only range (PMP2)
.8byte 0x80100100, 0x600D12, 0x1 # confirm write with read
# test a read from each read only range verify a write causes an access fault
.8byte 0x80100010, 0xBAD, 0x0 # Write fault in read-only range (PMP2)
.8byte 0x80100010, 0x600DAA, 0x1 # read correct value out
# test read and write fault on region with no access
.8byte 0x80100208, 0x600D15, 0x0 # Write fault on no-access range (PMP6)
.8byte 0x80100208, 0x600D15, 0x1 # read fault on no-access range (PMP6)
# test jalr to region with X=0 causes access fault
.8byte 0x80100400, 0xF, 0x2 # instr fault on no-execute range (PMP6)
# test jalr to region with X=1 returns successfully
# *** This has the same problem as the note above where we want actual instructions to be in this range,
# but it's difficult to make sure the exe_code in the library will compile into the right pmp range for this to work
.8byte 0x0, 0x0, 0x3 // terminate tests

View file

@ -0,0 +1,657 @@
///////////////////////////////////////////
//
// WALLY-TEST-LIB-32.S
//
// Author: Kip Macsai-Goren <kmacsaigoren@g.hmc.edu>
//
// 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 "riscv_test_macros.h"
#include "compliance_test.h"
#include "compliance_io.h"
RV_COMPLIANCE_RV64M
RV_COMPLIANCE_CODE_BEGIN
RVTEST_IO_INIT
RVTEST_IO_ASSERT_GPR_EQ(x31, x0, 0x00000000)
RVTEST_IO_WRITE_STR(x31, "Test Begin\n")
# ---------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------
# 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
# address for trap handler
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.
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): Upper bits of change of return address after trap
# Put it in the bottom bits of a1.
#
# Default : 0x0 (defaults to the next instruction in the same location as the return address)
# Megapage: returnAddr[END-1:22]
# Kilopage: returnAddr[END-1:12] (this value also works for baremetal)
#
# a2 (x12): Pagetype for change of return address after trap
# Put the Source page in a2[7:4] and Dest page in a2[3:0]
# Ex: giga -> mega a2=0x21
#
# Default : Ignored if a1 == 0x0
# Megapage: 1
# Kilopage: 0
#
# --------------------------------------------------------------------------------------------
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:
# update mepc and stack (x1 and x5) to have new virtual addresses.
beqz a1, trapreturn_finished # either update values, of go to default return address.
# Get Mask Bits
la x5, trap_return_pagetype_table
mv x7, a2
li x28, 0xF0 # mask bits for current pagetype
and x7, x28, x7
srli x7, x7, 2
add x5, x5, x7
lw x7, 0(x5) # x7 = number of offset bits in current page type
la x5, trap_return_pagetype_table
li x28, 0xF # mask bits for new pagetype
and a2, x28, a2
slli a2, a2, 2
add x5, x5, a2
lw a2, 0(x5) # a2 = number of offset bits in new page type
li x5, 1
sll x5, x5, x7
addi x5, x5, -1 # x5 = mask bits for offset into current pagetype
sll a1, a1, a2 # a1 = the VPN of the new return page.
# set x1 stack spot
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)
# set x5 stack spot
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)
# set x6
and x7, x5, x6 # x7 = offset for the result pointer (x6)
add x6, x7, a1 # x6 = new address for the result pointer
# set return address
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 inputs
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
# case statements for which test behavior to perform.
# *** We would use the same table method as the test types and trap handler,
# but that presents problems with virtual addressing and updating the address after the la command
# x30 Value : Function : Fault output value : Normal output values
# ----------:---------------------------------------:------------------------:------------------------------------------------------
li x7, 0x0 # : : :
beq x30, x7, write_test # 0x0 : Write to address : 0xf : None
li x7, 0x1 # : : :
beq x30, x7, read_test # 0x1 : Read from address : 0xd, 0xbad : readvalue in hex
li x7, 0xB # : : :
beq x30, x7, access_test # 0xB : Mem access at any width (see table) : 0x1, 0x5, or 0x7 : 0x32001608, 0x32001608, 0x1608, 0x08, // *** Execute, cahceable, etc values
li x7, 0xC # : : :
beq x30, x7, access_denied_test # 0xC : Access memory regions with no device : 0x7, 0x5, 0x1, 0x600d : 0xbad, 0x3
li x7, 0x2 # : : :
beq x30, x7, executable_test # 0x2 : test executable at address : 0xc, 0xbad : leading 12 bits of the li instr written to address. (be sure to also write a return instruction)
li x7, 0x3 # : : :
beq x30, x7, terminate_test # 0x3 : terminate tests : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
li x7, 0xF # : : :
beq x30, x7, edit_pte # 0xF : edit an already instantiated pte : None : None
li x7, 0x10 # : : :
beq x30, x7, push_to_stack # 0x10 : put a value onto the top of the stack : None : None
li x7, 0x4 # : : :
beq x30, x7, goto_baremetal # 0x4 : satp.MODE = bare metal : None : None
li x7, 0x5 # : : :
beq x30, x7, goto_sv32 # 0x5 : satp.MODE = sv32 : None : None
li x7, 0x7 # : : :
beq x30, x7, write_mxr_sum # 0x7 : write sstatus.[19:18] = MXR, SUM bits : None : None
li x7, 0xD # : : :
beq x30, x7, write_pmpcfg_0 # 0xD : Write one of the pmpcfg csr's : mstatuses?, 0xD : readback of pmpcfg value
li x7, 0xE # : : :
beq x30, x7, write_pmpaddr_0 # 0xE : Write one of the pmpaddr csr's : None : None
li x7, 0x8 # : : :
beq x30, x7, goto_m_mode # 0x8 : go to mahcine mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
li x7, 0x9 # : : :
beq x30, x7, goto_s_mode # 0x9 : go to supervisor mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
li x7, 0xA # : : :
beq x30, x7, goto_u_mode # 0xA : go to user mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
# ------------------------------------------------------------------------------------------------------------------------------------
j terminate_test # default case: break
write_test:
# address to write in x28, value in x29
sw x29, 0(x28)
j test_loop # go to next test case
read_test:
# address to read in x28, expected 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
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.
li x7, 0x0
bne x7, x28, write_pmpaddr_1
csrw pmpaddr0, x29
write_pmpaddr_1:
li x7, 0x1
bne x7, x28, write_pmpaddr_2
csrw pmpaddr1, x29
write_pmpaddr_2:
li x7, 0x2
bne x7, x28, write_pmpaddr_3
csrw pmpaddr2, x29
write_pmpaddr_3:
li x7, 0x3
bne x7, x28, write_pmpaddr_4
csrw pmpaddr3, x29
write_pmpaddr_4:
li x7, 0x4
bne x7, x28, write_pmpaddr_5
csrw pmpaddr4, x29
write_pmpaddr_5:
li x7, 0x5
bne x7, x28, write_pmpaddr_6
csrw pmpaddr5, x29
write_pmpaddr_6:
li x7, 0x6
bne x7, x28, write_pmpaddr_7
csrw pmpaddr6, x29
write_pmpaddr_7:
li x7, 0x7
bne x7, x28, write_pmpaddr_8
csrw pmpaddr7, x29
write_pmpaddr_8:
li x7, 0x8
bne x7, x28, write_pmpaddr_9
csrw pmpaddr8, x29
write_pmpaddr_9:
li x7, 0x9
bne x7, x28, write_pmpaddr_10
csrw pmpaddr9, x29
write_pmpaddr_10:
li x7, 0xA
bne x7, x28, write_pmpaddr_11
csrw pmpaddr10, x29
write_pmpaddr_11:
li x7, 0xB
bne x7, x28, write_pmpaddr_12
csrw pmpaddr11, x29
write_pmpaddr_12:
li x7, 0xC
bne x7, x28, write_pmpaddr_13
csrw pmpaddr12, x29
write_pmpaddr_13:
li x7, 0xD
bne x7, x28, write_pmpaddr_14
csrw pmpaddr13, x29
write_pmpaddr_14:
li x7, 0xE
bne x7, x28, write_pmpaddr_15
csrw pmpaddr14, x29
write_pmpaddr_15:
li x7, 0xF
bne x7, x28, write_pmpaddr_end
csrw pmpaddr15, x29
write_pmpaddr_end:
j test_loop
executable_test:
# using a virtual page number in x28, and the page type in x29, test execution on that virtual page
# note: that x28 page must point to program and data memory
# Another unfortunate case of not being able to use a little table like above, again because of the virtual addressing problem
li x7, 0x0
beq x7, x29, exe_kilopage
li x7, 0x1
beq x7, x29, exe_megapage
li x7, 0xF
beq x7, x29, exe_physical
exe_kilopage:
li x7, 0xFFFFF000
and x28, x28, x7 # x28 = virtual page number
li x29, 0xFFF
j exe_combine_and_test
exe_megapage:
li x7, 0xFFE00000
and x28, x28, x7 # x28 = virtual page number
li x29, 0x1FFFFF
j exe_combine_and_test
exe_combine_and_test: # at this point x28 is the VPN and x29 physical offset mask bits
la x7, exe_code
and x7, x7, x29
or x28, x28, x7 # x28 = full virtual address for executable_code
exe_physical:
li x7, 0xBAD # load a bad value into x7 in case this fetch doesnt work.
jalr x28 # jump to executable code virtual address
sw x7, 0(x6)
addi x6, x6, 4
addi x16, x16, 4
j test_loop
exe_code:
li x7, 0xE600D
ret #jumps back to the original virtual PC and continues with this program.
access_test:
# test write, read, and *** Execute permissions on the region of memory beginning at the address in x28
# Load output: (None) if pass, (0x7) if fail
# Store output: (0x600DXX) if pass, (0x5, 0xBAD) if fail
# execute output: *** N/A
# *** idempotent, atomic, etc...
# *** unfortunately, there's no guarantee that this write will work since the access width applies to writes and reads
# So I'm sorry, but I'm going to have to do loads and stores at all widths. its either that or have a test for every width
li x7, 0x32001608
sw x7, 0(x28) # test 32 bit write
sh x7, 4(x28) # test 16 bit write
sb x7, 12(x28) # test 8 bit write
# *** Double unfortunately, there are cases where we aren't allowed to write a known value to the range of addresses
# so instead I have to do all this work to check if ANY value get read out of memory, but I can't verfy the value in the output necessarily.
li x7, 0xBAD
access_32:
li x29, 0xBAD
lw x29, 0(x28)
beq x29, x7, access_16
li x29, 0x600D32
access_16:
sw x29, 0(x6)
li x29, 0xBAD
lh x29, 4(x28)
beq x29, x7, access_08
li x29, 0x600D16
access_08:
sw x29, 4(x6)
li x29, 0xBAD
lb x29, 8(x28)
beq x29, x7, access_end
li x29, 0x600D08
access_end:
sw x29, 8(x6)
/* *** EXECUTE, idempotent atomic, etc tests. how do we do it? */
addi x6, x6, 12
addi x16, x16, 12
j test_loop
access_denied_test:
# check that lw, sw and jalr all cause faults in a memory region (beginning at x28 address) where no device is intantiated.
lw x7, 0(x28) # cause a load access fault
li x7, 0xBADBAD // *** Necessary?
sw x7, 0(x28) # cause a store access fault
jalr x7, 0(x28) # cause an instruction access fault
j test_loop
edit_pte:
# write the PTE (value in x29) to address x28. This is different from a normal write since it includes an sfence.vma
sw x29, 0(x28)
lw x30, 0(sp) # the sfence.vma requires a virtual address within the page, it needs to be loaded into the stack.
addi sp, sp, 4 # put the stack pointer one value down, effectively popping this value by allowing it to be overwritten.
sfence.vma x0, x30
j test_loop
push_to_stack:
# write the value in x29 to the stack address pointed to by sp. update sp.
# this for those handy times when address, value, test type isn't enough info and you need more so you put it on the stack.
# any test that uses this info is also respnsible for removing the value or moving the stack pointer back.
sw x29, -4(sp)
addi sp, sp, -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_IO_WRITE_STR(x31, "Test End\n")
# ---------------------------------------------------------------------------------------------
RV_COMPLIANCE_HALT
RV_COMPLIANCE_CODE_END
# Input data section.
.data
.align 2 # align stack to 4 byte boundary
bottom_of_stack:
.fill 1024, 4, -1
top_of_stack:
# Output data section.
RV_COMPLIANCE_DATA_BEGIN
.align 2 # align output to 4 byte boundary
test_1_res:
.fill 1024, 4, -1
RV_COMPLIANCE_DATA_END
.align 2
test_cases:
# These tests follow the testing plan in Chapter 12 of the riscv-wally textbook *** what is it called and how do I refer to it?

View file

@ -28,7 +28,10 @@
# Description: Makefrag for RV64I architectural tests
rv64i_sc_tests = \
WALLY-MMU-SV39 \
WALLY-MMU-SV48 \
WALLY-PMA \
WALLY-PMP
rv64i_tests = $(addsuffix .elf, $(rv64i_sc_tests))

View file

@ -0,0 +1,169 @@
///////////////////////////////////////////
//
// WALLY-MMU
//
// Author: David_Harris@hmc.edu and Kip Macsai-Goren <kmacsaigoren@g.hmc.edu>
//
// Created 2021-06-15
//
// 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 "WALLY-TEST-LIB-64.S"
// *** new line
test_contents:
// 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.
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.8byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.8byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler
#
# ---------------------------------------------------------------------------------------------
# =========== test 12.3.1.1 Page Table Translation ===========
# test 12.3.1.1.1 write page tables / entries to phyiscal memory
# sv39 page table (See Figure 12.12***):
# Level 2 page table, situated at 0x8000D000
.8byte 0x000000008000D000, 0x0000000020004CC1, 0x0 # points to level 1 page table A
.8byte 0x000000008000D008, 0x00000000200050C1, 0x0 # points to level 1 page table B
.8byte 0x000000008000D010, 0x00000000200000CF, 0x0 # Vaddr 0x8000_0000, Paddr 0x80000000: aligned gigapage (program and data memory)
.8byte 0x000000008000D018, 0x00004000004000C7, 0x0 # Vaddr 0xC000_0000: misaligned gigapage
.8byte 0x000000008000DFF8, 0x00000000200054E1, 0x0 # points to level 1 page table C
# Level 1 page table A
.8byte 0x0000000080013000, 0x00000000200060C1, 0x0 # points to level 0 page table A
# Level 1 page table B
.8byte 0x0000000080014000, 0x00000000200000CB, 0x0 # Vaddr 0x4000_0000, Paddr 0x80000000: aligned megapage, W=0, used for execution tests
.8byte 0x0000000080014008, 0x00000400000080C3, 0x0 # Vaddr 0x4020_0000: misaligned megapage
.8byte 0x0000000080014010, 0x00000000200000DF, 0x0 # Vaddr 0x4040_0000, Paddr 0x80000000: aligned megapage, aliased with program, U=1
.8byte 0x0000000080014018, 0x00000000210800C9, 0x0 # Vaddr 0x4060_0000, Paddr 0x84200000: R=0, reads should fault
# Level 1 page table C
.8byte 0x0000000080015FF8, 0x00000000200058C1, 0x0 # points to level 0 page table B
# Level 0 page table A
.8byte 0x0000000080018000, 0x00000000200070D1, 0x0 # Vaddr 0x0000: bad PTE points to level -1 table
.8byte 0x0000000080018008, 0x00000000200800DF, 0x0 # Vaddr 0x1000, Paddr = 0x80200000: aligned kilopage
.8byte 0x0000000080018010, 0x00000000200810D5, 0x0 # Vaddr 0x2000: bad PTE has W but not R
.8byte 0x0000000080018018, 0x0000000020080817, 0x0 # Vaddr 0x3000 Paddr 0x80202000: A=0, should cause read fault
.8byte 0x0000000080018020, 0x0000000020080C57, 0x0 # Vaddr 0x4000 Paddr 0x80203000: D=0, should cause write fault
.8byte 0x0000000080018028, 0x00000000200814C7, 0x0 # Vaddr 0x5000 Paddr 0x80205000: X=0, fetches should fault
.8byte 0x0000000080018030, 0x00000000200814C0, 0x0 # Vaddr 0x6000: invalid page
# Level 0 page table B
.8byte 0x0000000080016FF8, 0x00000000200804CF, 0x0 # Vaddr 0xFFFFFFFFFFFFF000, Paddr 0x80201000 aligned kilopage
# test 12.3.1.1.2 write values to Paddrs in each page
# each of these values is used for 12.3.1.1.3 and some other tests, specified in the comments.
# when a test is supposed to fault, nothing is written into where it'll be reading/executing since it shuold fault before getting there.
.8byte 0x80200AB0, 0x0000DEADBEEF0000, 0x0 # 12.3.1.1.4
.8byte 0x800FFAB8, 0x0880DEADBEEF0055, 0x0 # 12.3.1.1.4
.8byte 0x80200AC0, 0x0990DEADBEEF0033, 0x0 # 12.3.1.3.2
.8byte 0x80203130, 0x0110DEADBEEF0077, 0x0 # 12.3.1.3.2
.8byte 0x80099000, 0x0000806711100393, 0x0 # 12.3.1.3.1 and 12.3.1.3.2 write executable code for "li x7, 0x111; ret"
.8byte 0x80205AA0, 0x0000806711100393, 0x0 # 12.3.1.3.5 write same executable code
.8byte 0x80201888, 0x0220DEADBEEF0099, 0x0 # 12.3.1.1.4
.8byte 0x84212348, 0x0330DEADBEEF0440, 0x0 # 12.3.1.3.3
.8byte 0x80203AA0, 0x0440DEADBEEF0BB0, 0x0 # 12.3.1.3.7
# test 12.3.1.1.3 read values back from Paddrs without translation (this also verifies the previous test)
.8byte 0x0, 0x0, 0x4 # satp.MODE = baremetal / no translation.
.8byte 0x0, 0x0, 0x9 # change to S mode, 0xb written to output
.8byte 0x80200AB0, 0x0000DEADBEEF0000, 0x1
.8byte 0x800FFAB8, 0x0880DEADBEEF0055, 0x1
.8byte 0x80200AC0, 0x0990DEADBEEF0033, 0x1
.8byte 0x80203130, 0x0110DEADBEEF0077, 0x1
.8byte 0x80201888, 0x0220DEADBEEF0099, 0x1
.8byte 0x84212348, 0x0330DEADBEEF0440, 0x1
.8byte 0x80203AA0, 0x0440DEADBEEF0BB0, 0x1
# test 12.3.1.1.4 check translation works in sv39, read the same values from previous tests, this time with Vaddrs
.8byte 0x0, 0x0, 0x5 # satp.MODE = sv39, Nothing written to output
.8byte 0x80200AB0, 0x0000DEADBEEF0000, 0x1 # gigapage at Vaddr 0x80000000, Paddr 0x80000000
.8byte 0x400FFAB8, 0x0880DEADBEEF0055, 0x1 # megapage at Vaddr 0x40400000, Paddr 0x80000000
.8byte 0xFFFFFFFFFFFFF888, 0x0220DEADBEEF0099, 0x1 # kilopage at Vaddr 0xFFFFFFFFFFFFF000, Paddr 0x80201000
# =========== test 12.3.1.2 page fault tests ===========
# test 12.3.1.2.1 load page fault if upper bits of Vaddr are not the same
.8byte 0x0010000080000AB0, 0x0, 0x1 # gigapage at Vaddr 0x80000000, Paddr 0x80000000, bad 1 in upper bits
.8byte 0xFF0FFFFFFFFFF888, 0x0, 0x1 # kilopage at Vaddr 0xFFFFFFFFFFFFF000, Paddr 0x80201000, bad 0000 in upper bits
# test 12.3.1.2.2 load page fault when reading an address where the valid flag is zero
.8byte 0x6000, 0x0, 0x1
# test 12.3.1.2.3 store page fault if PTE has W and ~R flags set
.8byte 0x2000, 0x0, 0x0
# test 12.3.1.2.4 Fault if last level PTE is a pointer
.8byte 0x0020, 0x0, 0x1
# test 12.3.1.2.5 load page fault on misaligned pages
.8byte 0xC0000000, 0x0, 0x1 # misaligned gigapage
.8byte 0x40200000, 0x0, 0x1 # misaligned megapage
# =========== test 12.3.1.3 PTE Protection flags ===========
# test 12.3.1.3.1 User flag == 0
# *** reads on pages with U=0 already tested in 12.3.1.1.4
.8byte 0x40099000, 0x111, 0x2 # execute success when U=0, priv=S
.8byte 0x202, 0x21, 0xA # go to U mode, return to megapgage at 0x40400000 where U = 1. 0x9 written to output
.8byte 0xFFFFFFFFFFFFFC80, 0x0880DEADBEEF0550, 0x1 # load page fault when U=0, priv=U
.8byte 0x40099000, 0xbad, 0x2 # execute fault when U=0, priv=U
# test 12.3.1.3.2 User flag == 1
.8byte 0x1AC0, 0x0990DEADBEEF0033, 0x1 # read success when U=1, priv=U
.8byte 0x2, 0x12, 0x9 # go back to S mode, return to gigapage at 0x80000000 where U = 0. 0x8 written to output
.8byte 0x0, 0x3, 0x7 # set sstatus.[MXR, SUM] = 11
.8byte 0x4130, 0x0110DEADBEEF0077, 0x1 # read success when U=1, priv=S, sstatus.SUM=1
.8byte 0x40499000, 0xbad, 0x2 # instr page fault when U=1, priv=S (with any sstatus.SUM)
.8byte 0x0, 0x2, 0x7 # set sstatus.[MXR, SUM] = 10.
.8byte 0x1AC0, 0x0990DEADBEEF0033, 0x1 # load page fault when U-1, priv=S, sstatus.SUM=0
# test 12.3.1.3.3 Read flag
# *** reads on pages with R=1 already tested in 12.3.1.1.4
.8byte 0x0, 0x1, 0x7 # set sstatus.[MXR, SUM] = 01.
.8byte 0x40612348, 0x0330DEADBEEF0440, 0x1 # load page fault when R=0, sstatus.MXR=0
.8byte 0x0, 0x3, 0x7 # set sstatus.[MXR, SUM] = 11.
.8byte 0x40612348, 0x0330DEADBEEF0440, 0x1 # read success when MXR=1, X=1
# test 12.3.1.3.4 Write flag
.8byte 0x80AAAAA0, 0x0440DEADBEEF0110, 0x0 # write success when W=1
.8byte 0x80AAAAA0, 0x0440DEADBEEF0110, 0x1 # check write success by reading the same address
.8byte 0x40000000, 0x0220DEADBEEF0BB0, 0x0 # store page fault when W=0
# test 12.3.1.3.5 eXecute flag
# *** fetches on pages with X = 1 already tested in 12.3.1.3.1
.8byte 0x5AA0, 0x1, 0x2 # instr page fault when X=0
# test 12.3.1.3.6 Accessed flag == 0
.8byte 0x36D0, 0x0990DEADBEEF0770, 0x0 # store page fault when A=0
.8byte 0x3AB8, 0x0990DEADBEEF0990, 0x1 # load page fault when A=0
# test 12.3.1.3.7 Dirty flag == 0
.8byte 0x4658, 0x0440DEADBEEF0AA0, 0x0 # store page fault when D=0
.8byte 0x4AA0, 0x0440DEADBEEF0BB0, 0x1 # read success when D=0
# terminate tests
.8byte 0x0, 0x0, 0x3 # brings us back into machine mode with a final ecall, writing 0x9 to the output.

View file

@ -0,0 +1,177 @@
///////////////////////////////////////////
//
// WALLY-MMU
//
// Author: David_Harris@hmc.edu and Kip Macsai-Goren <kmacsaigoren@g.hmc.edu>
//
// Created 2021-06-15
//
// 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 "WALLY-TEST-LIB-64.S"
// 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.
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.8byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.8byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler in the framework file
#
# ---------------------------------------------------------------------------------------------
# These tests follow the testing plan in Chapter 12 of the riscv-wally textbook
# =========== test 12.3.1.1 Page Table Translation ===========
# test 12.3.1.1.1 write page tables / entries to phyiscal memory
# sv48 page table (See Figure 12.12***):
# Level 3 page table, situated at 0x8000D000
.8byte 0x000000008000D000, 0x0000000020004CC1, 0x0 # points to level 2 page table A
.8byte 0x000000008000D008, 0x00000000200050C1, 0x0 # points to level 2 page table B
.8byte 0x000000008000D010, 0x00000000000000C7, 0x0 # Vaddr 0x010000000000, Paddr 0x00000000: aligned terapage
.8byte 0x000000008000D018, 0x00004000004000C7, 0x0 # Vaddr 0x018000000000, misaligned terapage
.8byte 0x000000008000DFF8, 0x00000000200054E1, 0x0 # points to level 2 page table C
# Level 2 page table A
.8byte 0x0000000080013010, 0x00000000200060C1, 0x0 # points to level 1 page table A
# Level 2 page table B
.8byte 0x0000000080014000, 0x00000000200000CB, 0x0 # Vaddr 0x008000000000, Paddr 0x80000000: aligned gigapage used for execution tests
.8byte 0x0000000080014008, 0x00000000200000DF, 0x0 # Vaddr 0x008040000000, Paddr 0x80000000: aligned gigapage (aliased with data and instr memory) U bit set.
.8byte 0x0000000080014010, 0x00000400080000C3, 0x0 # Vaddr 0x008080000000, misaligned gigapage
# Level 2 page table C
.8byte 0x0000000080015FF8, 0x00000000200058C1, 0x0 # points to level 1 page table B
# Level 1 page table A
.8byte 0x0000000080018000, 0x00000000200000CF, 0x0 # Vaddr 0x80000000, Paddr 0x80000000: aligned megapage (data and instr memory)
.8byte 0x0000000080018008, 0x00000000200064C1, 0x0 # points to level 0 page table A
.8byte 0x0000000080018010, 0x000000C0000400CF, 0x0 # Vaddr 0x80400000, misaligned megapage
.8byte 0x0000000080018018, 0x00000000214800C9, 0x0 # Vaddr 0x80600000, Paddr 0x85200000: aligned megapage, R=0
# Level 1 page table B
.8byte 0x0000000080016FF8, 0x00000000200068C1, 0x0 # points to level 0 page table B
# Level 0 page table A
.8byte 0x0000000080019000, 0x00000000200070D1, 0x0 # Vaddr 0x80200000, Paddr 0x8001C000: bad PTE points to level -1 table
.8byte 0x0000000080019008, 0x00000000200800DF, 0x0 # Vaddr 0x80201000, Paddr 0x80200000: aligned kilopage
.8byte 0x0000000080019010, 0x00000000200810DF, 0x0 # Vaddr 0x80202000, Paddr 0x80204000: bad PTE has W but not R
.8byte 0x0000000080019018, 0x0000000020080817, 0x0 # Vaddr 0x80203000, Paddr 0x80202000: A=0, should cause read fault
.8byte 0x0000000080019020, 0x0000000020080C57, 0x0 # Vaddr 0x80204000, Paddr 0x80203000: D=0, should cause write fault
.8byte 0x0000000080019028, 0x0000000020333000, 0x0 # Vaddr 0x80205000, Paddr 0x80CCC000, invalid page.
# Level 0 page table B
.8byte 0x000000008001AFF8, 0x00000000200804CF, 0x0 # Vaddr 0xFFFFFFFFF000, Paddr 0x80201000: aligned kilopage
# test 12.3.1.1.2 write values to Paddrs in each page
# each of these values is used for 12.3.1.1.3 and some other tests, specified in the comments.
# when a test is supposed to fault, nothing is written into where it'll be reading/executing since it should fault before getting there.
.8byte 0x82777778, 0x0EE0DEADBEEF0CC0, 0x0 # 12.3.1.1.4 terapage
.8byte 0x85BC0AB0, 0x0000DEADBEEF0000, 0x0 # 12.3.1.1.4 gigapage
.8byte 0x800F0AB8, 0x0880DEADBEEF0055, 0x0 # 12.3.1.1.4 megapage
.8byte 0x80201888, 0x0220DEADBEEF0099, 0x0 # 12.3.1.1.4 kilopage
.8byte 0x80099000, 0x0000806711100393, 0x0 # 12.3.1.3.1 write executable code for "li x7, 0x111; ret"
.8byte 0x80200400, 0x0000806711100393, 0x0 # 12.3.1.3.2 write same executable code
.8byte 0x80200AC0, 0x0990DEADBEEF0033, 0x0 # 12.3.1.3.2
.8byte 0x80200130, 0x0110DEADBEEF0077, 0x0 # 12.3.1.3.2
.8byte 0x85212348, 0x0330DEADBEEF0440, 0x0 # 12.3.1.3.3
.8byte 0x88888000, 0x0000806711100393, 0x0 # 12.3.1.3.5 write same executable code
.8byte 0x80203AA0, 0x0440DEADBEEF0BB0, 0x0 # 12.3.1.3.7
# test 12.3.1.1.3 read values back from Paddrs without translation (this also verifies the previous test)
.8byte 0x0, 0x0, 0x4 # satp.MODE = baremetal / no translation.
.8byte 0x0, 0x0, 0x9 # change to S mode, 0xb written to output
.8byte 0x82777778, 0x0EE0DEADBEEF0CC0, 0x1
.8byte 0x85BC0AB0, 0x0000DEADBEEF0000, 0x1
.8byte 0x800F0AB8, 0x0880DEADBEEF0055, 0x1
.8byte 0x80200AC0, 0x0990DEADBEEF0033, 0x1
.8byte 0x80200130, 0x0110DEADBEEF0077, 0x1
.8byte 0x80201888, 0x0220DEADBEEF0099, 0x1
.8byte 0x85212348, 0x0330DEADBEEF0440, 0x1
.8byte 0x80203AA0, 0x0440DEADBEEF0BB0, 0x1
# test 12.3.1.1.4 check translation works in sv48, read the same values from previous tests, this time with Vaddrs
.8byte 0x0, 0x0, 0x6 # satp.MODE = sv48, Nothing written to output
.8byte 0x10082777778, 0x0EE0DEADBEEF0CC0, 0x1 # terapage at Vaddr 0x010000000000, Paddr 0x0
.8byte 0x8005BC0AB0, 0x0000DEADBEEF0000, 0x1 # gigapage at Vaddr 0x008000000000, Paddr 0x80000000
.8byte 0x800F0AB8, 0x0880DEADBEEF0055, 0x1 # megapage at Vaddr 0x80000000, Paddr 0x80000000
.8byte 0xFFFFFFFFFFFFF888, 0x0220DEADBEEF0099, 0x1 # kilopage at Vaddr 0xFFFFFFFFFFFFF000, Paddr 0x80201000
# =========== test 12.3.1.2 page fault tests ===========
# test 12.3.1.2.1 page fault if upper bits of Vaddr are not the same
.8byte 0x001000800ABC0AB0, 0x0, 0x1 # gigapage at Vaddr 0x008000000000, Paddr 0x80000000, bad 1 in upper bits
.8byte 0xFF0FFFFFFFFFF888, 0x0, 0x1 # kilopage at Vaddr 0xFFFFFFFFFFFFF000, Paddr 0x80201000, bad 0000 in upper bits
# test 12.3.1.2.2 read fault when reading an address where the valid flag is zero
.8byte 0x80205000, 0x0, 0x1
# test 12.3.1.2.3 write fault if PTE has W and ~R flags set
.8byte 0x80202000, 0x0, 0x0
# test 12.3.1.2.4 Fault if last level PTE is a pointer
.8byte 0x80200000, 0x0, 0x1
# test 12.3.1.2.5 read fault on misaligned pages
.8byte 0x18000000000, 0x0, 0x1 # misaligned terapage
.8byte 0x8080000000, 0x0, 0x1 # misaligned gigapage
.8byte 0x80400000, 0x0, 0x1 # misaligned megapage
# =========== test 12.3.1.3 PTE Protection flags ===========
# test 12.3.1.3.1 User flag == 0
# reads on pages with U=0 already tested in 12.3.1.1.4
.8byte 0x008000099000, 0x111, 0x2 # execute success when U=0, priv=S
.8byte 0x201, 0x12, 0xA # go to U mode, return to gigapage at 0x008040000000 where PTE.U = 1. 0x9 written to output
.8byte 0xFFFFFFFFFFFFFC80, 0x0880DEADBEEF0550, 0x1 # read fault when U=0, priv=U
.8byte 0x008000099000, 0xbad, 0x2 # execute fault when U=0, priv=U
# test 12.3.1.3.2 User flag == 1
.8byte 0x80201AC0, 0x0990DEADBEEF0033, 0x1 # read success when U=1, priv=U
.8byte 0x400, 0x21, 0x9 # go back to S mode, return to megapage at 0x80000000 where PTE.U = 0. 0x8 written to output
.8byte 0x0, 0x3, 0x7 # set sstatus.[MXR, SUM] = 11
.8byte 0x80201130, 0x0110DEADBEEF0077, 0x1 # read success when U=1, priv=S, sstatus.SUM=1
.8byte 0x80201400, 0xbad, 0x2 # execute fault when U=1, priv=S (with any sstatus.SUM)
.8byte 0x0, 0x2, 0x7 # set sstatus.[MXR, SUM] = 10.
.8byte 0x80201AC0, 0x0990DEADBEEF0033, 0x1 # read fault when U=1, priv=S, sstatus.SUM=0
# test 12.3.1.3.3 Read flag
# reads on pages with R=1 already tested in 12.3.1.1.4
.8byte 0x0, 0x1, 0x7 # set sstatus.[MXR, SUM] = 01.
.8byte 0x80612348, 0x0330DEADBEEF0440, 0x1 # read fault when R=0, sstatus.MXR=0
.8byte 0x0, 0x3, 0x7 # set sstatus.[MXR, SUM] = 11.
.8byte 0x80612348, 0x0330DEADBEEF0440, 0x1 # read success when MXR=1, X=1
# test 12.3.1.3.4 Write flag
.8byte 0x10080BCDED8, 0x0440DEADBEEF0110, 0x0 # write success when W=1 (corresponding Paddr = 0x80BCDED8)
.8byte 0x10080BCDED8, 0x0440DEADBEEF0110, 0x1 # check write success by reading value back
.8byte 0x80C0009E88, 0x0220DEADBEEF0BB0, 0x0 # write fault when W=0
# test 12.3.1.3.5 eXecute flag
# executes on pages with X = 1 already tested in 12.3.1.3.1
.8byte 0x010088888000, 0x2, 0x2 # execute fault when X=0
# test 12.3.1.3.6 Accessed flag == 0
.8byte 0x802036D0, 0x0990DEADBEEF0770, 0x0 # write fault when A=0
.8byte 0x80203AB8, 0x0990DEADBEEF0990, 0x1 # read fault when A=0
# test 12.3.1.3.7 Dirty flag == 0
.8byte 0x80204658, 0x0440DEADBEEF0AA0, 0x0 # write fault when D=0
.8byte 0x80204AA0, 0x0440DEADBEEF0BB0, 0x1 # read success when D=0
# terminate tests
.8byte 0x0, 0x0, 0x3 # brings us back into machine mode with a final ecall, writing 0x9 to the output.

View file

@ -0,0 +1,82 @@
///////////////////////////////////////////
//
// WALLY-PMA
//
// Author: Kip Macsai-Goren <kmacsaigoren@g.hmc.edu> (Copied heavily from SV48 test).
//
// Created 2021-06-15
//
// 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 "WALLY-TEST-LIB-64.S"
// 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.
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.8byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.8byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler
#
# ---------------------------------------------------------------------------------------------
# =========== test 12.3.2.1 PMAs: Memory Access Size, Type protection test ===========
# Tests memory load, store, and /* *** execute? */ permissions based on table 12.3 in the *** riscv book, copied below
# Test 12.3.2.1.1 check enabled devices
# | Region | Read widths | R | W | X | Cacheable | Idempotent | Atomic |
.8byte 0x1000, 0x0, 0xB # | ROM | Any | YES | NO | YES | YES | NO | NO | # *** Impossible to write? how am I supposed to put a known value in ROM to read out?
.8byte 0x2000000, 0x0, 0xB # | CLINT | Any | YES | YES | NO | NO | NO | NO |
.8byte 0xC000000, 0x0, 0xB # | PLIC | 32-bit | YES | YES | NO | NO | NO | NO |
.8byte 0x10000000, 0x0, 0xB # | UART0 | 8-bit | YES | YES | NO | NO | NO | NO |
.8byte 0x20000000, 0x0, 0xB # | GPIO | 32-bit | YES | YES | NO | NO | NO | NO |
.8byte 0x800F0000, 0x0, 0xB # | DRAM | Any | YES | YES | YES | YES | YES | YES |
# *** the dram one has a little offset so we don't accidentally write over the code of this test.
# Test 12.3.2.1.2 Check Regions with no enabled device fail all
.8byte 0x0000, 0x0, 0xC
.8byte 0x3000, 0x0, 0xC
.8byte 0x4000000, 0x0, 0xC
.8byte 0xE0000000, 0x0, 0xC
.8byte 0x12000000, 0x0, 0xC
.8byte 0xA0000000, 0x0, 0xC
.8byte 0x0, 0x0, 0x3 // terminate tests

View file

@ -0,0 +1,112 @@
///////////////////////////////////////////
//
// WALLY-PMP
//
// Author: Kip Macsai-Goren <kmacsaigoren@g.hmc.edu>
//
// Created 2021-06-15
//
// 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 "WALLY-TEST-LIB-64.S"
// 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.
# ---------------------------------------------------------------------------------------------
# Test Contents
#
# Here is where the actual tests are held, or rather, what the actual tests do.
# each entry consists of 3 values that will be read in as follows:
#
# '.8byte [x28 Value], [x29 Value], [x30 value]'
# or
# '.8byte [address], [value], [test type]'
#
# The encoding for x30 test type values can be found in the test handler in the framework file
#
# ---------------------------------------------------------------------------------------------
# These tests follow the testing plan in Chapter 12 of the riscv-wally textbook *** what is it called and how do I refer to it?
# =========== test 12.3.2.2 PMPs ===========
# 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. Each of these should output the value of the pmpaddr after being written.
# | Reg | pmpaddr | pmpcfg | L | A | X | W | R | Comments |
.8byte 0x0, 0x0FFFFFFF, 0xE # | 0 | 0x0FFFFFFF | 1F | 0 | NAPOT | 0 | 1 | 1 | I/O 00000000-7FFFFFFF RW |
.8byte 0x1, 0x20040000, 0xE # | 1 | 0x20040000 | 00 | 0 | OFF | 0 | 0 | 0 | |
.8byte 0x2, 0x2004003F, 0xE # | 2 | 0x2004003F | 09 | 0 | TOR | 0 | 0 | 1 | 80100000-801000FF R |
.8byte 0x3, 0x20040080, 0xE # | 3 | 0x20040080 | 00 | 0 | OFF | 0 | 0 | 0 | |
.8byte 0x4, 0x20040084, 0xE # | 4 | 0x20040084 | 0C | 0 | TOR | 1 | 0 | 0 | 80100200-80100210 X |
.8byte 0x5, 0x200400C0, 0xE # | 5 | 0x200400C0 | 90 | 1 | NA4 | 0 | 0 | 0 | 80100300-80100303 locked out |
.8byte 0x6, 0x2004013F, 0xE # | 6 | 0x2004013F | 18 | 0 | NAPOT | 0 | 0 | 0 | 80100400-801004FF no access |
# Pmpaddr 7-14 are all zeroed out in this test, so they don't need writes.
.8byte 0xF, 0x2FFFFFFF, 0xE # | 15 | 0x2FFFFFFF | 1F | 0 | NAPOT | 1 | 1 | 1 | Main mem 80000000-FFFFFFFF RWX|
# write pmpcfg regs with the information in the table above. this should also write the value of these registers to the output.
.8byte 0x0, 0x0018900C0009001F, 0xD # write pmpcfg0, output 0x0018900C0009001F
.8byte 0x2, 0x1F00000000000000, 0xD # write pmpcfg2, output 0x1F00000000000000
# write known values to memory where W=0. This should be possible since we're in machine mode.
.8byte 0x80100010, 0x600DAA, 0x0 # write to pmpaddr 1-2 range
.8byte 0x80100400, 0x600DBB, 0x0 # write to pmpaddr 6 range
# Write executable code to regions where X = 0, 1 in main memory
.8byte 0x80100200, 0x0000806711100393, 0x0 # write executable code for "li x7, 0x111; ret" to region with X=1 (PMP4)
.8byte 0x80100020, 0x0000806711100393, 0x0 # Write same executable code to region with X=0 (PMP2)
# attempt to write to pmpaddr5 and pmp5cfg after lockout
.8byte 0x0, 0x0018FF0C0009001F, 0xD # attempt to edit only pmp5cfg (pmpcfg0[47:40]) after lockout.
# instruction ignored, output is 0x0018900C0009001F, NOT 0x0018FF0C0009001F
.8byte 0x5, 0xFFFFFFFF, 0xE # attempt to edit pmpaddr5 after lockout.
# instruction ignored, output is 0x80100300, NOT 0xFFFFFFFF
# Test 12.3.2.2.2 Machine mode access
.8byte 0x80100300, 0x0, 0x1 # access fault to region with L=1, R=0
.8byte 0x80100400, 0x0, 0x1 # successful access to region with L=X=W=R=0
# Test 12.3.2.2.3 System mode access
.8byte 0x0, 0x0, 0x9 # go to S mode. 0xb written to output
# test a write followed by a read to each region with R=W=1
.8byte 0x80200000, 0x600D15, 0x0 # Write "good value" to RW range (PMP15)
.8byte 0x80200000, 0x600D15, 0x1 # confirm write with read
# test a write followed by a read on the edges of a read-only range
.8byte 0x800FFFF8, 0x600D02, 0x0 # Write "good value" just below read-only range (PMP2)
.8byte 0x800FFFF8, 0x600D02, 0x1 # confirm write with read
.8byte 0x80100100, 0x600D12, 0x0 # Write "good value" just above read-only range (PMP2)
.8byte 0x80100100, 0x600D12, 0x1 # confirm write with read
# test a read from each read only range verify a write causes an access fault
.8byte 0x80100010, 0xBAD, 0x0 # Write fault in read-only range (PMP2)
.8byte 0x80100010, 0x600DAA, 0x1 # read correct value out
# test read and write fault on region with no access
.8byte 0x80100208, 0x600D15, 0x0 # Write fault on no-access range (PMP6)
.8byte 0x80100208, 0x600D15, 0x1 # read fault on no-access range (PMP6)
############## *********** Test works up to here. Adding in these tests somehow exes out the regions of memory where we wrote the original pmpaddr values to it.
# # test jalr to region with X=0 causes access fault
# .8byte 0x80100020, 0xbad, 0x2 # execute fault on no-execute range (PMP2)
# # test jalr to region with X=1 returns successfully
# .8byte 0x80100200, 0x111, 0x2 # execute success when X=1
.8byte 0x0, 0x0, 0x3 // terminate tests

View file

@ -0,0 +1,728 @@
///////////////////////////////////////////
//
// WALLY-TEST-LIB-64.S
//
// Author: Kip Macsai-Goren <kmacsaigoren@g.hmc.edu>
//
// 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
/*
#include "riscv_test_macros.h"
#include "compliance_test.h"
#include "compliance_io.h"
RV_COMPLIANCE_RV64M
RV_COMPLIANCE_CODE_BEGIN
RVTEST_IO_INIT
RVTEST_IO_ASSERT_GPR_EQ(x31, x0, 0x00000000)
RVTEST_IO_WRITE_STR(x31, "Test Begin\n")
# ---------------------------------------------------------------------------------------------
RVTEST_IO_WRITE_STR(x31, "# Test group 1\n")
*/
# ---------------------------------------------------------------------------------------------
# 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
# address for trap handler
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.
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): Upper bits of change of return address after trap
# Put it in the bottom bits of a1. *** soon to be changed to just the base address of the return page.
# Default : 0x0 (defaults to the next instruction in the same location as the return address)
# Terapage: returnAddr[END-1:39]
# Gigapage: returnAddr[END-1:30]
# Megapage: returnAddr[END-1:21]
# Kilopage: returnAddr[END-1:12] (this value also works for baremetal)
# a2 (x12): Pagetype for change of return address after trap
# Put the Source page in a2[7:4] and Dest page in a2[3:0]
# Ex: giga -> mega a2=0x21
#
# Default : Ignored if a1 == 0x0
# Terapage: 3
# Gigapage: 2
# Megapage: 1
# Kilopage: 0
#
# --------------------------------------------------------------------------------------------
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.
# Get Mask Bits
la x5, trap_return_pagetype_table
mv x7, a2
li x28, 0xF0 # mask bits for current pagetype
and x7, x28, x7
srli x7, x7, 1
add x5, x5, x7
ld x7, 0(x5) # x7 = number of offset bits in current page type
la x5, trap_return_pagetype_table
li x28, 0xF # mask bits for new pagetype
and a2, x28, a2
slli a2, a2, 3
add x5, x5, a2
ld a2, 0(x5) # a2 = number of offset bits in new page type
li x5, 1
sll x5, x5, x7
addi x5, x5, -1 # x5 = mask bits for offset into current pagetype
# *** This shoulf be removed
sll a1, a1, a2 # a1 = the VPN of the new return page.
# set x1, the stack pointer, to the new virtual address
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)
# set x5, the pointer for where we are in the test cases, to the new virtual address
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)
# set x6, the pointer for the virtual address of the output of the tests, to the new virtual address
and x7, x5, x6 # x7 = offset for x6
add x6, x7, a1 # x6 = new address for the result pointer
# set return address 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 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
# case statements for which test behavior to perform.
# *** We would use the same table method as the test types and trap handler,
# but using the la command to load the base of the table loads only the physical address
# So it doesn't work with virtual memory.
# x30 Value : Function : Fault output value : Normal output values
# ----------:---------------------------------------:------------------------:------------------------------------------------------
li x7, 0x0 # : : :
beq x30, x7, write64_test # 0x0 : Write 64 bits to address : 0xf : None
li x7, 0x11 # : : :
beq x30, x7, write32_test # 0x11 : Write 32 bits to address : 0xf : None
li x7, 0x12 # : : :
beq x30, x7, write16_test # 0x12 : Write 16 bits to address : 0xf : None
li x7, 0x13 # : : :
beq x30, x7, write08_test # 0x13 : Write 8 bits to address : 0xf : None
li x7, 0x1 # : : :
beq x30, x7, read64_test # 0x1 : Read 64 bits from address : 0xd, 0xbad : readvalue in hex
li x7, 0x14 # : : :
beq x30, x7, read32_test # 0x14 : Read 32 bitsfrom address : 0xd, 0xbad : readvalue in hex
li x7, 0x15 # : : :
beq x30, x7, read16_test # 0x15 : Read 16 bitsfrom address : 0xd, 0xbad : readvalue in hex
li x7, 0x16 # : : :
beq x30, x7, read08_test # 0x16 : Read 8 bitsfrom address : 0xd, 0xbad : readvalue in hex
li x7, 0x2 # : : :
beq x30, x7, executable_test # 0x2 : test executable on virtual page : 0xc, 0xbad : value of x7 modified by exectuion code (usually 0x111)
li x7, 0x3 # : : :
beq x30, x7, terminate_test # 0x3 : terminate tests : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
li x7, 0x4 # : : :
beq x30, x7, goto_baremetal # 0x4 : satp.MODE = bare metal : None : None
li x7, 0x5 # : : :
beq x30, x7, goto_sv39 # 0x5 : satp.MODE = sv39 : None : None
li x7, 0x6 # : : :
beq x30, x7, goto_sv48 # 0x6 : satp.MODE = sv48 : None : None
li x7, 0x7 # : : :
beq x30, x7, write_mxr_sum # 0x7 : write sstatus.[19:18] = MXR, SUM bits : None : None
li x7, 0xD # : : :
beq x30, x7, write_pmpcfg_0 # 0xD : Write one of the pmpcfg csr's : mstatuses?, 0xD : readback of pmpcfg value
li x7, 0xE # : : :
beq x30, x7, write_pmpaddr_0 # 0xE : Write one of the pmpaddr csr's : None : None
li x7, 0x8 # : : :
beq x30, x7, goto_m_mode # 0x8 : go to mahcine mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
li x7, 0x9 # : : :
beq x30, x7, goto_s_mode # 0x9 : go to supervisor mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
li x7, 0xA # : : :
beq x30, x7, goto_u_mode # 0xA : go to user mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
# ------------------------------------------------------------------------------------------------------------------------------------
j terminate_test # default case: break
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_IO_WRITE_STR(x31, "Test End\n")
# ---------------------------------------------------------------------------------------------
RV_COMPLIANCE_HALT
RV_COMPLIANCE_CODE_END
# Input data section.
.data
.align 3 # align stack to 8 byte boundary
bottom_of_stack:
.fill 1024, 4, -1
top_of_stack:
# Output data section.
RV_COMPLIANCE_DATA_BEGIN
.align 3 # align output to 8 byte boundary
test_1_res:
.fill 1024, 4, -1
RV_COMPLIANCE_DATA_END
.align 3
test_cases:
*/
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, -1
top_of_stack:
RVMODEL_DATA_BEGIN
// next lines through test cases copied over from old framework
test_1_res:
.fill 1024, 4, -1
RVMODEL_DATA_END
/*
signature_x8_0:
.fill 0*(XLEN/32),4,0xdeadbeef
signature_x8_1:
.fill 19*(XLEN/32),4,0xdeadbeef
signature_x1_0:
.fill 256*(XLEN/32),4,0xdeadbeef
signature_x1_1:
.fill 256*(XLEN/32),4,0xdeadbeef
signature_x1_2:
.fill 148*(XLEN/32),4,0xdeadbeef
*/
#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: