trap-entry-dual-stack.S (3255B)
1 // Copyright 2022, Brian Swetland <swetland@frotz.net> 2 // Licensed under the Apache License, Version 2.0 3 4 // This file provides assembly glue for handling traps 5 // (interrupts or exceptions) and safely saving and 6 // restoring the processor state of the code running 7 // when the trap happened. 8 9 // It assume a dual stack setup -- when an interrupt 10 // or exception occurs, a kernel stack will be used to 11 // save the state -- whether or not the active user 12 // stack is valid will not matter. 13 14 // It will call into interrupt_handler() or exception_handler() 15 // to process the interrupt or exception. 16 17 // For interrupts, only the registers that must be saved 18 // are saved (the others are callee-save so the C code 19 // called into will save them if necessary). 20 21 // For exceptions, ALL registers are saved so that the 22 // exception handler my inspect, display, or modify them 23 // as necesary. 24 25 // hw/context.h defines structures tframe_t and eframe_t 26 // that correspond to how the registers are saved on the 27 // stack 28 29 .global trap_entry 30 trap_entry: 31 // swap the user sp with the kernel sp 32 // stored in SSCRATCH 33 csrrw sp, sscratch, sp 34 35 // reserve stack space for a full eframe_t 36 addi sp, sp, - (32 * 4) 37 38 // save caller-save registers (tframe_t) 39 sw ra, 0x00(sp) 40 sw t0, 0x04(sp) 41 sw t1, 0x08(sp) 42 sw t2, 0x0C(sp) 43 sw t3, 0x10(sp) 44 sw t4, 0x14(sp) 45 sw t5, 0x18(sp) 46 sw t6, 0x1C(sp) 47 sw a0, 0x20(sp) 48 sw a1, 0x24(sp) 49 sw a2, 0x28(sp) 50 sw a3, 0x2C(sp) 51 sw a4, 0x30(sp) 52 sw a5, 0x34(sp) 53 sw a6, 0x38(sp) 54 sw a7, 0x3C(sp) 55 56 // save user pc which hw stashed in SEPC 57 // and user sp which we stashed in SSCRATCH 58 csrr t0, sepc 59 csrr t1, sscratch 60 sw t0, 0x40(sp) 61 sw t1, 0x44(sp) 62 63 // if the scause high bit is clear, it is an exception 64 csrr t0, scause 65 bge t0, zero, exception_entry 66 67 // otherwise it is an interrupt, call interrupt_handler() 68 jal interrupt_handler 69 70 .globl trap_exit 71 trap_exit: 72 // restore kernel sp to sscratch 73 addi t0, sp, (32 * 4) 74 csrw sscratch, t0 75 76 // user pc goes into sepc for sret 77 lw t0, 0x40(sp) 78 csrw sepc, t0 79 80 // restore the caller-save registers 81 lw ra, 0x00(sp) 82 lw t0, 0x04(sp) 83 lw t1, 0x08(sp) 84 lw t2, 0x0C(sp) 85 lw t3, 0x10(sp) 86 lw t4, 0x14(sp) 87 lw t5, 0x18(sp) 88 lw t6, 0x1C(sp) 89 lw a0, 0x20(sp) 90 lw a1, 0x24(sp) 91 lw a2, 0x28(sp) 92 lw a3, 0x2C(sp) 93 lw a4, 0x30(sp) 94 lw a5, 0x34(sp) 95 lw a6, 0x38(sp) 96 lw a7, 0x3C(sp) 97 98 // finally restore the user sp 99 lw sp, 0x44(sp) 100 101 // and return from trap 102 sret 103 104 exception_entry: 105 // save the callee-save registers (cframe_t) 106 // user pc and sp already stored at 0x40(sp), 0x44(sp) 107 sw gp, 0x48(sp) 108 sw tp, 0x4C(sp) 109 sw s0, 0x50(sp) 110 sw s1, 0x54(sp) 111 sw s2, 0x58(sp) 112 sw s3, 0x5C(sp) 113 sw s4, 0x60(sp) 114 sw s5, 0x64(sp) 115 sw s6, 0x68(sp) 116 sw s7, 0x6C(sp) 117 sw s8, 0x70(sp) 118 sw s9, 0x74(sp) 119 sw s10, 0x78(sp) 120 sw s11, 0x7C(sp) 121 122 // call exception_handler() passing eframe_t* 123 // as the first argument 124 mv a0, sp 125 jal exception_handler 126 127 .globl exception_exit 128 exception_exit: 129 lw gp, 0x48(sp) 130 lw tp, 0x4C(sp) 131 lw s0, 0x50(sp) 132 lw s1, 0x54(sp) 133 lw s2, 0x58(sp) 134 lw s3, 0x5C(sp) 135 lw s4, 0x60(sp) 136 lw s5, 0x64(sp) 137 lw s6, 0x68(sp) 138 lw s7, 0x6C(sp) 139 lw s8, 0x70(sp) 140 lw s9, 0x74(sp) 141 lw s10, 0x78(sp) 142 lw s11, 0x7C(sp) 143 144 j trap_exit 145 146 .globl user_mode_entry 147 user_mode_entry: 148 mv sp, a0 149 j exception_exit