#include "os_config.h" #if __riscv_xlen == 64 #define REG_BYTES 8 #define STORE sd #define LOAD ld #define FSTORE fsd #define FLOAD fld #elif __riscv_xlen == 32 #define REG_BYTES 4 #define STORE sw #define LOAD lw #define FSTORE fsw #define FLOAD flw #else #error Assembler did not define __riscv_xlen #endif #define CONTEXT_SIZE (32 * REG_BYTES) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //// CODE #ifdef OS_CFG_CPU_CLZ_ASM_PRESENT .section .text.cpu_clz,"ax",%progbits .align 8 .func .global cpu_clz cpu_clz: clz a0, a0 ret .endfunc #endif .section .text.os_port_context_switch_to,"ax",%progbits .align 2 .func .global os_port_context_switch_to .extern os_port_on_switch_success os_port_context_switch_to: li t0, 0x1800 csrw mstatus, t0 // 1. 关中断 /* 设置中断栈/系统栈空间 */ la t0, _eusrstack addi t0, t0, -512 csrw mscratch, t0 // 备用栈指针存入 mscratch /* ===================================================================== * 第一步:切换到中断栈,安全调用通知 C 函数 * ===================================================================== */ jal os_port_on_switch_success // 调用 C 函数(此时随便它怎么污染寄存器) /* ===================================================================== * 第二步:获取新任务的栈指针 SP * ===================================================================== */ LOAD sp, 0(a0) // a0 是传入的 &g_os_port_switch_to_sp,从中取出 sp /* ===================================================================== * 第三步:恢复 FPU 浮点寄存器(与保存栈帧严格镜像) * 修复宏定义:将 MPU 改回 FPU * ===================================================================== */ #if (OS_CFG_CPU_FPU_PRESENT) FLOAD f0, (CONTEXT_SIZE + 0 * REG_BYTES)(sp) FLOAD f1, (CONTEXT_SIZE + 1 * REG_BYTES)(sp) FLOAD f2, (CONTEXT_SIZE + 2 * REG_BYTES)(sp) FLOAD f3, (CONTEXT_SIZE + 3 * REG_BYTES)(sp) FLOAD f4, (CONTEXT_SIZE + 4 * REG_BYTES)(sp) FLOAD f5, (CONTEXT_SIZE + 5 * REG_BYTES)(sp) FLOAD f6, (CONTEXT_SIZE + 6 * REG_BYTES)(sp) FLOAD f7, (CONTEXT_SIZE + 7 * REG_BYTES)(sp) FLOAD f8, (CONTEXT_SIZE + 8 * REG_BYTES)(sp) FLOAD f9, (CONTEXT_SIZE + 9 * REG_BYTES)(sp) FLOAD f10, (CONTEXT_SIZE + 10 * REG_BYTES)(sp) FLOAD f11, (CONTEXT_SIZE + 11 * REG_BYTES)(sp) FLOAD f12, (CONTEXT_SIZE + 12 * REG_BYTES)(sp) FLOAD f13, (CONTEXT_SIZE + 13 * REG_BYTES)(sp) FLOAD f14, (CONTEXT_SIZE + 14 * REG_BYTES)(sp) FLOAD f15, (CONTEXT_SIZE + 15 * REG_BYTES)(sp) FLOAD f16, (CONTEXT_SIZE + 16 * REG_BYTES)(sp) FLOAD f17, (CONTEXT_SIZE + 17 * REG_BYTES)(sp) FLOAD f18, (CONTEXT_SIZE + 18 * REG_BYTES)(sp) FLOAD f19, (CONTEXT_SIZE + 19 * REG_BYTES)(sp) FLOAD f20, (CONTEXT_SIZE + 20 * REG_BYTES)(sp) FLOAD f21, (CONTEXT_SIZE + 21 * REG_BYTES)(sp) FLOAD f22, (CONTEXT_SIZE + 22 * REG_BYTES)(sp) FLOAD f23, (CONTEXT_SIZE + 23 * REG_BYTES)(sp) FLOAD f24, (CONTEXT_SIZE + 24 * REG_BYTES)(sp) FLOAD f25, (CONTEXT_SIZE + 25 * REG_BYTES)(sp) FLOAD f26, (CONTEXT_SIZE + 26 * REG_BYTES)(sp) FLOAD f27, (CONTEXT_SIZE + 27 * REG_BYTES)(sp) FLOAD f28, (CONTEXT_SIZE + 28 * REG_BYTES)(sp) FLOAD f29, (CONTEXT_SIZE + 29 * REG_BYTES)(sp) FLOAD f30, (CONTEXT_SIZE + 30 * REG_BYTES)(sp) FLOAD f31, (CONTEXT_SIZE + 31 * REG_BYTES)(sp) #endif /* ===================================================================== * 第四步:恢复通用寄存器(最后恢复 t0) * ===================================================================== */ LOAD x1, 1 * REG_BYTES(sp) LOAD x4, 4 * REG_BYTES(sp) LOAD x6, 6 * REG_BYTES(sp) LOAD x7, 7 * REG_BYTES(sp) LOAD x8, 8 * REG_BYTES(sp) LOAD x9, 9 * REG_BYTES(sp) LOAD x10, 10 * REG_BYTES(sp) LOAD x11, 11 * REG_BYTES(sp) LOAD x12, 12 * REG_BYTES(sp) LOAD x13, 13 * REG_BYTES(sp) LOAD x14, 14 * REG_BYTES(sp) LOAD x15, 15 * REG_BYTES(sp) LOAD x16, 16 * REG_BYTES(sp) LOAD x17, 17 * REG_BYTES(sp) LOAD x18, 18 * REG_BYTES(sp) LOAD x19, 19 * REG_BYTES(sp) LOAD x20, 20 * REG_BYTES(sp) LOAD x21, 21 * REG_BYTES(sp) LOAD x22, 22 * REG_BYTES(sp) LOAD x23, 23 * REG_BYTES(sp) LOAD x24, 24 * REG_BYTES(sp) LOAD x25, 25 * REG_BYTES(sp) LOAD x26, 26 * REG_BYTES(sp) LOAD x27, 27 * REG_BYTES(sp) LOAD x28, 28 * REG_BYTES(sp) LOAD x29, 29 * REG_BYTES(sp) LOAD x30, 30 * REG_BYTES(sp) LOAD x31, 31 * REG_BYTES(sp) /* ===================================================================== * 第五步:恢复特权级控制 CSR 寄存器 * ===================================================================== */ LOAD t0, 2 * REG_BYTES(sp) // 恢复初始 PC 到 mepc csrw mepc, t0 LOAD t0, 0 * REG_BYTES(sp) // 从栈中读取准备好的初始 mstatus csrw mstatus, t0 // 修复:改用 csrw 强行覆盖 LOAD x5, 5 * REG_BYTES(sp) // 此时最后安全恢复 t0(x5) /* ===================================================================== * 第六步:统一释放栈空间并退出 * ===================================================================== */ #if (OS_CFG_CPU_FPU_PRESENT) addi sp, sp, (CONTEXT_SIZE + 32 * REG_BYTES) #else addi sp, sp, CONTEXT_SIZE #endif mret .endfunc .section .text.SW_Handler,"ax",%progbits .align 2 .func .global SW_Handler .extern g_os_port_switch_from_sp .extern g_os_port_switch_to_sp .extern os_port_on_switch_success SW_Handler: csrci mstatus, 0x08 // 立刻关闭全局中断 MIE = 0 /* ===================================================================== * 第一步:一揽子分配所有栈空间(防止碎片和二次偏移错误) * ===================================================================== */ #if (OS_CFG_CPU_FPU_PRESENT) addi sp, sp, -(CONTEXT_SIZE + 32 * REG_BYTES) #else addi sp, sp, -CONTEXT_SIZE #endif /* ===================================================================== * 第二步:保存通用寄存器 * ===================================================================== */ STORE x5, 5 * REG_BYTES(sp) // 优先保存 t0,腾出临时寄存器 li t0, 0x1800 csrw mstatus, t0 // M 模式 li t0, 0x1880 STORE t0, 0 * REG_BYTES(sp) // 设置 MPIE csrr t0, mepc STORE t0, 2*REG_BYTES(sp) // 保存正在运行任务的 pc 指针 STORE x1, 1 * REG_BYTES(sp) // ra STORE x4, 4 * REG_BYTES(sp) // tp STORE x6, 6 * REG_BYTES(sp) // t1 STORE x7, 7 * REG_BYTES(sp) // t2 STORE x8, 8 * REG_BYTES(sp) // s0/fp STORE x9, 9 * REG_BYTES(sp) // s1 STORE x10, 10 * REG_BYTES(sp) // a0 STORE x11, 11 * REG_BYTES(sp) // a1 STORE x12, 12 * REG_BYTES(sp) // a2 STORE x13, 13 * REG_BYTES(sp) // a3 STORE x14, 14 * REG_BYTES(sp) // a4 STORE x15, 15 * REG_BYTES(sp) // a5 STORE x16, 16 * REG_BYTES(sp) // a6 STORE x17, 17 * REG_BYTES(sp) // a7 STORE x18, 18 * REG_BYTES(sp) // s2 STORE x19, 19 * REG_BYTES(sp) // s3 STORE x20, 20 * REG_BYTES(sp) // s4 STORE x21, 21 * REG_BYTES(sp) // s5 STORE x22, 22 * REG_BYTES(sp) // s6 STORE x23, 23 * REG_BYTES(sp) // s7 STORE x24, 24 * REG_BYTES(sp) // s8 STORE x25, 25 * REG_BYTES(sp) // s9 STORE x26, 26 * REG_BYTES(sp) // s10 STORE x27, 27 * REG_BYTES(sp) // s11 STORE x28, 28 * REG_BYTES(sp) // t3 STORE x29, 29 * REG_BYTES(sp) // t4 STORE x30, 30 * REG_BYTES(sp) // t5 STORE x31, 31 * REG_BYTES(sp) // t6 /* ===================================================================== * 第三步:保存 FPU 浮点寄存器(使用确定的、不受干扰的高位偏移) * ===================================================================== */ #if (OS_CFG_CPU_FPU_PRESENT) FSTORE f0, (CONTEXT_SIZE + 0 * REG_BYTES)(sp) FSTORE f1, (CONTEXT_SIZE + 1 * REG_BYTES)(sp) FSTORE f2, (CONTEXT_SIZE + 2 * REG_BYTES)(sp) FSTORE f3, (CONTEXT_SIZE + 3 * REG_BYTES)(sp) FSTORE f4, (CONTEXT_SIZE + 4 * REG_BYTES)(sp) FSTORE f5, (CONTEXT_SIZE + 5 * REG_BYTES)(sp) FSTORE f6, (CONTEXT_SIZE + 6 * REG_BYTES)(sp) FSTORE f7, (CONTEXT_SIZE + 7 * REG_BYTES)(sp) FSTORE f8, (CONTEXT_SIZE + 8 * REG_BYTES)(sp) FSTORE f9, (CONTEXT_SIZE + 9 * REG_BYTES)(sp) FSTORE f10, (CONTEXT_SIZE + 10 * REG_BYTES)(sp) FSTORE f11, (CONTEXT_SIZE + 11 * REG_BYTES)(sp) FSTORE f12, (CONTEXT_SIZE + 12 * REG_BYTES)(sp) FSTORE f13, (CONTEXT_SIZE + 13 * REG_BYTES)(sp) FSTORE f14, (CONTEXT_SIZE + 14 * REG_BYTES)(sp) FSTORE f15, (CONTEXT_SIZE + 15 * REG_BYTES)(sp) FSTORE f16, (CONTEXT_SIZE + 16 * REG_BYTES)(sp) FSTORE f17, (CONTEXT_SIZE + 17 * REG_BYTES)(sp) FSTORE f18, (CONTEXT_SIZE + 18 * REG_BYTES)(sp) FSTORE f19, (CONTEXT_SIZE + 19 * REG_BYTES)(sp) FSTORE f20, (CONTEXT_SIZE + 20 * REG_BYTES)(sp) FSTORE f21, (CONTEXT_SIZE + 21 * REG_BYTES)(sp) FSTORE f22, (CONTEXT_SIZE + 22 * REG_BYTES)(sp) FSTORE f23, (CONTEXT_SIZE + 23 * REG_BYTES)(sp) FSTORE f24, (CONTEXT_SIZE + 24 * REG_BYTES)(sp) FSTORE f25, (CONTEXT_SIZE + 25 * REG_BYTES)(sp) FSTORE f26, (CONTEXT_SIZE + 26 * REG_BYTES)(sp) FSTORE f27, (CONTEXT_SIZE + 27 * REG_BYTES)(sp) FSTORE f28, (CONTEXT_SIZE + 28 * REG_BYTES)(sp) FSTORE f29, (CONTEXT_SIZE + 29 * REG_BYTES)(sp) FSTORE f30, (CONTEXT_SIZE + 30 * REG_BYTES)(sp) FSTORE f31, (CONTEXT_SIZE + 31 * REG_BYTES)(sp) #endif /* ===================================================================== * 第四步:保存旧任务 sp,并安全调用通知函数 * ===================================================================== */ la t0, g_os_port_switch_from_sp LOAD t0, 0(t0) STORE sp, 0(t0) // 将 sp 存入 g_os_port_switch_from_sp // 此时调用 C 函数是完全安全的,因为所有寄存器都已在任务栈里备考 jal os_port_on_switch_success /* ===================================================================== * 第五步:载入新任务的栈指针(SP) * ===================================================================== */ la t0, g_os_port_switch_to_sp LOAD t0, 0(t0) LOAD sp, 0(t0) // 将 sp 指向 g_os_port_switch_to_sp 栈 /* ===================================================================== * 第六步:恢复新任务的 FPU 浮点寄存器 * ===================================================================== */ #if (OS_CFG_CPU_FPU_PRESENT) FLOAD f0, (CONTEXT_SIZE + 0 * REG_BYTES)(sp) FLOAD f1, (CONTEXT_SIZE + 1 * REG_BYTES)(sp) FLOAD f2, (CONTEXT_SIZE + 2 * REG_BYTES)(sp) FLOAD f3, (CONTEXT_SIZE + 3 * REG_BYTES)(sp) FLOAD f4, (CONTEXT_SIZE + 4 * REG_BYTES)(sp) FLOAD f5, (CONTEXT_SIZE + 5 * REG_BYTES)(sp) FLOAD f6, (CONTEXT_SIZE + 6 * REG_BYTES)(sp) FLOAD f7, (CONTEXT_SIZE + 7 * REG_BYTES)(sp) FLOAD f8, (CONTEXT_SIZE + 8 * REG_BYTES)(sp) FLOAD f9, (CONTEXT_SIZE + 9 * REG_BYTES)(sp) FLOAD f10, (CONTEXT_SIZE + 10 * REG_BYTES)(sp) FLOAD f11, (CONTEXT_SIZE + 11 * REG_BYTES)(sp) FLOAD f12, (CONTEXT_SIZE + 12 * REG_BYTES)(sp) FLOAD f13, (CONTEXT_SIZE + 13 * REG_BYTES)(sp) FLOAD f14, (CONTEXT_SIZE + 14 * REG_BYTES)(sp) FLOAD f15, (CONTEXT_SIZE + 15 * REG_BYTES)(sp) FLOAD f16, (CONTEXT_SIZE + 16 * REG_BYTES)(sp) FLOAD f17, (CONTEXT_SIZE + 17 * REG_BYTES)(sp) FLOAD f18, (CONTEXT_SIZE + 18 * REG_BYTES)(sp) FLOAD f19, (CONTEXT_SIZE + 19 * REG_BYTES)(sp) FLOAD f20, (CONTEXT_SIZE + 20 * REG_BYTES)(sp) FLOAD f21, (CONTEXT_SIZE + 21 * REG_BYTES)(sp) FLOAD f22, (CONTEXT_SIZE + 22 * REG_BYTES)(sp) FLOAD f23, (CONTEXT_SIZE + 23 * REG_BYTES)(sp) FLOAD f24, (CONTEXT_SIZE + 24 * REG_BYTES)(sp) FLOAD f25, (CONTEXT_SIZE + 25 * REG_BYTES)(sp) FLOAD f26, (CONTEXT_SIZE + 26 * REG_BYTES)(sp) FLOAD f27, (CONTEXT_SIZE + 27 * REG_BYTES)(sp) FLOAD f28, (CONTEXT_SIZE + 28 * REG_BYTES)(sp) FLOAD f29, (CONTEXT_SIZE + 29 * REG_BYTES)(sp) FLOAD f30, (CONTEXT_SIZE + 30 * REG_BYTES)(sp) FLOAD f31, (CONTEXT_SIZE + 31 * REG_BYTES)(sp) #endif /* ===================================================================== * 第七步:全面恢复通用寄存器(最后恢复 t0) * ===================================================================== */ LOAD x1, 1 * REG_BYTES(sp) LOAD x4, 4 * REG_BYTES(sp) // LOAD x5, 5 * REG_BYTES(sp) // 恢复 t0 LOAD x6, 6 * REG_BYTES(sp) LOAD x7, 7 * REG_BYTES(sp) LOAD x8, 8 * REG_BYTES(sp) LOAD x9, 9 * REG_BYTES(sp) LOAD x10, 10 * REG_BYTES(sp) LOAD x11, 11 * REG_BYTES(sp) LOAD x12, 12 * REG_BYTES(sp) LOAD x13, 13 * REG_BYTES(sp) LOAD x14, 14 * REG_BYTES(sp) LOAD x15, 15 * REG_BYTES(sp) LOAD x16, 16 * REG_BYTES(sp) LOAD x17, 17 * REG_BYTES(sp) LOAD x18, 18 * REG_BYTES(sp) LOAD x19, 19 * REG_BYTES(sp) LOAD x20, 20 * REG_BYTES(sp) LOAD x21, 21 * REG_BYTES(sp) LOAD x22, 22 * REG_BYTES(sp) LOAD x23, 23 * REG_BYTES(sp) LOAD x24, 24 * REG_BYTES(sp) LOAD x25, 25 * REG_BYTES(sp) LOAD x26, 26 * REG_BYTES(sp) LOAD x27, 27 * REG_BYTES(sp) LOAD x28, 28 * REG_BYTES(sp) LOAD x29, 29 * REG_BYTES(sp) LOAD x30, 30 * REG_BYTES(sp) LOAD x31, 31 * REG_BYTES(sp) /* ===================================================================== * 第八步:恢复新任务的 CSR 寄存器 * ===================================================================== */ LOAD t0, 2 * REG_BYTES(sp) // 恢复 mepc csrw mepc, t0 LOAD t0, 0 * REG_BYTES(sp) // 恢复 mstatus csrw mstatus, t0 LOAD x5, 5 * REG_BYTES(sp) // 恢复 t0 /* ===================================================================== * 第九步:彻底释放栈空间并退出 * ===================================================================== */ #if (OS_CFG_CPU_FPU_PRESENT) addi sp, sp, (CONTEXT_SIZE + 32 * REG_BYTES) #else addi sp, sp, CONTEXT_SIZE #endif /* 执行 mret。此时: * 1. 硬件会自动把当前 mstatus.MPIE (1) 复制到 mstatus.MIE,从而开启全局中断。 * 2. 程序跳转到 mepc 寄存器指向的地址(即新任务继续运行的代码处)。 */ mret // 从 M 模式退出 .endfunc .section .text.SysTick_Handler,"ax",%progbits .align 2 .global SysTick_Handler .extern SysTick_Handler_C .func SysTick_Handler: // csrci mstatus, 8 // 关闭中断 /* 1. 因为是硬件中断,先在当前栈上保存必要的临时寄存器(Caller-saved) */ addi sp, sp, -16 * REG_BYTES STORE x1, 0 * REG_BYTES(sp) # ra STORE x5, 1 * REG_BYTES(sp) # t0 STORE x6, 2 * REG_BYTES(sp) # t1 STORE x7, 3 * REG_BYTES(sp) # t2 STORE x10, 4 * REG_BYTES(sp) # a0 STORE x11, 5 * REG_BYTES(sp) # a1 STORE x12, 6 * REG_BYTES(sp) # a2 STORE x13, 7 * REG_BYTES(sp) # a3 STORE x14, 8 * REG_BYTES(sp) # a4 STORE x15, 9 * REG_BYTES(sp) # a5 STORE x16, 10 * REG_BYTES(sp) # a6 STORE x17, 11 * REG_BYTES(sp) # a7 STORE x28, 12 * REG_BYTES(sp) # t3 STORE x29, 13 * REG_BYTES(sp) # t4 STORE x30, 14 * REG_BYTES(sp) # t5 STORE x31, 15 * REG_BYTES(sp) # t6 /* 2. 清除定时器硬件中断标志位(防止重复触发),并调用 C 语言的时钟处理函数 */ jal SysTick_Handler_C /* 3. 恢复临时寄存器 */ LOAD x1, 0 * REG_BYTES(sp) # ra LOAD x5, 1 * REG_BYTES(sp) # t0 LOAD x6, 2 * REG_BYTES(sp) # t1 LOAD x7, 3 * REG_BYTES(sp) # t2 LOAD x10, 4 * REG_BYTES(sp) # a0 LOAD x11, 5 * REG_BYTES(sp) # a1 LOAD x12, 6 * REG_BYTES(sp) # a2 LOAD x13, 7 * REG_BYTES(sp) # a3 LOAD x14, 8 * REG_BYTES(sp) # a4 LOAD x15, 9 * REG_BYTES(sp) # a5 LOAD x16, 10 * REG_BYTES(sp) # a6 LOAD x17, 11 * REG_BYTES(sp) # a7 LOAD x28, 12 * REG_BYTES(sp) # t3 LOAD x29, 13 * REG_BYTES(sp) # t4 LOAD x30, 14 * REG_BYTES(sp) # t5 LOAD x31, 15 * REG_BYTES(sp) # t6 addi sp, sp, 16 * REG_BYTES /* 4. 退出硬件中断 */ mret .endfunc .align 4 .end