mirror of
				https://github.com/openhwgroup/cvw
				synced 2025-02-11 06:05:49 +00:00 
			
		
		
		
	tentatively remade test lib to use macros for more flexibility
This commit is contained in:
		
							parent
							
								
									ee982c7588
								
							
						
					
					
						commit
						3c61d6eec2
					
				| @ -0,0 +1,560 @@ | ||||
| ///////////////////////////////////////////
 | ||||
| //
 | ||||
| // WALLY-TEST-LIB-64.h
 | ||||
| //
 | ||||
| // Author: Kip Macsai-Goren <kmacsaigoren@g.hmc.edu>
 | ||||
| //
 | ||||
| // Created 2022-01-30
 | ||||
| //
 | ||||
| // 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.
 | ||||
| ///////////////////////////////////////////
 | ||||
| 
 | ||||
| 
 | ||||
| .macro INIT_TESTS | ||||
| 
 | ||||
| #include "model_test.h" | ||||
| #include "arch_test.h" | ||||
| RVTEST_ISA("RV64I") | ||||
| 
 | ||||
| .section .text.init | ||||
| .globl rvtest_entry_point | ||||
| rvtest_entry_point: | ||||
| RVMODEL_BOOT | ||||
| RVTEST_CODE_BEGIN | ||||
| 
 | ||||
| 
 | ||||
|     // ---------------------------------------------------------------------------------------------
 | ||||
|     // Initialization Overview:
 | ||||
|     //   
 | ||||
|     //   Initialize x6 as a virtual pointer to the test results
 | ||||
|     //   Initialize x16 as a physical pointer to the test results
 | ||||
|     //   Set up stack pointer (sp = x2)
 | ||||
|     //   Set up the exception Handler, keeping the original handler in x4.
 | ||||
|     //   
 | ||||
| 	// ---------------------------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     // address for test results
 | ||||
|     la x6, test_1_res | ||||
|     la x16, test_1_res // x16 reserved for the physical address equivalent of x6 to be used in trap handlers
 | ||||
|                         // any time either is used, both must be updated.
 | ||||
| 
 | ||||
|     // address for stack
 | ||||
|     la sp, top_of_stack | ||||
| 
 | ||||
|     // trap handler setup
 | ||||
|     la x1, machine_trap_handler | ||||
|     csrrw x4, mtvec, x1  // x4 reserved for "default" trap handler address that needs to be restored before halting this test.
 | ||||
|     li a0, 0 | ||||
|     li a1, 0  | ||||
|     li a2, 0 // reset trap handler inputs to zero
 | ||||
| 
 | ||||
|     // go to first test!
 | ||||
|     j begin_test | ||||
| 
 | ||||
| 
 | ||||
| 	// ---------------------------------------------------------------------------------------------
 | ||||
|     // General traps Handler
 | ||||
|     // 
 | ||||
|     //   Handles traps by branching to different behaviors based on mcause.
 | ||||
|     //   
 | ||||
|     //   Note that allowing the exception handler to change mode for a program is a huge security
 | ||||
|     //   hole, but this is an expedient way of writing tests that need different modes
 | ||||
|     // 
 | ||||
|     // input parameters:
 | ||||
|     // 
 | ||||
|     //   a0 (x10): 
 | ||||
|     //       0: halt program with no failures
 | ||||
|     //       1: halt program with failure in x11 = a1
 | ||||
|     //       2: go to machine mode
 | ||||
|     //       3: go to supervisor mode
 | ||||
|     //       4: go to user mode
 | ||||
|     //       others: do nothing
 | ||||
|     //
 | ||||
|     //   a1 (x11): 
 | ||||
|     //       VPN for return address after changing privilege mode.
 | ||||
|     //       This should be the base VPN with no offset.
 | ||||
|     //       0x0 : defaults to next instruction on the same page the trap was called on.
 | ||||
|     //
 | ||||
|     //   a2 (x12): 
 | ||||
|     //       Pagetype of the current address VPN before changing privilge mode
 | ||||
|     //       Used so that we can know how many bits of the adress are the offset.
 | ||||
|     //       Ignored if a1 == 0x0
 | ||||
|     //       0: Kilopage
 | ||||
|     //       1: Megapage
 | ||||
|     //       2: Gigapage
 | ||||
|     //       3: Terapage
 | ||||
|     //     
 | ||||
|     // --------------------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| 
 | ||||
| machine_trap_handler: | ||||
|     // The processor is always in machine mode when a trap takes us here
 | ||||
|     // save registers on stack before using
 | ||||
|     sd x1, -8(sp)        | ||||
|     sd x5, -16(sp)      | ||||
| 
 | ||||
|     // Record trap
 | ||||
|     csrr x1, mcause     // record the mcause
 | ||||
|     sd x1, 0(x16)         | ||||
|     addi x6, x6, 8      | ||||
|     addi x16, x16, 8    // update pointers for logging results
 | ||||
| 
 | ||||
|     // Respond to trap based on cause
 | ||||
|     // All interrupts should return after being logged
 | ||||
|     li x5, 0x8000000000000000   // if msb is set, it is an interrupt
 | ||||
|     and x5, x5, x1 | ||||
|     bnez x5, trapreturn   // return from interrupt
 | ||||
|     // Other trap handling is specified in the vector Table
 | ||||
|     slli x1, x1, 3      // multiply cause by 8 to get offset in vector Table
 | ||||
|     la x5, trap_handler_vector_table | ||||
|     add x5, x5, x1      // compute address of vector in Table
 | ||||
|     ld x5, 0(x5)        // fectch address of handler from vector Table
 | ||||
|     jr x5               // and jump to the handler
 | ||||
|      | ||||
| segfault: | ||||
|     ld x5, -16(sp)      // restore registers from stack before faulting
 | ||||
|     ld x1, -8(sp)        | ||||
|     j terminate_test          // halt program.
 | ||||
| 
 | ||||
| trapreturn: | ||||
|     // look at the instruction to figure out whether to add 2 or 4 bytes to PC, or go to address specified in a1
 | ||||
|     csrr x1, mepc       // get the mepc
 | ||||
|     addi x1, x1, 4 // *** should be 2 for compressed instructions, see note.
 | ||||
| 
 | ||||
| 
 | ||||
| // ****** KMG: the following is no longer as easy to determine. mepc gets the virtual address of the trapped instruction, 
 | ||||
| // ********     but in the handler, we work in M mode with physical addresses
 | ||||
| //              This means the address in mepc is suddenly pointing somewhere else.
 | ||||
| //              to get this to work, We could either retranslate the vaddr back into a paddr (probably on the scale of difficult to intractible)
 | ||||
| //              or we could come up with some other ingenious way to stay in M mode and see if the instruction was compressed.
 | ||||
| 
 | ||||
| //     lw x5, 0(x1)        // read the faulting instruction
 | ||||
| //     li x1, 3            // check bottom 2 bits of instruction to see if compressed
 | ||||
| //     and x5, x5, x1      // mask the other bits
 | ||||
| //     beq x5, x1, trapreturn_uncompressed  // if 11, the instruction is return_uncompressed
 | ||||
| 
 | ||||
| // trapreturn_compressed:
 | ||||
| //     csrr x1, mepc       // get the mepc again
 | ||||
| //     addi x1, x1, 2      // add 2 to find the next instruction
 | ||||
| //     j trapreturn_specified // and return
 | ||||
| 
 | ||||
| // trapreturn_uncompressed:
 | ||||
| //     csrr x1, mepc       // get the mepc again    
 | ||||
| //     addi x1, x1, 4      // add 4 to find the next instruction
 | ||||
| 
 | ||||
| trapreturn_specified: | ||||
|     // reset the necessary pointers and registers (x1, x5, x6, and the return address going to mepc)
 | ||||
|     // so that when we return to a new virtual address, they're all in the right spot as well.
 | ||||
| 
 | ||||
|     beqz a1, trapreturn_finished // either update values, of go to default return address.
 | ||||
| 
 | ||||
|     la x5, trap_return_pagetype_table | ||||
|     slli a2, a2, 3 | ||||
|     add x5, x5, a2 | ||||
|     ld a2, 0(x5) // a2 = number of offset bits in current page type
 | ||||
|      | ||||
|     li x5, 1 | ||||
|     sll x5, x5, a2 | ||||
|     addi x5, x5, -1 // x5 = mask bits for offset into current pagetype
 | ||||
| 
 | ||||
|     // reset the top of the stack, x1
 | ||||
|     ld x7, -8(sp)  | ||||
|     and x7, x5, x7 // x7 = offset for x1
 | ||||
|     add x7, x7, a1 // x7 = new address for x1
 | ||||
|     sd x7, -8(sp) | ||||
| 
 | ||||
|     // reset the second spot in the stack, x5
 | ||||
|     ld x7, -16(sp) | ||||
|     and x7, x5, x7 // x7 = offset for x5
 | ||||
|     add x7, x7, a1 // x7 = new address for x5
 | ||||
|     sd x7, -16(sp) | ||||
| 
 | ||||
|     // reset x6, the pointer for the virtual address of the output of the tests
 | ||||
|     and x7, x5, x6 // x7 = offset for x6
 | ||||
|     add x6, x7, a1 // x6 = new address for the result pointer
 | ||||
|      | ||||
|     // set return address, stored temporarily in x1, to the next instruction, but in the new virtual page.
 | ||||
|     and x1, x5, x1 // x1 = offset for the return address
 | ||||
|     add x1, x1, a1 // x1 = new return address.
 | ||||
| 
 | ||||
|     li a1, 0  | ||||
|     li a2, 0 // reset trapreturn inputs to the trap handler
 | ||||
| 
 | ||||
| trapreturn_finished: | ||||
|     csrw mepc, x1       // update the mepc with address of next instruction
 | ||||
|     ld x5, -16(sp)      // restore registers from stack before returning
 | ||||
|     ld x1, -8(sp) | ||||
|     mret  // return from trap
 | ||||
| 
 | ||||
| ecallhandler: | ||||
|     // Check input parameter a0. encoding above. 
 | ||||
|     // *** ASSUMES: that this trap is being handled in machine mode. in other words, that nothing odd has been written to the medeleg or mideleg csrs.
 | ||||
|     li x5, 2            // case 2: change to machine mode
 | ||||
|     beq a0, x5, ecallhandler_changetomachinemode | ||||
|     li x5, 3            // case 3: change to supervisor mode
 | ||||
|     beq a0, x5, ecallhandler_changetosupervisormode | ||||
|     li x5, 4            // case 4: change to user mode
 | ||||
|     beq a0, x5, ecallhandler_changetousermode | ||||
|     // unsupported ecalls should segfault
 | ||||
|     j segfault | ||||
| 
 | ||||
| ecallhandler_changetomachinemode: | ||||
|     // Force mstatus.MPP (bits 12:11) to 11 to enter machine mode after mret
 | ||||
|     li x1, 0b1100000000000 | ||||
|     csrs mstatus, x1 | ||||
|     j trapreturn         | ||||
| 
 | ||||
| ecallhandler_changetosupervisormode: | ||||
|     // Force mstatus.MPP (bits 12:11) to 01 to enter supervisor mode after mret
 | ||||
|     li x1, 0b1100000000000   | ||||
|     csrc mstatus, x1 | ||||
|     li x1, 0b0100000000000 | ||||
|     csrs mstatus, x1 | ||||
|     j trapreturn | ||||
| 
 | ||||
| ecallhandler_changetousermode: | ||||
|     // Force mstatus.MPP (bits 12:11) to 00 to enter user mode after mret
 | ||||
|     li x1, 0b1100000000000   | ||||
|     csrc mstatus, x1 | ||||
|     j trapreturn | ||||
| 
 | ||||
| instrfault: | ||||
|     ld x1, -8(sp) // load return address int x1 (the address AFTER the jal into faulting page)
 | ||||
|     j trapreturn_finished // puts x1 into mepc, restores stack and returns to program (outside of faulting page)
 | ||||
| 
 | ||||
| illegalinstr: | ||||
|     j trapreturn // return to the code after recording the mcause
 | ||||
| 
 | ||||
| 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 illegalinstr  // 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
 | ||||
| 
 | ||||
| begin_test: // label here to jump to so we dont go through the trap handler before starting the test
 | ||||
| 
 | ||||
| .endm // Ends the initialization macro that set up the begginnning of the tests and the trap handler.
 | ||||
| 
 | ||||
| 
 | ||||
| // Test Summary table!
 | ||||
| 
 | ||||
| // Test Name            : Description                               : Fault output value            : Normal output values
 | ||||
| // ---------------------:-------------------------------------------:-------------------------------:------------------------------------------------------
 | ||||
| //   write64_test       : Write 64 bits to address                  : 0x6, 0x7, or 0xf              : None
 | ||||
| //   write32_test       : Write 32 bits to address                  : 0x6, 0x7, or 0xf              : None 
 | ||||
| //   write16_test       : Write 16 bits to address                  : 0x6, 0x7, or 0xf              : None 
 | ||||
| //   write08_test       : Write 8 bits to address                   : 0x6, 0x7, or 0xf              : None
 | ||||
| //   read64_test        : Read 64 bits from address                 : 0x4, 0x5, or 0xd, then 0xbad  : readvalue in hex
 | ||||
| //   read32_test        : Read 32 bitsfrom address                  : 0x4, 0x5, or 0xd, then 0xbad  : readvalue in hex
 | ||||
| //   read16_test        : Read 16 bitsfrom address                  : 0x4, 0x5, or 0xd, then 0xbad  : readvalue in hex
 | ||||
| //   read08_test        : Read 8 bitsfrom address                   : 0x4, 0x5, or 0xd, then 0xbad  : readvalue in hex
 | ||||
| //   executable_test    : test executable on virtual page           : 0x0, 0x1, or 0xc, then 0xbad  : value of x7 modified by exectuion code (usually 0x111)
 | ||||
| //   terminate_test     : terminate tests                           : mcause value for fault        : from M 0xb, from S 0x9, from U 0x8  
 | ||||
| //   goto_baremetal     : satp.MODE = bare metal                    : None                          : None 
 | ||||
| //   goto_sv39          : satp.MODE = sv39                          : None                          : None 
 | ||||
| //   goto_sv48          : satp.MODE = sv48                          : None                          : None
 | ||||
| //   goto_m_mode        : go to mahcine mode                        : mcause value for fault        : from M 0xb, from S 0x9, from U 0x8  
 | ||||
| //   goto_s_mode        : go to supervisor mode                     : mcause value for fault        : from M 0xb, from S 0x9, from U 0x8
 | ||||
| //   goto_u_mode        : go to user mode                           : mcause value for fault        : from M 0xb, from S 0x9, from U 0x8 
 | ||||
| //   write_csr          : write to specified CSR                    : CSR value before test attempt : value written to CSR
 | ||||
| //   read_csr           : read from specified CSR                   : *** None? Mcause or fault?    : value read back from CSR
 | ||||
| 
 | ||||
| 
 | ||||
| // *** TESTS TO ADD: execute inline, read unknown value out, read CSR unknown value
 | ||||
| 
 | ||||
| .macro write64_test ADDR VAL | ||||
|     // attempt to write VAL to ADDR
 | ||||
|     // Success outputs:
 | ||||
|     //      None
 | ||||
|     // Fault outputs:
 | ||||
|     //      0x6: misaligned address
 | ||||
|     //      0x7: access fault
 | ||||
|     //      0xf: page fault     
 | ||||
|     li x29, \VAL | ||||
|     li x30, \ADDR | ||||
|     sd x29, 0(x30) | ||||
| .endm | ||||
| 
 | ||||
| .macro write32_test ADDR VAL | ||||
|     // all write tests have the same description/outputs as write64
 | ||||
|     li x29, \VAL | ||||
|     li x30, \ADDR | ||||
|     sw x29, 0(x30) | ||||
| .endm | ||||
| 
 | ||||
| .macro write16_test ADDR VAL | ||||
|     // all write tests have the same description/outputs as write64
 | ||||
|     li x29, \VAL | ||||
|     li x30, \ADDR | ||||
|     sh x29, 0(x30) | ||||
| .endm | ||||
| 
 | ||||
| .macro write08_test ADDR VAL | ||||
|     // all write tests have the same description/outputs as write64
 | ||||
|     li x29, \VAL | ||||
|     li x30, \ADDR | ||||
|     sb x29, 0(x30) | ||||
| .endm | ||||
| 
 | ||||
| .macro read64_test ADDR | ||||
|     // Attempt read at ADDR. Write the value read out to the output *** Consider adding specific test for reading a non known value
 | ||||
|     // Success outputs:
 | ||||
|     //      value read out from ADDR
 | ||||
|     // Fault outputs:
 | ||||
|     //      One of the following followed by 0xBAD
 | ||||
|     //      0x4: misaligned address
 | ||||
|     //      0x5: access fault
 | ||||
|     //      0xD: page fault
 | ||||
|     li x7, 0xBAD // bad value that will be overwritten on good reads.
 | ||||
|     li x29, \ADDR  | ||||
|     ld x7, 0(x29)  | ||||
|     sd x7, 0(x6) | ||||
|     addi x6, x6, 8  | ||||
|     addi x16, x16, 8 | ||||
| .endm | ||||
| 
 | ||||
| .macro read32_test ADDR | ||||
|     // All reads have the same description/outputs as read64. 
 | ||||
|     // They will store the sign extended value of what was read out at ADDR
 | ||||
|     li x7, 0xBAD // bad value that will be overwritten on good reads.
 | ||||
|     li x29, \ADDR  | ||||
|     lw x7, 0(x29)  | ||||
|     sd x7, 0(x6) | ||||
|     addi x6, x6, 8  | ||||
|     addi x16, x16, 8 | ||||
| .endm | ||||
| 
 | ||||
| .macro read16_test ADDR | ||||
|     // All reads have the same description/outputs as read64. 
 | ||||
|     // They will store the sign extended value of what was read out at ADDR
 | ||||
|     li x7, 0xBAD // bad value that will be overwritten on good reads.
 | ||||
|     li x29, \ADDR  | ||||
|     lh x7, 0(x29)  | ||||
|     sd x7, 0(x6) | ||||
|     addi x6, x6, 8  | ||||
|     addi x16, x16, 8 | ||||
| .endm | ||||
| 
 | ||||
| .macro read08_test ADDR | ||||
|     // All reads have the same description/outputs as read64. 
 | ||||
|     // They will store the sign extended value of what was read out at ADDR
 | ||||
|     li x7, 0xBAD // bad value that will be overwritten on good reads.
 | ||||
|     li x29, \ADDR  | ||||
|     lb x7, 0(x29)  | ||||
|     sd x7, 0(x6) | ||||
|     addi x6, x6, 8  | ||||
|     addi x16, x16, 8 | ||||
| .endm | ||||
| 
 | ||||
| // These goto_x_mode tests all involve invoking the trap handler,
 | ||||
| // So their outputs are inevitably:
 | ||||
| //      0x8: test called from U mode
 | ||||
| //      0x9: test called from S mode
 | ||||
| //      0xB: test called from M mode
 | ||||
| // they generally do not fault or cause issues as long as these modes are enabled 
 | ||||
| // *** add functionality to check if modes are enabled before jumping? maybe cause a fault if not?
 | ||||
| 
 | ||||
| .macro goto_m_mode RETURN_VPN RETURN_PAGETYPE | ||||
|     li a0, 2 // determine trap handler behavior (go to supervisor mode)
 | ||||
|     li a1, \RETURN_VPN // return VPN
 | ||||
|     li a2, \RETURN_PAGETYPE // return page types
 | ||||
|     ecall // writes mcause to the output.
 | ||||
|     // now in S mode
 | ||||
| .endm | ||||
| 
 | ||||
| .macro goto_s_mode RETURN_VPN RETURN_PAGETYPE | ||||
|     li a0, 3 // determine trap handler behavior (go to supervisor mode)
 | ||||
|     li a1, \RETURN_VPN // return VPN
 | ||||
|     li a2, \RETURN_PAGETYPE // return page types
 | ||||
|     ecall // writes mcause to the output.
 | ||||
|     // now in S mode
 | ||||
| .endm | ||||
| 
 | ||||
| .macro goto_u_mode RETURN_VPN RETURN_PAGETYPE | ||||
|     li a0, 4 // determine trap handler behavior (go to supervisor mode)
 | ||||
|     li a1, \RETURN_VPN // return VPN
 | ||||
|     li a2, \RETURN_PAGETYPE // return page types
 | ||||
|     ecall // writes mcause to the output.
 | ||||
|     // now in S mode
 | ||||
| .endm | ||||
| 
 | ||||
| // These tests change virtual memory settings, turning it on/off and changing between types.
 | ||||
| // They don't have outputs as any error with turning on virtual memory should reveal itself in the tests *** Consider changing this policy?
 | ||||
| 
 | ||||
| .macro 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 option for different pagetable location
 | ||||
|     add x7, x7, x28 | ||||
|     csrw satp, x7 | ||||
|     sfence.vma x0, x0 // *** flushes global pte's as well
 | ||||
| .endm | ||||
| 
 | ||||
| .macro goto_sv39 | ||||
|     // Turn on sv39 virtual memory
 | ||||
|     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 option for different pagetable location
 | ||||
|     add x7, x7, x28 | ||||
|     csrw satp, x7 | ||||
|     sfence.vma x0, x0 // *** flushes global pte's as well
 | ||||
| .endm | ||||
| 
 | ||||
| .macro goto_sv48 | ||||
|     // Turn on sv48 virtual memory
 | ||||
|     li x7, 9 // satp.MODE value for Sv39 (8)
 | ||||
|     slli x7, x7, 60 | ||||
|     li x28, 0x8000D // Base Pagetable physical page number, satp.PPN field. *** add option for different pagetable location
 | ||||
|     add x7, x7, x28 | ||||
|     csrw satp, x7 | ||||
|     sfence.vma x0, x0 // *** flushes global pte's as well
 | ||||
| .endm | ||||
| 
 | ||||
| .macro write_csr CSR VAL | ||||
|     // attempt to write CSR with VAL *** ASSUMES RW access to CSR in whatever privilege mode is running
 | ||||
|     // Success outputs:
 | ||||
|     //      value read back out from CSR after writing
 | ||||
|     // Fault outputs:
 | ||||
|     //      The previous CSR value before write attempt
 | ||||
|     //      *** Is there an associated mstatus? maybe 0x2???
 | ||||
|     li x29, \VAL | ||||
|     csrw \CSR\(), x29 | ||||
|     csrr x30, \CSR | ||||
|     sd x30, 0(x6) | ||||
|     addi x6, x6, 8 | ||||
|     addi x16, x16, 8 | ||||
| .endm | ||||
| 
 | ||||
| .macro csr_r_access CSR | ||||
|     // verify that a csr is accessible to read but not to write
 | ||||
|     // Success outputs:
 | ||||
|     //      0x11 *** consider changing to something more meaningful
 | ||||
|     // Fault outputs:
 | ||||
|     //      0x2, then
 | ||||
|     //      0xBAD *** consider changing this one as well. in general, do we need the branching if it hould cause an illegal instruction fault? 
 | ||||
|     csrr x29, \CSR | ||||
|     csrwi \CSR\(), 0xA // Attempt to write a 'random' value to the CSR
 | ||||
|     csrr x30, \CSR | ||||
|     bne x30, x29, 1f // 1f represents r_access_success
 | ||||
|     li x30, 0xBAD // Write succeeded, violating read only permissions.
 | ||||
|     j 2f // j r_access_end
 | ||||
| 1: // r_access_success
 | ||||
|     li x30, 0x11 | ||||
| 2: // r_access end
 | ||||
|     sd x30, 0(x6) | ||||
|     addi x6, x6, 8 | ||||
|     addi x16, x16, 8 | ||||
| .endm | ||||
| 
 | ||||
| .macro execute_at_address ADDR | ||||
|     // Execute the code already written to ADDR, returning the value in x7. 
 | ||||
|     // *** Note: this test itself doesn't write the code to ADDR because it might be callled at a point where we dont have write access to ADDR
 | ||||
|     // Assumes the code modifies x7, usually to become 0x111. 
 | ||||
|     // Sample code:  0x11100393 (li x7, 0x111), 0x00008067 (ret)
 | ||||
|     // Success outputs:
 | ||||
|     //      modified value of x7. (0x111 if you use the sample code)
 | ||||
|     // Fault outputs:
 | ||||
|     //      One of the following followed by 0xBAD
 | ||||
|     //      0x0: misaligned address
 | ||||
|     //      0x1: access fault
 | ||||
|     //      0xC: page fault
 | ||||
|     fence.i // forces caches and main memory to sync so execution code written to ADDR can run.
 | ||||
|     li x7, 0xBAD | ||||
|     li x28, \ADDR | ||||
|     jalr x28 // jump to executable test code 
 | ||||
|     sd x7, 0(x6) | ||||
|     addi x6, x6, 8 | ||||
|     addi x16, x16, 8  | ||||
| .endm | ||||
| 
 | ||||
| .macro END_TESTS | ||||
| // invokes one final ecall to return to machine mode then terminates this program, so the output is
 | ||||
| //      0x8: termination called from U mode
 | ||||
| //      0x9: termination called from S mode
 | ||||
| //      0xB: termination called from M mode
 | ||||
| 
 | ||||
| terminate_test: | ||||
| 
 | ||||
|     li a0, 2 // Trap handler behavior (go to machine mode)
 | ||||
|     ecall //  writes mcause to the output.
 | ||||
|     csrw mtvec, x4  // restore original trap handler to halt program
 | ||||
| 
 | ||||
| RVTEST_CODE_END | ||||
| RVMODEL_HALT | ||||
| 
 | ||||
| RVTEST_DATA_BEGIN | ||||
| .align 4 | ||||
| rvtest_data: | ||||
| .word 0xbabecafe | ||||
| RVTEST_DATA_END | ||||
| 
 | ||||
| .align 3 // align stack to 8 byte boundary
 | ||||
| bottom_of_stack: | ||||
|     .fill 1024, 4, 0xdeadbeef  | ||||
| top_of_stack: | ||||
| 
 | ||||
| 
 | ||||
| RVMODEL_DATA_BEGIN | ||||
| 
 | ||||
| test_1_res: | ||||
|     .fill 1024, 4, 0xdeadbeef | ||||
| 
 | ||||
| RVMODEL_DATA_END | ||||
| 
 | ||||
| #ifdef rvtest_mtrap_routine | ||||
| 
 | ||||
| mtrap_sigptr: | ||||
|     .fill 64*(XLEN/32),4,0xdeadbeef | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #ifdef rvtest_gpr_save | ||||
| 
 | ||||
| gpr_save: | ||||
|     .fill 32*(XLEN/32),4,0xdeadbeef | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| .endm // ends the macro that terminates this test program.
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user