Files
2026-08-13 16:50:52 +08:00

593 lines
18 KiB
ArmAsm

/*
* FreeRTOS Kernel V11.1.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* The FreeRTOS kernel's RISC-V port is split between the the code that is
* common across all currently supported RISC-V chips (implementations of the
* RISC-V ISA), and code which tailors the port to a specific RISC-V chip:
*
* + The code that is common to all RISC-V chips is implemented in
* FreeRTOS\Source\portable\GCC\RISC-V-RV32\portASM.S. There is only one
* portASM.S file because the same file is used no matter which RISC-V chip is
* in use.
*
* + The code that tailors the kernel's RISC-V port to a specific RISC-V
* chip is implemented in freertos_risc_v_chip_specific_extensions.h. There
* is one freertos_risc_v_chip_specific_extensions.h that can be used with any
* RISC-V chip that both includes a standard CLINT and does not add to the
* base set of RISC-V registers. There are additional
* freertos_risc_v_chip_specific_extensions.h files for RISC-V implementations
* that do not include a standard CLINT or do add to the base set of RISC-V
* registers.
*
* CARE MUST BE TAKEN TO INCLDUE THE CORRECT
* freertos_risc_v_chip_specific_extensions.h HEADER FILE FOR THE CHIP
* IN USE. To include the correct freertos_risc_v_chip_specific_extensions.h
* header file ensure the path to the correct header file is in the assembler's
* include path.
*
* This freertos_risc_v_chip_specific_extensions.h is for use on RISC-V chips
* that include a standard CLINT and do not add to the base set of RISC-V
* registers.
*
*/
#include "riscv_encoding.h"
#ifndef __riscv_32e
#define portRegNum 30
#else
#define portRegNum 14
#endif
#define portCONTEXT_SIZE ( portRegNum * REGBYTES )
#ifdef CONFIG_RISCV_FPU
#define portCONTEXT_SIZE_FPU ( 20 * REGBYTES )
#endif
.section .text.entry
.align 8
.extern xPortTaskSwitch
.extern pxCurrentTCB
.global prvPortStartFirstTask
#if CONFIG_FREERTOS_STACK_HW_CHECK
.extern ulStackTop
.extern ulStackBottom
#endif
/**
* \brief Global interrupt disabled
* \details
* This function disable global interrupt.
* \remarks
* - All the interrupt requests will be ignored by CPU.
*/
.macro DISABLE_MIE
csrc CSR_MSTATUS, MSTATUS_MIE
.endm
/**
* \brief Macro for context save
* \details
* This macro save ABI defined caller saved registers in the stack.
* \remarks
* - This Macro could use to save context when you enter to interrupt
* or exception
*/
/* Save caller registers */
.macro SAVE_CONTEXT
csrrw sp, CSR_MSCRATCH, sp
/* Allocate stack space for context saving */
#ifndef __riscv_32e
addi sp, sp, -20*REGBYTES
#else
addi sp, sp, -14*REGBYTES
#endif /* __riscv_32e */
STORE x1, 0*REGBYTES(sp)
STORE x4, 1*REGBYTES(sp)
STORE x5, 2*REGBYTES(sp)
STORE x6, 3*REGBYTES(sp)
STORE x7, 4*REGBYTES(sp)
STORE x10, 5*REGBYTES(sp)
STORE x11, 6*REGBYTES(sp)
STORE x12, 7*REGBYTES(sp)
STORE x13, 8*REGBYTES(sp)
STORE x14, 9*REGBYTES(sp)
STORE x15, 10*REGBYTES(sp)
#ifndef __riscv_32e
STORE x16, 14*REGBYTES(sp)
STORE x17, 15*REGBYTES(sp)
STORE x28, 16*REGBYTES(sp)
STORE x29, 17*REGBYTES(sp)
STORE x30, 18*REGBYTES(sp)
STORE x31, 19*REGBYTES(sp)
#endif /* __riscv_32e */
.endm
/**
* \brief Macro for restore caller registers
* \details
* This macro restore ABI defined caller saved registers from stack.
* \remarks
* - You could use this macro to restore context before you want return
* from interrupt or exeception
*/
/* Restore caller registers */
.macro RESTORE_CONTEXT
LOAD x1, 0*REGBYTES(sp)
LOAD x4, 1*REGBYTES(sp)
LOAD x5, 2*REGBYTES(sp)
LOAD x6, 3*REGBYTES(sp)
LOAD x7, 4*REGBYTES(sp)
LOAD x10, 5*REGBYTES(sp)
LOAD x11, 6*REGBYTES(sp)
LOAD x12, 7*REGBYTES(sp)
LOAD x13, 8*REGBYTES(sp)
LOAD x14, 9*REGBYTES(sp)
LOAD x15, 10*REGBYTES(sp)
#ifndef __riscv_32e
LOAD x16, 14*REGBYTES(sp)
LOAD x17, 15*REGBYTES(sp)
LOAD x28, 16*REGBYTES(sp)
LOAD x29, 17*REGBYTES(sp)
LOAD x30, 18*REGBYTES(sp)
LOAD x31, 19*REGBYTES(sp)
/* De-allocate the stack space */
addi sp, sp, 20*REGBYTES
#else
/* De-allocate the stack space */
addi sp, sp, 14*REGBYTES
#endif /* __riscv_32e */
csrrw sp, CSR_MSCRATCH, sp
.endm
/**
* \brief Macro for save necessary CSRs to stack
* \details
* This macro store MCAUSE, MEPC, MSUBM to stack.
*/
.macro SAVE_CSR_CONTEXT
/* Store CSR mcause to stack using pushmcause */
csrrwi x0, CSR_PUSHMCAUSE, 11
/* Store CSR mepc to stack using pushmepc */
csrrwi x0, CSR_PUSHMEPC, 12
/* Store CSR msub to stack using pushmsub */
csrrwi x0, CSR_PUSHMSUBM, 13
.endm
/**
* \brief Macro for restore necessary CSRs from stack
* \details
* This macro restore MSUBM, MEPC, MCAUSE from stack.
*/
.macro RESTORE_CSR_CONTEXT
LOAD x5, 13*REGBYTES(sp)
csrw CSR_MSUBM, x5
LOAD x5, 12*REGBYTES(sp)
csrw CSR_MEPC, x5
LOAD x5, 11*REGBYTES(sp)
csrw CSR_MCAUSE, x5
.endm
/**
* \brief Exception/NMI Entry
* \details
* This function provide common entry functions for exception/nmi.
* \remarks
* This function provide a default exception/nmi entry.
* ABI defined caller save register and some CSR registers
* to be saved before enter interrupt handler and be restored before return.
*/
.section .text.trap
/* In CLIC mode, the exeception entry must be 64bytes aligned */
.align 6
.global exc_entry
.type exc_entry, @function
exc_entry:
#if CONFIG_FREERTOS_STACK_HW_CHECK
/* 关闭硬件栈溢出检测 */
csrw mstack_ctl, 0x0
#endif
/* Save the caller saving registers (context) */
csrrw sp, CSR_MSCRATCH, sp
/* Allocate stack space for context saving */
#ifndef __riscv_32e
/* 让sp进行16字节地址对齐, 否则浮点运行会异常 */
addi sp, sp, -40*REGBYTES
#else
addi sp, sp, -20*REGBYTES
#endif /* __riscv_32e */
STORE x0, 0*REGBYTES(sp)
STORE x1, 1*REGBYTES(sp)
/* x2/sp寄存器等t0寄存器保存后在保存 */
STORE x3, 3*REGBYTES(sp)
STORE x4, 4*REGBYTES(sp)
/* 保存t0寄存器 */
STORE x5, 5*REGBYTES(sp)
/* 读取之前的SP到t0中 */
csrr t0, mscratch
/* 将保存到sp */
STORE t0, 2*REGBYTES(sp)
STORE x6, 6*REGBYTES(sp)
STORE x7, 7*REGBYTES(sp)
STORE x8, 8*REGBYTES(sp)
STORE x9, 9*REGBYTES(sp)
STORE x10, 10*REGBYTES(sp)
STORE x11, 11*REGBYTES(sp)
STORE x12, 12*REGBYTES(sp)
STORE x13, 13*REGBYTES(sp)
STORE x14, 14*REGBYTES(sp)
STORE x15, 15*REGBYTES(sp)
#ifndef __riscv_32e
STORE x16, 16*REGBYTES(sp)
STORE x17, 17*REGBYTES(sp)
STORE x18, 18*REGBYTES(sp)
STORE x19, 19*REGBYTES(sp)
STORE x20, 20*REGBYTES(sp)
STORE x21, 21*REGBYTES(sp)
STORE x22, 22*REGBYTES(sp)
STORE x23, 23*REGBYTES(sp)
STORE x24, 24*REGBYTES(sp)
STORE x25, 25*REGBYTES(sp)
STORE x26, 26*REGBYTES(sp)
STORE x27, 27*REGBYTES(sp)
STORE x28, 28*REGBYTES(sp)
STORE x29, 29*REGBYTES(sp)
STORE x30, 30*REGBYTES(sp)
STORE x31, 31*REGBYTES(sp)
csrr t0, mcause
STORE t0, 32*REGBYTES(sp)
csrr t0, mepc
STORE t0, 33*REGBYTES(sp)
csrr t0, msubm
STORE t0, 34*REGBYTES(sp)
#else
csrr t0, mcause
STORE t0, 16*REGBYTES(sp)
csrr t0, mepc
STORE t0, 17*REGBYTES(sp)
csrr t0, msubm
STORE t0, 18*REGBYTES(sp)
#endif /* __riscv_32e */
/*
* Set the exception handler function arguments
* argument 1: mcause value
* argument 2: current stack point(SP) value
*/
csrr a0, mcause
mv a1, sp
/*
* TODO: Call the exception handler function
* By default, the function template is provided in
* system_Device.c, you can adjust it as you want
*/
call core_exception_handler
/* Restore the necessary CSR registers */
RESTORE_CSR_CONTEXT
/* Restore the caller saving registers (context) */
RESTORE_CONTEXT
/* Return to regular code */
mret
.size exc_entry, . - exc_entry
/**
* \brief Non-Vector Interrupt Entry
* \details
* This function provide common entry functions for handling
* non-vector interrupts
* \remarks
* This function provide a default non-vector interrupt entry.
* ABI defined caller save register and some CSR registers need
* to be saved before enter interrupt handler and be restored before return.
*/
.section .text.irq
/* In CLIC mode, the interrupt entry must be 4bytes aligned */
.align 2
.global irq_entry
.type irq_entry, @function
/* This label will be set to MTVT2 register */
irq_entry:
#if CONFIG_FREERTOS_STACK_HW_CHECK
/* 关闭硬件栈溢出检测 */
csrw mstack_ctl, 0x0
#endif
/* Save the caller saving registers (context) */
SAVE_CONTEXT
/* Save the necessary CSR registers */
SAVE_CSR_CONTEXT
/* This special CSR read/write operation, which is actually
* claim the CLIC to find its pending highest ID, if the ID
* is not 0, then automatically enable the mstatus.MIE, and
* jump to its vector-entry-label, and update the link register
*/
csrrw ra, CSR_JALMNXTI, ra
/* Critical section with interrupts disabled */
DISABLE_MIE
/* Restore the necessary CSR registers */
RESTORE_CSR_CONTEXT
/* Restore the caller saving registers (context) */
RESTORE_CONTEXT
/* Return to regular code */
mret
.size irq_entry, . - irq_entry
/* Default Handler for Exceptions / Interrupts */
.global default_intexc_handler
.type default_intexc_handler, @function
default_intexc_handler:
1:
j 1b
.size default_intexc_handler, . - default_intexc_handler
/* Start the first task. This also clears the bit that indicates the FPU is
in use in case the FPU was used before the scheduler was started - which
would otherwise result in the unnecessary leaving of space in the stack
for lazy saving of FPU registers. */
.section .text
.type prvPortStartFirstTask, @function
.align 3
prvPortStartFirstTask:
/* Setup Interrupt Stack using
The stack that was used by main()
before the scheduler is started is
no longer required after the scheduler is started.
Interrupt stack pointer is stored in CSR_MSCRATCH */
la t0, __StackTop
csrw CSR_MSCRATCH, t0
LOAD t0, pxCurrentTCB /* Load pxCurrentTCB. */
LOAD sp, 0x0(t0) /* Read sp from first TCB member */
/* Pop PC from stack and set MEPC */
LOAD t0, 0 * REGBYTES(sp)
csrw CSR_MEPC, t0
/* Pop mstatus from stack and set it */
LOAD t0, (portRegNum - 1) * REGBYTES(sp)
csrw CSR_MSTATUS, t0
/* Interrupt still disable here */
/* Restore Registers from Stack */
LOAD x1, 1 * REGBYTES(sp) /* RA */
LOAD x5, 2 * REGBYTES(sp)
LOAD x6, 3 * REGBYTES(sp)
LOAD x7, 4 * REGBYTES(sp)
LOAD x8, 5 * REGBYTES(sp)
LOAD x9, 6 * REGBYTES(sp)
LOAD x10, 7 * REGBYTES(sp)
LOAD x11, 8 * REGBYTES(sp)
LOAD x12, 9 * REGBYTES(sp)
LOAD x13, 10 * REGBYTES(sp)
LOAD x14, 11 * REGBYTES(sp)
LOAD x15, 12 * REGBYTES(sp)
#ifndef __riscv_32e
LOAD x16, 13 * REGBYTES(sp)
LOAD x17, 14 * REGBYTES(sp)
LOAD x18, 15 * REGBYTES(sp)
LOAD x19, 16 * REGBYTES(sp)
LOAD x20, 17 * REGBYTES(sp)
LOAD x21, 18 * REGBYTES(sp)
LOAD x22, 19 * REGBYTES(sp)
LOAD x23, 20 * REGBYTES(sp)
LOAD x24, 21 * REGBYTES(sp)
LOAD x25, 22 * REGBYTES(sp)
LOAD x26, 23 * REGBYTES(sp)
LOAD x27, 24 * REGBYTES(sp)
LOAD x28, 25 * REGBYTES(sp)
LOAD x29, 26 * REGBYTES(sp)
LOAD x30, 27 * REGBYTES(sp)
LOAD x31, 28 * REGBYTES(sp)
#endif
addi sp, sp, portCONTEXT_SIZE
mret
.size prvPortStartFirstTask, . - prvPortStartFirstTask
.section .text.irq
.align 2
.global eclic_msip_handler
.type eclic_msip_handler, @function
eclic_msip_handler:
#if CONFIG_FREERTOS_STACK_HW_CHECK
/* 关闭硬件栈溢出检测 */
csrw mstack_ctl, 0x0
#endif
#ifdef CONFIG_RISCV_FPU
/* Push additional registers */
addi sp, sp, -portCONTEXT_SIZE_FPU
FPSTORE ft0, 0 * REGBYTES(sp) /* FT0 */
FPSTORE ft1, 1 * REGBYTES(sp) /* FT1 */
FPSTORE ft2, 2 * REGBYTES(sp) /* FT2 */
FPSTORE ft3, 3 * REGBYTES(sp) /* FT3 */
FPSTORE ft4, 4 * REGBYTES(sp) /* FT4 */
FPSTORE ft5, 5 * REGBYTES(sp) /* FT5 */
FPSTORE ft6, 6 * REGBYTES(sp) /* FT6 */
FPSTORE ft7, 7 * REGBYTES(sp) /* FT7 */
FPSTORE fa0, 8 * REGBYTES(sp) /* FA0 */
FPSTORE fa1, 9 * REGBYTES(sp) /* FA1 */
FPSTORE fa2, 10 * REGBYTES(sp) /* FA2 */
FPSTORE fa3, 11 * REGBYTES(sp) /* FA3 */
FPSTORE fa4, 12 * REGBYTES(sp) /* FA4 */
FPSTORE fa5, 13 * REGBYTES(sp) /* FA5 */
FPSTORE fa6, 14 * REGBYTES(sp) /* FA6 */
FPSTORE fa7, 15 * REGBYTES(sp) /* FA7 */
FPSTORE ft8, 16 * REGBYTES(sp) /* FT8 */
FPSTORE ft9, 17 * REGBYTES(sp) /* FT9 */
FPSTORE ft10, 18 * REGBYTES(sp) /* FT10 */
FPSTORE ft11, 19 * REGBYTES(sp) /* FT11 */
#endif
addi sp, sp, -portCONTEXT_SIZE
STORE x1, 1 * REGBYTES(sp) /* RA */
STORE x5, 2 * REGBYTES(sp)
STORE x6, 3 * REGBYTES(sp)
STORE x7, 4 * REGBYTES(sp)
STORE x8, 5 * REGBYTES(sp)
STORE x9, 6 * REGBYTES(sp)
STORE x10, 7 * REGBYTES(sp)
STORE x11, 8 * REGBYTES(sp)
STORE x12, 9 * REGBYTES(sp)
STORE x13, 10 * REGBYTES(sp)
STORE x14, 11 * REGBYTES(sp)
STORE x15, 12 * REGBYTES(sp)
#ifndef __riscv_32e
STORE x16, 13 * REGBYTES(sp)
STORE x17, 14 * REGBYTES(sp)
STORE x18, 15 * REGBYTES(sp)
STORE x19, 16 * REGBYTES(sp)
STORE x20, 17 * REGBYTES(sp)
STORE x21, 18 * REGBYTES(sp)
STORE x22, 19 * REGBYTES(sp)
STORE x23, 20 * REGBYTES(sp)
STORE x24, 21 * REGBYTES(sp)
STORE x25, 22 * REGBYTES(sp)
STORE x26, 23 * REGBYTES(sp)
STORE x27, 24 * REGBYTES(sp)
STORE x28, 25 * REGBYTES(sp)
STORE x29, 26 * REGBYTES(sp)
STORE x30, 27 * REGBYTES(sp)
STORE x31, 28 * REGBYTES(sp)
#endif
/* Push mstatus to stack */
csrr t0, CSR_MSTATUS
STORE t0, (portRegNum - 1) * REGBYTES(sp)
/* Push additional registers */
/* Store sp to task stack */
LOAD t0, pxCurrentTCB /* Load pxCurrentTCB. */
STORE sp, 0(t0)
csrr t0, CSR_MEPC
STORE t0, 0(sp)
jal xPortTaskSwitch
/* Switch task context */
LOAD t0, pxCurrentTCB /* Load pxCurrentTCB. */
LOAD sp, 0x0(t0) /* Read sp from first TCB member */
#if CONFIG_FREERTOS_STACK_HW_CHECK
/* 开启硬件栈保护 */
LOAD t0, ulStackTop
csrw mstack_base, t0
LOAD t0, ulStackBottom
csrw mstack_bound, t0
csrw mstack_ctl, 0x3
#endif
/* Pop PC from stack and set MEPC */
LOAD t0, 0 * REGBYTES(sp)
csrw CSR_MEPC, t0
/* Pop additional registers */
/* Pop mstatus from stack and set it */
LOAD t0, (portRegNum - 1) * REGBYTES(sp)
csrw CSR_MSTATUS, t0
/* Interrupt still disable here */
/* Restore Registers from Stack */
LOAD x1, 1 * REGBYTES(sp) /* RA */
LOAD x5, 2 * REGBYTES(sp)
LOAD x6, 3 * REGBYTES(sp)
LOAD x7, 4 * REGBYTES(sp)
LOAD x8, 5 * REGBYTES(sp)
LOAD x9, 6 * REGBYTES(sp)
LOAD x10, 7 * REGBYTES(sp)
LOAD x11, 8 * REGBYTES(sp)
LOAD x12, 9 * REGBYTES(sp)
LOAD x13, 10 * REGBYTES(sp)
LOAD x14, 11 * REGBYTES(sp)
LOAD x15, 12 * REGBYTES(sp)
#ifndef __riscv_32e
LOAD x16, 13 * REGBYTES(sp)
LOAD x17, 14 * REGBYTES(sp)
LOAD x18, 15 * REGBYTES(sp)
LOAD x19, 16 * REGBYTES(sp)
LOAD x20, 17 * REGBYTES(sp)
LOAD x21, 18 * REGBYTES(sp)
LOAD x22, 19 * REGBYTES(sp)
LOAD x23, 20 * REGBYTES(sp)
LOAD x24, 21 * REGBYTES(sp)
LOAD x25, 22 * REGBYTES(sp)
LOAD x26, 23 * REGBYTES(sp)
LOAD x27, 24 * REGBYTES(sp)
LOAD x28, 25 * REGBYTES(sp)
LOAD x29, 26 * REGBYTES(sp)
LOAD x30, 27 * REGBYTES(sp)
LOAD x31, 28 * REGBYTES(sp)
#endif
addi sp, sp, portCONTEXT_SIZE
#ifdef CONFIG_RISCV_FPU
/* Pop additional registers */
FPLOAD ft0, 0 * REGBYTES(sp) /* FT0 */
FPLOAD ft1, 1 * REGBYTES(sp) /* FT1 */
FPLOAD ft2, 2 * REGBYTES(sp) /* FT2 */
FPLOAD ft3, 3 * REGBYTES(sp) /* FT3 */
FPLOAD ft4, 4 * REGBYTES(sp) /* FT4 */
FPLOAD ft5, 5 * REGBYTES(sp) /* FT5 */
FPLOAD ft6, 6 * REGBYTES(sp) /* FT6 */
FPLOAD ft7, 7 * REGBYTES(sp) /* FT7 */
FPLOAD fa0, 8 * REGBYTES(sp) /* FA0 */
FPLOAD fa1, 9 * REGBYTES(sp) /* FA1 */
FPLOAD fa2, 10 * REGBYTES(sp) /* FA2 */
FPLOAD fa3, 11 * REGBYTES(sp) /* FA3 */
FPLOAD fa4, 12 * REGBYTES(sp) /* FA4 */
FPLOAD fa5, 13 * REGBYTES(sp) /* FA5 */
FPLOAD fa6, 14 * REGBYTES(sp) /* FA6 */
FPLOAD fa7, 15 * REGBYTES(sp) /* FA7 */
FPLOAD ft8, 16 * REGBYTES(sp) /* FT8 */
FPLOAD ft9, 17 * REGBYTES(sp) /* FT9 */
FPLOAD ft10, 18 * REGBYTES(sp) /* FT10 */
FPLOAD ft11, 19 * REGBYTES(sp) /* FT11 */
addi sp, sp, portCONTEXT_SIZE_FPU
#endif
mret
.size eclic_msip_handler, . - eclic_msip_handler