kernel.S (7291B)
1 .section .text, "ax" 2 3 #ifdef __TINYC__ 4 /* tcc 0.9.26's riscv64 assembler doesn't accept GAS's `off(reg)` form 5 * for ld/sd/sw and parses three-comma operands as `<rs1>, <rs2>, <imm>`, 6 * where rs1 is the base for both loads (rd ← [rs1+imm]) and stores 7 * ([rs1+imm] ← rs2). So `SD(rs, base, off)` must emit base FIRST. */ 8 #define LA(rd, sym) lla rd, sym 9 #define LD(rd, base, off) ld rd, base, off 10 #define SD(rs, base, off) sd base, rs, off 11 #define SW(rs, base, off) sw base, rs, off 12 #define J(label) jal zero, label 13 #define RET jalr zero, ra, 0 14 #define CSRW_STVEC_T0 .long 0x10529073 15 #define CSRRW_SP_SSCRATCH_SP .long 0x14011173 16 #define CSRR_T0_SSCRATCH .long 0x140022f3 17 #define CSRR_T0_SEPC .long 0x141022f3 18 #define CSRR_A0_SCAUSE .long 0x14202573 19 #define CSRR_T0_SSTATUS .long 0x100022f3 20 #define CSRW_SEPC_T0 .long 0x14129073 21 #define CSRW_SSTATUS_T0 .long 0x10029073 22 #define CSRW_SSCRATCH_T1 .long 0x14031073 23 #define CSRW_SSCRATCH_T0 .long 0x14029073 24 #define CSRW_SEPC_A0 .long 0x14151073 25 #define CSRR_A0_STVAL .long 0x14302573 26 #define CSRW_SATP_A0 .long 0x18051073 27 #define SFENCE_VMA .long 0x12000073 28 #define FENCE_I .long 0x0000100f 29 #define FENCE_W_W .long 0x0110000f 30 #define FENCE_R_R .long 0x0220000f 31 #define SRET .long 0x10200073 32 #define NOP .long 0x00000013 33 #else 34 #define LA(rd, sym) la rd, sym 35 #define LD(rd, base, off) ld rd, off(base) 36 #define SD(rs, base, off) sd rs, off(base) 37 #define SW(rs, base, off) sw rs, off(base) 38 #define J(label) j label 39 #define RET ret 40 #define CSRW_STVEC_T0 csrw stvec, t0 41 #define CSRRW_SP_SSCRATCH_SP csrrw sp, sscratch, sp 42 #define CSRR_T0_SSCRATCH csrr t0, sscratch 43 #define CSRR_T0_SEPC csrr t0, sepc 44 #define CSRR_A0_SCAUSE csrr a0, scause 45 #define CSRR_T0_SSTATUS csrr t0, sstatus 46 #define CSRW_SEPC_T0 csrw sepc, t0 47 #define CSRW_SSTATUS_T0 csrw sstatus, t0 48 #define CSRW_SSCRATCH_T1 csrw sscratch, t1 49 #define CSRW_SSCRATCH_T0 csrw sscratch, t0 50 #define CSRW_SEPC_A0 csrw sepc, a0 51 #define CSRR_A0_STVAL csrr a0, stval 52 #define CSRW_SATP_A0 csrw satp, a0 53 #define SFENCE_VMA sfence.vma 54 #define FENCE_I fence.i 55 #define FENCE_W_W fence w, w 56 #define FENCE_R_R fence r, r 57 #define SRET sret 58 #define NOP nop 59 #endif 60 61 .globl _start 62 _start: 63 mv s0, a1 64 LA(sp, kstack_top) 65 LA(t0, trap_entry) 66 CSRW_STVEC_T0 67 68 LA(t0, __bss_start) 69 LA(t1, _end) 70 1: 71 #ifdef __TINYC__ 72 bgeu t0, t1, 16 73 #else 74 bgeu t0, t1, 2f 75 #endif 76 SD(zero, t0, 0) 77 addi t0, t0, 8 78 J(1b) 79 2: 80 mv a0, s0 81 jal ra, kmain 82 3: 83 wfi 84 J(3b) 85 86 .align 2 87 .globl trap_entry 88 trap_entry: 89 CSRRW_SP_SSCRATCH_SP 90 addi sp, sp, -272 91 92 /* Save user regs first — including t0 (x5) and t1 (x6) — *before* 93 * we clobber them for trap-entry bookkeeping. Linux's RISC-V 94 * syscall ABI preserves every GPR except a0; if t0/t1 carry caller 95 * state across an ecall, they must be restored. trap_entry's own 96 * scratch must therefore come out of a register the kernel has 97 * already preserved on the stack. */ 98 SD(x1, sp, 8) 99 SD(x3, sp, 24) 100 SD(x4, sp, 32) 101 SD(x5, sp, 40) 102 SD(x6, sp, 48) 103 /* t0 and t1 are now in tf->x[5]/tf->x[6]; safe to clobber. */ 104 CSRR_T0_SSCRATCH 105 SD(t0, sp, 16) 106 LA(t1, saved_user_sp) 107 SD(t0, t1, 0) 108 SD(x7, sp, 56) 109 SD(x8, sp, 64) 110 SD(x9, sp, 72) 111 SD(x10, sp, 80) 112 SD(x11, sp, 88) 113 SD(x12, sp, 96) 114 SD(x13, sp, 104) 115 SD(x14, sp, 112) 116 SD(x15, sp, 120) 117 SD(x16, sp, 128) 118 SD(x17, sp, 136) 119 SD(x18, sp, 144) 120 SD(x19, sp, 152) 121 SD(x20, sp, 160) 122 SD(x21, sp, 168) 123 SD(x22, sp, 176) 124 SD(x23, sp, 184) 125 SD(x24, sp, 192) 126 SD(x25, sp, 200) 127 SD(x26, sp, 208) 128 SD(x27, sp, 216) 129 SD(x28, sp, 224) 130 SD(x29, sp, 232) 131 SD(x30, sp, 240) 132 SD(x31, sp, 248) 133 134 CSRR_T0_SEPC 135 CSRR_A0_SCAUSE 136 li t1, 8 137 #ifdef __TINYC__ 138 bne a0, t1, 8 139 #else 140 bne a0, t1, 4f 141 #endif 142 addi t0, t0, 4 143 4: 144 SD(t0, sp, 256) 145 CSRR_T0_SSTATUS 146 SD(t0, sp, 264) 147 148 mv a1, sp 149 jal ra, trap_sync 150 151 LD(t0, sp, 256) 152 CSRW_SEPC_T0 153 LD(t0, sp, 264) 154 CSRW_SSTATUS_T0 155 156 LD(x1, sp, 8) 157 LD(x3, sp, 24) 158 LD(x4, sp, 32) 159 LD(x7, sp, 56) 160 LD(x8, sp, 64) 161 LD(x9, sp, 72) 162 LD(x10, sp, 80) 163 LD(x11, sp, 88) 164 LD(x12, sp, 96) 165 LD(x13, sp, 104) 166 LD(x14, sp, 112) 167 LD(x15, sp, 120) 168 LD(x16, sp, 128) 169 LD(x17, sp, 136) 170 LD(x18, sp, 144) 171 LD(x19, sp, 152) 172 LD(x20, sp, 160) 173 LD(x21, sp, 168) 174 LD(x22, sp, 176) 175 LD(x23, sp, 184) 176 LD(x24, sp, 192) 177 LD(x25, sp, 200) 178 LD(x26, sp, 208) 179 LD(x27, sp, 216) 180 LD(x28, sp, 224) 181 LD(x29, sp, 232) 182 LD(x30, sp, 240) 183 LD(x31, sp, 248) 184 185 LA(t0, saved_user_sp) 186 LD(t1, t0, 0) 187 CSRW_SSCRATCH_T1 188 LD(x5, sp, 40) 189 LD(x6, sp, 48) 190 addi sp, sp, 272 191 CSRRW_SP_SSCRATCH_SP 192 SRET 193 194 .globl eret_to_user 195 eret_to_user: 196 LA(t0, saved_user_sp) 197 SD(a1, t0, 0) 198 LA(t0, kstack_top) 199 CSRW_SSCRATCH_T0 200 CSRW_SEPC_A0 201 CSRR_T0_SSTATUS 202 li t1, -257 203 and t0, t0, t1 204 lui t1, 0x40 205 addi t1, t1, 32 206 or t0, t0, t1 207 CSRW_SSTATUS_T0 208 mv sp, a1 209 li ra, 0 210 li gp, 0 211 li tp, 0 212 li t0, 0 213 li t1, 0 214 li t2, 0 215 li s0, 0 216 li s1, 0 217 li a0, 0 218 li a1, 0 219 li a2, 0 220 li a3, 0 221 li a4, 0 222 li a5, 0 223 li a6, 0 224 li a7, 0 225 li s2, 0 226 li s3, 0 227 li s4, 0 228 li s5, 0 229 li s6, 0 230 li s7, 0 231 li s8, 0 232 li s9, 0 233 li s10, 0 234 li s11, 0 235 li t3, 0 236 li t4, 0 237 li t5, 0 238 li t6, 0 239 SRET 240 241 /* C-callable thunks. arch.h synthesizes the arch_*() API on top of these 242 * (mirrors aarch64's sysreg_read/arm64_barrier/cpu_pause primitive set). */ 243 244 /* PAUSE_* — matches arch.h enum. */ 245 .globl cpu_pause 246 cpu_pause: 247 li t0, 1 /* PAUSE_WFI */ 248 #ifdef __TINYC__ 249 beq a0, t0, 12 250 #else 251 beq a0, t0, 1f 252 #endif 253 NOP 254 RET 255 1: 256 wfi 257 RET 258 259 /* BAR_* — matches arch.h enum. */ 260 .globl riscv_fence 261 riscv_fence: 262 li t0, 1 /* BAR_RMB */ 263 #ifdef __TINYC__ 264 beq a0, t0, 28 265 #else 266 beq a0, t0, 1f 267 #endif 268 li t0, 2 /* BAR_ICACHE */ 269 #ifdef __TINYC__ 270 beq a0, t0, 28 271 #else 272 beq a0, t0, 2f 273 #endif 274 li t0, 3 /* BAR_ICACHE_CTX */ 275 #ifdef __TINYC__ 276 beq a0, t0, 28 277 #else 278 beq a0, t0, 3f 279 #endif 280 /* default: BAR_WMB */ 281 FENCE_W_W 282 RET 283 1: 284 FENCE_R_R 285 RET 286 2: 287 FENCE_I 288 RET 289 3: 290 SFENCE_VMA 291 FENCE_I 292 RET 293 294 .globl riscv_read_stval 295 riscv_read_stval: 296 CSRR_A0_STVAL 297 RET 298 299 .globl riscv_write_satp 300 riscv_write_satp: 301 CSRW_SATP_A0 302 SFENCE_VMA 303 RET 304 305 .globl riscv_set_sum 306 riscv_set_sum: 307 CSRR_T0_SSTATUS 308 lui t1, 0x40 309 or t0, t0, t1 310 CSRW_SSTATUS_T0 311 RET 312 313 .globl arch_system_off 314 arch_system_off: 315 lui t0, 0x100 316 lui t1, 5 317 addi t1, t1, 1365 318 SW(t1, t0, 0) 319 1: 320 wfi 321 J(1b) 322 323 .section .bss, "aw", @nobits 324 #ifdef __TINYC__ 325 .align 8 326 #else 327 .align 3 328 #endif 329 .globl saved_user_sp 330 saved_user_sp: 331 .skip 8 332 #ifdef __TINYC__ 333 .align 16 334 #else 335 .align 4 336 #endif 337 .skip 0x10000 338 .globl kstack_top 339 kstack_top: