Files
riscv-operating-system-mooc/code/os/09-lock/entry.S
Wang Chen fd1d098906 Encapsulate some types related to cpu word length.
The purpose is to facilitate porting to RV64.

Signed-off-by: Wang Chen <wangchen20@iscas.ac.cn>
2024-03-27 14:30:53 +08:00

155 lines
4.2 KiB
ArmAsm

#define LOAD lw
#define STORE sw
#define SIZE_REG 4
# Save all General-Purpose(GP) registers to context.
# struct context *base = &ctx_task;
# base->ra = ra;
# ......
# These GP registers to be saved don't include gp
# and tp, because they are not caller-saved or
# callee-saved. These two registers are often used
# for special purpose. For example, in RVOS, 'tp'
# (aka "thread pointer") is used to store hartid,
# which is a global value and would not be changed
# during context-switch.
.macro reg_save base
STORE ra, 0*SIZE_REG(\base)
STORE sp, 1*SIZE_REG(\base)
STORE t0, 4*SIZE_REG(\base)
STORE t1, 5*SIZE_REG(\base)
STORE t2, 6*SIZE_REG(\base)
STORE s0, 7*SIZE_REG(\base)
STORE s1, 8*SIZE_REG(\base)
STORE a0, 9*SIZE_REG(\base)
STORE a1, 10*SIZE_REG(\base)
STORE a2, 11*SIZE_REG(\base)
STORE a3, 12*SIZE_REG(\base)
STORE a4, 13*SIZE_REG(\base)
STORE a5, 14*SIZE_REG(\base)
STORE a6, 15*SIZE_REG(\base)
STORE a7, 16*SIZE_REG(\base)
STORE s2, 17*SIZE_REG(\base)
STORE s3, 18*SIZE_REG(\base)
STORE s4, 19*SIZE_REG(\base)
STORE s5, 20*SIZE_REG(\base)
STORE s6, 21*SIZE_REG(\base)
STORE s7, 22*SIZE_REG(\base)
STORE s8, 23*SIZE_REG(\base)
STORE s9, 24*SIZE_REG(\base)
STORE s10, 25*SIZE_REG(\base)
STORE s11, 26*SIZE_REG(\base)
STORE t3, 27*SIZE_REG(\base)
STORE t4, 28*SIZE_REG(\base)
STORE t5, 29*SIZE_REG(\base)
# we don't save t6 here, due to we have used
# it as base, we have to save t6 in an extra step
# outside of reg_save
.endm
# restore all General-Purpose(GP) registers from the context
# except gp & tp.
# struct context *base = &ctx_task;
# ra = base->ra;
# ......
.macro reg_restore base
LOAD ra, 0*SIZE_REG(\base)
LOAD sp, 1*SIZE_REG(\base)
LOAD t0, 4*SIZE_REG(\base)
LOAD t1, 5*SIZE_REG(\base)
LOAD t2, 6*SIZE_REG(\base)
LOAD s0, 7*SIZE_REG(\base)
LOAD s1, 8*SIZE_REG(\base)
LOAD a0, 9*SIZE_REG(\base)
LOAD a1, 10*SIZE_REG(\base)
LOAD a2, 11*SIZE_REG(\base)
LOAD a3, 12*SIZE_REG(\base)
LOAD a4, 13*SIZE_REG(\base)
LOAD a5, 14*SIZE_REG(\base)
LOAD a6, 15*SIZE_REG(\base)
LOAD a7, 16*SIZE_REG(\base)
LOAD s2, 17*SIZE_REG(\base)
LOAD s3, 18*SIZE_REG(\base)
LOAD s4, 19*SIZE_REG(\base)
LOAD s5, 20*SIZE_REG(\base)
LOAD s6, 21*SIZE_REG(\base)
LOAD s7, 22*SIZE_REG(\base)
LOAD s8, 23*SIZE_REG(\base)
LOAD s9, 24*SIZE_REG(\base)
LOAD s10, 25*SIZE_REG(\base)
LOAD s11, 26*SIZE_REG(\base)
LOAD t3, 27*SIZE_REG(\base)
LOAD t4, 28*SIZE_REG(\base)
LOAD t5, 29*SIZE_REG(\base)
LOAD t6, 30*SIZE_REG(\base)
.endm
# Something to note about save/restore:
# - We use mscratch to hold a pointer to context of current task
# - We use t6 as the 'base' for reg_save/reg_restore, because it is the
# very bottom register (x31) and would not be overwritten during loading.
# Note: CSRs(mscratch) can not be used as 'base' due to load/restore
# instruction only accept general purpose registers.
.text
# interrupts and exceptions while in machine mode come here.
.globl trap_vector
# the trap vector base address must always be aligned on a 4-byte boundary
.balign 4
trap_vector:
# save context(registers).
csrrw t6, mscratch, t6 # swap t6 and mscratch
reg_save t6
# Save the actual t6 register, which we swapped into
# mscratch
mv t5, t6 # t5 points to the context of current task
csrr t6, mscratch # read t6 back from mscratch
STORE t6, 30*SIZE_REG(t5) # save t6 with t5 as base
# save mepc to context of current task
csrr a0, mepc
STORE a0, 31*SIZE_REG(t5)
# Restore the context pointer into mscratch
csrw mscratch, t5
# call the C trap handler in trap.c
csrr a0, mepc
csrr a1, mcause
call trap_handler
# trap_handler will return the return address via a0.
csrw mepc, a0
# restore context(registers).
csrr t6, mscratch
reg_restore t6
# return to whatever we were doing before trap.
mret
# void switch_to(struct context *next);
# a0: pointer to the context of the next task
.globl switch_to
.balign 4
switch_to:
# switch mscratch to point to the context of the next task
csrw mscratch, a0
# set mepc to the pc of the next task
LOAD a1, 31*SIZE_REG(a0)
csrw mepc, a1
# Restore all GP registers
# Use t6 to point to the context of the new task
mv t6, a0
reg_restore t6
# Do actual context switching.
# Notice this will enable global interrupt
mret
.end