rt-thread-official/libcpu/arm/arm926/start_gcc.S

306 lines
8.3 KiB
ArmAsm

/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-01-13 weety first version
* 2015-04-15 ArdaFu Split from AT91SAM9260 BSP
* 2015-04-21 ArdaFu Remove remap code. Using mmu to map vector table
* 2015-06-04 aozima Align stack address to 8 byte.
*/
#include "rt_low_level_init.h"
#define S_FRAME_SIZE (18*4) //72
@#define S_SPSR (17*4) //SPSR
@#define S_CPSR (16*4) //CPSR
#define S_PC (15*4) //R15
@#define S_LR (14*4) //R14
@#define S_SP (13*4) //R13
@#define S_IP (12*4) //R12
@#define S_FP (11*4) //R11
@#define S_R10 (10*4)
@#define S_R9 (9*4)
@#define S_R8 (8*4)
@#define S_R7 (7*4)
@#define S_R6 (6*4)
@#define S_R5 (5*4)
@#define S_R4 (4*4)
@#define S_R3 (3*4)
@#define S_R2 (2*4)
@#define S_R1 (1*4)
@#define S_R0 (0*4)
#define MODE_SYS 0x1F
#define MODE_FIQ 0x11
#define MODE_IRQ 0x12
#define MODE_SVC 0x13
#define MODE_ABT 0x17
#define MODE_UND 0x1B
#define MODEMASK 0x1F
#define NOINT 0xC0
@;----------------------- Stack and Heap Definitions ---------------------------
.section .nobss, "w"
.space UND_STK_SIZE
.align 3
.global UND_STACK_START
UND_STACK_START:
.space ABT_STK_SIZE
.align 3
.global ABT_STACK_START
ABT_STACK_START:
.space FIQ_STK_SIZE
.align 3
.global FIQ_STACK_START
FIQ_STACK_START:
.space IRQ_STK_SIZE
.align 3
.global IRQ_STACK_START
IRQ_STACK_START:
.skip SYS_STK_SIZE
.align 3
.global SYS_STACK_START
SYS_STACK_START:
.space SVC_STK_SIZE
.align 3
.global SVC_STACK_START
SVC_STACK_START:
@;--------------Jump vector table-----------------------------------------------
.section .init, "ax"
.arm
.global start
start:
LDR PC, vector_reset
LDR PC, vector_undef
LDR PC, vector_swi
LDR PC, vector_pabt
LDR PC, vector_dabt
LDR PC, vector_resv
LDR PC, vector_irq
LDR PC, vector_fiq
vector_reset:
.word Reset_Handler
vector_undef:
.word Undef_Handler
vector_swi:
.word SWI_Handler
vector_pabt:
.word PAbt_Handler
vector_dabt:
.word DAbt_Handler
vector_resv:
.word Resv_Handler
vector_irq:
.word IRQ_Handler
vector_fiq:
.word FIQ_Handler
.balignl 16,0xdeadbeef
@;----------------- Reset Handler ---------------------------------------------
.global rt_low_level_init
.global main
.global Reset_Handler
Reset_Handler:
@; Set the cpu to SVC32 mode
MRS R0, CPSR
BIC R0, R0, #MODEMASK
ORR R0, R0, #MODE_SVC|NOINT
MSR CPSR_cxsf, R0
@; Set CO-Processor
@; little-end锛宒isbale I/D Cache MMU, vector table is 0x00000000
MRC P15, 0, R0, C1, C0, 0 @; Read CP15
LDR R1, =0x00003085 @; set clear bits
BIC R0, R0, R1
MCR P15, 0, R0, C1, C0, 0 @; Write CP15
@; Call low level init function,
@; disable and clear all IRQs, Init MMU, Init interrupt controller, etc.
LDR SP, =SVC_STACK_START
LDR R0, =rt_low_level_init
BLX R0
Setup_Stack:
@; Setup Stack for each mode
MRS R0, CPSR
BIC R0, R0, #MODEMASK
ORR R1, R0, #MODE_UND|NOINT
MSR CPSR_cxsf, R1 @; Undef mode
LDR SP, =UND_STACK_START
ORR R1, R0, #MODE_ABT|NOINT
MSR CPSR_cxsf, R1 @; Abort mode
LDR SP, =ABT_STACK_START
ORR R1, R0, #MODE_IRQ|NOINT
MSR CPSR_cxsf, R1 @; IRQ mode
LDR SP, =IRQ_STACK_START
ORR R1, R0, #MODE_FIQ|NOINT
MSR CPSR_cxsf, R1 @; FIQ mode
LDR SP, =FIQ_STACK_START
ORR R1, R0, #MODE_SYS|NOINT
MSR CPSR_cxsf,R1 @; SYS/User mode
LDR SP, =SYS_STACK_START
ORR R1, R0, #MODE_SVC|NOINT
MSR CPSR_cxsf, R1 @; SVC mode
LDR SP, =SVC_STACK_START
@; clear .bss
MOV R0, #0 @; get a zero
LDR R1, =__bss_start__ @; bss start
LDR R2, =__bss_end__ @; bss end
bss_clear_loop:
CMP R1, R2 @; check if data to clear
STRLO R0, [R1], #4 @; clear 4 bytes
BLO bss_clear_loop @; loop until done
@; call C++ constructors of global objects
LDR R0, =__ctors_start__
LDR R1, =__ctors_end__
ctor_loop:
CMP R0, R1
BEQ ctor_end
LDR R2, [R0], #4
STMFD SP!, {R0-R1}
MOV LR, PC
BX R2
LDMFD SP!, {R0-R1}
B ctor_loop
ctor_end:
@; Enter the C code
LDR R0, =rtthread_startup
BLX R0
@;----------------- Exception Handler -----------------------------------------
.global rt_hw_trap_udef
.global rt_hw_trap_swi
.global rt_hw_trap_pabt
.global rt_hw_trap_dabt
.global rt_hw_trap_resv
.global rt_hw_trap_irq
.global rt_hw_trap_fiq
.global rt_interrupt_enter
.global rt_interrupt_leave
.global rt_thread_switch_interrupt_flag
.global rt_interrupt_from_thread
.global rt_interrupt_to_thread
.align 5
Undef_Handler:
SUB SP, SP, #S_FRAME_SIZE
STMIA SP, {R0 - R12} @; Calling R0-R12
ADD R8, SP, #S_PC
STMDB R8, {SP, LR} @; Calling SP, LR
STR LR, [R8, #0] @; Save calling PC
MRS R6, SPSR
STR R6, [R8, #4] @; Save CPSR
STR R0, [R8, #8] @; Save SPSR
MOV R0, SP
BL rt_hw_trap_udef
.align 5
SWI_Handler:
BL rt_hw_trap_swi
.align 5
PAbt_Handler:
BL rt_hw_trap_pabt
.align 5
DAbt_Handler:
SUB SP, SP, #S_FRAME_SIZE
STMIA SP, {R0 - R12} @; Calling R0-R12
ADD R8, SP, #S_PC
STMDB R8, {SP, LR} @; Calling SP, LR
STR LR, [R8, #0] @; Save calling PC
MRS R6, SPSR
STR R6, [R8, #4] @; Save CPSR
STR R0, [R8, #8] @; Save SPSR
MOV R0, SP
BL rt_hw_trap_dabt
.align 5
Resv_Handler:
BL rt_hw_trap_resv
.align 5
FIQ_Handler:
STMFD SP!, {R0-R7,LR}
BL rt_hw_trap_fiq
LDMFD SP!, {R0-R7,LR}
SUBS PC, LR, #4
.align 5
IRQ_Handler:
STMFD SP!, {R0-R12,LR}
BL rt_interrupt_enter
BL rt_hw_trap_irq
BL rt_interrupt_leave
@; If rt_thread_switch_interrupt_flag set,
@; jump to rt_hw_context_switch_interrupt_do and don't return
LDR R0, =rt_thread_switch_interrupt_flag
LDR R1, [R0]
CMP R1, #1
BEQ rt_hw_context_switch_interrupt_do
LDMFD SP!, {R0-R12,LR}
SUBS PC, LR, #4
@;------ void rt_hw_context_switch_interrupt_do(rt_base_t flag) -----------------
rt_hw_context_switch_interrupt_do:
MOV R1, #0 @; Clear flag
STR R1, [R0] @; Save to flag variable
LDMFD SP!, {R0-R12,LR} @; Reload saved registers
STMFD SP, {R0-R2} @; Save R0-R2
SUB R1, SP, #4*3 @; Save old task's SP to R1
SUB R2, LR, #4 @; Save old task's PC to R2
MRS R0, SPSR @; Get CPSR of interrupt thread
MSR CPSR_c, #MODE_SVC|NOINT @; Switch to SVC mode and no interrupt
STMFD SP!, {R2} @; Push old task's PC
STMFD SP!, {R3-R12,LR} @; Push old task's LR,R12-R3
LDMFD R1, {R1-R3}
STMFD SP!, {R1-R3} @; Push old task's R2-R0
STMFD SP!, {R0} @; Push old task's CPSR
LDR R4, =rt_interrupt_from_thread
LDR R5, [R4] @; R5 = stack ptr in old tasks's TCB
STR SP, [R5] @; Store SP in preempted tasks's TCB
LDR R6, =rt_interrupt_to_thread
LDR R6, [R6] @; R6 = stack ptr in new tasks's TCB
LDR SP, [R6] @; Get new task's stack pointer
LDMFD SP!, {R4} @; Pop new task's SPSR
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12,LR,PC}^ @; pop new task's R0-R12,LR & PC SPSR 2 CPSR