/* * Copyright (c) 2006-2020, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2018-10-06 ZhaoXiaowei the first version */ /* *enable gtimer */ .globl rt_hw_gtimer_enable rt_hw_gtimer_enable: MOV X0,#1 MSR CNTP_CTL_EL0,X0 RET /* *set gtimer CNTP_TVAL_EL0 value */ .globl rt_hw_set_gtimer_val rt_hw_set_gtimer_val: MSR CNTP_TVAL_EL0,X0 RET /* *get gtimer CNTP_TVAL_EL0 value */ .globl rt_hw_get_gtimer_val rt_hw_get_gtimer_val: MRS X0,CNTP_TVAL_EL0 RET .globl rt_hw_get_cntpct_val rt_hw_get_cntpct_val: MRS X0, CNTPCT_EL0 RET /* *get gtimer frq value */ .globl rt_hw_get_gtimer_frq rt_hw_get_gtimer_frq: MRS X0,CNTFRQ_EL0 RET .macro SAVE_CONTEXT /* Switch to use the EL0 stack pointer. */ MSR SPSEL, #0 /* Save the entire context. */ STP X0, X1, [SP, #-0x10]! STP X2, X3, [SP, #-0x10]! STP X4, X5, [SP, #-0x10]! STP X6, X7, [SP, #-0x10]! STP X8, X9, [SP, #-0x10]! STP X10, X11, [SP, #-0x10]! STP X12, X13, [SP, #-0x10]! STP X14, X15, [SP, #-0x10]! STP X16, X17, [SP, #-0x10]! STP X18, X19, [SP, #-0x10]! STP X20, X21, [SP, #-0x10]! STP X22, X23, [SP, #-0x10]! STP X24, X25, [SP, #-0x10]! STP X26, X27, [SP, #-0x10]! STP X28, X29, [SP, #-0x10]! STP X30, XZR, [SP, #-0x10]! MRS X0, CurrentEL CMP X0, 0xc B.EQ 3f CMP X0, 0x8 B.EQ 2f CMP X0, 0x4 B.EQ 1f B . 3: MRS X3, SPSR_EL3 /* Save the ELR. */ MRS X2, ELR_EL3 B 0f 2: MRS X3, SPSR_EL2 /* Save the ELR. */ MRS X2, ELR_EL2 B 0f 1: MRS X3, SPSR_EL1 MRS X2, ELR_EL1 B 0f 0: STP X2, X3, [SP, #-0x10]! MOV X0, SP /* Move SP into X0 for saving. */ /* Switch to use the ELx stack pointer. */ MSR SPSEL, #1 .endm .macro SAVE_CONTEXT_T /* Switch to use the EL0 stack pointer. */ MSR SPSEL, #0 /* Save the entire context. */ STP X0, X1, [SP, #-0x10]! STP X2, X3, [SP, #-0x10]! STP X4, X5, [SP, #-0x10]! STP X6, X7, [SP, #-0x10]! STP X8, X9, [SP, #-0x10]! STP X10, X11, [SP, #-0x10]! STP X12, X13, [SP, #-0x10]! STP X14, X15, [SP, #-0x10]! STP X16, X17, [SP, #-0x10]! STP X18, X19, [SP, #-0x10]! STP X20, X21, [SP, #-0x10]! STP X22, X23, [SP, #-0x10]! STP X24, X25, [SP, #-0x10]! STP X26, X27, [SP, #-0x10]! STP X28, X29, [SP, #-0x10]! STP X30, XZR, [SP, #-0x10]! MRS X0, CurrentEL CMP X0, 0xc B.EQ 3f CMP X0, 0x8 B.EQ 2f CMP X0, 0x4 B.EQ 1f B . 3: MRS X3, SPSR_EL3 MOV X2, X30 B 0f 2: MRS X3, SPSR_EL2 MOV X2, X30 B 0f 1: MRS X3, SPSR_EL1 MOV X2, X30 B 0f 0: STP X2, X3, [SP, #-0x10]! MOV X0, SP /* Move SP into X0 for saving. */ /* Switch to use the ELx stack pointer. */ MSR SPSEL, #1 .endm .macro RESTORE_CONTEXT /* Switch to use the EL0 stack pointer. */ MSR SPSEL, #0 /* Set the SP to point to the stack of the task being restored. */ MOV SP, X0 LDP X2, X3, [SP], #0x10 /* SPSR and ELR. */ MRS X0, CurrentEL CMP X0, 0xc B.EQ 3f CMP X0, 0x8 B.EQ 2f CMP X0, 0x4 B.EQ 1f B . 3: MSR SPSR_EL3, X3 MSR ELR_EL3, X2 B 0f 2: MSR SPSR_EL2, X3 MSR ELR_EL2, X2 B 0f 1: MSR SPSR_EL1, X3 MSR ELR_EL1, X2 B 0f 0: LDP X30, XZR, [SP], #0x10 LDP X28, X29, [SP], #0x10 LDP X26, X27, [SP], #0x10 LDP X24, X25, [SP], #0x10 LDP X22, X23, [SP], #0x10 LDP X20, X21, [SP], #0x10 LDP X18, X19, [SP], #0x10 LDP X16, X17, [SP], #0x10 LDP X14, X15, [SP], #0x10 LDP X12, X13, [SP], #0x10 LDP X10, X11, [SP], #0x10 LDP X8, X9, [SP], #0x10 LDP X6, X7, [SP], #0x10 LDP X4, X5, [SP], #0x10 LDP X2, X3, [SP], #0x10 LDP X0, X1, [SP], #0x10 /* Switch to use the ELx stack pointer. _RB_ Might not be required. */ MSR SPSEL, #1 ERET .endm .text /* * rt_base_t rt_hw_interrupt_disable(); */ .globl rt_hw_interrupt_disable rt_hw_interrupt_disable: MRS X0, DAIF MSR DAIFSet, #3 DSB SY RET /* * void rt_hw_interrupt_enable(rt_base_t level); */ .globl rt_hw_interrupt_enable rt_hw_interrupt_enable: DSB SY MOV X1, #0xC0 ANDS X0, X0, X1 B.NE rt_hw_interrupt_enable_exit MSR DAIFClr, #3 rt_hw_interrupt_enable_exit: RET /* * void rt_hw_context_switch_to(rt_ubase_t to); * r0 --> to */ .globl rt_hw_context_switch_to rt_hw_context_switch_to: LDR X0, [X0] RESTORE_CONTEXT .text /* * void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to); * r0 --> from * r1 --> to */ .globl rt_hw_context_switch rt_hw_context_switch: MOV X8,X0 MOV X9,X1 SAVE_CONTEXT_T STR X0, [X8] // store sp in preempted tasks TCB LDR X0, [X9] // get new task stack pointer RESTORE_CONTEXT /* * void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to); */ .globl rt_thread_switch_interrupt_flag .globl rt_interrupt_from_thread .globl rt_interrupt_to_thread .globl rt_hw_context_switch_interrupt rt_hw_context_switch_interrupt: ADR X2, rt_thread_switch_interrupt_flag LDR X3, [X2] CMP X3, #1 B.EQ _reswitch ADR X4, rt_interrupt_from_thread // set rt_interrupt_from_thread MOV X3, #1 // set rt_thread_switch_interrupt_flag to 1 STR X0, [X4] STR X3, [X2] _reswitch: ADR X2, rt_interrupt_to_thread // set rt_interrupt_to_thread STR X1, [X2] RET .text // -- Exception handlers ---------------------------------- .align 8 .globl vector_fiq vector_fiq: SAVE_CONTEXT STP X0, X1, [SP, #-0x10]! BL rt_hw_trap_fiq LDP X0, X1, [SP], #0x10 RESTORE_CONTEXT .globl rt_interrupt_enter .globl rt_interrupt_leave .globl rt_thread_switch_interrupt_flag .globl rt_interrupt_from_thread .globl rt_interrupt_to_thread // ------------------------------------------------------------------- .align 8 .globl vector_irq vector_irq: SAVE_CONTEXT STP X0, X1, [SP, #-0x10]! BL rt_interrupt_enter BL rt_hw_trap_irq BL rt_interrupt_leave LDP X0, X1, [SP], #0x10 // if rt_thread_switch_interrupt_flag set, jump to // rt_hw_context_switch_interrupt_do and don't return ADR X1, rt_thread_switch_interrupt_flag LDR X2, [X1] CMP X2, #1 B.NE vector_irq_exit MOV X2, #0 // clear flag STR X2, [X1] ADR X3, rt_interrupt_from_thread LDR X4, [X3] STR x0, [X4] // store sp in preempted tasks's TCB ADR x3, rt_interrupt_to_thread LDR X4, [X3] LDR x0, [X4] // get new task's stack pointer vector_irq_exit: RESTORE_CONTEXT // ------------------------------------------------- .align 8 .globl vector_error vector_error: SAVE_CONTEXT BL rt_hw_trap_error B .