diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h index ed16247d..4f96071e 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-TEST-LIB-64.h @@ -41,7 +41,7 @@ RVTEST_CODE_BEGIN // // 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 stack pointer, mscratch, sscratch // // --------------------------------------------------------------------------------------------- @@ -50,8 +50,12 @@ RVTEST_CODE_BEGIN 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 normal user stack, mscratch stack, and sscratch stack + la sp, mscratch_top + csrw mscratch, sp + la sp, sscratch_top + csrw sscratch, sp + la sp, stack_top .endm @@ -72,7 +76,7 @@ cause_instr_addr_misaligned: cause_instr_access: la x28, 0x0 // address zero is an address with no memory - sd x1, -8(sp) // push the return adress ontot the stack + sd x1, -8(sp) // push the return adress onto the stack addi sp, sp, -8 jalr x28 // cause instruction access trap ld x1, 0(sp) // pop return adress back from the stack @@ -83,7 +87,7 @@ cause_illegal_instr: .word 0x00000000 // a 32 bit zros is an illegal instruction ret -cause_breakpnt: // **** +cause_breakpnt: ebreak ret @@ -128,7 +132,9 @@ cause_time_interrupt: sw x31,4(x29) // store into most significant word of MTIMECMP nowrap: sw x28, 0(x29) // store into least significant word of MTIMECMP - loop: j loop // wait until interrupt occurs +loop: + wfi + j loop // wait until interrupt occurs ret cause_soft_interrupt: @@ -150,7 +156,7 @@ end_trap_triggers: .macro TRAP_HANDLER MODE, VECTORED=1, DEBUG=0 // MODE decides which mode this trap handler will be taken in (M or S mode) - // Vectored decides whether interrumpts are handled with the vector table at trap_handler_MODE (1) + // Vectored decides whether interrupts are handled with the vector table at trap_handler_MODE (1) // vs Using the non-vector approach the rest of the trap handler takes (0) // DEBUG decides whether we will print mtval a string with status.mpie, status.mie, and status.mpp to the signature (1) // vs not saving that info to the signature (0) @@ -216,23 +222,28 @@ trap_handler_\MODE\(): // *** ASSUMES that a cause value of 0 for an interrupt is unimplemented // otherwise, a vectored interrupt handler should jump to trap_handler_\MODE\() + 4 * Interrupt cause code // No matter the value of VECTORED, exceptions (not interrupts) are handled in an unvecotred way - j soft_interrupt_\MODE\() // 1: instruction access fault // the zero spot is taken up by the instruction to skip this table. + j s_soft_vector_\MODE\() // 1: instruction access fault // the zero spot is taken up by the instruction to skip this table. j segfault_\MODE\() // 2: reserved - j soft_interrupt_\MODE\() // 3: breakpoint + j m_soft_vector_\MODE\() // 3: breakpoint j segfault_\MODE\() // 4: reserved - j time_interrupt_\MODE\() // 5: load access fault + j s_time_vector_\MODE\() // 5: load access fault j segfault_\MODE\() // 6: reserved - j time_interrupt_\MODE\() // 7: store access fault + j m_time_vector_\MODE\() // 7: store access fault j segfault_\MODE\() // 8: reserved - j ext_interrupt_\MODE\() // 9: ecall from S-mode + j s_ext_vector_\MODE\() // 9: ecall from S-mode j segfault_\MODE\() // 10: reserved - j ext_interrupt_\MODE\() // 11: ecall from M-mode + j m_ext_vector_\MODE\() // 11: ecall from M-mode // 12 through >=16 are reserved or designated for platform use trap_unvectored_\MODE\(): + csrrw sp, \MODE\()scratch, sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself. + // *** NOTE: this means that nested traps will be screwed up but they shouldn't happen in any of these tests + +trap_stack_saved_\MODE\(): // jump here after handling vectored interupt since we already switch sp and scratch there // save registers on stack before using sd x1, -8(sp) - sd x5, -16(sp) + sd x5, -16(sp) + sd x7, -24(sp) // Record trap csrr x1, \MODE\()cause // record the mcause @@ -262,49 +273,35 @@ trap_unvectored_\MODE\(): // Respond to trap based on cause // All interrupts should return after being logged csrr x1, \MODE\()cause + slli x1, x1, 3 // multiply cause by 8 to get offset in vector Table li x5, 0x8000000000000000 // if msb is set, it is an interrupt and x5, x5, x1 - bnez x5, trapreturn_\MODE\() // return from interrupt + bnez x5, interrupt_handler_\MODE\() // 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, exception_vector_table_\MODE\() 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 - + +interrupt_handler_\MODE\(): + la x5, interrupt_vector_table_\MODE\() // NOTE THIS IS NOT THE SAME AS VECTORED INTERRUPTS!!! + 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_\MODE\(): - ld x5, -16(sp) // restore registers from stack before faulting + sd x7, -24(sp) // restore registers from stack before faulting + ld x5, -16(sp) ld x1, -8(sp) j terminate_test // halt program. trapreturn_\MODE\(): - // 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, \MODE\()epc // 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_\MODE\() // if 11, the instruction is return_uncompressed - -// trapreturn_compressed_\MODE\(): -// csrr x1, mepc // get the mepc again -// addi x1, x1, 2 // add 2 to find the next instruction -// j trapreturn_specified_\MODE\() // and return - -// trapreturn_uncompressed_\MODE\(): -// csrr x1, mepc // get the mepc again -// addi x1, x1, 4 // add 4 to find the next instruction + csrr x1, \MODE\()epc + addi x1, x1, 4 // return to the address AFTER the trapping instruction trapreturn_specified_\MODE\(): // reset the necessary pointers and registers (x1, x5, x6, and the return address going to mepc) + // note that we don't need to change x7 since it was a temporary register with no important address in it. // so that when we return to a new virtual address, they're all in the right spot as well. beqz a1, trapreturn_finished_\MODE\() // either update values, of go to default return address. @@ -318,13 +315,13 @@ trapreturn_specified_\MODE\(): sll x5, x5, a2 addi x5, x5, -1 // x5 = mask bits for offset into current pagetype - // reset the top of the stack, x1 + // reset the top of the stack, which will be put into ra 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 + // reset the second spot in the stack, which will be put into x5 ld x7, -16(sp) and x7, x5, x7 // x7 = offset for x5 add x7, x7, a1 // x7 = new address for x5 @@ -334,7 +331,7 @@ trapreturn_specified_\MODE\(): 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. + // reset x1, which temporarily holds the return address that will be written to mepc. and x1, x5, x1 // x1 = offset for the return address add x1, x1, a1 // x1 = new return address. @@ -342,10 +339,10 @@ trapreturn_specified_\MODE\(): li a2, 0 // reset trapreturn inputs to the trap handler trapreturn_finished_\MODE\(): - csrw \MODE\()epc, x1 // update the epc with address of next instruction - ld x5, -16(sp) // restore registers from stack before returning + csrw \MODE\()epc, x1 // update the epc with address of next instruction + ld x7, -24(sp) // restore registers from stack before returning + ld x5, -16(sp) ld x1, -8(sp) - // *** this should be handled by indirectly clearing this bit csrw \MODE\()ip, 0x0 // clear interrupt pending register to indicate interrupt has been handled \MODE\()ret // return from trap ecallhandler_\MODE\(): @@ -380,18 +377,17 @@ ecallhandler_changetousermode_\MODE\(): j trapreturn_\MODE\() instrpagefault_\MODE\(): - ld x1, -8(sp) // load return address int x1 (the address AFTER the jal to the faulting address) + ld x1, -8(sp) // load return address from stack into ra (the address AFTER the jal to the faulting address) j trapreturn_finished_\MODE\() // puts x1 into mepc, restores stack and returns to program (outside of faulting page) instrfault_\MODE\(): - ld x1, -8(sp) // load return address int x1 (the address AFTER the jal to the faulting address) - j trapreturn_finished_\MODE\() // return to the code after recording the mcause + ld x1, -8(sp) // load return address from stack into ra (the address AFTER the jal to the faulting address) + j trapreturn_finished_\MODE\() // return to the code at ra value from before trap illegalinstr_\MODE\(): j trapreturn_\MODE\() // return to the code after recording the mcause accessfault_\MODE\(): - // *** What do I have to do here? j trapreturn_\MODE\() addr_misaligned_\MODE\(): @@ -400,36 +396,67 @@ addr_misaligned_\MODE\(): breakpt_\MODE\(): j trapreturn_\MODE\() -soft_interrupt_\MODE\(): - li x5, 0x7EC // write 0x7EC (looks like VEC) to the output before the mcause and extras to indicate that this trap was handled with a vector table. - sd x5, 0(x16) +s_soft_vector_\MODE\(): + csrrw sp, \MODE\()scratch, sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself. + sd x5, -8(sp) // put x5 on the scratch stack before messing with it + li x5, 0x7EC01 // write 0x7ec01 (for "VEC"tored and 01 for the interrupt code) + j vectored_int_end_\MODE\() + +m_soft_vector_\MODE\(): + csrrw sp, \MODE\()scratch, sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself. + sd x5, -8(sp) // put x5 on the scratch stack before messing with it + li x5, 0x7EC03 // write 0x7ec03 (for "VEC"tored and 03 for the interrupt code) + j vectored_int_end_\MODE\() + +s_time_vector_\MODE\(): + csrrw sp, \MODE\()scratch, sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself. + sd x5, -8(sp) // put x5 on the scratch stack before messing with it + li x5, 0x7EC05 // write 0x7ec05 (for "VEC"tored and 05 for the interrupt code) + j vectored_int_end_\MODE\() + +m_time_vector_\MODE\(): + csrrw sp, \MODE\()scratch, sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself. + sd x5, -8(sp) // put x5 on the scratch stack before messing with it + li x5, 0x7EC07 // write 0x7ec07 (for "VEC"tored and 07 for the interrupt code) + j vectored_int_end_\MODE\() + +s_ext_vector_\MODE\(): + csrrw sp, \MODE\()scratch, sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself. + sd x5, -8(sp) // put x5 on the scratch stack before messing with it + li x5, 0x7EC09 // write 0x7ec09 (for "VEC"tored and 08 for the interrupt code) + j vectored_int_end_\MODE\() + +m_ext_vector_\MODE\(): + csrrw sp, \MODE\()scratch, sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself. + sd x5, -8(sp) // put x5 on the scratch stack before messing with it + li x5, 0x7EC0B // write 0x7ec0B (for "VEC"tored and 0B for the interrupt code) + j vectored_int_end_\MODE\() + +vectored_int_end_\MODE\(): + sd x5, 0(x16) // store to signature to show vectored interrupts succeeded. addi x6, x6, 8 addi x16, x16, 8 + ld x5, -8(sp) // restore x5 before continuing to handle trap in case its needed. + j trap_stack_saved_\MODE\() + +soft_interrupt_\MODE\(): la x28, 0x02000000 // Reset by clearing MSIP interrupt from CLINT sw x0, 0(x28) - j trap_unvectored_\MODE\() + j trapreturn_\MODE\() time_interrupt_\MODE\(): - li x5, 0x7EC - sd x5, 0(x16) - addi x6, x6, 8 - addi x16, x16, 8 - la x29, 0x02004000 // MTIMECMP register in CLINT li x30, 0xFFFFFFFF sd x30, 0(x29) // reset interrupt by setting mtimecmp to 0xFFFFFFFF - - j trap_unvectored_\MODE\() + + ld x1, -8(sp) // load return address from stack into ra (the address AFTER the jal to the faulting address) + j trapreturn_finished_\MODE\() // return to the code at ra value from before trap ext_interrupt_\MODE\(): - li x5, 0x7EC - sd x5, 0(x16) - addi x6, x6, 8 - addi x16, x16, 8 li x28, 0x10060000 // reset interrupt by clearing all the GPIO bits sw x0, 8(x28) // disable the first pin as an output sw x0, 40(x28) // write a 0 to the first output pin (reset interrupt) - j trap_unvectored_\MODE\() + j trapreturn_\MODE\() // Table of trap behavior // lists what to do on each exception (not interrupts) @@ -455,6 +482,21 @@ exception_vector_table_\MODE\(): .8byte segfault_\MODE\() // 14: reserved .8byte trapreturn_\MODE\() // 15: store page fault + .align 3 // aligns this data table to an 8 byte boundary +interrupt_vector_table_\MODE\(): + .8byte segfault_\MODE\() // 0: reserved + .8byte s_soft_vector_\MODE\() // 1: instruction access fault // the zero spot is taken up by the instruction to skip this table. + .8byte segfault_\MODE\() // 2: reserved + .8byte m_soft_vector_\MODE\() // 3: breakpoint + .8byte segfault_\MODE\() // 4: reserved + .8byte s_time_vector_\MODE\() // 5: load access fault + .8byte segfault_\MODE\() // 6: reserved + .8byte m_time_vector_\MODE\() // 7: store access fault + .8byte segfault_\MODE\() // 8: reserved + .8byte s_ext_vector_\MODE\() // 9: ecall from S-mode + .8byte segfault_\MODE\() // 10: reserved + .8byte m_ext_vector_\MODE\() // 11: ecall from M-mode + .align 3 trap_return_pagetype_table_\MODE\(): .8byte 0xC // 0: kilopage has 12 offset bits @@ -1051,9 +1093,20 @@ rvtest_data: RVTEST_DATA_END .align 3 // align stack to 8 byte boundary -bottom_of_stack: +stack_bottom: .fill 1024, 4, 0xdeadbeef -top_of_stack: +stack_top: + +.align 3 +mscratch_bottom: + .fill 512, 4, 0xdeadbeef +mscratch_top: + +.align 3 +sscratch_bottom: + .fill 512, 4, 0xdeadbeef +sscratch_top: + RVMODEL_DATA_BEGIN