Updated trap handler to check interrupt vectoring before handling them and to use the mscratch instead of sp for a stack.

This commit is contained in:
Kip Macsai-Goren 2022-04-06 06:43:03 +00:00
parent 3268f27f7a
commit 590b86147b

View File

@ -41,7 +41,7 @@ RVTEST_CODE_BEGIN
// //
// Initialize x6 as a virtual pointer to the test results // Initialize x6 as a virtual pointer to the test results
// Initialize x16 as a physical 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 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. // any time either is used, both must be updated.
// address for stack // address for normal user stack, mscratch stack, and sscratch stack
la sp, top_of_stack la sp, mscratch_top
csrw mscratch, sp
la sp, sscratch_top
csrw sscratch, sp
la sp, stack_top
.endm .endm
@ -72,7 +76,7 @@ cause_instr_addr_misaligned:
cause_instr_access: cause_instr_access:
la x28, 0x0 // address zero is an address with no memory 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 addi sp, sp, -8
jalr x28 // cause instruction access trap jalr x28 // cause instruction access trap
ld x1, 0(sp) // pop return adress back from the stack 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 .word 0x00000000 // a 32 bit zros is an illegal instruction
ret ret
cause_breakpnt: // **** cause_breakpnt:
ebreak ebreak
ret ret
@ -128,7 +132,9 @@ cause_time_interrupt:
sw x31,4(x29) // store into most significant word of MTIMECMP sw x31,4(x29) // store into most significant word of MTIMECMP
nowrap: nowrap:
sw x28, 0(x29) // store into least significant word of MTIMECMP 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 ret
cause_soft_interrupt: cause_soft_interrupt:
@ -150,7 +156,7 @@ end_trap_triggers:
.macro TRAP_HANDLER MODE, VECTORED=1, DEBUG=0 .macro TRAP_HANDLER MODE, VECTORED=1, DEBUG=0
// MODE decides which mode this trap handler will be taken in (M or S mode) // 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) // 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) // 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) // 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 // *** 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 // 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 // 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 segfault_\MODE\() // 2: reserved
j soft_interrupt_\MODE\() // 3: breakpoint j m_soft_vector_\MODE\() // 3: breakpoint
j segfault_\MODE\() // 4: reserved 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 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 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 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 // 12 through >=16 are reserved or designated for platform use
trap_unvectored_\MODE\(): 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 // save registers on stack before using
sd x1, -8(sp) sd x1, -8(sp)
sd x5, -16(sp) sd x5, -16(sp)
sd x7, -24(sp)
// Record trap // Record trap
csrr x1, \MODE\()cause // record the mcause csrr x1, \MODE\()cause // record the mcause
@ -262,49 +273,35 @@ trap_unvectored_\MODE\():
// Respond to trap based on cause // Respond to trap based on cause
// All interrupts should return after being logged // All interrupts should return after being logged
csrr x1, \MODE\()cause 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 li x5, 0x8000000000000000 // if msb is set, it is an interrupt
and x5, x5, x1 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 // 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\() la x5, exception_vector_table_\MODE\()
add x5, x5, x1 // compute address of vector in Table add x5, x5, x1 // compute address of vector in Table
ld x5, 0(x5) // fectch address of handler from vector Table ld x5, 0(x5) // fectch address of handler from vector Table
jr x5 // and jump to the handler 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\(): 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) ld x1, -8(sp)
j terminate_test // halt program. j terminate_test // halt program.
trapreturn_\MODE\(): 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
csrr x1, \MODE\()epc // get the mepc addi x1, x1, 4 // return to the address AFTER the trapping instruction
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
trapreturn_specified_\MODE\(): trapreturn_specified_\MODE\():
// reset the necessary pointers and registers (x1, x5, x6, and the return address going to mepc) // 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. // 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. 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 sll x5, x5, a2
addi x5, x5, -1 // x5 = mask bits for offset into current pagetype 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) ld x7, -8(sp)
and x7, x5, x7 // x7 = offset for x1 and x7, x5, x7 // x7 = offset for x1
add x7, x7, a1 // x7 = new address for x1 add x7, x7, a1 // x7 = new address for x1
sd x7, -8(sp) 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) ld x7, -16(sp)
and x7, x5, x7 // x7 = offset for x5 and x7, x5, x7 // x7 = offset for x5
add x7, x7, a1 // x7 = new address 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 and x7, x5, x6 // x7 = offset for x6
add x6, x7, a1 // x6 = new address for the result pointer 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 and x1, x5, x1 // x1 = offset for the return address
add x1, x1, a1 // x1 = new 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 li a2, 0 // reset trapreturn inputs to the trap handler
trapreturn_finished_\MODE\(): trapreturn_finished_\MODE\():
csrw \MODE\()epc, x1 // update the epc with address of next instruction csrw \MODE\()epc, x1 // update the epc with address of next instruction
ld x5, -16(sp) // restore registers from stack before returning ld x7, -24(sp) // restore registers from stack before returning
ld x5, -16(sp)
ld x1, -8(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 \MODE\()ret // return from trap
ecallhandler_\MODE\(): ecallhandler_\MODE\():
@ -380,18 +377,17 @@ ecallhandler_changetousermode_\MODE\():
j trapreturn_\MODE\() j trapreturn_\MODE\()
instrpagefault_\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) j trapreturn_finished_\MODE\() // puts x1 into mepc, restores stack and returns to program (outside of faulting page)
instrfault_\MODE\(): instrfault_\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\() // return to the code after recording the mcause j trapreturn_finished_\MODE\() // return to the code at ra value from before trap
illegalinstr_\MODE\(): illegalinstr_\MODE\():
j trapreturn_\MODE\() // return to the code after recording the mcause j trapreturn_\MODE\() // return to the code after recording the mcause
accessfault_\MODE\(): accessfault_\MODE\():
// *** What do I have to do here?
j trapreturn_\MODE\() j trapreturn_\MODE\()
addr_misaligned_\MODE\(): addr_misaligned_\MODE\():
@ -400,36 +396,67 @@ addr_misaligned_\MODE\():
breakpt_\MODE\(): breakpt_\MODE\():
j trapreturn_\MODE\() j trapreturn_\MODE\()
soft_interrupt_\MODE\(): s_soft_vector_\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. 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, 0(x16) 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 x6, x6, 8
addi x16, x16, 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 la x28, 0x02000000 // Reset by clearing MSIP interrupt from CLINT
sw x0, 0(x28) sw x0, 0(x28)
j trap_unvectored_\MODE\() j trapreturn_\MODE\()
time_interrupt_\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 la x29, 0x02004000 // MTIMECMP register in CLINT
li x30, 0xFFFFFFFF li x30, 0xFFFFFFFF
sd x30, 0(x29) // reset interrupt by setting mtimecmp to 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\(): 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 li x28, 0x10060000 // reset interrupt by clearing all the GPIO bits
sw x0, 8(x28) // disable the first pin as an output 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) 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 // Table of trap behavior
// lists what to do on each exception (not interrupts) // lists what to do on each exception (not interrupts)
@ -455,6 +482,21 @@ exception_vector_table_\MODE\():
.8byte segfault_\MODE\() // 14: reserved .8byte segfault_\MODE\() // 14: reserved
.8byte trapreturn_\MODE\() // 15: store page fault .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 .align 3
trap_return_pagetype_table_\MODE\(): trap_return_pagetype_table_\MODE\():
.8byte 0xC // 0: kilopage has 12 offset bits .8byte 0xC // 0: kilopage has 12 offset bits
@ -1051,9 +1093,20 @@ rvtest_data:
RVTEST_DATA_END RVTEST_DATA_END
.align 3 // align stack to 8 byte boundary .align 3 // align stack to 8 byte boundary
bottom_of_stack: stack_bottom:
.fill 1024, 4, 0xdeadbeef .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 RVMODEL_DATA_BEGIN