Quantum
e50fb2de2c
Mostly stolen from https://github.com/avdgrinten/riscv-toy-os Changed load address to 0x45000000 so it would run on real hardware Played around with GPIO and the watchdog
201 lines
3.2 KiB
ArmAsm
201 lines
3.2 KiB
ArmAsm
.section .text
|
|
|
|
.global _start
|
|
_start:
|
|
# a0: HART ID
|
|
# a1: DTB
|
|
|
|
la sp, stack_top
|
|
mv s0, zero
|
|
|
|
jal kmain
|
|
unimp
|
|
|
|
# void save_stack(void (*f)(void *, continuation), void *ctx)
|
|
.global save_stack
|
|
save_stack:
|
|
addi sp, sp, -0x78
|
|
|
|
sd gp, 0x00(sp)
|
|
sd tp, 0x08(sp)
|
|
sd s0, 0x10(sp)
|
|
sd s1, 0x18(sp)
|
|
sd s2, 0x20(sp)
|
|
sd s3, 0x28(sp)
|
|
sd s4, 0x30(sp)
|
|
sd s5, 0x38(sp)
|
|
sd s6, 0x40(sp)
|
|
sd s7, 0x48(sp)
|
|
sd s8, 0x50(sp)
|
|
sd s9, 0x58(sp)
|
|
sd s10, 0x60(sp)
|
|
sd s11, 0x68(sp)
|
|
sd ra, 0x70(sp)
|
|
|
|
mv t0, a0
|
|
mv a0, a1
|
|
mv a1, sp
|
|
jr t0
|
|
|
|
.global restore_stack
|
|
restore_stack:
|
|
mv sp, a0
|
|
ld gp, 0x00(sp)
|
|
ld tp, 0x08(sp)
|
|
ld s0, 0x10(sp)
|
|
ld s1, 0x18(sp)
|
|
ld s2, 0x20(sp)
|
|
ld s3, 0x28(sp)
|
|
ld s4, 0x30(sp)
|
|
ld s5, 0x38(sp)
|
|
ld s6, 0x40(sp)
|
|
ld s7, 0x48(sp)
|
|
ld s8, 0x50(sp)
|
|
ld s9, 0x58(sp)
|
|
ld s10, 0x60(sp)
|
|
ld s11, 0x68(sp)
|
|
ld ra, 0x70(sp)
|
|
|
|
addi sp, sp, 0x78
|
|
|
|
ret
|
|
|
|
# void enter_umode(void *entry);
|
|
.global enter_umode
|
|
enter_umode:
|
|
# Do not trash x10 (= a0)
|
|
mv x1, zero
|
|
#mv x2, zero # SP
|
|
mv x3, zero
|
|
mv x4, zero
|
|
mv x5, zero
|
|
mv x6, zero
|
|
mv x7, zero
|
|
mv x8, zero
|
|
mv x9, zero
|
|
mv x11, zero
|
|
mv x12, zero
|
|
mv x13, zero
|
|
mv x14, zero
|
|
mv x15, zero
|
|
mv x16, zero
|
|
mv x17, zero
|
|
mv x18, zero
|
|
mv x19, zero
|
|
mv x20, zero
|
|
mv x21, zero
|
|
mv x22, zero
|
|
mv x23, zero
|
|
mv x24, zero
|
|
mv x25, zero
|
|
mv x26, zero
|
|
mv x27, zero
|
|
mv x28, zero
|
|
mv x29, zero
|
|
mv x30, zero
|
|
mv x31, zero
|
|
|
|
csrw sepc, a0
|
|
|
|
csrr a0, sstatus
|
|
# Set SPIE.
|
|
ori a0, a0, 0x20
|
|
# Clear SPP.
|
|
andi a0, a0, -1 - 0x100
|
|
csrw sstatus, a0
|
|
|
|
sret
|
|
|
|
.global isr
|
|
.align 2
|
|
isr:
|
|
# Exchange s1 and sscratch.
|
|
csrrw s1, sscratch, s1
|
|
|
|
# Store all temporary registers.
|
|
sd ra, 0x10(s1)
|
|
sd a0, 0x18(s1)
|
|
sd a1, 0x20(s1)
|
|
sd a2, 0x28(s1)
|
|
sd a3, 0x30(s1)
|
|
sd a4, 0x38(s1)
|
|
sd a5, 0x40(s1)
|
|
sd a6, 0x48(s1)
|
|
sd a7, 0x50(s1)
|
|
sd t0, 0x58(s1)
|
|
sd t1, 0x60(s1)
|
|
sd t2, 0x68(s1)
|
|
sd t3, 0x70(s1)
|
|
sd t4, 0x78(s1)
|
|
sd t5, 0x80(s1)
|
|
sd t6, 0x88(s1)
|
|
|
|
# Save sstatus (contains interrupt state etc.)
|
|
csrr t0, sstatus
|
|
sd t0, 0x98(s1)
|
|
# Save sepc.
|
|
csrr t0, sepc
|
|
sd t0, 0xA0(s1)
|
|
|
|
# Check if we interrupted user mode or supervisor mode.
|
|
# csrr t0, scause
|
|
# andi t0, t0, 0x100
|
|
# bnez t0, 1f
|
|
|
|
# TODO: If we interrupted user mode: also store callee-saved registers.
|
|
# (For example, to implement signals.)
|
|
# TODO: If we interrupted user mode: load a kernel stack pointer.
|
|
|
|
1:
|
|
# Store the next isr_frame in sccratch and re-load the saved s1 (which is still in sccratch).
|
|
ld t0, 0x08(s1)
|
|
beqz t0, 2f
|
|
csrrw t1, sscratch, t0
|
|
# Store the saved s1 in the isr_frame.
|
|
sd t1, 0x90(s1)
|
|
|
|
mv a0, s1
|
|
jal handle_isr
|
|
|
|
# Load the saved s1 into sscratch.
|
|
ld t0, 0x90(s1)
|
|
csrw sscratch, t0
|
|
|
|
# Restore sstatus.
|
|
ld t0, 0x98(s1)
|
|
csrw sstatus, t0
|
|
# Restore sepc.
|
|
ld t0, 0xA0(s1)
|
|
csrw sepc, t0
|
|
|
|
# Store all temporary registers.
|
|
ld ra, 0x10(s1)
|
|
ld a0, 0x18(s1)
|
|
ld a1, 0x20(s1)
|
|
ld a2, 0x28(s1)
|
|
ld a3, 0x30(s1)
|
|
ld a4, 0x38(s1)
|
|
ld a5, 0x40(s1)
|
|
ld a6, 0x48(s1)
|
|
ld a7, 0x50(s1)
|
|
ld t0, 0x58(s1)
|
|
ld t1, 0x60(s1)
|
|
ld t2, 0x68(s1)
|
|
ld t3, 0x70(s1)
|
|
ld t4, 0x78(s1)
|
|
ld t5, 0x80(s1)
|
|
ld t6, 0x88(s1)
|
|
|
|
# Exchange s1 and sscratch.
|
|
csrrw s1, sscratch, s1
|
|
|
|
# Returns from the trap.
|
|
sret
|
|
|
|
2:
|
|
jal isr_frame_overflow
|
|
unimp
|
|
|
|
.section .bss
|
|
.space 0x10000
|
|
stack_top:
|