初始化版本
This commit is contained in:
79
rt-thread/libcpu/arm/arm926/context_gcc.S
Normal file
79
rt-thread/libcpu/arm/arm926/context_gcc.S
Normal file
@ -0,0 +1,79 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2011-08-14 weety copy from mini2440
|
||||
; */
|
||||
|
||||
#define NOINT 0xC0
|
||||
|
||||
.text
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
.globl rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS R0, CPSR
|
||||
ORR R1, R0, #NOINT
|
||||
MSR CPSR_c, R1
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.globl rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR CPSR, R0
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
STMFD SP!, {LR} @; push pc (lr should be pushed in place of pc)
|
||||
STMFD SP!, {R0-R12, LR} @; push lr & register file
|
||||
MRS R4, CPSR
|
||||
STMFD SP!, {R4} @; push cpsr
|
||||
STR SP, [R0] @; store sp in preempted tasks tcb
|
||||
LDR SP, [R1] @; get new task stack pointer
|
||||
LDMFD SP!, {R4} @; pop new task spsr
|
||||
MSR SPSR_cxsf, R4
|
||||
LDMFD SP!, {R0-R12, LR, PC}^ @; pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* r0 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
LDR SP, [R0] @; get new task stack pointer
|
||||
LDMFD SP!, {R4} @; pop new task cpsr
|
||||
MSR SPSR_cxsf, R4
|
||||
LDMFD SP!, {R0-R12, LR, PC}^ @; pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 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:
|
||||
LDR R2, =rt_thread_switch_interrupt_flag
|
||||
LDR R3, [R2]
|
||||
CMP R3, #1
|
||||
BEQ _reswitch
|
||||
MOV R3, #1 @; set flag to 1
|
||||
STR R3, [R2]
|
||||
LDR R2, =rt_interrupt_from_thread @; set rt_interrupt_from_thread
|
||||
STR R0, [R2]
|
||||
_reswitch:
|
||||
LDR R2, =rt_interrupt_to_thread @; set rt_interrupt_to_thread
|
||||
STR R1, [R2]
|
||||
BX LR
|
||||
82
rt-thread/libcpu/arm/arm926/context_iar.S
Normal file
82
rt-thread/libcpu/arm/arm926/context_iar.S
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-08-14 weety copy from mini2440
|
||||
* 2015-04-15 ArdaFu convert from context_gcc.s
|
||||
*/
|
||||
|
||||
#define NOINT 0xc0
|
||||
|
||||
SECTION .text:CODE(6)
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
PUBLIC rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS R0, CPSR
|
||||
ORR R1, R0, #NOINT
|
||||
MSR CPSR_C, R1
|
||||
MOV PC, LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
PUBLIC rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR CPSR_CXSF, R0
|
||||
MOV PC, LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
PUBLIC rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
STMFD SP!, {LR} ; push pc (lr should be pushed in place of PC)
|
||||
STMFD SP!, {R0-R12, LR} ; push lr & register file
|
||||
MRS R4, CPSR
|
||||
STMFD SP!, {R4} ; push cpsr
|
||||
STR SP, [R0] ; store sp in preempted tasks TCB
|
||||
LDR SP, [R1] ; get new task stack pointer
|
||||
LDMFD SP!, {R4} ; pop new task spsr
|
||||
MSR SPSR_cxsf, R4
|
||||
LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* r0 --> to
|
||||
*/
|
||||
PUBLIC rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
LDR SP, [R0] ; get new task stack pointer
|
||||
LDMFD SP!, {R4} ; pop new task spsr
|
||||
MSR SPSR_cxsf, R4
|
||||
LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
*/
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
PUBLIC rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch_interrupt:
|
||||
LDR R2, =rt_thread_switch_interrupt_flag
|
||||
LDR R3, [R2]
|
||||
CMP R3, #1
|
||||
BEQ _reswitch
|
||||
MOV R3, #1 ; set flag to 1
|
||||
STR R3, [R2]
|
||||
LDR R2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR R0, [R2]
|
||||
_reswitch:
|
||||
LDR R2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR R1, [R2]
|
||||
MOV PC, LR
|
||||
END
|
||||
|
||||
91
rt-thread/libcpu/arm/arm926/context_rvds.S
Normal file
91
rt-thread/libcpu/arm/arm926/context_rvds.S
Normal file
@ -0,0 +1,91 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2011-08-14 weety copy from mini2440
|
||||
; */
|
||||
|
||||
NOINT EQU 0XC0 ; disable interrupt in psr
|
||||
|
||||
AREA |.TEXT|, CODE, READONLY, ALIGN=2
|
||||
ARM
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS R0, CPSR
|
||||
ORR R1, R0, #NOINT
|
||||
MSR CPSR_C, R1
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable proc
|
||||
export rt_hw_interrupt_enable
|
||||
msr cpsr_c, r0
|
||||
bx lr
|
||||
endp
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch proc
|
||||
export rt_hw_context_switch
|
||||
stmfd sp!, {lr} ; push pc (lr should be pushed in place of pc)
|
||||
stmfd sp!, {r0-r12, lr} ; push lr & register file
|
||||
mrs r4, cpsr
|
||||
stmfd sp!, {r4} ; push cpsr
|
||||
str sp, [r0] ; store sp in preempted tasks tcb
|
||||
ldr sp, [r1] ; get new task stack pointer
|
||||
ldmfd sp!, {r4} ; pop new task spsr
|
||||
msr spsr_cxsf, r4
|
||||
ldmfd sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc
|
||||
endp
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; */
|
||||
rt_hw_context_switch_to proc
|
||||
export rt_hw_context_switch_to
|
||||
ldr sp, [r0] ; get new task stack pointer
|
||||
ldmfd sp!, {r4} ; pop new task spsr
|
||||
msr spsr_cxsf, r4
|
||||
ldmfd sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc
|
||||
endp
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
; */
|
||||
import rt_thread_switch_interrupt_flag
|
||||
import rt_interrupt_from_thread
|
||||
import rt_interrupt_to_thread
|
||||
|
||||
rt_hw_context_switch_interrupt proc
|
||||
export rt_hw_context_switch_interrupt
|
||||
ldr r2, =rt_thread_switch_interrupt_flag
|
||||
ldr r3, [r2]
|
||||
cmp r3, #1
|
||||
beq _reswitch
|
||||
mov r3, #1 ; set flag to 1
|
||||
str r3, [r2]
|
||||
ldr r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
str r0, [r2]
|
||||
_reswitch
|
||||
ldr r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
endp
|
||||
|
||||
end
|
||||
216
rt-thread/libcpu/arm/arm926/cpuport.c
Normal file
216
rt-thread/libcpu/arm/arm926/cpuport.c
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety modified from mini2440
|
||||
* 2015-04-15 ArdaFu Add code for IAR
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#define ICACHE_MASK (rt_uint32_t)(1 << 12)
|
||||
#define DCACHE_MASK (rt_uint32_t)(1 << 2)
|
||||
|
||||
extern void machine_reset(void);
|
||||
extern void machine_shutdown(void);
|
||||
|
||||
#if defined(__GNUC__) || defined(__ICCARM__)
|
||||
rt_inline rt_uint32_t cp15_rd(void)
|
||||
{
|
||||
rt_uint32_t i;
|
||||
|
||||
__asm volatile("mrc p15, 0, %0, c1, c0, 0":"=r"(i));
|
||||
return i;
|
||||
}
|
||||
|
||||
rt_inline void cache_enable(rt_uint32_t bit)
|
||||
{
|
||||
__asm volatile(\
|
||||
"mrc p15,0,r0,c1,c0,0\n\t" \
|
||||
"orr r0,r0,%0\n\t" \
|
||||
"mcr p15,0,r0,c1,c0,0" \
|
||||
: \
|
||||
: "r"(bit) \
|
||||
: "memory");
|
||||
}
|
||||
|
||||
rt_inline void cache_disable(rt_uint32_t bit)
|
||||
{
|
||||
__asm volatile(\
|
||||
"mrc p15,0,r0,c1,c0,0\n\t" \
|
||||
"bic r0,r0,%0\n\t" \
|
||||
"mcr p15,0,r0,c1,c0,0" \
|
||||
: \
|
||||
: "r"(bit) \
|
||||
: "memory");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__CC_ARM)
|
||||
rt_inline rt_uint32_t cp15_rd(void)
|
||||
{
|
||||
rt_uint32_t i;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, i, c1, c0, 0
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
rt_inline void cache_enable(rt_uint32_t bit)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, bit
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
rt_inline void cache_disable(rt_uint32_t bit)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, bit
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enable I-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_icache_enable()
|
||||
{
|
||||
cache_enable(ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* disable I-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_icache_disable()
|
||||
{
|
||||
cache_disable(ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the status of I-Cache
|
||||
*
|
||||
*/
|
||||
rt_base_t rt_hw_cpu_icache_status()
|
||||
{
|
||||
return (cp15_rd() & ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* enable D-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_dcache_enable()
|
||||
{
|
||||
cache_enable(DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* disable D-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_dcache_disable()
|
||||
{
|
||||
cache_disable(DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the status of D-Cache
|
||||
*
|
||||
*/
|
||||
rt_base_t rt_hw_cpu_dcache_status()
|
||||
{
|
||||
return (cp15_rd() & DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset cpu by dog's time-out
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset()
|
||||
{
|
||||
|
||||
rt_kprintf("Restarting system...\n");
|
||||
machine_reset();
|
||||
|
||||
while (1); /* loop forever and wait for reset to happen */
|
||||
|
||||
/* NEVER REACHED */
|
||||
}
|
||||
|
||||
/**
|
||||
* shutdown CPU
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown()
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
machine_shutdown();
|
||||
while (level)
|
||||
{
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
/**
|
||||
* This function finds the first bit set (beginning with the least significant bit)
|
||||
* in value and return the index of that bit.
|
||||
*
|
||||
* Bits are numbered starting at 1 (the least significant bit). A return value of
|
||||
* zero from any of these functions means that the argument was zero.
|
||||
*
|
||||
* @return return the index of the first bit set. If value is 0, then this function
|
||||
* shall return 0.
|
||||
*/
|
||||
#if defined(__CC_ARM)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
register rt_uint32_t x;
|
||||
|
||||
if (value == 0)
|
||||
return value;
|
||||
|
||||
__asm
|
||||
{
|
||||
rsb x, value, #0
|
||||
and x, x, value
|
||||
clz x, x
|
||||
rsb x, x, #32
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
#elif defined(__GNUC__) || defined(__ICCARM__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
return __builtin_ffs(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*@}*/
|
||||
27
rt-thread/libcpu/arm/arm926/machine.c
Normal file
27
rt-thread/libcpu/arm/arm926/machine.c
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-02-08 RT-Thread the first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
RT_WEAK void machine_reset(void)
|
||||
{
|
||||
rt_kprintf("reboot system...\n");
|
||||
rt_hw_interrupt_disable();
|
||||
while (1);
|
||||
}
|
||||
|
||||
RT_WEAK void machine_shutdown(void)
|
||||
{
|
||||
rt_kprintf("shutdown...\n");
|
||||
rt_hw_interrupt_disable();
|
||||
while (1);
|
||||
}
|
||||
|
||||
443
rt-thread/libcpu/arm/arm926/mmu.c
Normal file
443
rt-thread/libcpu/arm/arm926/mmu.c
Normal file
@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-04-15 ArdaFu Add code for IAR
|
||||
*/
|
||||
|
||||
#include "mmu.h"
|
||||
|
||||
/*----- Keil -----------------------------------------------------------------*/
|
||||
#ifdef __CC_ARM
|
||||
void mmu_setttbase(rt_uint32_t i)
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
/* Invalidates all TLBs.Domain access is selected as
|
||||
* client by configuring domain access register,
|
||||
* in that case access controlled by permission value
|
||||
* set by page table entry
|
||||
*/
|
||||
value = 0;
|
||||
__asm volatile{ mcr p15, 0, value, c8, c7, 0 }
|
||||
value = 0x55555555;
|
||||
__asm volatile { mcr p15, 0, value, c3, c0, 0 }
|
||||
__asm volatile { mcr p15, 0, i, c2, c0, 0 }
|
||||
}
|
||||
|
||||
void mmu_set_domain(rt_uint32_t i)
|
||||
{
|
||||
__asm volatile { mcr p15, 0, i, c3, c0, 0 }
|
||||
}
|
||||
|
||||
void mmu_enable()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x01
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x01
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable_icache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x1000
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable_dcache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x04
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable_icache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x1000
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable_dcache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x04
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable_alignfault()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x02
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable_alignfault()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x02
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_cache_index(int index)
|
||||
{
|
||||
__asm volatile { mcr p15, 0, index, c7, c14, 2 }
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
__asm volatile { MCR p15, 0, ptr, c7, c14, 1 }
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
__asm volatile { MCR p15, 0, ptr, c7, c10, 1 }
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
__asm volatile { MCR p15, 0, ptr, c7, c6, 1 }
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_tlb()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
value = 0;
|
||||
__asm volatile { mcr p15, 0, value, c8, c7, 0 }
|
||||
}
|
||||
|
||||
void mmu_invalidate_icache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
value = 0;
|
||||
|
||||
__asm volatile { mcr p15, 0, value, c7, c5, 0 }
|
||||
}
|
||||
|
||||
|
||||
void mmu_invalidate_dcache_all()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
value = 0;
|
||||
|
||||
__asm volatile { mcr p15, 0, value, c7, c6, 0 }
|
||||
}
|
||||
/*----- GNU ------------------------------------------------------------------*/
|
||||
#elif defined(__GNUC__) || defined(__ICCARM__)
|
||||
void mmu_setttbase(register rt_uint32_t i)
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
/* Invalidates all TLBs.Domain access is selected as
|
||||
* client by configuring domain access register,
|
||||
* in that case access controlled by permission value
|
||||
* set by page table entry
|
||||
*/
|
||||
value = 0;
|
||||
asm volatile("mcr p15, 0, %0, c8, c7, 0"::"r"(value));
|
||||
|
||||
value = 0x55555555;
|
||||
asm volatile("mcr p15, 0, %0, c3, c0, 0"::"r"(value));
|
||||
|
||||
asm volatile("mcr p15, 0, %0, c2, c0, 0"::"r"(i));
|
||||
|
||||
}
|
||||
|
||||
void mmu_set_domain(register rt_uint32_t i)
|
||||
{
|
||||
asm volatile("mcr p15,0, %0, c3, c0, 0": :"r"(i));
|
||||
}
|
||||
|
||||
void mmu_enable()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"orr r0, r0, #0x1 \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
}
|
||||
|
||||
void mmu_disable()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"bic r0, r0, #0x1 \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void mmu_enable_icache()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"orr r0, r0, #(1<<12) \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
}
|
||||
|
||||
void mmu_enable_dcache()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"orr r0, r0, #(1<<2) \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void mmu_disable_icache()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"bic r0, r0, #(1<<12) \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void mmu_disable_dcache()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"bic r0, r0, #(1<<2) \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void mmu_enable_alignfault()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"orr r0, r0, #1 \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void mmu_disable_alignfault()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"bic r0, r0, #1 \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_cache_index(int index)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c7, c14, 2": :"r"(index));
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c7, c14, 1": :"r"(ptr));
|
||||
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c7, c10, 1": :"r"(ptr));
|
||||
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c7, c6, 1": :"r"(ptr));
|
||||
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_tlb()
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c8, c7, 0": :"r"(0));
|
||||
|
||||
}
|
||||
|
||||
void mmu_invalidate_icache()
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c7, c5, 0": :"r"(0));
|
||||
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache_all()
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c7, c6, 0": :"r"(0));
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* level1 page table */
|
||||
#if defined(__ICCARM__)
|
||||
#pragma data_alignment=(16*1024)
|
||||
static volatile rt_uint32_t _page_table[4 * 1024];
|
||||
#else
|
||||
static volatile rt_uint32_t _page_table[4 * 1024] \
|
||||
__attribute__((aligned(16 * 1024)));
|
||||
#endif
|
||||
|
||||
void mmu_setmtt(rt_uint32_t vaddrStart, rt_uint32_t vaddrEnd,
|
||||
rt_uint32_t paddrStart, rt_uint32_t attr)
|
||||
{
|
||||
volatile rt_uint32_t *pTT;
|
||||
volatile int nSec;
|
||||
int i = 0;
|
||||
pTT = (rt_uint32_t *)_page_table + (vaddrStart >> 20);
|
||||
nSec = (vaddrEnd >> 20) - (vaddrStart >> 20);
|
||||
for (i = 0; i <= nSec; i++)
|
||||
{
|
||||
*pTT = attr | (((paddrStart >> 20) + i) << 20);
|
||||
pTT++;
|
||||
}
|
||||
}
|
||||
|
||||
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size)
|
||||
{
|
||||
/* disable I/D cache */
|
||||
mmu_disable_dcache();
|
||||
mmu_disable_icache();
|
||||
mmu_disable();
|
||||
mmu_invalidate_tlb();
|
||||
|
||||
/* set page table */
|
||||
for (; size > 0; size--)
|
||||
{
|
||||
mmu_setmtt(mdesc->vaddr_start, mdesc->vaddr_end,
|
||||
mdesc->paddr_start, mdesc->attr);
|
||||
mdesc++;
|
||||
}
|
||||
|
||||
/* set MMU table address */
|
||||
mmu_setttbase((rt_uint32_t)_page_table);
|
||||
|
||||
/* enables MMU */
|
||||
mmu_enable();
|
||||
|
||||
/* enable Instruction Cache */
|
||||
mmu_enable_icache();
|
||||
|
||||
/* enable Data Cache */
|
||||
mmu_enable_dcache();
|
||||
|
||||
mmu_invalidate_icache();
|
||||
mmu_invalidate_dcache_all();
|
||||
}
|
||||
52
rt-thread/libcpu/arm/arm926/mmu.h
Normal file
52
rt-thread/libcpu/arm/arm926/mmu.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-02-08 RT-Thread the first version
|
||||
*/
|
||||
|
||||
#ifndef __MMU_H__
|
||||
#define __MMU_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define CACHE_LINE_SIZE 32
|
||||
|
||||
#define DESC_SEC (0x2|(1<<4))
|
||||
#define CB (3<<2) //cache_on, write_back
|
||||
#define CNB (2<<2) //cache_on, write_through
|
||||
#define NCB (1<<2) //cache_off,WR_BUF on
|
||||
#define NCNB (0<<2) //cache_off,WR_BUF off
|
||||
#define AP_RW (3<<10) //supervisor=RW, user=RW
|
||||
#define AP_RO (2<<10) //supervisor=RW, user=RO
|
||||
|
||||
#define DOMAIN_FAULT (0x0)
|
||||
#define DOMAIN_CHK (0x1)
|
||||
#define DOMAIN_NOTCHK (0x3)
|
||||
#define DOMAIN0 (0x0<<5)
|
||||
#define DOMAIN1 (0x1<<5)
|
||||
|
||||
#define DOMAIN0_ATTR (DOMAIN_CHK<<0)
|
||||
#define DOMAIN1_ATTR (DOMAIN_FAULT<<2)
|
||||
|
||||
#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) /* Read/Write, cache, write back */
|
||||
#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) /* Read/Write, cache, write through */
|
||||
#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
|
||||
#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
|
||||
|
||||
struct mem_desc
|
||||
{
|
||||
rt_uint32_t vaddr_start;
|
||||
rt_uint32_t vaddr_end;
|
||||
rt_uint32_t paddr_start;
|
||||
rt_uint32_t attr;
|
||||
};
|
||||
|
||||
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size);
|
||||
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size);
|
||||
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size);
|
||||
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size);
|
||||
#endif
|
||||
66
rt-thread/libcpu/arm/arm926/stack.c
Normal file
66
rt-thread/libcpu/arm/arm926/stack.c
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety copy from mini2440
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
|
||||
/*****************************/
|
||||
/* CPU Mode */
|
||||
/*****************************/
|
||||
#define USERMODE 0x10
|
||||
#define FIQMODE 0x11
|
||||
#define IRQMODE 0x12
|
||||
#define SVCMODE 0x13
|
||||
#define ABORTMODE 0x17
|
||||
#define UNDEFMODE 0x1b
|
||||
#define MODEMASK 0x1f
|
||||
#define NOINT 0xc0
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
|
||||
rt_uint8_t *stack_addr, void *texit)
|
||||
{
|
||||
rt_uint32_t *stk;
|
||||
|
||||
stack_addr += sizeof(rt_uint32_t);
|
||||
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
|
||||
stk = (rt_uint32_t *)stack_addr;
|
||||
|
||||
*(--stk) = (rt_uint32_t)tentry; /* entry point */
|
||||
*(--stk) = (rt_uint32_t)texit; /* lr */
|
||||
*(--stk) = 0xdeadbeef; /* r12 */
|
||||
*(--stk) = 0xdeadbeef; /* r11 */
|
||||
*(--stk) = 0xdeadbeef; /* r10 */
|
||||
*(--stk) = 0xdeadbeef; /* r9 */
|
||||
*(--stk) = 0xdeadbeef; /* r8 */
|
||||
*(--stk) = 0xdeadbeef; /* r7 */
|
||||
*(--stk) = 0xdeadbeef; /* r6 */
|
||||
*(--stk) = 0xdeadbeef; /* r5 */
|
||||
*(--stk) = 0xdeadbeef; /* r4 */
|
||||
*(--stk) = 0xdeadbeef; /* r3 */
|
||||
*(--stk) = 0xdeadbeef; /* r2 */
|
||||
*(--stk) = 0xdeadbeef; /* r1 */
|
||||
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
|
||||
/* cpsr */
|
||||
if ((rt_uint32_t)tentry & 0x01)
|
||||
*(--stk) = SVCMODE | 0x20; /* thumb mode */
|
||||
else
|
||||
*(--stk) = SVCMODE; /* arm mode */
|
||||
|
||||
/* return task's current stack address */
|
||||
return (rt_uint8_t *)stk;
|
||||
}
|
||||
306
rt-thread/libcpu/arm/arm926/start_gcc.S
Normal file
306
rt-thread/libcpu/arm/arm926/start_gcc.S
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, 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.
|
||||
*/
|
||||
|
||||
.equ MODE_USR, 0x10
|
||||
.equ MODE_FIQ, 0x11
|
||||
.equ MODE_IRQ, 0x12
|
||||
.equ MODE_SVC, 0x13
|
||||
.equ MODE_ABT, 0x17
|
||||
.equ MODE_UND, 0x1B
|
||||
.equ MODE_SYS, 0x1F
|
||||
.equ MODEMASK, 0x1F
|
||||
.equ NOINT, 0xC0
|
||||
|
||||
.equ I_BIT, 0x80
|
||||
.equ F_BIT, 0x40
|
||||
|
||||
.equ UND_STACK_SIZE, 0x00000100
|
||||
.equ SVC_STACK_SIZE, 0x00000100
|
||||
.equ ABT_STACK_SIZE, 0x00000100
|
||||
.equ FIQ_STACK_SIZE, 0x00000100
|
||||
.equ IRQ_STACK_SIZE, 0x00000100
|
||||
.equ SYS_STACK_SIZE, 0x00000100
|
||||
|
||||
/*
|
||||
***************************************
|
||||
* Interrupt vector table
|
||||
***************************************
|
||||
*/
|
||||
.section .vectors
|
||||
.code 32
|
||||
|
||||
.global system_vectors
|
||||
system_vectors:
|
||||
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
|
||||
_vector_undef:
|
||||
.word vector_undef
|
||||
_vector_swi:
|
||||
.word vector_swi
|
||||
_vector_pabt:
|
||||
.word vector_pabt
|
||||
_vector_dabt:
|
||||
.word vector_dabt
|
||||
_vector_resv:
|
||||
.word vector_resv
|
||||
_vector_irq:
|
||||
.word vector_irq
|
||||
_vector_fiq:
|
||||
.word vector_fiq
|
||||
|
||||
.balignl 16,0xdeadbeef
|
||||
|
||||
/*
|
||||
***************************************
|
||||
* Stack and Heap Definitions
|
||||
***************************************
|
||||
*/
|
||||
.section .data
|
||||
.space UND_STACK_SIZE
|
||||
.align 3
|
||||
.global und_stack_start
|
||||
und_stack_start:
|
||||
|
||||
.space ABT_STACK_SIZE
|
||||
.align 3
|
||||
.global abt_stack_start
|
||||
abt_stack_start:
|
||||
|
||||
.space FIQ_STACK_SIZE
|
||||
.align 3
|
||||
.global fiq_stack_start
|
||||
fiq_stack_start:
|
||||
|
||||
.space IRQ_STACK_SIZE
|
||||
.align 3
|
||||
.global irq_stack_start
|
||||
irq_stack_start:
|
||||
|
||||
.skip SYS_STACK_SIZE
|
||||
.align 3
|
||||
.global sys_stack_start
|
||||
sys_stack_start:
|
||||
|
||||
.space SVC_STACK_SIZE
|
||||
.align 3
|
||||
.global svc_stack_start
|
||||
svc_stack_start:
|
||||
|
||||
/*
|
||||
***************************************
|
||||
* Startup Code
|
||||
***************************************
|
||||
*/
|
||||
.section .text
|
||||
.global reset
|
||||
reset:
|
||||
/* Enter svc mode and mask interrupts */
|
||||
mrs r0, cpsr
|
||||
bic r0, r0, #MODEMASK
|
||||
orr r0, r0, #MODE_SVC|NOINT
|
||||
msr cpsr_cxsf, r0
|
||||
|
||||
/* init cpu */
|
||||
bl cpu_init_crit
|
||||
|
||||
/* Call low level init function */
|
||||
ldr sp, =svc_stack_start
|
||||
ldr r0, =rt_low_level_init
|
||||
blx r0
|
||||
|
||||
/* init stack */
|
||||
bl stack_setup
|
||||
|
||||
/* clear bss */
|
||||
mov r0, #0
|
||||
ldr r1, =__bss_start
|
||||
ldr r2, =__bss_end
|
||||
|
||||
bss_clear_loop:
|
||||
cmp r1, r2
|
||||
strlo r0, [r1], #4
|
||||
blo bss_clear_loop
|
||||
|
||||
/* 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:
|
||||
*/
|
||||
/* start RT-Thread Kernel */
|
||||
ldr pc, _rtthread_startup
|
||||
_rtthread_startup:
|
||||
.word rtthread_startup
|
||||
|
||||
|
||||
|
||||
cpu_init_crit:
|
||||
/* invalidate I/D caches */
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c7, 0
|
||||
mcr p15, 0, r0, c8, c7, 0
|
||||
|
||||
/* disable MMU stuff and caches */
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
bic r0, r0, #0x00002300
|
||||
bic r0, r0, #0x00000087
|
||||
orr r0, r0, #0x00000002
|
||||
orr r0, r0, #0x00001000
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
bx lr
|
||||
|
||||
stack_setup:
|
||||
/* Setup Stack for each mode */
|
||||
mrs r0, cpsr
|
||||
bic r0, r0, #MODEMASK
|
||||
|
||||
orr r1, r0, #MODE_UND|NOINT
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, =und_stack_start
|
||||
|
||||
orr r1, r0, #MODE_ABT|NOINT
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, =abt_stack_start
|
||||
|
||||
orr r1, r0, #MODE_IRQ|NOINT
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, =irq_stack_start
|
||||
|
||||
orr r1, r0, #MODE_FIQ|NOINT
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, =fiq_stack_start
|
||||
|
||||
orr r1, r0, #MODE_SYS|NOINT
|
||||
msr cpsr_cxsf,r1
|
||||
ldr sp, =sys_stack_start
|
||||
|
||||
orr r1, r0, #MODE_SVC|NOINT
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, =svc_stack_start
|
||||
|
||||
bx lr
|
||||
|
||||
/*
|
||||
***************************************
|
||||
* exception handlers
|
||||
***************************************
|
||||
*/
|
||||
/* Interrupt */
|
||||
vector_fiq:
|
||||
stmfd sp!,{r0-r7,lr}
|
||||
bl rt_hw_trap_fiq
|
||||
ldmfd sp!,{r0-r7,lr}
|
||||
subs pc, lr, #4
|
||||
|
||||
vector_irq:
|
||||
stmfd sp!, {r0-r12,lr}
|
||||
|
||||
bl rt_interrupt_enter
|
||||
bl rt_hw_trap_irq
|
||||
bl rt_interrupt_leave
|
||||
|
||||
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
|
||||
|
||||
rt_hw_context_switch_interrupt_do:
|
||||
mov r1, #0
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, sp
|
||||
add sp, sp, #4*4
|
||||
ldmfd sp!, {r4-r12,lr}
|
||||
mrs r0, spsr
|
||||
sub r2, lr, #4
|
||||
|
||||
msr cpsr_c, #I_BIT|F_BIT|MODE_SVC
|
||||
|
||||
stmfd sp!, {r2}
|
||||
stmfd sp!, {r4-r12,lr}
|
||||
ldmfd r1, {r1-r4}
|
||||
stmfd sp!, {r1-r4}
|
||||
stmfd sp!, {r0}
|
||||
|
||||
ldr r4, =rt_interrupt_from_thread
|
||||
ldr r5, [r4]
|
||||
str sp, [r5]
|
||||
|
||||
ldr r6, =rt_interrupt_to_thread
|
||||
ldr r6, [r6]
|
||||
ldr sp, [r6]
|
||||
|
||||
ldmfd sp!, {r4}
|
||||
msr spsr_cxsf, r4
|
||||
|
||||
ldmfd sp!, {r0-r12,lr,pc}^
|
||||
|
||||
/* Exception */
|
||||
.macro push_svc_reg
|
||||
sub sp, sp, #17 * 4
|
||||
stmia sp, {r0 - r12}
|
||||
mov r0, sp
|
||||
mrs r6, spsr
|
||||
str lr, [r0, #15*4]
|
||||
str r6, [r0, #16*4]
|
||||
str sp, [r0, #13*4]
|
||||
str lr, [r0, #14*4]
|
||||
.endm
|
||||
|
||||
vector_swi:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_swi
|
||||
b .
|
||||
|
||||
vector_undef:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_udef
|
||||
b .
|
||||
|
||||
vector_pabt:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_pabt
|
||||
b .
|
||||
|
||||
vector_dabt:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_dabt
|
||||
b .
|
||||
|
||||
vector_resv:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_resv
|
||||
b .
|
||||
278
rt-thread/libcpu/arm/arm926/start_iar.S
Normal file
278
rt-thread/libcpu/arm/arm926/start_iar.S
Normal file
@ -0,0 +1,278 @@
|
||||
;/*
|
||||
; * 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 ----------------------------
|
||||
MODULE ?cstartup
|
||||
SECTION .noinit:DATA:NOROOT(3)
|
||||
DATA
|
||||
|
||||
ALIGNRAM 3
|
||||
DS8 UND_STK_SIZE
|
||||
PUBLIC UND_STACK_START
|
||||
UND_STACK_START:
|
||||
|
||||
ALIGNRAM 3
|
||||
DS8 ABT_STK_SIZE
|
||||
PUBLIC ABT_STACK_START
|
||||
ABT_STACK_START:
|
||||
|
||||
ALIGNRAM 3
|
||||
DS8 FIQ_STK_SIZE
|
||||
PUBLIC FIQ_STACK_START
|
||||
FIQ_STACK_START:
|
||||
|
||||
ALIGNRAM 3
|
||||
DS8 IRQ_STK_SIZE
|
||||
PUBLIC IRQ_STACK_START
|
||||
IRQ_STACK_START:
|
||||
|
||||
ALIGNRAM 3
|
||||
DS8 SYS_STK_SIZE
|
||||
PUBLIC SYS_STACK_START
|
||||
SYS_STACK_START:
|
||||
|
||||
ALIGNRAM 3
|
||||
DS8 SVC_STK_SIZE
|
||||
PUBLIC SVC_STACK_START
|
||||
SVC_STACK_START:
|
||||
|
||||
;--------------Jump vector table------------------------------------------------
|
||||
SECTION .intvec:CODE:ROOT(2)
|
||||
ARM
|
||||
PUBLIC Entry_Point
|
||||
Entry_Point:
|
||||
__iar_init$$done: ; The interrupt vector is not needed
|
||||
; until after copy initialization is done
|
||||
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:
|
||||
DC32 Reset_Handler
|
||||
vector_undef:
|
||||
DC32 Undef_Handler
|
||||
vector_swi:
|
||||
DC32 SWI_Handler
|
||||
vector_pabt:
|
||||
DC32 PAbt_Handler
|
||||
vector_dabt:
|
||||
DC32 DAbt_Handler
|
||||
vector_resv:
|
||||
DC32 Resv_Handler
|
||||
vector_irq:
|
||||
DC32 IRQ_Handler
|
||||
vector_fiq:
|
||||
DC32 FIQ_Handler
|
||||
|
||||
;----------------- Reset Handler -----------------------------------------------
|
||||
EXTERN rt_low_level_init
|
||||
EXTERN ?main
|
||||
PUBLIC __iar_program_start
|
||||
__iar_program_start:
|
||||
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,disbale 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
|
||||
|
||||
; Enter the C code
|
||||
LDR R0, =?main
|
||||
BLX R0
|
||||
|
||||
;----------------- Exception Handler -------------------------------------------
|
||||
IMPORT rt_hw_trap_udef
|
||||
IMPORT rt_hw_trap_swi
|
||||
IMPORT rt_hw_trap_pabt
|
||||
IMPORT rt_hw_trap_dabt
|
||||
IMPORT rt_hw_trap_resv
|
||||
IMPORT rt_hw_trap_irq
|
||||
IMPORT rt_hw_trap_fiq
|
||||
|
||||
IMPORT rt_interrupt_enter
|
||||
IMPORT rt_interrupt_leave
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
SECTION .text:CODE:ROOT(2)
|
||||
ARM
|
||||
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
|
||||
|
||||
SWI_Handler:
|
||||
BL rt_hw_trap_swi
|
||||
|
||||
PAbt_Handler:
|
||||
BL rt_hw_trap_pabt
|
||||
|
||||
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
|
||||
|
||||
Resv_Handler:
|
||||
BL rt_hw_trap_resv
|
||||
|
||||
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
|
||||
|
||||
FIQ_Handler:
|
||||
STMFD SP!, {R0-R7,LR}
|
||||
BL rt_hw_trap_fiq
|
||||
LDMFD SP!, {R0-R7,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 to CPSR
|
||||
END
|
||||
301
rt-thread/libcpu/arm/arm926/start_rvds.S
Normal file
301
rt-thread/libcpu/arm/arm926/start_rvds.S
Normal file
@ -0,0 +1,301 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2011-08-14 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.
|
||||
; */
|
||||
|
||||
UND_STK_SIZE EQU 512
|
||||
SVC_STK_SIZE EQU 4096
|
||||
ABT_STK_SIZE EQU 512
|
||||
IRQ_STK_SIZE EQU 1024
|
||||
FIQ_STK_SIZE EQU 1024
|
||||
SYS_STK_SIZE EQU 512
|
||||
Heap_Size EQU 512
|
||||
|
||||
S_FRAME_SIZE EQU (18*4) ;72
|
||||
S_PC EQU (15*4) ;R15
|
||||
|
||||
MODE_USR EQU 0X10
|
||||
MODE_FIQ EQU 0X11
|
||||
MODE_IRQ EQU 0X12
|
||||
MODE_SVC EQU 0X13
|
||||
MODE_ABT EQU 0X17
|
||||
MODE_UND EQU 0X1B
|
||||
MODE_SYS EQU 0X1F
|
||||
MODEMASK EQU 0X1F
|
||||
|
||||
NOINT EQU 0xC0
|
||||
|
||||
;----------------------- Stack and Heap Definitions ----------------------------
|
||||
AREA STACK, NOINIT, READWRITE, ALIGN=3
|
||||
Stack_Mem
|
||||
|
||||
SPACE UND_STK_SIZE
|
||||
EXPORT UND_STACK_START
|
||||
UND_STACK_START
|
||||
|
||||
ALIGN 8
|
||||
SPACE ABT_STK_SIZE
|
||||
EXPORT ABT_STACK_START
|
||||
ABT_STACK_START
|
||||
|
||||
ALIGN 8
|
||||
SPACE FIQ_STK_SIZE
|
||||
EXPORT FIQ_STACK_START
|
||||
FIQ_STACK_START
|
||||
|
||||
ALIGN 8
|
||||
SPACE IRQ_STK_SIZE
|
||||
EXPORT IRQ_STACK_START
|
||||
IRQ_STACK_START
|
||||
|
||||
ALIGN 8
|
||||
SPACE SYS_STK_SIZE
|
||||
EXPORT SYS_STACK_START
|
||||
SYS_STACK_START
|
||||
|
||||
ALIGN 8
|
||||
SPACE SVC_STK_SIZE
|
||||
EXPORT SVC_STACK_START
|
||||
SVC_STACK_START
|
||||
Stack_Top
|
||||
__initial_sp
|
||||
|
||||
__heap_base
|
||||
Heap_Mem SPACE Heap_Size
|
||||
__heap_limit
|
||||
|
||||
PRESERVE8
|
||||
;--------------Jump vector table------------------------------------------------
|
||||
EXPORT Entry_Point
|
||||
AREA RESET, CODE, READONLY
|
||||
ARM
|
||||
Entry_Point
|
||||
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
|
||||
DCD Reset_Handler
|
||||
vector_undef
|
||||
DCD Undef_Handler
|
||||
vector_swi
|
||||
DCD SWI_Handler
|
||||
vector_pabt
|
||||
DCD PAbt_Handler
|
||||
vector_dabt
|
||||
DCD DAbt_Handler
|
||||
vector_resv
|
||||
DCD Resv_Handler
|
||||
vector_irq
|
||||
DCD IRQ_Handler
|
||||
vector_fiq
|
||||
DCD FIQ_Handler
|
||||
|
||||
;----------------- Reset Handler -----------------------------------------------
|
||||
IMPORT rt_low_level_init
|
||||
IMPORT __main
|
||||
EXPORT Reset_Handler
|
||||
Reset_Handler
|
||||
; set the cpu to SVC32 mode
|
||||
MRS R0,CPSR
|
||||
BIC R0,R0,#MODEMASK
|
||||
ORR R0,R0,#MODE_SVC:OR:NOINT
|
||||
MSR CPSR_cxsf,R0
|
||||
|
||||
; Set CO-Processor
|
||||
; little-end,disbale 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:OR:NOINT
|
||||
MSR CPSR_cxsf, R1 ; Undef mode
|
||||
LDR SP, =UND_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_ABT:OR:NOINT
|
||||
MSR CPSR_cxsf,R1 ; Abort mode
|
||||
LDR SP, =ABT_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_IRQ:OR:NOINT
|
||||
MSR CPSR_cxsf,R1 ; IRQ mode
|
||||
LDR SP, =IRQ_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_FIQ:OR:NOINT
|
||||
MSR CPSR_cxsf,R1 ; FIQ mode
|
||||
LDR SP, =FIQ_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_SYS:OR:NOINT
|
||||
MSR CPSR_cxsf,R1 ; SYS/User mode
|
||||
LDR SP, =SYS_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_SVC:OR:NOINT
|
||||
MSR CPSR_cxsf,R1 ; SVC mode
|
||||
LDR SP, =SVC_STACK_START
|
||||
|
||||
; Enter the C code
|
||||
LDR R0, =__main
|
||||
BLX R0
|
||||
|
||||
;----------------- Exception Handler -------------------------------------------
|
||||
IMPORT rt_hw_trap_udef
|
||||
IMPORT rt_hw_trap_swi
|
||||
IMPORT rt_hw_trap_pabt
|
||||
IMPORT rt_hw_trap_dabt
|
||||
IMPORT rt_hw_trap_resv
|
||||
IMPORT rt_hw_trap_irq
|
||||
IMPORT rt_hw_trap_fiq
|
||||
|
||||
IMPORT rt_interrupt_enter
|
||||
IMPORT rt_interrupt_leave
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
Undef_Handler PROC
|
||||
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
|
||||
ENDP
|
||||
|
||||
SWI_Handler PROC
|
||||
BL rt_hw_trap_swi
|
||||
ENDP
|
||||
|
||||
PAbt_Handler PROC
|
||||
BL rt_hw_trap_pabt
|
||||
ENDP
|
||||
|
||||
DAbt_Handler PROC
|
||||
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
|
||||
ENDP
|
||||
|
||||
Resv_Handler PROC
|
||||
BL rt_hw_trap_resv
|
||||
ENDP
|
||||
|
||||
FIQ_Handler PROC
|
||||
STMFD SP!, {R0-R7,LR}
|
||||
BL rt_hw_trap_fiq
|
||||
LDMFD SP!, {R0-R7,LR}
|
||||
SUBS PC, LR, #4
|
||||
ENDP
|
||||
|
||||
IRQ_Handler PROC
|
||||
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
|
||||
ENDP
|
||||
|
||||
;------ void rt_hw_context_switch_interrupt_do(rt_base_t flag) -----------------
|
||||
rt_hw_context_switch_interrupt_do PROC
|
||||
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:OR: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 to CPSR
|
||||
ENDP
|
||||
|
||||
;*******************************************************************************
|
||||
; User Stack and Heap initialization
|
||||
;*******************************************************************************
|
||||
IF :DEF:__MICROLIB
|
||||
|
||||
EXPORT __initial_sp
|
||||
EXPORT __heap_base
|
||||
EXPORT __heap_limit
|
||||
|
||||
ELSE
|
||||
|
||||
IMPORT __use_two_region_memory
|
||||
EXPORT __user_initial_stackheap
|
||||
|
||||
__user_initial_stackheap
|
||||
|
||||
LDR R0, = Heap_Mem ; heap base
|
||||
LDR R1, = SVC_STACK_START ; stack base (top-address)
|
||||
LDR R2, = (Heap_Mem + Heap_Size) ; heap limit
|
||||
LDR R3, = (SVC_STACK_START - SVC_STK_SIZE) ; stack limit (low-address)
|
||||
BX LR
|
||||
|
||||
ALIGN
|
||||
|
||||
ENDIF
|
||||
|
||||
END
|
||||
210
rt-thread/libcpu/arm/arm926/trap.c
Normal file
210
rt-thread/libcpu/arm/arm926/trap.c
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety modified from mini2440
|
||||
* 2015-04-15 ArdaFu Split from AT91SAM9260 BSP
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
#define INT_IRQ 0x00
|
||||
#define INT_FIQ 0x01
|
||||
|
||||
extern struct rt_thread *rt_current_thread;
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
|
||||
struct rt_hw_register
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t fp;
|
||||
rt_uint32_t ip;
|
||||
rt_uint32_t sp;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t cpsr;
|
||||
rt_uint32_t ORIG_r0;
|
||||
};
|
||||
static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL;
|
||||
void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context))
|
||||
{
|
||||
rt_exception_hook = exception_handle;
|
||||
}
|
||||
/**
|
||||
* this function will show registers of CPU
|
||||
*
|
||||
* @param regs the registers point
|
||||
*/
|
||||
|
||||
void rt_hw_show_register(struct rt_hw_register *regs)
|
||||
{
|
||||
rt_kprintf("Execption:\n");
|
||||
rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n",
|
||||
regs->r0, regs->r1, regs->r2, regs->r3);
|
||||
rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n",
|
||||
regs->r4, regs->r5, regs->r6, regs->r7);
|
||||
rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n",
|
||||
regs->r8, regs->r9, regs->r10);
|
||||
rt_kprintf("fp :0x%08x ip :0x%08x\n",
|
||||
regs->fp, regs->ip);
|
||||
rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n",
|
||||
regs->sp, regs->lr, regs->pc);
|
||||
rt_kprintf("cpsr:0x%08x\n", regs->cpsr);
|
||||
}
|
||||
|
||||
/**
|
||||
* When ARM7TDMI comes across an instruction which it cannot handle,
|
||||
* it takes the undefined instruction trap.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_udef(struct rt_hw_register *regs)
|
||||
{
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(regs);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
rt_hw_show_register(regs);
|
||||
|
||||
rt_kprintf("undefined instruction\n");
|
||||
rt_kprintf("thread - %s stack:\n", rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* The software interrupt instruction (SWI) is used for entering
|
||||
* Supervisor mode, usually to request a particular supervisor
|
||||
* function.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_swi(struct rt_hw_register *regs)
|
||||
{
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(regs);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
rt_hw_show_register(regs);
|
||||
|
||||
rt_kprintf("software interrupt\n");
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* An abort indicates that the current memory access cannot be completed,
|
||||
* which occurs during an instruction prefetch.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_pabt(struct rt_hw_register *regs)
|
||||
{
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(regs);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
rt_hw_show_register(regs);
|
||||
|
||||
rt_kprintf("prefetch abort\n");
|
||||
rt_kprintf("thread - %s stack:\n", RT_NAME_MAX, rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* An abort indicates that the current memory access cannot be completed,
|
||||
* which occurs during a data access.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_dabt(struct rt_hw_register *regs)
|
||||
{
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(regs);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
rt_hw_show_register(regs);
|
||||
|
||||
rt_kprintf("data abort\n");
|
||||
rt_kprintf("thread - %s stack:\n", RT_NAME_MAX, rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Normally, system will never reach here
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_resv(struct rt_hw_register *regs)
|
||||
{
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(regs);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
rt_kprintf("not used\n");
|
||||
rt_hw_show_register(regs);
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
extern void rt_interrupt_dispatch(rt_uint32_t fiq_irq);
|
||||
|
||||
void rt_hw_trap_irq(void)
|
||||
{
|
||||
rt_interrupt_dispatch(INT_IRQ);
|
||||
}
|
||||
|
||||
void rt_hw_trap_fiq(void)
|
||||
{
|
||||
rt_interrupt_dispatch(INT_FIQ);
|
||||
}
|
||||
126
rt-thread/libcpu/arm/armv6/arm_entry_gcc.S
Normal file
126
rt-thread/libcpu/arm/armv6/arm_entry_gcc.S
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-11-07 weety first version
|
||||
*/
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#include "armv6.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
.macro PRINT, str
|
||||
#ifdef DEBUG
|
||||
stmfd sp!, {r0-r3, ip, lr}
|
||||
add r0, pc, #4
|
||||
bl rt_kprintf
|
||||
b 1f
|
||||
.asciz "UNDEF: \str\n"
|
||||
.balign 4
|
||||
1: ldmfd sp!, {r0-r3, ip, lr}
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro PRINT1, str, arg
|
||||
#ifdef DEBUG
|
||||
stmfd sp!, {r0-r3, ip, lr}
|
||||
mov r1, \arg
|
||||
add r0, pc, #4
|
||||
bl rt_kprintf
|
||||
b 1f
|
||||
.asciz "UNDEF: \str\n"
|
||||
.balign 4
|
||||
1: ldmfd sp!, {r0-r3, ip, lr}
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro PRINT3, str, arg1, arg2, arg3
|
||||
#ifdef DEBUG
|
||||
stmfd sp!, {r0-r3, ip, lr}
|
||||
mov r3, \arg3
|
||||
mov r2, \arg2
|
||||
mov r1, \arg1
|
||||
add r0, pc, #4
|
||||
bl rt_kprintf
|
||||
b 1f
|
||||
.asciz "UNDEF: \str\n"
|
||||
.balign 4
|
||||
1: ldmfd sp!, {r0-r3, ip, lr}
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro get_current_thread, rd
|
||||
ldr \rd, .current_thread
|
||||
ldr \rd, [\rd]
|
||||
.endm
|
||||
|
||||
.current_thread:
|
||||
.word rt_current_thread
|
||||
|
||||
#ifdef RT_USING_NEON
|
||||
.align 6
|
||||
|
||||
/* is the neon instuction on arm mode? */
|
||||
.neon_opcode:
|
||||
.word 0xfe000000 @ mask
|
||||
.word 0xf2000000 @ opcode
|
||||
|
||||
.word 0xff100000 @ mask
|
||||
.word 0xf4000000 @ opcode
|
||||
|
||||
.word 0x00000000 @ end mask
|
||||
.word 0x00000000 @ end opcode
|
||||
#endif
|
||||
|
||||
/* undefined instruction exception processing */
|
||||
.globl undef_entry
|
||||
undef_entry:
|
||||
PRINT1 "r0=0x%08x", r0
|
||||
PRINT1 "r2=0x%08x", r2
|
||||
PRINT1 "r9=0x%08x", r9
|
||||
PRINT1 "sp=0x%08x", sp
|
||||
|
||||
#ifdef RT_USING_NEON
|
||||
ldr r6, .neon_opcode
|
||||
__check_neon_instruction:
|
||||
ldr r7, [r6], #4 @ load mask value
|
||||
cmp r7, #0 @ end mask?
|
||||
beq __check_vfp_instruction
|
||||
and r8, r0, r7
|
||||
ldr r7, [r6], #4 @ load opcode value
|
||||
cmp r8, r7 @ is NEON instruction?
|
||||
bne __check_neon_instruction
|
||||
b vfp_entry
|
||||
__check_vfp_instruction:
|
||||
#endif
|
||||
tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC instruction has bit 27
|
||||
tstne r0, #0x04000000 @ bit 26 set on both ARM and Thumb-2 instruction
|
||||
moveq pc, lr @ no vfp coprocessor instruction, return
|
||||
get_current_thread r10
|
||||
and r8, r0, #0x00000f00 @ get coprocessor number
|
||||
PRINT1 "CP=0x%08x", r8
|
||||
add pc, pc, r8, lsr #6
|
||||
nop
|
||||
mov pc, lr @ CP0
|
||||
mov pc, lr @ CP1
|
||||
mov pc, lr @ CP2
|
||||
mov pc, lr @ CP3
|
||||
mov pc, lr @ CP4
|
||||
mov pc, lr @ CP5
|
||||
mov pc, lr @ CP6
|
||||
mov pc, lr @ CP7
|
||||
mov pc, lr @ CP8
|
||||
mov pc, lr @ CP9
|
||||
mov pc, lr @ CP10 VFP
|
||||
mov pc, lr @ CP11 VFP
|
||||
mov pc, lr @ CP12
|
||||
mov pc, lr @ CP13
|
||||
mov pc, lr @ CP14 DEBUG
|
||||
mov pc, lr @ CP15 SYS CONTROL
|
||||
|
||||
|
||||
93
rt-thread/libcpu/arm/armv6/armv6.h
Normal file
93
rt-thread/libcpu/arm/armv6/armv6.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef __ARMV6_H__
|
||||
#define __ARMV6_H__
|
||||
|
||||
|
||||
/*****************************/
|
||||
/* CPU Mode */
|
||||
/*****************************/
|
||||
#define USERMODE 0x10
|
||||
#define FIQMODE 0x11
|
||||
#define IRQMODE 0x12
|
||||
#define SVCMODE 0x13
|
||||
#define ABORTMODE 0x17
|
||||
#define UNDEFMODE 0x1b
|
||||
#define MODEMASK 0x1f
|
||||
#define NOINT 0xc0
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
struct rt_hw_register
|
||||
{
|
||||
rt_uint32_t cpsr;
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t fp;
|
||||
rt_uint32_t ip;
|
||||
rt_uint32_t sp;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
};
|
||||
#if(0)
|
||||
struct rt_hw_register{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t fp;
|
||||
rt_uint32_t ip;
|
||||
rt_uint32_t sp;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t cpsr;
|
||||
rt_uint32_t ORIG_r0;
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* rt_hw_register offset */
|
||||
#define S_FRAME_SIZE 68
|
||||
|
||||
#define S_PC 64
|
||||
#define S_LR 60
|
||||
#define S_SP 56
|
||||
#define S_IP 52
|
||||
#define S_FP 48
|
||||
#define S_R10 44
|
||||
#define S_R9 40
|
||||
#define S_R8 36
|
||||
#define S_R7 32
|
||||
#define S_R6 28
|
||||
#define S_R5 24
|
||||
#define S_R4 20
|
||||
#define S_R3 16
|
||||
#define S_R2 12
|
||||
#define S_R1 8
|
||||
#define S_R0 4
|
||||
#define S_CPSR 0
|
||||
|
||||
|
||||
#endif
|
||||
96
rt-thread/libcpu/arm/armv6/context_gcc.S
Normal file
96
rt-thread/libcpu/arm/armv6/context_gcc.S
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety copy from mini2440
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \addtogroup ARMv6
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#define NOINT 0xc0
|
||||
#define FPEXC_EN (1 << 30) /* VFP enable bit */
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.globl rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
mrs r0, cpsr
|
||||
cpsid if
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.globl rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
msr cpsr_c, r0
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC)
|
||||
stmfd sp!, {r0-r12, lr} @ push lr & register file
|
||||
|
||||
mrs r4, cpsr
|
||||
tst lr, #0x01
|
||||
orrne r4, r4, #0x20 @ it's thumb code
|
||||
|
||||
stmfd sp!, {r4} @ push cpsr
|
||||
|
||||
str sp, [r0] @ store sp in preempted tasks TCB
|
||||
ldr sp, [r1] @ get new task stack pointer
|
||||
|
||||
ldmfd sp!, {r4} @ pop new task cpsr to spsr
|
||||
msr spsr_cxsf, r4
|
||||
_do_switch:
|
||||
ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* r0 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
ldr sp, [r0] @ get new task stack pointer
|
||||
|
||||
ldmfd sp!, {r4} @ pop new task spsr
|
||||
msr spsr_cxsf, r4
|
||||
|
||||
bic r4, r4, #0x20 @ must be ARM mode
|
||||
msr cpsr_cxsf, r4
|
||||
ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 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:
|
||||
ldr r2, =rt_thread_switch_interrupt_flag
|
||||
ldr r3, [r2]
|
||||
cmp r3, #1
|
||||
beq _reswitch
|
||||
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
|
||||
str r3, [r2]
|
||||
ldr r2, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
|
||||
str r0, [r2]
|
||||
_reswitch:
|
||||
ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
234
rt-thread/libcpu/arm/armv6/cpuport.c
Normal file
234
rt-thread/libcpu/arm/armv6/cpuport.c
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety modified from mini2440
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#define ICACHE_MASK (rt_uint32_t)(1 << 12)
|
||||
#define DCACHE_MASK (rt_uint32_t)(1 << 2)
|
||||
|
||||
extern void machine_reset(void);
|
||||
extern void machine_shutdown(void);
|
||||
|
||||
#ifdef __GNUC__
|
||||
rt_inline rt_uint32_t cp15_rd(void)
|
||||
{
|
||||
rt_uint32_t i;
|
||||
|
||||
asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
return i;
|
||||
}
|
||||
|
||||
rt_inline void cache_enable(rt_uint32_t bit)
|
||||
{
|
||||
__asm__ __volatile__( \
|
||||
"mrc p15,0,r0,c1,c0,0\n\t" \
|
||||
"orr r0,r0,%0\n\t" \
|
||||
"mcr p15,0,r0,c1,c0,0" \
|
||||
: \
|
||||
:"r" (bit) \
|
||||
:"memory");
|
||||
}
|
||||
|
||||
rt_inline void cache_disable(rt_uint32_t bit)
|
||||
{
|
||||
__asm__ __volatile__( \
|
||||
"mrc p15,0,r0,c1,c0,0\n\t" \
|
||||
"bic r0,r0,%0\n\t" \
|
||||
"mcr p15,0,r0,c1,c0,0" \
|
||||
: \
|
||||
:"r" (bit) \
|
||||
:"memory");
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __CC_ARM
|
||||
rt_inline rt_uint32_t cp15_rd(void)
|
||||
{
|
||||
rt_uint32_t i;
|
||||
|
||||
__asm
|
||||
{
|
||||
mrc p15, 0, i, c1, c0, 0
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
rt_inline void cache_enable(rt_uint32_t bit)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
|
||||
__asm
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, bit
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
rt_inline void cache_disable(rt_uint32_t bit)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
|
||||
__asm
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, bit
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enable I-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_icache_enable()
|
||||
{
|
||||
cache_enable(ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* disable I-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_icache_disable()
|
||||
{
|
||||
cache_disable(ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the status of I-Cache
|
||||
*
|
||||
*/
|
||||
rt_base_t rt_hw_cpu_icache_status()
|
||||
{
|
||||
return (cp15_rd() & ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* enable D-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_dcache_enable()
|
||||
{
|
||||
cache_enable(DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* disable D-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_dcache_disable()
|
||||
{
|
||||
cache_disable(DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the status of D-Cache
|
||||
*
|
||||
*/
|
||||
rt_base_t rt_hw_cpu_dcache_status()
|
||||
{
|
||||
return (cp15_rd() & DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset cpu by dog's time-out
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset()
|
||||
{
|
||||
|
||||
rt_kprintf("Restarting system...\n");
|
||||
machine_reset();
|
||||
|
||||
while(1); /* loop forever and wait for reset to happen */
|
||||
|
||||
/* NEVER REACHED */
|
||||
}
|
||||
|
||||
/**
|
||||
* shutdown CPU
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown()
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
machine_shutdown();
|
||||
while (level)
|
||||
{
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
/**
|
||||
* This function finds the first bit set (beginning with the least significant bit)
|
||||
* in value and return the index of that bit.
|
||||
*
|
||||
* Bits are numbered starting at 1 (the least significant bit). A return value of
|
||||
* zero from any of these functions means that the argument was zero.
|
||||
*
|
||||
* @return return the index of the first bit set. If value is 0, then this function
|
||||
* shall return 0.
|
||||
*/
|
||||
#if defined(__CC_ARM)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
register rt_uint32_t x;
|
||||
|
||||
if (value == 0)
|
||||
return value;
|
||||
|
||||
__asm
|
||||
{
|
||||
rsb x, value, #0
|
||||
and x, x, value
|
||||
clz x, x
|
||||
rsb x, x, #32
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
if (value == 0)
|
||||
return value;
|
||||
|
||||
__ASM("RSB r4, r0, #0");
|
||||
__ASM("AND r4, r4, r0");
|
||||
__ASM("CLZ r4, r4");
|
||||
__ASM("RSB r0, r4, #32");
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
if (value == 0)
|
||||
return value;
|
||||
|
||||
value &= (-value);
|
||||
asm ("clz %0, %1": "=r"(value) :"r"(value));
|
||||
|
||||
return (32 - value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*@}*/
|
||||
548
rt-thread/libcpu/arm/armv6/mmu.c
Normal file
548
rt-thread/libcpu/arm/armv6/mmu.c
Normal file
@ -0,0 +1,548 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "mmu.h"
|
||||
|
||||
#ifdef __CC_ARM
|
||||
void mmu_setttbase(rt_uint32_t i)
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
/* Invalidates all TLBs.Domain access is selected as
|
||||
* client by configuring domain access register,
|
||||
* in that case access controlled by permission value
|
||||
* set by page table entry
|
||||
*/
|
||||
value = 0;
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15, 0, value, c8, c7, 0
|
||||
}
|
||||
|
||||
value = 0x55555555;
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15, 0, value, c3, c0, 0
|
||||
mcr p15, 0, i, c2, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_set_domain(rt_uint32_t i)
|
||||
{
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15,0, i, c3, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x01
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x01
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable_icache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x1000
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable_dcache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x04
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable_icache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x1000
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable_dcache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x04
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable_alignfault()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x02
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable_alignfault()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x02
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_cache_index(int index)
|
||||
{
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15, 0, index, c7, c14, 2
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while(ptr < buffer + size)
|
||||
{
|
||||
__asm volatile
|
||||
{
|
||||
MCR p15, 0, ptr, c7, c14, 1
|
||||
}
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
__asm volatile
|
||||
{
|
||||
MCR p15, 0, ptr, c7, c10, 1
|
||||
}
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
__asm volatile
|
||||
{
|
||||
MCR p15, 0, ptr, c7, c6, 1
|
||||
}
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_tlb()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
value = 0;
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15, 0, value, c8, c7, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_icache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
value = 0;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15, 0, value, c7, c5, 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mmu_invalidate_dcache_all()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
value = 0;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15, 0, value, c7, c6, 0
|
||||
}
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
void mmu_setttbase(register rt_uint32_t i)
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
/* Invalidates all TLBs.Domain access is selected as
|
||||
* client by configuring domain access register,
|
||||
* in that case access controlled by permission value
|
||||
* set by page table entry
|
||||
*/
|
||||
value = 0;
|
||||
asm volatile ("mcr p15, 0, %0, c8, c7, 0"::"r"(value));
|
||||
|
||||
value = 0x55555555;
|
||||
asm volatile ("mcr p15, 0, %0, c3, c0, 0"::"r"(value));
|
||||
asm volatile ("mcr p15, 0, %0, c2, c0, 0"::"r"(i));
|
||||
}
|
||||
|
||||
void mmu_set_domain(register rt_uint32_t i)
|
||||
{
|
||||
asm volatile ("mcr p15,0, %0, c3, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_enable()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i |= 0x1;
|
||||
/* Enables the extended page tables to be configured for
|
||||
the hardware page translation mechanism, Subpage AP bits disabled */
|
||||
i |= (1 << 23); /* support for ARMv6 MMU features */
|
||||
i |= (1 << 13); /* High exception vectors selected, address range = 0xFFFF0000-0xFFFF001C */
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_disable()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i &= ~0x1;
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_enable_icache()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i |= (1 << 12);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_enable_dcache()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i |= (1 << 2);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_disable_icache()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i &= ~(1 << 12);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_disable_dcache()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i &= ~(1 << 2);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_enable_alignfault()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i |= (1 << 1);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_disable_alignfault()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i &= ~(1 << 1);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_cache_index(int index)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 2": :"r" (index));
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while(ptr < buffer + size)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 1": :"r" (ptr));
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c10, 1": :"r" (ptr));
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c6, 1": :"r" (ptr));
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_tlb()
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c8, c7, 0": :"r" (0));
|
||||
}
|
||||
|
||||
void mmu_invalidate_icache()
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c5, 0": :"r" (0));
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache_all()
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c6, 0": :"r" (0));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* level1 page table */
|
||||
static volatile unsigned int _pgd_table[4*1024] ALIGN(16*1024);
|
||||
/*
|
||||
* level2 page table
|
||||
* RT_MMU_PTE_SIZE must be 1024*n
|
||||
*/
|
||||
#define RT_MMU_PTE_SIZE 4096
|
||||
static volatile unsigned int _pte_table[RT_MMU_PTE_SIZE] ALIGN(1*1024);
|
||||
|
||||
void mmu_create_pgd(struct mem_desc *mdesc)
|
||||
{
|
||||
volatile rt_uint32_t *pTT;
|
||||
volatile int i, nSec;
|
||||
pTT = (rt_uint32_t *)_pgd_table + (mdesc->vaddr_start >> 20);
|
||||
nSec = (mdesc->vaddr_end >> 20) - (mdesc->vaddr_start >> 20);
|
||||
for(i = 0; i <= nSec; i++)
|
||||
{
|
||||
*pTT = mdesc->sect_attr | (((mdesc->paddr_start >> 20) + i) << 20);
|
||||
pTT++;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_create_pte(struct mem_desc *mdesc)
|
||||
{
|
||||
volatile rt_uint32_t *pTT;
|
||||
volatile rt_uint32_t *p_pteentry;
|
||||
int i;
|
||||
rt_uint32_t vaddr;
|
||||
rt_uint32_t total_page = 0;
|
||||
rt_uint32_t pte_offset = 0;
|
||||
rt_uint32_t sect_attr = 0;
|
||||
|
||||
total_page = (mdesc->vaddr_end >> 12) - (mdesc->vaddr_start >> 12) + 1;
|
||||
pte_offset = mdesc->sect_attr & 0xfffffc00;
|
||||
sect_attr = mdesc->sect_attr & 0x3ff;
|
||||
vaddr = mdesc->vaddr_start;
|
||||
|
||||
for(i = 0; i < total_page; i++)
|
||||
{
|
||||
pTT = (rt_uint32_t *)_pgd_table + (vaddr >> 20);
|
||||
if (*pTT == 0) /* Level 1 page table item not used, now update pgd item */
|
||||
{
|
||||
*pTT = pte_offset | sect_attr;
|
||||
p_pteentry = (rt_uint32_t *)pte_offset +
|
||||
((vaddr & 0x000ff000) >> 12);
|
||||
pte_offset += 1024;
|
||||
}
|
||||
else /* using old Level 1 page table item */
|
||||
{
|
||||
p_pteentry = (rt_uint32_t *)(*pTT & 0xfffffc00) +
|
||||
((vaddr & 0x000ff000) >> 12);
|
||||
}
|
||||
|
||||
|
||||
*p_pteentry = mdesc->page_attr | (((mdesc->paddr_start >> 12) + i) << 12);
|
||||
vaddr += 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
static void build_pte_mem_desc(struct mem_desc *mdesc, rt_uint32_t size)
|
||||
{
|
||||
rt_uint32_t pte_offset = 0;
|
||||
rt_uint32_t nsec = 0;
|
||||
/* set page table */
|
||||
for (; size > 0; size--)
|
||||
{
|
||||
if (mdesc->mapped_mode == PAGE_MAPPED)
|
||||
{
|
||||
nsec = (RT_ALIGN(mdesc->vaddr_end, 0x100000) - RT_ALIGN_DOWN(mdesc->vaddr_start, 0x100000)) >> 20;
|
||||
mdesc->sect_attr |= (((rt_uint32_t)_pte_table)& 0xfffffc00) + pte_offset;
|
||||
pte_offset += nsec << 10;
|
||||
}
|
||||
if (pte_offset >= RT_MMU_PTE_SIZE)
|
||||
{
|
||||
rt_kprintf("PTE table size too little\n");
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
|
||||
mdesc++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size)
|
||||
{
|
||||
/* disable I/D cache */
|
||||
mmu_disable_dcache();
|
||||
mmu_disable_icache();
|
||||
mmu_disable();
|
||||
mmu_invalidate_tlb();
|
||||
|
||||
/* clear pgd and pte table */
|
||||
rt_memset((void *)_pgd_table, 0, 16*1024);
|
||||
rt_memset((void *)_pte_table, 0, RT_MMU_PTE_SIZE);
|
||||
build_pte_mem_desc(mdesc, size);
|
||||
/* set page table */
|
||||
for (; size > 0; size--)
|
||||
{
|
||||
if (mdesc->mapped_mode == SECT_MAPPED)
|
||||
{
|
||||
mmu_create_pgd(mdesc);
|
||||
}
|
||||
else
|
||||
{
|
||||
mmu_create_pte(mdesc);
|
||||
}
|
||||
|
||||
mdesc++;
|
||||
}
|
||||
|
||||
/* set MMU table address */
|
||||
mmu_setttbase((rt_uint32_t)_pgd_table);
|
||||
|
||||
/* enables MMU */
|
||||
mmu_enable();
|
||||
|
||||
/* enable Instruction Cache */
|
||||
mmu_enable_icache();
|
||||
|
||||
/* enable Data Cache */
|
||||
mmu_enable_dcache();
|
||||
|
||||
mmu_invalidate_icache();
|
||||
mmu_invalidate_dcache_all();
|
||||
}
|
||||
|
||||
194
rt-thread/libcpu/arm/armv6/mmu.h
Normal file
194
rt-thread/libcpu/arm/armv6/mmu.h
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef __MMU_H__
|
||||
#define __MMU_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define CACHE_LINE_SIZE 32
|
||||
|
||||
/*
|
||||
* Hardware page table definitions.
|
||||
*
|
||||
* + Level 1 descriptor (PGD)
|
||||
* - common
|
||||
*/
|
||||
#define PGD_TYPE_MASK (3 << 0)
|
||||
#define PGD_TYPE_FAULT (0 << 0)
|
||||
#define PGD_TYPE_TABLE (1 << 0)
|
||||
#define PGD_TYPE_SECT (2 << 0)
|
||||
#define PGD_BIT4 (1 << 4)
|
||||
#define PGD_DOMAIN(x) ((x) << 5)
|
||||
#define PGD_PROTECTION (1 << 9) /* ARMv5 */
|
||||
/*
|
||||
* - section
|
||||
*/
|
||||
#define PGD_SECT_BUFFERABLE (1 << 2)
|
||||
#define PGD_SECT_CACHEABLE (1 << 3)
|
||||
#define PGD_SECT_XN (1 << 4) /* ARMv6 */
|
||||
#define PGD_SECT_AP0 (1 << 10)
|
||||
#define PGD_SECT_AP1 (1 << 11)
|
||||
#define PGD_SECT_TEX(x) ((x) << 12) /* ARMv5 */
|
||||
#define PGD_SECT_APX (1 << 15) /* ARMv6 */
|
||||
#define PGD_SECT_S (1 << 16) /* ARMv6 */
|
||||
#define PGD_SECT_nG (1 << 17) /* ARMv6 */
|
||||
#define PGD_SECT_SUPER (1 << 18) /* ARMv6 */
|
||||
|
||||
#define PGD_SECT_UNCACHED (0)
|
||||
#define PGD_SECT_BUFFERED (PGD_SECT_BUFFERABLE)
|
||||
#define PGD_SECT_WT (PGD_SECT_CACHEABLE)
|
||||
#define PGD_SECT_WB (PGD_SECT_CACHEABLE | PGD_SECT_BUFFERABLE)
|
||||
#define PGD_SECT_MINICACHE (PGD_SECT_TEX(1) | PGD_SECT_CACHEABLE)
|
||||
#define PGD_SECT_WBWA (PGD_SECT_TEX(1) | PGD_SECT_CACHEABLE | PGD_SECT_BUFFERABLE)
|
||||
#define PGD_SECT_NONSHARED_DEV (PGD_SECT_TEX(2))
|
||||
|
||||
|
||||
/*
|
||||
* + Level 2 descriptor (PTE)
|
||||
* - common
|
||||
*/
|
||||
#define PTE_TYPE_MASK (3 << 0)
|
||||
#define PTE_TYPE_FAULT (0 << 0)
|
||||
#define PTE_TYPE_LARGE (1 << 0)
|
||||
#define PTE_TYPE_SMALL (2 << 0)
|
||||
#define PTE_TYPE_EXT (3 << 0) /* ARMv5 */
|
||||
#define PTE_BUFFERABLE (1 << 2)
|
||||
#define PTE_CACHEABLE (1 << 3)
|
||||
|
||||
/*
|
||||
* - extended small page/tiny page
|
||||
*/
|
||||
#define PTE_EXT_XN (1 << 0) /* ARMv6 */
|
||||
#define PTE_EXT_AP_MASK (3 << 4)
|
||||
#define PTE_EXT_AP0 (1 << 4)
|
||||
#define PTE_EXT_AP1 (2 << 4)
|
||||
#define PTE_EXT_AP_UNO_SRO (0 << 4)
|
||||
#define PTE_EXT_AP_UNO_SRW (PTE_EXT_AP0)
|
||||
#define PTE_EXT_AP_URO_SRW (PTE_EXT_AP1)
|
||||
#define PTE_EXT_AP_URW_SRW (PTE_EXT_AP1|PTE_EXT_AP0)
|
||||
#define PTE_EXT_TEX(x) ((x) << 6) /* ARMv5 */
|
||||
#define PTE_EXT_APX (1 << 9) /* ARMv6 */
|
||||
#define PTE_EXT_SHARED (1 << 10) /* ARMv6 */
|
||||
#define PTE_EXT_NG (1 << 11) /* ARMv6 */
|
||||
|
||||
/*
|
||||
* - small page
|
||||
*/
|
||||
#define PTE_SMALL_AP_MASK (0xff << 4)
|
||||
#define PTE_SMALL_AP_UNO_SRO (0x00 << 4)
|
||||
#define PTE_SMALL_AP_UNO_SRW (0x55 << 4)
|
||||
#define PTE_SMALL_AP_URO_SRW (0xaa << 4)
|
||||
#define PTE_SMALL_AP_URW_SRW (0xff << 4)
|
||||
|
||||
|
||||
/*
|
||||
* sector table properities
|
||||
*/
|
||||
#define SECT_CB (PGD_SECT_CACHEABLE|PGD_SECT_BUFFERABLE) //cache_on, write_back
|
||||
#define SECT_CNB (PGD_SECT_CACHEABLE) //cache_on, write_through
|
||||
#define SECT_NCB (PGD_SECT_BUFFERABLE) //cache_off,WR_BUF on
|
||||
#define SECT_NCNB (0 << 2) //cache_off,WR_BUF off
|
||||
|
||||
#define SECT_AP_RW (PGD_SECT_AP0|PGD_SECT_AP1) //supervisor=RW, user=RW
|
||||
#define SECT_AP_RO (PGD_SECT_AP0|PGD_SECT_AP1|PGD_SECT_APX) //supervisor=RO, user=RO
|
||||
|
||||
#define SECT_RWX_CB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT) /* Read/Write/executable, cache, write back */
|
||||
#define SECT_RWX_CNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT) /* Read/Write/executable, cache, write through */
|
||||
#define SECT_RWX_NCNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_TYPE_SECT) /* Read/Write/executable without cache and write buffer */
|
||||
#define SECT_RWX_FAULT (SECT_AP_RW|PGD_DOMAIN(1)|PGD_TYPE_SECT) /* Read/Write without cache and write buffer */
|
||||
|
||||
#define SECT_RWNX_CB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write, cache, write back */
|
||||
#define SECT_RWNX_CNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write, cache, write through */
|
||||
#define SECT_RWNX_NCNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write without cache and write buffer */
|
||||
#define SECT_RWNX_FAULT (SECT_AP_RW|PGD_DOMAIN(1)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write without cache and write buffer */
|
||||
|
||||
|
||||
#define SECT_ROX_CB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT) /* Read Only/executable, cache, write back */
|
||||
#define SECT_ROX_CNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT) /* Read Only/executable, cache, write through */
|
||||
#define SECT_ROX_NCNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_TYPE_SECT) /* Read Only/executable without cache and write buffer */
|
||||
#define SECT_ROX_FAULT (SECT_AP_RO|PGD_DOMAIN(1)|PGD_TYPE_SECT) /* Read Only without cache and write buffer */
|
||||
|
||||
#define SECT_RONX_CB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only, cache, write back */
|
||||
#define SECT_RONX_CNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only, cache, write through */
|
||||
#define SECT_RONX_NCNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only without cache and write buffer */
|
||||
#define SECT_RONX_FAULT (SECT_AP_RO|PGD_DOMAIN(1)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only without cache and write buffer */
|
||||
|
||||
#define SECT_TO_PAGE (PGD_DOMAIN(0)|PGD_TYPE_TABLE) /* Level 2 descriptor (PTE) entry properity */
|
||||
|
||||
/*
|
||||
* page table properities
|
||||
*/
|
||||
#define PAGE_CB (PTE_BUFFERABLE|PTE_CACHEABLE) //cache_on, write_back
|
||||
#define PAGE_CNB (PTE_CACHEABLE) //cache_on, write_through
|
||||
#define PAGE_NCB (PTE_BUFFERABLE) //cache_off,WR_BUF on
|
||||
#define PAGE_NCNB (0 << 2) //cache_off,WR_BUF off
|
||||
|
||||
#define PAGE_AP_RW (PTE_EXT_AP0|PTE_EXT_AP1) //supervisor=RW, user=RW
|
||||
#define PAGE_AP_RO (PTE_EXT_AP0|PTE_EXT_AP1|PTE_EXT_APX) //supervisor=RO, user=RO
|
||||
|
||||
#define PAGE_RWX_CB (PAGE_AP_RW|PAGE_CB|PTE_TYPE_SMALL) /* Read/Write/executable, cache, write back */
|
||||
#define PAGE_RWX_CNB (PAGE_AP_RW|PAGE_CNB|PTE_TYPE_SMALL) /* Read/Write/executable, cache, write through */
|
||||
#define PAGE_RWX_NCNB (PAGE_AP_RW|PTE_TYPE_SMALL) /* Read/Write/executable without cache and write buffer */
|
||||
#define PAGE_RWX_FAULT (PAGE_AP_RW|PTE_TYPE_SMALL) /* Read/Write without cache and write buffer */
|
||||
|
||||
#define PAGE_RWNX_CB (PAGE_AP_RW|PAGE_CB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write, cache, write back */
|
||||
#define PAGE_RWNX_CNB (PAGE_AP_RW|PAGE_CNB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write, cache, write through */
|
||||
#define PAGE_RWNX_NCNB (PAGE_AP_RW|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write without cache and write buffer */
|
||||
#define PAGE_RWNX_FAULT (PAGE_AP_RW|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write without cache and write buffer */
|
||||
|
||||
|
||||
#define PAGE_ROX_CB (PAGE_AP_RO|PAGE_CB|PTE_TYPE_SMALL) /* Read Only/executable, cache, write back */
|
||||
#define PAGE_ROX_CNB (PAGE_AP_RO|PAGE_CNB|PTE_TYPE_SMALL) /* Read Only/executable, cache, write through */
|
||||
#define PAGE_ROX_NCNB (PAGE_AP_RO|PTE_TYPE_SMALL) /* Read Only/executable without cache and write buffer */
|
||||
#define PAGE_ROX_FAULT (PAGE_AP_RO|PTE_TYPE_SMALL) /* Read Only without cache and write buffer */
|
||||
|
||||
#define PAGE_RONX_CB (PAGE_AP_RO|PAGE_CB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only, cache, write back */
|
||||
#define PAGE_RONX_CNB (PAGE_AP_RO|PAGE_CNB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only, cache, write through */
|
||||
#define PAGE_RONX_NCNB (PAGE_AP_RO|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only without cache and write buffer */
|
||||
#define PAGE_RONX_FAULT (PAGE_AP_RO|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only without cache and write buffer */
|
||||
|
||||
|
||||
#define DESC_SEC (0x2|(1<<4))
|
||||
#define CB (3<<2) //cache_on, write_back
|
||||
#define CNB (2<<2) //cache_on, write_through
|
||||
#define NCB (1<<2) //cache_off,WR_BUF on
|
||||
#define NCNB (0<<2) //cache_off,WR_BUF off
|
||||
#define AP_RW (3<<10) //supervisor=RW, user=RW
|
||||
#define AP_RO (2<<10) //supervisor=RW, user=RO
|
||||
|
||||
#define DOMAIN_FAULT (0x0)
|
||||
#define DOMAIN_CHK (0x1)
|
||||
#define DOMAIN_NOTCHK (0x3)
|
||||
#define DOMAIN0 (0x0<<5)
|
||||
#define DOMAIN1 (0x1<<5)
|
||||
|
||||
#define DOMAIN0_ATTR (DOMAIN_CHK<<0)
|
||||
#define DOMAIN1_ATTR (DOMAIN_FAULT<<2)
|
||||
|
||||
#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) /* Read/Write, cache, write back */
|
||||
#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) /* Read/Write, cache, write through */
|
||||
#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
|
||||
#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
|
||||
|
||||
struct mem_desc {
|
||||
rt_uint32_t vaddr_start;
|
||||
rt_uint32_t vaddr_end;
|
||||
rt_uint32_t paddr_start;
|
||||
rt_uint32_t sect_attr; /* when page mapped */
|
||||
rt_uint32_t page_attr; /* only sector mapped valid */
|
||||
rt_uint32_t mapped_mode;
|
||||
#define SECT_MAPPED 0
|
||||
#define PAGE_MAPPED 1
|
||||
};
|
||||
|
||||
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size);
|
||||
|
||||
#endif
|
||||
|
||||
68
rt-thread/libcpu/arm/armv6/stack.c
Normal file
68
rt-thread/libcpu/arm/armv6/stack.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety copy from mini2440
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
|
||||
/*****************************/
|
||||
/* CPU Mode */
|
||||
/*****************************/
|
||||
#define USERMODE 0x10
|
||||
#define FIQMODE 0x11
|
||||
#define IRQMODE 0x12
|
||||
#define SVCMODE 0x13
|
||||
#define ABORTMODE 0x17
|
||||
#define UNDEFMODE 0x1b
|
||||
#define MODEMASK 0x1f
|
||||
#define NOINT 0xc0
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
|
||||
rt_uint8_t *stack_addr, void *texit)
|
||||
{
|
||||
rt_uint32_t *stk;
|
||||
|
||||
stack_addr += sizeof(rt_uint32_t);
|
||||
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
|
||||
stk = (rt_uint32_t *)stack_addr;
|
||||
|
||||
*(--stk) = (rt_uint32_t)tentry; /* entry point */
|
||||
*(--stk) = (rt_uint32_t)texit; /* lr */
|
||||
*(--stk) = 0xdeadbeef; /* r12 */
|
||||
*(--stk) = 0xdeadbeef; /* r11 */
|
||||
*(--stk) = 0xdeadbeef; /* r10 */
|
||||
*(--stk) = 0xdeadbeef; /* r9 */
|
||||
*(--stk) = 0xdeadbeef; /* r8 */
|
||||
*(--stk) = 0xdeadbeef; /* r7 */
|
||||
*(--stk) = 0xdeadbeef; /* r6 */
|
||||
*(--stk) = 0xdeadbeef; /* r5 */
|
||||
*(--stk) = 0xdeadbeef; /* r4 */
|
||||
*(--stk) = 0xdeadbeef; /* r3 */
|
||||
*(--stk) = 0xdeadbeef; /* r2 */
|
||||
*(--stk) = 0xdeadbeef; /* r1 */
|
||||
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
|
||||
|
||||
/* cpsr */
|
||||
if ((rt_uint32_t)tentry & 0x01)
|
||||
*(--stk) = SVCMODE | 0x20; /* thumb mode */
|
||||
else
|
||||
*(--stk) = SVCMODE; /* arm mode */
|
||||
|
||||
/* return task's current stack address */
|
||||
return (rt_uint8_t *)stk;
|
||||
}
|
||||
|
||||
38
rt-thread/libcpu/arm/armv6/vfp.c
Normal file
38
rt-thread/libcpu/arm/armv6/vfp.c
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-11-07 weety first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include "vfp.h"
|
||||
|
||||
#ifdef RT_USING_VFP
|
||||
|
||||
void vfp_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int value;
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 2"
|
||||
:"=r"(value)
|
||||
:);
|
||||
value |= 0xf00000;/*enable CP10, CP11 user access*/
|
||||
asm volatile("mcr p15, 0, %0, c1, c0, 2"
|
||||
:
|
||||
:"r"(value));
|
||||
|
||||
asm volatile("fmrx %0, fpexc"
|
||||
:"=r"(value));
|
||||
value |=(1<<30);
|
||||
asm volatile("fmxr fpexc, %0"
|
||||
:
|
||||
:"r"(value));
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
96
rt-thread/libcpu/arm/armv6/vfp.h
Normal file
96
rt-thread/libcpu/arm/armv6/vfp.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-11-07 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __VFP_H__
|
||||
#define __VFP_H__
|
||||
|
||||
/* FPSID register bits */
|
||||
#define FPSID_IMPLEMENTER_BIT (24)
|
||||
#define FPSID_IMPLEMENTER_MASK (0xff << FPSID_IMPLEMENTER_BIT)
|
||||
#define FPSID_SW (1 << 23)
|
||||
#define FPSID_FORMAT_BIT (21)
|
||||
#define FPSID_FORMAT_MASK (0x3 << FPSID_FORMAT_BIT)
|
||||
#define FPSID_NODOUBLE (1 << 20)
|
||||
#define FPSID_ARCH_BIT (16)
|
||||
#define FPSID_ARCH_MASK (0xF << FPSID_ARCH_BIT)
|
||||
#define FPSID_PART_BIT (8)
|
||||
#define FPSID_PART_MASK (0xFF << FPSID_PART_BIT)
|
||||
#define FPSID_VARIANT_BIT (4)
|
||||
#define FPSID_VARIANT_MASK (0xF << FPSID_VARIANT_BIT)
|
||||
#define FPSID_REVISION_BIT (0)
|
||||
#define FPSID_REVISION_MASK (0xF << FPSID_REVISION_BIT)
|
||||
|
||||
/* FPSCR register bits */
|
||||
#define FPSCR_DN (1<<25) /* Default NaN mode enable bit */
|
||||
#define FPSCR_FZ (1<<24) /* Flush-to-zero mode enable bit */
|
||||
#define FPSCR_RN (0<<22) /* Round to nearest (RN) mode */
|
||||
#define FPSCR_RP (1<<22) /* Round towards plus infinity (RP) mode */
|
||||
#define FPSCR_RM (2<<22) /* Round towards minus infinity (RM) mode */
|
||||
#define FPSCR_RZ (3<<22) /* Round towards zero (RZ) mode */
|
||||
#define FPSCR_RMODE_BIT (22)
|
||||
#define FPSCR_RMODE_MASK (3 << FPSCR_RMODE_BIT)
|
||||
#define FPSCR_STRIDE_BIT (20)
|
||||
#define FPSCR_STRIDE_MASK (3 << FPSCR_STRIDE_BIT)
|
||||
#define FPSCR_LENGTH_BIT (16)
|
||||
#define FPSCR_LENGTH_MASK (7 << FPSCR_LENGTH_BIT)
|
||||
#define FPSCR_IDE (1<<15) /* Input Subnormal exception trap enable bit */
|
||||
#define FPSCR_IXE (1<<12) /* Inexact exception trap enable bit */
|
||||
#define FPSCR_UFE (1<<11) /* Underflow exception trap enable bit */
|
||||
#define FPSCR_OFE (1<<10) /* Overflow exception trap enable bit */
|
||||
#define FPSCR_DZE (1<<9) /* Division by Zero exception trap enable bit */
|
||||
#define FPSCR_IOE (1<<8) /* Invalid Operation exception trap enable bit */
|
||||
#define FPSCR_IDC (1<<7) /* Input Subnormal cumulative exception flag */
|
||||
#define FPSCR_IXC (1<<4) /* Inexact cumulative exception flag */
|
||||
#define FPSCR_UFC (1<<3) /* Underflow cumulative exception flag */
|
||||
#define FPSCR_OFC (1<<2) /* Overflow cumulative exception flag */
|
||||
#define FPSCR_DZC (1<<1) /* Division by Zero cumulative exception flag */
|
||||
#define FPSCR_IOC (1<<0) /* Invalid Operation cumulative exception flag */
|
||||
|
||||
/* FPEXC register bits */
|
||||
#define FPEXC_EX (1 << 31) /* When EX is set, the VFP coprocessor is in the exceptional state */
|
||||
#define FPEXC_EN (1 << 30) /* VFP enable bit */
|
||||
#define FPEXC_DEX (1 << 29) /* Defined synchronous instruction exceptional flag */
|
||||
#define FPEXC_FP2V (1 << 28) /* FPINST2 instruction valid flag */
|
||||
#define FPEXC_LENGTH_BIT (8)
|
||||
#define FPEXC_LENGTH_MASK (7 << FPEXC_LENGTH_BIT)
|
||||
#define FPEXC_INV (1 << 7) /* Input exception flag */
|
||||
#define FPEXC_UFC (1 << 3) /* Potential underflow flag */
|
||||
#define FPEXC_OFC (1 << 2) /* Potential overflow flag */
|
||||
#define FPEXC_IOC (1 << 0) /* Potential invalid operation flag */
|
||||
#define FPEXC_TRAP_MASK (FPEXC_INV|FPEXC_UFC|FPEXC_OFC|FPEXC_IOC)
|
||||
|
||||
|
||||
/* MVFR0 register bits */
|
||||
#define MVFR0_A_SIMD_BIT (0)
|
||||
#define MVFR0_A_SIMD_MASK (0xf << MVFR0_A_SIMD_BIT)
|
||||
|
||||
|
||||
/* thread switch micro */
|
||||
#define THREAD_INIT 0
|
||||
#define THREAD_EXIT 1
|
||||
|
||||
/*
|
||||
* get VFP register
|
||||
*/
|
||||
|
||||
#define vmrs(vfp) ({ \
|
||||
rt_uint32_t var; \
|
||||
asm("vmrs %0, "#vfp"" : "=r" (var) : : "cc"); \
|
||||
var; \
|
||||
})
|
||||
|
||||
#define vmsr(vfp, var) \
|
||||
asm("vmsr "#vfp", %0" \
|
||||
: : "r" (var) : "cc")
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
63
rt-thread/libcpu/arm/common/backtrace.c
Normal file
63
rt-thread/libcpu/arm/common/backtrace.c
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2008-07-29 Bernard first version from QiuYi implementation
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
/*
|
||||
-->High Address,Stack Top
|
||||
PC<------|
|
||||
LR |
|
||||
IP |
|
||||
FP |
|
||||
...... |
|
||||
PC <-| |
|
||||
LR | |
|
||||
IP | |
|
||||
FP---|-- |
|
||||
...... |
|
||||
PC |
|
||||
LR |
|
||||
IP |
|
||||
FP---
|
||||
-->Low Address,Stack Bottom
|
||||
*/
|
||||
void rt_hw_backtrace(rt_uint32_t *fp, rt_uint32_t thread_entry)
|
||||
{
|
||||
rt_uint32_t i, pc, func_entry;
|
||||
|
||||
pc = *fp;
|
||||
rt_kprintf("[0x%x]\n", pc - 0xC);
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
fp = (rt_uint32_t *) * (fp - 3);
|
||||
pc = *fp ;
|
||||
|
||||
func_entry = pc - 0xC;
|
||||
|
||||
if (func_entry <= 0x30000000) break;
|
||||
|
||||
if (func_entry == thread_entry)
|
||||
{
|
||||
rt_kprintf("EntryPoint:0x%x\n", func_entry);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
rt_kprintf("[0x%x]\n", func_entry);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void rt_hw_backtrace(rt_uint32_t *fp, rt_uint32_t thread_entry)
|
||||
{
|
||||
/* old compiler implementation */
|
||||
}
|
||||
#endif
|
||||
12
rt-thread/libcpu/arm/common/div0.c
Normal file
12
rt-thread/libcpu/arm/common/div0.c
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
void __div0(void)
|
||||
{
|
||||
while (1) ;
|
||||
}
|
||||
401
rt-thread/libcpu/arm/common/divsi3.S
Normal file
401
rt-thread/libcpu/arm/common/divsi3.S
Normal file
@ -0,0 +1,401 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
/* $NetBSD: divsi3.S,v 1.5 2005/02/26 22:58:56 perry Exp $ */
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* stack is aligned as there's a possibility of branching to L_overflow
|
||||
* which makes a C call
|
||||
*/
|
||||
.text
|
||||
.align 0
|
||||
.globl __umodsi3
|
||||
.type __umodsi3 , function
|
||||
__umodsi3:
|
||||
stmfd sp!, {lr}
|
||||
sub sp, sp, #4 /* align stack */
|
||||
bl .L_udivide
|
||||
add sp, sp, #4 /* unalign stack */
|
||||
mov r0, r1
|
||||
ldmfd sp!, {pc}
|
||||
|
||||
.text
|
||||
.align 0
|
||||
.globl __modsi3
|
||||
.type __modsi3 , function
|
||||
__modsi3:
|
||||
stmfd sp!, {lr}
|
||||
sub sp, sp, #4 /* align stack */
|
||||
bl .L_divide
|
||||
add sp, sp, #4 /* unalign stack */
|
||||
mov r0, r1
|
||||
ldmfd sp!, {pc}
|
||||
|
||||
.L_overflow:
|
||||
/* XXX should cause a fatal error */
|
||||
mvn r0, #0
|
||||
mov pc, lr
|
||||
|
||||
.text
|
||||
.align 0
|
||||
.globl __udivsi3
|
||||
.type __udivsi3 , function
|
||||
__udivsi3:
|
||||
.L_udivide: /* r0 = r0 / r1; r1 = r0 % r1 */
|
||||
eor r0, r1, r0
|
||||
eor r1, r0, r1
|
||||
eor r0, r1, r0
|
||||
/* r0 = r1 / r0; r1 = r1 % r0 */
|
||||
cmp r0, #1
|
||||
bcc .L_overflow
|
||||
beq .L_divide_l0
|
||||
mov ip, #0
|
||||
movs r1, r1
|
||||
bpl .L_divide_l1
|
||||
orr ip, ip, #0x20000000 /* ip bit 0x20000000 = -ve r1 */
|
||||
movs r1, r1, lsr #1
|
||||
orrcs ip, ip, #0x10000000 /* ip bit 0x10000000 = bit 0 of r1 */
|
||||
b .L_divide_l1
|
||||
|
||||
.L_divide_l0: /* r0 == 1 */
|
||||
mov r0, r1
|
||||
mov r1, #0
|
||||
mov pc, lr
|
||||
|
||||
.text
|
||||
.align 0
|
||||
.globl __divsi3
|
||||
.type __divsi3 , function
|
||||
__divsi3:
|
||||
.L_divide: /* r0 = r0 / r1; r1 = r0 % r1 */
|
||||
eor r0, r1, r0
|
||||
eor r1, r0, r1
|
||||
eor r0, r1, r0
|
||||
/* r0 = r1 / r0; r1 = r1 % r0 */
|
||||
cmp r0, #1
|
||||
bcc .L_overflow
|
||||
beq .L_divide_l0
|
||||
ands ip, r0, #0x80000000
|
||||
rsbmi r0, r0, #0
|
||||
ands r2, r1, #0x80000000
|
||||
eor ip, ip, r2
|
||||
rsbmi r1, r1, #0
|
||||
orr ip, r2, ip, lsr #1 /* ip bit 0x40000000 = -ve division */
|
||||
/* ip bit 0x80000000 = -ve remainder */
|
||||
|
||||
.L_divide_l1:
|
||||
mov r2, #1
|
||||
mov r3, #0
|
||||
|
||||
/*
|
||||
* If the highest bit of the dividend is set, we have to be
|
||||
* careful when shifting the divisor. Test this.
|
||||
*/
|
||||
movs r1,r1
|
||||
bpl .L_old_code
|
||||
|
||||
/*
|
||||
* At this point, the highest bit of r1 is known to be set.
|
||||
* We abuse this below in the tst instructions.
|
||||
*/
|
||||
tst r1, r0 /*, lsl #0 */
|
||||
bmi .L_divide_b1
|
||||
tst r1, r0, lsl #1
|
||||
bmi .L_divide_b2
|
||||
tst r1, r0, lsl #2
|
||||
bmi .L_divide_b3
|
||||
tst r1, r0, lsl #3
|
||||
bmi .L_divide_b4
|
||||
tst r1, r0, lsl #4
|
||||
bmi .L_divide_b5
|
||||
tst r1, r0, lsl #5
|
||||
bmi .L_divide_b6
|
||||
tst r1, r0, lsl #6
|
||||
bmi .L_divide_b7
|
||||
tst r1, r0, lsl #7
|
||||
bmi .L_divide_b8
|
||||
tst r1, r0, lsl #8
|
||||
bmi .L_divide_b9
|
||||
tst r1, r0, lsl #9
|
||||
bmi .L_divide_b10
|
||||
tst r1, r0, lsl #10
|
||||
bmi .L_divide_b11
|
||||
tst r1, r0, lsl #11
|
||||
bmi .L_divide_b12
|
||||
tst r1, r0, lsl #12
|
||||
bmi .L_divide_b13
|
||||
tst r1, r0, lsl #13
|
||||
bmi .L_divide_b14
|
||||
tst r1, r0, lsl #14
|
||||
bmi .L_divide_b15
|
||||
tst r1, r0, lsl #15
|
||||
bmi .L_divide_b16
|
||||
tst r1, r0, lsl #16
|
||||
bmi .L_divide_b17
|
||||
tst r1, r0, lsl #17
|
||||
bmi .L_divide_b18
|
||||
tst r1, r0, lsl #18
|
||||
bmi .L_divide_b19
|
||||
tst r1, r0, lsl #19
|
||||
bmi .L_divide_b20
|
||||
tst r1, r0, lsl #20
|
||||
bmi .L_divide_b21
|
||||
tst r1, r0, lsl #21
|
||||
bmi .L_divide_b22
|
||||
tst r1, r0, lsl #22
|
||||
bmi .L_divide_b23
|
||||
tst r1, r0, lsl #23
|
||||
bmi .L_divide_b24
|
||||
tst r1, r0, lsl #24
|
||||
bmi .L_divide_b25
|
||||
tst r1, r0, lsl #25
|
||||
bmi .L_divide_b26
|
||||
tst r1, r0, lsl #26
|
||||
bmi .L_divide_b27
|
||||
tst r1, r0, lsl #27
|
||||
bmi .L_divide_b28
|
||||
tst r1, r0, lsl #28
|
||||
bmi .L_divide_b29
|
||||
tst r1, r0, lsl #29
|
||||
bmi .L_divide_b30
|
||||
tst r1, r0, lsl #30
|
||||
bmi .L_divide_b31
|
||||
/*
|
||||
* instead of:
|
||||
* tst r1, r0, lsl #31
|
||||
* bmi .L_divide_b32
|
||||
*/
|
||||
b .L_divide_b32
|
||||
|
||||
.L_old_code:
|
||||
cmp r1, r0
|
||||
bcc .L_divide_b0
|
||||
cmp r1, r0, lsl #1
|
||||
bcc .L_divide_b1
|
||||
cmp r1, r0, lsl #2
|
||||
bcc .L_divide_b2
|
||||
cmp r1, r0, lsl #3
|
||||
bcc .L_divide_b3
|
||||
cmp r1, r0, lsl #4
|
||||
bcc .L_divide_b4
|
||||
cmp r1, r0, lsl #5
|
||||
bcc .L_divide_b5
|
||||
cmp r1, r0, lsl #6
|
||||
bcc .L_divide_b6
|
||||
cmp r1, r0, lsl #7
|
||||
bcc .L_divide_b7
|
||||
cmp r1, r0, lsl #8
|
||||
bcc .L_divide_b8
|
||||
cmp r1, r0, lsl #9
|
||||
bcc .L_divide_b9
|
||||
cmp r1, r0, lsl #10
|
||||
bcc .L_divide_b10
|
||||
cmp r1, r0, lsl #11
|
||||
bcc .L_divide_b11
|
||||
cmp r1, r0, lsl #12
|
||||
bcc .L_divide_b12
|
||||
cmp r1, r0, lsl #13
|
||||
bcc .L_divide_b13
|
||||
cmp r1, r0, lsl #14
|
||||
bcc .L_divide_b14
|
||||
cmp r1, r0, lsl #15
|
||||
bcc .L_divide_b15
|
||||
cmp r1, r0, lsl #16
|
||||
bcc .L_divide_b16
|
||||
cmp r1, r0, lsl #17
|
||||
bcc .L_divide_b17
|
||||
cmp r1, r0, lsl #18
|
||||
bcc .L_divide_b18
|
||||
cmp r1, r0, lsl #19
|
||||
bcc .L_divide_b19
|
||||
cmp r1, r0, lsl #20
|
||||
bcc .L_divide_b20
|
||||
cmp r1, r0, lsl #21
|
||||
bcc .L_divide_b21
|
||||
cmp r1, r0, lsl #22
|
||||
bcc .L_divide_b22
|
||||
cmp r1, r0, lsl #23
|
||||
bcc .L_divide_b23
|
||||
cmp r1, r0, lsl #24
|
||||
bcc .L_divide_b24
|
||||
cmp r1, r0, lsl #25
|
||||
bcc .L_divide_b25
|
||||
cmp r1, r0, lsl #26
|
||||
bcc .L_divide_b26
|
||||
cmp r1, r0, lsl #27
|
||||
bcc .L_divide_b27
|
||||
cmp r1, r0, lsl #28
|
||||
bcc .L_divide_b28
|
||||
cmp r1, r0, lsl #29
|
||||
bcc .L_divide_b29
|
||||
cmp r1, r0, lsl #30
|
||||
bcc .L_divide_b30
|
||||
.L_divide_b32:
|
||||
cmp r1, r0, lsl #31
|
||||
subhs r1, r1,r0, lsl #31
|
||||
addhs r3, r3,r2, lsl #31
|
||||
.L_divide_b31:
|
||||
cmp r1, r0, lsl #30
|
||||
subhs r1, r1,r0, lsl #30
|
||||
addhs r3, r3,r2, lsl #30
|
||||
.L_divide_b30:
|
||||
cmp r1, r0, lsl #29
|
||||
subhs r1, r1,r0, lsl #29
|
||||
addhs r3, r3,r2, lsl #29
|
||||
.L_divide_b29:
|
||||
cmp r1, r0, lsl #28
|
||||
subhs r1, r1,r0, lsl #28
|
||||
addhs r3, r3,r2, lsl #28
|
||||
.L_divide_b28:
|
||||
cmp r1, r0, lsl #27
|
||||
subhs r1, r1,r0, lsl #27
|
||||
addhs r3, r3,r2, lsl #27
|
||||
.L_divide_b27:
|
||||
cmp r1, r0, lsl #26
|
||||
subhs r1, r1,r0, lsl #26
|
||||
addhs r3, r3,r2, lsl #26
|
||||
.L_divide_b26:
|
||||
cmp r1, r0, lsl #25
|
||||
subhs r1, r1,r0, lsl #25
|
||||
addhs r3, r3,r2, lsl #25
|
||||
.L_divide_b25:
|
||||
cmp r1, r0, lsl #24
|
||||
subhs r1, r1,r0, lsl #24
|
||||
addhs r3, r3,r2, lsl #24
|
||||
.L_divide_b24:
|
||||
cmp r1, r0, lsl #23
|
||||
subhs r1, r1,r0, lsl #23
|
||||
addhs r3, r3,r2, lsl #23
|
||||
.L_divide_b23:
|
||||
cmp r1, r0, lsl #22
|
||||
subhs r1, r1,r0, lsl #22
|
||||
addhs r3, r3,r2, lsl #22
|
||||
.L_divide_b22:
|
||||
cmp r1, r0, lsl #21
|
||||
subhs r1, r1,r0, lsl #21
|
||||
addhs r3, r3,r2, lsl #21
|
||||
.L_divide_b21:
|
||||
cmp r1, r0, lsl #20
|
||||
subhs r1, r1,r0, lsl #20
|
||||
addhs r3, r3,r2, lsl #20
|
||||
.L_divide_b20:
|
||||
cmp r1, r0, lsl #19
|
||||
subhs r1, r1,r0, lsl #19
|
||||
addhs r3, r3,r2, lsl #19
|
||||
.L_divide_b19:
|
||||
cmp r1, r0, lsl #18
|
||||
subhs r1, r1,r0, lsl #18
|
||||
addhs r3, r3,r2, lsl #18
|
||||
.L_divide_b18:
|
||||
cmp r1, r0, lsl #17
|
||||
subhs r1, r1,r0, lsl #17
|
||||
addhs r3, r3,r2, lsl #17
|
||||
.L_divide_b17:
|
||||
cmp r1, r0, lsl #16
|
||||
subhs r1, r1,r0, lsl #16
|
||||
addhs r3, r3,r2, lsl #16
|
||||
.L_divide_b16:
|
||||
cmp r1, r0, lsl #15
|
||||
subhs r1, r1,r0, lsl #15
|
||||
addhs r3, r3,r2, lsl #15
|
||||
.L_divide_b15:
|
||||
cmp r1, r0, lsl #14
|
||||
subhs r1, r1,r0, lsl #14
|
||||
addhs r3, r3,r2, lsl #14
|
||||
.L_divide_b14:
|
||||
cmp r1, r0, lsl #13
|
||||
subhs r1, r1,r0, lsl #13
|
||||
addhs r3, r3,r2, lsl #13
|
||||
.L_divide_b13:
|
||||
cmp r1, r0, lsl #12
|
||||
subhs r1, r1,r0, lsl #12
|
||||
addhs r3, r3,r2, lsl #12
|
||||
.L_divide_b12:
|
||||
cmp r1, r0, lsl #11
|
||||
subhs r1, r1,r0, lsl #11
|
||||
addhs r3, r3,r2, lsl #11
|
||||
.L_divide_b11:
|
||||
cmp r1, r0, lsl #10
|
||||
subhs r1, r1,r0, lsl #10
|
||||
addhs r3, r3,r2, lsl #10
|
||||
.L_divide_b10:
|
||||
cmp r1, r0, lsl #9
|
||||
subhs r1, r1,r0, lsl #9
|
||||
addhs r3, r3,r2, lsl #9
|
||||
.L_divide_b9:
|
||||
cmp r1, r0, lsl #8
|
||||
subhs r1, r1,r0, lsl #8
|
||||
addhs r3, r3,r2, lsl #8
|
||||
.L_divide_b8:
|
||||
cmp r1, r0, lsl #7
|
||||
subhs r1, r1,r0, lsl #7
|
||||
addhs r3, r3,r2, lsl #7
|
||||
.L_divide_b7:
|
||||
cmp r1, r0, lsl #6
|
||||
subhs r1, r1,r0, lsl #6
|
||||
addhs r3, r3,r2, lsl #6
|
||||
.L_divide_b6:
|
||||
cmp r1, r0, lsl #5
|
||||
subhs r1, r1,r0, lsl #5
|
||||
addhs r3, r3,r2, lsl #5
|
||||
.L_divide_b5:
|
||||
cmp r1, r0, lsl #4
|
||||
subhs r1, r1,r0, lsl #4
|
||||
addhs r3, r3,r2, lsl #4
|
||||
.L_divide_b4:
|
||||
cmp r1, r0, lsl #3
|
||||
subhs r1, r1,r0, lsl #3
|
||||
addhs r3, r3,r2, lsl #3
|
||||
.L_divide_b3:
|
||||
cmp r1, r0, lsl #2
|
||||
subhs r1, r1,r0, lsl #2
|
||||
addhs r3, r3,r2, lsl #2
|
||||
.L_divide_b2:
|
||||
cmp r1, r0, lsl #1
|
||||
subhs r1, r1,r0, lsl #1
|
||||
addhs r3, r3,r2, lsl #1
|
||||
.L_divide_b1:
|
||||
cmp r1, r0
|
||||
subhs r1, r1, r0
|
||||
addhs r3, r3, r2
|
||||
.L_divide_b0:
|
||||
|
||||
tst ip, #0x20000000
|
||||
bne .L_udivide_l1
|
||||
mov r0, r3
|
||||
cmp ip, #0
|
||||
rsbmi r1, r1, #0
|
||||
movs ip, ip, lsl #1
|
||||
bicmi r0, r0, #0x80000000 /* Fix incase we divided 0x80000000 */
|
||||
rsbmi r0, r0, #0
|
||||
mov pc, lr
|
||||
|
||||
.L_udivide_l1:
|
||||
tst ip, #0x10000000
|
||||
mov r1, r1, lsl #1
|
||||
orrne r1, r1, #1
|
||||
mov r3, r3, lsl #1
|
||||
cmp r1, r0
|
||||
subhs r1, r1, r0
|
||||
addhs r3, r3, r2
|
||||
mov r0, r3
|
||||
mov pc, lr
|
||||
38
rt-thread/libcpu/arm/common/showmem.c
Normal file
38
rt-thread/libcpu/arm/common/showmem.c
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2008-07-29 Bernard first version from QiuYi implementation
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
void rt_hw_show_memory(rt_uint32_t addr, rt_uint32_t size)
|
||||
{
|
||||
unsigned int i = 0, j = 0;
|
||||
|
||||
RT_ASSERT(addr);
|
||||
|
||||
addr = addr & ~0xF;
|
||||
size = 4 * ((size + 3) / 4);
|
||||
|
||||
while (i < size)
|
||||
{
|
||||
rt_kprintf("0x%08x: ", addr);
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
rt_kprintf("0x%08x ", *(rt_uint32_t *)addr);
|
||||
|
||||
addr += 4;
|
||||
i++;
|
||||
}
|
||||
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
78
rt-thread/libcpu/arm/cortex-a/armv7.h
Normal file
78
rt-thread/libcpu/arm/cortex-a/armv7.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
#ifndef __ARMV7_H__
|
||||
#define __ARMV7_H__
|
||||
|
||||
/* the exception stack without VFP registers */
|
||||
struct rt_hw_exp_stack
|
||||
{
|
||||
unsigned long r0;
|
||||
unsigned long r1;
|
||||
unsigned long r2;
|
||||
unsigned long r3;
|
||||
unsigned long r4;
|
||||
unsigned long r5;
|
||||
unsigned long r6;
|
||||
unsigned long r7;
|
||||
unsigned long r8;
|
||||
unsigned long r9;
|
||||
unsigned long r10;
|
||||
unsigned long fp;
|
||||
unsigned long ip;
|
||||
unsigned long sp;
|
||||
unsigned long lr;
|
||||
unsigned long pc;
|
||||
unsigned long cpsr;
|
||||
};
|
||||
|
||||
struct rt_hw_stack
|
||||
{
|
||||
unsigned long cpsr;
|
||||
unsigned long r0;
|
||||
unsigned long r1;
|
||||
unsigned long r2;
|
||||
unsigned long r3;
|
||||
unsigned long r4;
|
||||
unsigned long r5;
|
||||
unsigned long r6;
|
||||
unsigned long r7;
|
||||
unsigned long r8;
|
||||
unsigned long r9;
|
||||
unsigned long r10;
|
||||
unsigned long fp;
|
||||
unsigned long ip;
|
||||
unsigned long lr;
|
||||
unsigned long pc;
|
||||
};
|
||||
|
||||
#define USERMODE 0x10
|
||||
#define FIQMODE 0x11
|
||||
#define IRQMODE 0x12
|
||||
#define SVCMODE 0x13
|
||||
#define MONITORMODE 0x16
|
||||
#define ABORTMODE 0x17
|
||||
#define HYPMODE 0x1b
|
||||
#define UNDEFMODE 0x1b
|
||||
#define MODEMASK 0x1f
|
||||
#define NOINT 0xc0
|
||||
|
||||
#define T_Bit (1<<5)
|
||||
#define F_Bit (1<<6)
|
||||
#define I_Bit (1<<7)
|
||||
#define A_Bit (1<<8)
|
||||
#define E_Bit (1<<9)
|
||||
#define J_Bit (1<<24)
|
||||
|
||||
#define PABT_EXCEPTION 0x1
|
||||
#define DABT_EXCEPTION 0x2
|
||||
#define UND_EXCEPTION 0x3
|
||||
#define SWI_EXCEPTION 0x4
|
||||
#define RESV_EXCEPTION 0xF
|
||||
|
||||
#endif
|
||||
148
rt-thread/libcpu/arm/cortex-a/cache.c
Normal file
148
rt-thread/libcpu/arm/cortex-a/cache.c
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-03-29 quanzhao the first version
|
||||
*/
|
||||
#include <rthw.h>
|
||||
#include <rtdef.h>
|
||||
|
||||
rt_inline rt_uint32_t rt_cpu_icache_line_size(void)
|
||||
{
|
||||
rt_uint32_t ctr;
|
||||
asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r"(ctr));
|
||||
return 4 << (ctr & 0xF);
|
||||
}
|
||||
|
||||
rt_inline rt_uint32_t rt_cpu_dcache_line_size(void)
|
||||
{
|
||||
rt_uint32_t ctr;
|
||||
asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r"(ctr));
|
||||
return 4 << ((ctr >> 16) & 0xF);
|
||||
}
|
||||
|
||||
void rt_hw_cpu_icache_invalidate(void *addr, int size)
|
||||
{
|
||||
rt_uint32_t line_size = rt_cpu_icache_line_size();
|
||||
rt_uint32_t start_addr = (rt_uint32_t)addr;
|
||||
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
|
||||
|
||||
asm volatile ("dmb":::"memory");
|
||||
start_addr &= ~(line_size-1);
|
||||
end_addr &= ~(line_size-1);
|
||||
while (start_addr < end_addr)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c5, 1" :: "r"(start_addr)); /* icimvau */
|
||||
start_addr += line_size;
|
||||
}
|
||||
asm volatile ("dsb\n\tisb":::"memory");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_invalidate(void *addr, int size)
|
||||
{
|
||||
rt_uint32_t line_size = rt_cpu_dcache_line_size();
|
||||
rt_uint32_t start_addr = (rt_uint32_t)addr;
|
||||
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
|
||||
|
||||
asm volatile ("dmb":::"memory");
|
||||
start_addr &= ~(line_size-1);
|
||||
end_addr &= ~(line_size-1);
|
||||
while (start_addr < end_addr)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c6, 1" :: "r"(start_addr)); /* dcimvac */
|
||||
start_addr += line_size;
|
||||
}
|
||||
asm volatile ("dsb":::"memory");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_inv_range(void *addr, int size)
|
||||
{
|
||||
rt_uint32_t line_size = rt_cpu_dcache_line_size();
|
||||
rt_uint32_t start_addr = (rt_uint32_t)addr;
|
||||
rt_uint32_t end_addr = (rt_uint32_t)addr + size;
|
||||
|
||||
asm volatile ("dmb":::"memory");
|
||||
|
||||
if ((start_addr & (line_size - 1)) != 0)
|
||||
{
|
||||
start_addr &= ~(line_size - 1);
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 1" :: "r"(start_addr));
|
||||
start_addr += line_size;
|
||||
asm volatile ("dsb":::"memory");
|
||||
}
|
||||
|
||||
if ((end_addr & (line_size - 1)) != 0)
|
||||
{
|
||||
end_addr &= ~(line_size - 1);
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 1" :: "r"(end_addr));
|
||||
asm volatile ("dsb":::"memory");
|
||||
}
|
||||
|
||||
while (start_addr < end_addr)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c6, 1" :: "r"(start_addr)); /* dcimvac */
|
||||
start_addr += line_size;
|
||||
}
|
||||
asm volatile ("dsb":::"memory");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_clean(void *addr, int size)
|
||||
{
|
||||
rt_uint32_t line_size = rt_cpu_dcache_line_size();
|
||||
rt_uint32_t start_addr = (rt_uint32_t)addr;
|
||||
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
|
||||
|
||||
asm volatile ("dmb":::"memory");
|
||||
start_addr &= ~(line_size-1);
|
||||
end_addr &= ~(line_size-1);
|
||||
while (start_addr < end_addr)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c10, 1" :: "r"(start_addr)); /* dccmvac */
|
||||
start_addr += line_size;
|
||||
}
|
||||
asm volatile ("dsb":::"memory");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_clean_inv(void *addr, int size)
|
||||
{
|
||||
rt_uint32_t line_size = rt_cpu_dcache_line_size();
|
||||
rt_uint32_t start_addr = (rt_uint32_t)addr;
|
||||
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
|
||||
|
||||
asm volatile ("dmb":::"memory");
|
||||
start_addr &= ~(line_size-1);
|
||||
end_addr &= ~(line_size-1);
|
||||
while (start_addr < end_addr)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 1" :: "r"(start_addr));
|
||||
start_addr += line_size;
|
||||
}
|
||||
asm volatile ("dsb":::"memory");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
|
||||
{
|
||||
if (ops == RT_HW_CACHE_INVALIDATE)
|
||||
rt_hw_cpu_icache_invalidate(addr, size);
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
|
||||
{
|
||||
if (ops == RT_HW_CACHE_FLUSH)
|
||||
rt_hw_cpu_dcache_clean(addr, size);
|
||||
else if (ops == RT_HW_CACHE_INVALIDATE)
|
||||
rt_hw_cpu_dcache_invalidate(addr, size);
|
||||
}
|
||||
|
||||
rt_base_t rt_hw_cpu_icache_status(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
rt_base_t rt_hw_cpu_dcache_status(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
182
rt-thread/libcpu/arm/cortex-a/context_gcc.S
Normal file
182
rt-thread/libcpu/arm/cortex-a/context_gcc.S
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-05 Bernard the first version
|
||||
*/
|
||||
|
||||
#include "rtconfig.h"
|
||||
.section .text, "ax"
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
#define rt_hw_interrupt_disable rt_hw_local_irq_disable
|
||||
#define rt_hw_interrupt_enable rt_hw_local_irq_enable
|
||||
#endif
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.globl rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
mrs r0, cpsr
|
||||
cpsid i
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.globl rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
msr cpsr, r0
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to, struct rt_thread *to_thread);
|
||||
* r0 --> to (thread stack)
|
||||
* r1 --> to_thread
|
||||
*/
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
ldr sp, [r0] @ get new task stack pointer
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
mov r0, r1
|
||||
bl rt_cpus_lock_status_restore
|
||||
#endif /*RT_USING_SMP*/
|
||||
b rt_hw_context_switch_exit
|
||||
|
||||
.section .bss.share.isr
|
||||
_guest_switch_lvl:
|
||||
.word 0
|
||||
|
||||
.globl vmm_virq_update
|
||||
|
||||
.section .text.isr, "ax"
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to, struct rt_thread *to_thread);
|
||||
* r0 --> from (from_thread stack)
|
||||
* r1 --> to (to_thread stack)
|
||||
* r2 --> to_thread
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC)
|
||||
stmfd sp!, {r0-r12, lr} @ push lr & register file
|
||||
|
||||
mrs r4, cpsr
|
||||
tst lr, #0x01
|
||||
orrne r4, r4, #0x20 @ it's thumb code
|
||||
|
||||
stmfd sp!, {r4} @ push cpsr
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
stmfd sp, {r13, r14}^ @ push usr_sp usr_lr
|
||||
sub sp, #8
|
||||
#endif
|
||||
#ifdef RT_USING_FPU
|
||||
/* fpu context */
|
||||
vmrs r6, fpexc
|
||||
tst r6, #(1<<30)
|
||||
beq 1f
|
||||
vstmdb sp!, {d0-d15}
|
||||
vstmdb sp!, {d16-d31}
|
||||
vmrs r5, fpscr
|
||||
stmfd sp!, {r5}
|
||||
1:
|
||||
stmfd sp!, {r6}
|
||||
#endif
|
||||
|
||||
str sp, [r0] @ store sp in preempted tasks TCB
|
||||
ldr sp, [r1] @ get new task stack pointer
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
mov r0, r2
|
||||
bl rt_cpus_lock_status_restore
|
||||
#endif /*RT_USING_SMP*/
|
||||
b rt_hw_context_switch_exit
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
*/
|
||||
.equ Mode_USR, 0x10
|
||||
.equ Mode_FIQ, 0x11
|
||||
.equ Mode_IRQ, 0x12
|
||||
.equ Mode_SVC, 0x13
|
||||
.equ Mode_ABT, 0x17
|
||||
.equ Mode_UND, 0x1B
|
||||
.equ Mode_SYS, 0x1F
|
||||
|
||||
.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled
|
||||
.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled
|
||||
|
||||
.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:
|
||||
#ifdef RT_USING_SMP
|
||||
/* r0 :svc_mod context
|
||||
* r1 :addr of from_thread's sp
|
||||
* r2 :addr of to_thread's sp
|
||||
* r3 :to_thread's tcb
|
||||
*/
|
||||
|
||||
str r0, [r1]
|
||||
|
||||
ldr sp, [r2]
|
||||
mov r0, r3
|
||||
bl rt_cpus_lock_status_restore
|
||||
|
||||
b rt_hw_context_switch_exit
|
||||
|
||||
#else /*RT_USING_SMP*/
|
||||
ldr r2, =rt_thread_switch_interrupt_flag
|
||||
ldr r3, [r2]
|
||||
cmp r3, #1
|
||||
beq _reswitch
|
||||
ldr ip, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
|
||||
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
|
||||
str r0, [ip]
|
||||
str r3, [r2]
|
||||
_reswitch:
|
||||
ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
#endif /*RT_USING_SMP*/
|
||||
|
||||
.global rt_hw_context_switch_exit
|
||||
rt_hw_context_switch_exit:
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
#ifdef RT_USING_SIGNALS
|
||||
mov r0, sp
|
||||
cps #Mode_IRQ
|
||||
bl rt_signal_check
|
||||
cps #Mode_SVC
|
||||
mov sp, r0
|
||||
#endif
|
||||
#endif
|
||||
#ifdef RT_USING_FPU
|
||||
/* fpu context */
|
||||
ldmfd sp!, {r6}
|
||||
vmsr fpexc, r6
|
||||
tst r6, #(1<<30)
|
||||
beq 1f
|
||||
ldmfd sp!, {r5}
|
||||
vmsr fpscr, r5
|
||||
vldmia sp!, {d16-d31}
|
||||
vldmia sp!, {d0-d15}
|
||||
1:
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
ldmfd sp, {r13, r14}^ /* usr_sp, usr_lr */
|
||||
add sp, #8
|
||||
#endif
|
||||
ldmfd sp!, {r1}
|
||||
msr spsr_cxsf, r1 /* original mode */
|
||||
ldmfd sp!, {r0-r12,lr,pc}^ /* irq return */
|
||||
|
||||
28
rt-thread/libcpu/arm/cortex-a/cp15.h
Normal file
28
rt-thread/libcpu/arm/cortex-a/cp15.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-03-25 quanzhao the first version
|
||||
*/
|
||||
#ifndef __CP15_H__
|
||||
#define __CP15_H__
|
||||
|
||||
#define __get_cp(cp, op1, Rt, CRn, CRm, op2) __asm__ volatile("MRC p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : "=r" (Rt) : : "memory" )
|
||||
#define __set_cp(cp, op1, Rt, CRn, CRm, op2) __asm__ volatile("MCR p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : : "r" (Rt) : "memory" )
|
||||
#define __get_cp64(cp, op1, Rt, CRm) __asm__ volatile("MRRC p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : "=r" (Rt) : : "memory" )
|
||||
#define __set_cp64(cp, op1, Rt, CRm) __asm__ volatile("MCRR p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : : "r" (Rt) : "memory" )
|
||||
|
||||
int rt_hw_cpu_id(void);
|
||||
void rt_cpu_mmu_disable(void);
|
||||
void rt_cpu_mmu_enable(void);
|
||||
void rt_cpu_tlb_set(volatile unsigned long*);
|
||||
|
||||
void rt_cpu_dcache_clean_flush(void);
|
||||
void rt_cpu_icache_flush(void);
|
||||
|
||||
void rt_cpu_vector_set_base(unsigned int addr);
|
||||
|
||||
#endif
|
||||
140
rt-thread/libcpu/arm/cortex-a/cp15_gcc.S
Normal file
140
rt-thread/libcpu/arm/cortex-a/cp15_gcc.S
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-05 Bernard the first version
|
||||
*/
|
||||
|
||||
.weak rt_hw_cpu_id
|
||||
rt_hw_cpu_id:
|
||||
mrc p15, #0, r0, c0, c0, #5 @ read multiprocessor affinity register
|
||||
ldr r1, =0xFFFF03 @ Affinity mask off, leaving CPU ID field, [0:1]CPU ID, [8:15]Cluster ID Aff1, [16:23]Cluster ID Aff2
|
||||
and r0, r0, r1
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_vector_set_base
|
||||
rt_cpu_vector_set_base:
|
||||
/* clear SCTRL.V to customize the vector address */
|
||||
mrc p15, #0, r1, c1, c0, #0
|
||||
bic r1, #(1 << 13)
|
||||
mcr p15, #0, r1, c1, c0, #0
|
||||
/* set up the vector address */
|
||||
mcr p15, #0, r0, c12, c0, #0
|
||||
dsb
|
||||
bx lr
|
||||
|
||||
.globl rt_hw_cpu_dcache_enable
|
||||
rt_hw_cpu_dcache_enable:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
orr r0, r0, #0x00000004
|
||||
mcr p15, #0, r0, c1, c0, #0
|
||||
bx lr
|
||||
|
||||
.globl rt_hw_cpu_icache_enable
|
||||
rt_hw_cpu_icache_enable:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
orr r0, r0, #0x00001000
|
||||
mcr p15, #0, r0, c1, c0, #0
|
||||
bx lr
|
||||
|
||||
_FLD_MAX_WAY:
|
||||
.word 0x3ff
|
||||
_FLD_MAX_IDX:
|
||||
.word 0x7fff
|
||||
|
||||
.globl rt_cpu_dcache_clean_flush
|
||||
rt_cpu_dcache_clean_flush:
|
||||
push {r4-r11}
|
||||
dmb
|
||||
mrc p15, #1, r0, c0, c0, #1 @ read clid register
|
||||
ands r3, r0, #0x7000000 @ get level of coherency
|
||||
mov r3, r3, lsr #23
|
||||
beq finished
|
||||
mov r10, #0
|
||||
loop1:
|
||||
add r2, r10, r10, lsr #1
|
||||
mov r1, r0, lsr r2
|
||||
and r1, r1, #7
|
||||
cmp r1, #2
|
||||
blt skip
|
||||
mcr p15, #2, r10, c0, c0, #0
|
||||
isb
|
||||
mrc p15, #1, r1, c0, c0, #0
|
||||
and r2, r1, #7
|
||||
add r2, r2, #4
|
||||
ldr r4, _FLD_MAX_WAY
|
||||
ands r4, r4, r1, lsr #3
|
||||
clz r5, r4
|
||||
ldr r7, _FLD_MAX_IDX
|
||||
ands r7, r7, r1, lsr #13
|
||||
loop2:
|
||||
mov r9, r4
|
||||
loop3:
|
||||
orr r11, r10, r9, lsl r5
|
||||
orr r11, r11, r7, lsl r2
|
||||
mcr p15, #0, r11, c7, c14, #2
|
||||
subs r9, r9, #1
|
||||
bge loop3
|
||||
subs r7, r7, #1
|
||||
bge loop2
|
||||
skip:
|
||||
add r10, r10, #2
|
||||
cmp r3, r10
|
||||
bgt loop1
|
||||
|
||||
finished:
|
||||
dsb
|
||||
isb
|
||||
pop {r4-r11}
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_icache_flush
|
||||
rt_cpu_icache_flush:
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
|
||||
dsb
|
||||
isb
|
||||
bx lr
|
||||
|
||||
.globl rt_hw_cpu_dcache_disable
|
||||
rt_hw_cpu_dcache_disable:
|
||||
push {r4-r11, lr}
|
||||
bl rt_cpu_dcache_clean_flush
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
bic r0, r0, #0x00000004
|
||||
mcr p15, #0, r0, c1, c0, #0
|
||||
pop {r4-r11, lr}
|
||||
bx lr
|
||||
|
||||
.globl rt_hw_cpu_icache_disable
|
||||
rt_hw_cpu_icache_disable:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
bic r0, r0, #0x00001000
|
||||
mcr p15, #0, r0, c1, c0, #0
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_mmu_disable
|
||||
rt_cpu_mmu_disable:
|
||||
mcr p15, #0, r0, c8, c7, #0 @ invalidate tlb
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
bic r0, r0, #1
|
||||
mcr p15, #0, r0, c1, c0, #0 @ clear mmu bit
|
||||
dsb
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_mmu_enable
|
||||
rt_cpu_mmu_enable:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
orr r0, r0, #0x001
|
||||
mcr p15, #0, r0, c1, c0, #0 @ set mmu enable bit
|
||||
dsb
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_tlb_set
|
||||
rt_cpu_tlb_set:
|
||||
mcr p15, #0, r0, c2, c0, #0
|
||||
dmb
|
||||
bx lr
|
||||
95
rt-thread/libcpu/arm/cortex-a/cpu.c
Normal file
95
rt-thread/libcpu/arm/cortex-a/cpu.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-09-15 Bernard first version
|
||||
* 2018-11-22 Jesven add rt_hw_cpu_id()
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
|
||||
void rt_hw_spin_lock_init(rt_hw_spinlock_t *lock)
|
||||
{
|
||||
lock->slock = 0;
|
||||
}
|
||||
|
||||
void rt_hw_spin_lock(rt_hw_spinlock_t *lock)
|
||||
{
|
||||
unsigned long tmp;
|
||||
unsigned long newval;
|
||||
rt_hw_spinlock_t lockval;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"pld [%0]"
|
||||
::"r"(&lock->slock)
|
||||
);
|
||||
|
||||
__asm__ __volatile__(
|
||||
"1: ldrex %0, [%3]\n"
|
||||
" add %1, %0, %4\n"
|
||||
" strex %2, %1, [%3]\n"
|
||||
" teq %2, #0\n"
|
||||
" bne 1b"
|
||||
: "=&r" (lockval), "=&r" (newval), "=&r" (tmp)
|
||||
: "r" (&lock->slock), "I" (1 << 16)
|
||||
: "cc");
|
||||
|
||||
while (lockval.tickets.next != lockval.tickets.owner) {
|
||||
__asm__ __volatile__("wfe":::"memory");
|
||||
lockval.tickets.owner = *(volatile unsigned short *)(&lock->tickets.owner);
|
||||
}
|
||||
|
||||
__asm__ volatile ("dmb":::"memory");
|
||||
}
|
||||
|
||||
void rt_hw_spin_unlock(rt_hw_spinlock_t *lock)
|
||||
{
|
||||
__asm__ volatile ("dmb":::"memory");
|
||||
lock->tickets.owner++;
|
||||
__asm__ volatile ("dsb ishst\nsev":::"memory");
|
||||
}
|
||||
#endif /*RT_USING_SMP*/
|
||||
|
||||
/**
|
||||
* @addtogroup ARM CPU
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/** shutdown CPU */
|
||||
RT_WEAK void rt_hw_cpu_shutdown()
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
while (level)
|
||||
{
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
/**
|
||||
* This function finds the first bit set (beginning with the least significant bit)
|
||||
* in value and return the index of that bit.
|
||||
*
|
||||
* Bits are numbered starting at 1 (the least significant bit). A return value of
|
||||
* zero from any of these functions means that the argument was zero.
|
||||
*
|
||||
* @return return the index of the first bit set. If value is 0, then this function
|
||||
* shall return 0.
|
||||
*/
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
return __builtin_ffs(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*@}*/
|
||||
495
rt-thread/libcpu/arm/cortex-a/gic.c
Normal file
495
rt-thread/libcpu/arm/cortex-a/gic.c
Normal file
@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
* 2014-04-03 Grissiom many enhancements
|
||||
* 2018-11-22 Jesven add rt_hw_ipi_send()
|
||||
* add rt_hw_ipi_handler_install()
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "gic.h"
|
||||
#include "cp15.h"
|
||||
|
||||
struct arm_gic
|
||||
{
|
||||
rt_uint32_t offset; /* the first interrupt index in the vector table */
|
||||
|
||||
rt_uint32_t dist_hw_base; /* the base address of the gic distributor */
|
||||
rt_uint32_t cpu_hw_base; /* the base addrees of the gic cpu interface */
|
||||
};
|
||||
|
||||
/* 'ARM_GIC_MAX_NR' is the number of cores */
|
||||
static struct arm_gic _gic_table[ARM_GIC_MAX_NR];
|
||||
|
||||
/** Macro to access the Generic Interrupt Controller Interface (GICC)
|
||||
*/
|
||||
#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U)
|
||||
#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U)
|
||||
#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U)
|
||||
#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU)
|
||||
#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U)
|
||||
#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U)
|
||||
#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U)
|
||||
#define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU)
|
||||
|
||||
/** Macro to access the Generic Interrupt Controller Distributor (GICD)
|
||||
*/
|
||||
#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
|
||||
#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U)
|
||||
#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n)/16U) * 4U)
|
||||
#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U)
|
||||
#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U)
|
||||
|
||||
static unsigned int _gic_max_irq;
|
||||
|
||||
int arm_gic_get_active_irq(rt_uint32_t index)
|
||||
{
|
||||
int irq;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = GIC_CPU_INTACK(_gic_table[index].cpu_hw_base);
|
||||
irq += _gic_table[index].offset;
|
||||
return irq;
|
||||
}
|
||||
|
||||
void arm_gic_ack(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq;
|
||||
}
|
||||
|
||||
void arm_gic_mask(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
void arm_gic_umask(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t pend;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTID 0-15 Software Generated Interrupt */
|
||||
pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
/* No CPU identification offered */
|
||||
if (pend != 0U)
|
||||
{
|
||||
pend = 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
pend = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
return (pend);
|
||||
}
|
||||
|
||||
void arm_gic_set_pending_irq(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1U << (irq % 32U);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTID 0-15 Software Generated Interrupt */
|
||||
/* Forward the interrupt to the CPU interface that requested it */
|
||||
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000U);
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
mask = 1U << (irq % 32U);
|
||||
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = 1U << ((irq % 4U) * 8U);
|
||||
GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config)
|
||||
{
|
||||
rt_uint32_t icfgr;
|
||||
rt_uint32_t shift;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq);
|
||||
shift = (irq % 16U) << 1U;
|
||||
|
||||
icfgr &= (~(3U << shift));
|
||||
icfgr |= (config << shift);
|
||||
|
||||
GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
|
||||
}
|
||||
|
||||
void arm_gic_clear_active(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
/* Set up the cpu mask for the specific interrupt */
|
||||
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask)
|
||||
{
|
||||
rt_uint32_t old_tgt;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);
|
||||
|
||||
old_tgt &= ~(0x0FFUL << ((irq % 4U)*8U));
|
||||
old_tgt |= cpumask << ((irq % 4U)*8U);
|
||||
|
||||
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
}
|
||||
|
||||
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority)
|
||||
{
|
||||
rt_uint32_t mask;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq);
|
||||
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
|
||||
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
|
||||
GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
}
|
||||
|
||||
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
/* set priority mask */
|
||||
GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base) = priority & 0xFFUL;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
return GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point)
|
||||
{
|
||||
GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base) = binary_point & 0x7U;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index)
|
||||
{
|
||||
return GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t pending;
|
||||
rt_uint32_t active;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
|
||||
return ((active << 1U) | pending);
|
||||
}
|
||||
|
||||
void arm_gic_send_sgi(rt_uint32_t index, int irq, rt_uint32_t target_list, rt_uint32_t filter_list)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = ((filter_list & 0x3U) << 24U) | ((target_list & 0xFFUL) << 16U) | (irq & 0x0FUL);
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
return GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group)
|
||||
{
|
||||
rt_uint32_t igroupr;
|
||||
rt_uint32_t shift;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT(group <= 1U);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq);
|
||||
shift = (irq % 32U);
|
||||
igroupr &= (~(1U << shift));
|
||||
igroupr |= ( (group & 0x1U) << shift);
|
||||
|
||||
GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
}
|
||||
|
||||
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start)
|
||||
{
|
||||
unsigned int gic_type, i;
|
||||
rt_uint32_t cpumask = 1U << 0U;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
_gic_table[index].dist_hw_base = dist_base;
|
||||
_gic_table[index].offset = irq_start;
|
||||
|
||||
/* Find out how many interrupts are supported. */
|
||||
gic_type = GIC_DIST_TYPE(dist_base);
|
||||
_gic_max_irq = ((gic_type & 0x1fU) + 1U) * 32U;
|
||||
|
||||
/*
|
||||
* The GIC only supports up to 1020 interrupt sources.
|
||||
* Limit this to either the architected maximum, or the
|
||||
* platform maximum.
|
||||
*/
|
||||
if (_gic_max_irq > 1020U)
|
||||
_gic_max_irq = 1020U;
|
||||
if (_gic_max_irq > ARM_GIC_NR_IRQS) /* the platform maximum interrupts */
|
||||
_gic_max_irq = ARM_GIC_NR_IRQS;
|
||||
|
||||
cpumask |= cpumask << 8U;
|
||||
cpumask |= cpumask << 16U;
|
||||
cpumask |= cpumask << 24U;
|
||||
|
||||
GIC_DIST_CTRL(dist_base) = 0x0U;
|
||||
|
||||
/* Set all global interrupts to be level triggered, active low. */
|
||||
for (i = 32U; i < _gic_max_irq; i += 16U)
|
||||
GIC_DIST_CONFIG(dist_base, i) = 0x0U;
|
||||
|
||||
/* Set all global interrupts to this CPU only. */
|
||||
for (i = 32U; i < _gic_max_irq; i += 4U)
|
||||
GIC_DIST_TARGET(dist_base, i) = cpumask;
|
||||
|
||||
/* Set priority on all interrupts. */
|
||||
for (i = 0U; i < _gic_max_irq; i += 4U)
|
||||
GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0U;
|
||||
|
||||
/* Disable all interrupts. */
|
||||
for (i = 0U; i < _gic_max_irq; i += 32U)
|
||||
GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffffU;
|
||||
|
||||
#if 0
|
||||
/* All interrupts defaults to IGROUP1(IRQ). */
|
||||
for (i = 0; i < _gic_max_irq; i += 32)
|
||||
GIC_DIST_IGROUP(dist_base, i) = 0xffffffff;
|
||||
#endif
|
||||
for (i = 0U; i < _gic_max_irq; i += 32U)
|
||||
GIC_DIST_IGROUP(dist_base, i) = 0U;
|
||||
|
||||
/* Enable group0 and group1 interrupt forwarding. */
|
||||
GIC_DIST_CTRL(dist_base) = 0x01U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
_gic_table[index].cpu_hw_base = cpu_base;
|
||||
|
||||
GIC_CPU_PRIMASK(cpu_base) = 0xf0U;
|
||||
GIC_CPU_BINPOINT(cpu_base) = 0x7U;
|
||||
/* Enable CPU interrupt */
|
||||
GIC_CPU_CTRL(cpu_base) = 0x01U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void arm_gic_dump_type(rt_uint32_t index)
|
||||
{
|
||||
unsigned int gic_type;
|
||||
|
||||
gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base);
|
||||
rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n",
|
||||
(GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4U) & 0xfUL,
|
||||
_gic_table[index].dist_hw_base,
|
||||
_gic_max_irq,
|
||||
gic_type & (1U << 10U) ? "has" : "no",
|
||||
gic_type);
|
||||
}
|
||||
|
||||
void arm_gic_dump(rt_uint32_t index)
|
||||
{
|
||||
unsigned int i, k;
|
||||
|
||||
k = GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
|
||||
rt_kprintf("--- high pending priority: %d(%08x)\n", k, k);
|
||||
rt_kprintf("--- hw mask ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ",
|
||||
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base,
|
||||
i * 32U));
|
||||
}
|
||||
rt_kprintf("\n--- hw pending ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ",
|
||||
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base,
|
||||
i * 32U));
|
||||
}
|
||||
rt_kprintf("\n--- hw active ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ",
|
||||
GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base,
|
||||
i * 32U));
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
long gic_dump(void)
|
||||
{
|
||||
arm_gic_dump_type(0);
|
||||
arm_gic_dump(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT(gic_dump, show gic status);
|
||||
|
||||
62
rt-thread/libcpu/arm/cortex-a/gic.h
Normal file
62
rt-thread/libcpu/arm/cortex-a/gic.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
*/
|
||||
|
||||
#ifndef __GIC_H__
|
||||
#define __GIC_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
int arm_gic_get_active_irq(rt_uint32_t index);
|
||||
void arm_gic_ack(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_mask(rt_uint32_t index, int irq);
|
||||
void arm_gic_umask(rt_uint32_t index, int irq);
|
||||
|
||||
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq);
|
||||
void arm_gic_set_pending_irq(rt_uint32_t index, int irq);
|
||||
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config);
|
||||
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_clear_active(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask);
|
||||
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority);
|
||||
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority);
|
||||
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index);
|
||||
|
||||
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point);
|
||||
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index);
|
||||
|
||||
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_send_sgi(rt_uint32_t index, int irq, rt_uint32_t target_list, rt_uint32_t filter_list);
|
||||
|
||||
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index);
|
||||
|
||||
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index);
|
||||
|
||||
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group);
|
||||
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq);
|
||||
|
||||
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start);
|
||||
int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base);
|
||||
|
||||
void arm_gic_dump_type(rt_uint32_t index);
|
||||
void arm_gic_dump(rt_uint32_t index);
|
||||
|
||||
#endif
|
||||
|
||||
708
rt-thread/libcpu/arm/cortex-a/gicv3.c
Normal file
708
rt-thread/libcpu/arm/cortex-a/gicv3.c
Normal file
@ -0,0 +1,708 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
* 2014-04-03 Grissiom many enhancements
|
||||
* 2018-11-22 Jesven add rt_hw_ipi_send()
|
||||
* add rt_hw_ipi_handler_install()
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "gicv3.h"
|
||||
#include "cp15.h"
|
||||
|
||||
#ifndef RT_CPUS_NR
|
||||
#define RT_CPUS_NR 1
|
||||
#endif
|
||||
|
||||
struct arm_gic_v3
|
||||
{
|
||||
rt_uint32_t offset; /* the first interrupt index in the vector table */
|
||||
rt_uint32_t redist_hw_base[RT_CPUS_NR]; /* the pointer of the gic redistributor */
|
||||
rt_uint32_t dist_hw_base; /* the base address of the gic distributor */
|
||||
rt_uint32_t cpu_hw_base[RT_CPUS_NR]; /* the base addrees of the gic cpu interface */
|
||||
};
|
||||
|
||||
/* 'ARM_GIC_MAX_NR' is the number of cores */
|
||||
static struct arm_gic_v3 _gic_table[ARM_GIC_MAX_NR];
|
||||
static unsigned int _gic_max_irq;
|
||||
|
||||
/**
|
||||
* @name: arm_gic_cpumask_to_affval
|
||||
* @msg:
|
||||
* @in param cpu_mask:
|
||||
* @out param cluster_id: aff1 [0:7],aff2 [8:15],aff3 [16:23]
|
||||
* @out param target_list: Target List. The set of PEs for which SGI interrupts will be generated. Each bit corresponds to the
|
||||
* PE within a cluster with an Affinity 0 value equal to the bit number.
|
||||
* @return {rt_uint32_t} 0 is finish , 1 is data valid
|
||||
*/
|
||||
RT_WEAK rt_uint32_t arm_gic_cpumask_to_affval(rt_uint32_t *cpu_mask, rt_uint32_t *cluster_id, rt_uint32_t *target_list)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RT_WEAK rt_uint64_t get_main_cpu_affval(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_get_active_irq(rt_uint32_t index)
|
||||
{
|
||||
int irq;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
__get_gicv3_reg(ICC_IAR1, irq);
|
||||
|
||||
irq = (irq & 0x1FFFFFF) + _gic_table[index].offset;
|
||||
return irq;
|
||||
}
|
||||
|
||||
void arm_gic_ack(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
__asm__ volatile("dsb 0xF" ::
|
||||
: "memory");
|
||||
__set_gicv3_reg(ICC_EOIR1, irq);
|
||||
}
|
||||
|
||||
void arm_gic_mask(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq < 32U)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
GIC_RDISTSGI_ICENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_umask(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq < 32U)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
GIC_RDISTSGI_ISENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t pend;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTID 0-15 Software Generated Interrupt */
|
||||
pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
/* No CPU identification offered */
|
||||
if (pend != 0U)
|
||||
{
|
||||
pend = 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
pend = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
return (pend);
|
||||
}
|
||||
|
||||
void arm_gic_set_pending_irq(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1U << (irq % 32U);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTID 0-15 Software Generated Interrupt */
|
||||
/* Forward the interrupt to the CPU interface that requested it */
|
||||
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000U);
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
mask = 1U << (irq % 32U);
|
||||
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = 1U << ((irq % 4U) * 8U);
|
||||
GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config)
|
||||
{
|
||||
rt_uint32_t icfgr;
|
||||
rt_uint32_t shift;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq);
|
||||
shift = (irq % 16U) << 1U;
|
||||
|
||||
icfgr &= (~(3U << shift));
|
||||
icfgr |= (config << shift);
|
||||
|
||||
GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
|
||||
}
|
||||
|
||||
void arm_gic_clear_active(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
/* Set up the cpu mask for the specific interrupt */
|
||||
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask)
|
||||
{
|
||||
rt_uint32_t old_tgt;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);
|
||||
|
||||
old_tgt &= ~(0x0FFUL << ((irq % 4U) * 8U));
|
||||
old_tgt |= cpumask << ((irq % 4U) * 8U);
|
||||
|
||||
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
}
|
||||
|
||||
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority)
|
||||
{
|
||||
rt_uint32_t mask;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq < 32U)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
|
||||
mask = GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq);
|
||||
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
|
||||
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
|
||||
GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq);
|
||||
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
|
||||
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
|
||||
GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq < 32U)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
return (GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_set_system_register_enable_mask(rt_uint32_t index, rt_uint32_t value)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
value &= 0xFFUL;
|
||||
/* set priority mask */
|
||||
__set_gicv3_reg(ICC_SRE, value);
|
||||
__asm__ volatile ("isb 0xF"::
|
||||
:"memory");
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_system_register_enable_mask(rt_uint32_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
rt_uint32_t value;
|
||||
|
||||
__get_gicv3_reg(ICC_SRE, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
priority &= 0xFFUL;
|
||||
/* set priority mask */
|
||||
__set_gicv3_reg(ICC_PMR, priority);
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
rt_uint32_t priority;
|
||||
|
||||
__get_gicv3_reg(ICC_PMR, priority);
|
||||
return priority;
|
||||
}
|
||||
|
||||
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point)
|
||||
{
|
||||
index = index;
|
||||
binary_point &= 0x7U;
|
||||
|
||||
__set_gicv3_reg(ICC_BPR1, binary_point);
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index)
|
||||
{
|
||||
rt_uint32_t binary_point;
|
||||
|
||||
index = index;
|
||||
__get_gicv3_reg(ICC_BPR1, binary_point);
|
||||
return binary_point;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t pending;
|
||||
rt_uint32_t active;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
|
||||
return ((active << 1U) | pending);
|
||||
}
|
||||
|
||||
void arm_gic_send_affinity_sgi(rt_uint32_t index, int irq, rt_uint32_t cpu_mask, rt_uint32_t routing_mode)
|
||||
{
|
||||
rt_uint64_t sgi_val;
|
||||
|
||||
if (routing_mode)
|
||||
{
|
||||
sgi_val = (1ULL << 40) | ((irq & 0x0FULL) << 24); //Interrupts routed to all PEs in the system, excluding "self".
|
||||
/* Write the ICC_SGI1R registers */
|
||||
__asm__ volatile("dsb 0xF" ::
|
||||
: "memory");
|
||||
__set_cp64(15, 0, sgi_val, 12);
|
||||
__asm__ volatile("isb 0xF" ::
|
||||
: "memory");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_uint32_t cluster_id, target_list;
|
||||
while (arm_gic_cpumask_to_affval(&cpu_mask, &cluster_id, &target_list))
|
||||
{
|
||||
sgi_val = ((irq & 0x0FULL) << 24 |
|
||||
target_list |
|
||||
((cluster_id >> 8) & 0xFFULL) << GIC_RSGI_AFF1_OFFSET |
|
||||
((cluster_id >> 16) & 0xFFULL) << GIC_RSGI_AFF2_OFFSET |
|
||||
((cluster_id >> 24) & 0xFFull) << GIC_RSGI_AFF3_OFFSET);
|
||||
|
||||
__asm__ volatile("dsb 0xF" ::
|
||||
: "memory");
|
||||
__set_cp64(15, 0, sgi_val, 12);
|
||||
__asm__ volatile("isb 0xF" ::
|
||||
: "memory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index)
|
||||
{
|
||||
rt_uint32_t irq;
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
index = index;
|
||||
__get_gicv3_reg(ICC_HPPIR1, irq);
|
||||
return irq;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group)
|
||||
{
|
||||
rt_uint32_t igroupr;
|
||||
rt_uint32_t shift;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT(group <= 1U);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq);
|
||||
shift = (irq % 32U);
|
||||
igroupr &= (~(1U << shift));
|
||||
igroupr |= ((group & 0x1U) << shift);
|
||||
|
||||
GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
}
|
||||
|
||||
static int arm_gicv3_wait_rwp(rt_uint32_t index, rt_uint32_t irq)
|
||||
{
|
||||
rt_uint32_t rwp_bit;
|
||||
rt_uint32_t base;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
if (irq < 32u)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
base = _gic_table[index].redist_hw_base[cpu_id];
|
||||
rwp_bit = GICR_CTLR_RWP;
|
||||
}
|
||||
else
|
||||
{
|
||||
base = _gic_table[index].dist_hw_base;
|
||||
rwp_bit = GICD_CTLR_RWP;
|
||||
}
|
||||
|
||||
while (__REG32(base) & rwp_bit)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start)
|
||||
{
|
||||
rt_uint64_t cpu0_affval;
|
||||
unsigned int gic_type, i;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
_gic_table[index].dist_hw_base = dist_base;
|
||||
_gic_table[index].offset = irq_start;
|
||||
|
||||
/* Find out how many interrupts are supported. */
|
||||
gic_type = GIC_DIST_TYPE(dist_base);
|
||||
_gic_max_irq = ((gic_type & 0x1fU) + 1U) * 32U;
|
||||
|
||||
/*
|
||||
* The GIC only supports up to 1020 interrupt sources.
|
||||
* Limit this to either the architected maximum, or the
|
||||
* platform maximum.
|
||||
*/
|
||||
if (_gic_max_irq > 1020U)
|
||||
_gic_max_irq = 1020U;
|
||||
if (_gic_max_irq > ARM_GIC_NR_IRQS) /* the platform maximum interrupts */
|
||||
_gic_max_irq = ARM_GIC_NR_IRQS;
|
||||
|
||||
GIC_DIST_CTRL(dist_base) = 0x0U;
|
||||
/* Wait for register write pending */
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
|
||||
/* Set all global interrupts to be level triggered, active low. */
|
||||
for (i = 32U; i < _gic_max_irq; i += 16U)
|
||||
GIC_DIST_CONFIG(dist_base, i) = 0x0U;
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
|
||||
cpu0_affval = get_main_cpu_affval();
|
||||
/* Set all global interrupts to this CPU only. */
|
||||
for (i = 32U; i < _gic_max_irq; i++)
|
||||
{
|
||||
GIC_DIST_IROUTER_LOW(dist_base, i) = cpu0_affval;
|
||||
GIC_DIST_IROUTER_HIGH(dist_base, i) = cpu0_affval >> 32;
|
||||
}
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
|
||||
/* Set priority on spi interrupts. */
|
||||
for (i = 32U; i < _gic_max_irq; i += 4U)
|
||||
GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0U;
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
/* Disable all interrupts. */
|
||||
for (i = 0U; i < _gic_max_irq; i += 32U)
|
||||
{
|
||||
GIC_DIST_PENDING_CLEAR(dist_base, i) = 0xffffffffU;
|
||||
GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffffU;
|
||||
}
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
/* All interrupts defaults to IGROUP1(IRQ). */
|
||||
for (i = 0U; i < _gic_max_irq; i += 32U)
|
||||
GIC_DIST_IGROUP(dist_base, i) = 0xffffffffU;
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
|
||||
/*
|
||||
The Distributor control register (GICD_CTLR) must be configured to enable the interrupt groups and to set the routing mode.
|
||||
Enable Affinity routing (ARE bits) The ARE bits in GICD_CTLR control whether affinity routing is enabled.
|
||||
If affinity routing is not enabled, GICv3 can be configured for legacy operation.
|
||||
Whether affinity routing is enabled or not can be controlled separately for Secure and Non-secure state.
|
||||
Enables GICD_CTLR contains separate enable bits for Group 0, Secure Group 1 and Non-secure Group 1:
|
||||
GICD_CTLR.EnableGrp1S enables distribution of Secure Group 1 interrupts.
|
||||
GICD_CTLR.EnableGrp1NS enables distribution of Non-secure Group 1 interrupts.
|
||||
GICD_CTLR.EnableGrp0 enables distribution of Group 0 interrupts.
|
||||
*/
|
||||
GIC_DIST_CTRL(dist_base) = GICD_CTLR_ARE_NS | GICD_CTLR_ENGRP1NS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_redist_address_set(rt_uint32_t index, rt_uint32_t redist_addr, rt_uint32_t cpu_id)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
_gic_table[index].redist_hw_base[cpu_id] = redist_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_cpu_interface_address_set(rt_uint32_t index, rt_uint32_t interface_addr, rt_uint32_t cpu_id)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
_gic_table[index].cpu_hw_base[cpu_id] = interface_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_redist_init(rt_uint32_t index)
|
||||
{
|
||||
unsigned int i;
|
||||
rt_uint32_t base;
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
|
||||
base = _gic_table[index].redist_hw_base[cpu_id];
|
||||
/* redistributor enable */
|
||||
GIC_RDIST_WAKER(base) &= ~(1U << 1);
|
||||
while (GIC_RDIST_WAKER(base) & (1 << 2))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/* Disable all sgi and ppi interrupt */
|
||||
GIC_RDISTSGI_ICENABLER0(base) = 0xFFFFFFFF;
|
||||
arm_gicv3_wait_rwp(0, 0);
|
||||
|
||||
/* Clear all inetrrupt pending */
|
||||
GIC_RDISTSGI_ICPENDR0(base) = 0xFFFFFFFF;
|
||||
|
||||
/* the corresponding interrupt is Group 1 or Non-secure Group 1. */
|
||||
GIC_RDISTSGI_IGROUPR0(base, 0) = 0xFFFFFFFF;
|
||||
GIC_RDISTSGI_IGRPMODR0(base, 0) = 0xFFFFFFFF;
|
||||
|
||||
/* Configure default priorities for SGI 0:15 and PPI 16:31. */
|
||||
for (i = 0; i < 32; i += 4)
|
||||
{
|
||||
GIC_RDISTSGI_IPRIORITYR(base, i) = 0xa0a0a0a0U;
|
||||
}
|
||||
|
||||
/* Trigger level for PPI interrupts*/
|
||||
GIC_RDISTSGI_ICFGR1(base) = 0x0U; // PPI is level-sensitive.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_cpu_init(rt_uint32_t index)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
value = arm_gic_get_system_register_enable_mask(index);
|
||||
value |= (1U << 0);
|
||||
arm_gic_set_system_register_enable_mask(index, value);
|
||||
__set_gicv3_reg(ICC_CTLR, 0);
|
||||
|
||||
arm_gic_set_interface_prior_mask(index, 0xFFU);
|
||||
|
||||
/* Enable group1 interrupt */
|
||||
value = 0x1U;
|
||||
__set_gicv3_reg(ICC_IGRPEN1, value);
|
||||
|
||||
arm_gic_set_binary_point(0, 0);
|
||||
|
||||
/* ICC_BPR0_EL1 determines the preemption group for both
|
||||
Group 0 and Group 1 interrupts.
|
||||
*/
|
||||
value = 0x1U;
|
||||
__set_gicv3_reg(ICC_CTLR, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
void arm_gic_secondary_cpu_init(void)
|
||||
{
|
||||
arm_gic_redist_init(0);
|
||||
|
||||
arm_gic_cpu_init(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void arm_gic_dump_type(rt_uint32_t index)
|
||||
{
|
||||
unsigned int gic_type;
|
||||
|
||||
gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base);
|
||||
rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n",
|
||||
(GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4U) & 0xfUL,
|
||||
_gic_table[index].dist_hw_base,
|
||||
_gic_max_irq,
|
||||
gic_type & (1U << 10U) ? "has" : "no",
|
||||
gic_type);
|
||||
}
|
||||
|
||||
void arm_gic_dump(rt_uint32_t index)
|
||||
{
|
||||
unsigned int i, k;
|
||||
|
||||
k = arm_gic_get_high_pending_irq(0);
|
||||
rt_kprintf("--- high pending priority: %d(%08x)\n", k, k);
|
||||
rt_kprintf("--- hw mask ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ",
|
||||
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base,
|
||||
i * 32U));
|
||||
}
|
||||
rt_kprintf("\n--- hw pending ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ",
|
||||
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base,
|
||||
i * 32U));
|
||||
}
|
||||
rt_kprintf("\n--- hw active ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ",
|
||||
GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base,
|
||||
i * 32U));
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
long gic_dump(void)
|
||||
{
|
||||
arm_gic_dump_type(0);
|
||||
arm_gic_dump(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT(gic_dump, show gic status);
|
||||
194
rt-thread/libcpu/arm/cortex-a/gicv3.h
Normal file
194
rt-thread/libcpu/arm/cortex-a/gicv3.h
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
*/
|
||||
|
||||
#ifndef __GIC_V3_H__
|
||||
#define __GIC_V3_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
#define __get_gicv3_reg(CR, Rt) __asm__ volatile("MRC " CR \
|
||||
: "=r"(Rt) \
|
||||
: \
|
||||
: "memory")
|
||||
#define __set_gicv3_reg(CR, Rt) __asm__ volatile("MCR " CR \
|
||||
: \
|
||||
: "r"(Rt) \
|
||||
: "memory")
|
||||
|
||||
|
||||
/* AArch32 System register interface to GICv3 */
|
||||
#define ICC_IAR0 "p15, 0, %0, c12, c8, 0"
|
||||
#define ICC_IAR1 "p15, 0, %0, c12, c12, 0"
|
||||
#define ICC_EOIR0 "p15, 0, %0, c12, c8, 1"
|
||||
#define ICC_EOIR1 "p15, 0, %0, c12, c12, 1"
|
||||
#define ICC_HPPIR0 "p15, 0, %0, c12, c8, 2"
|
||||
#define ICC_HPPIR1 "p15, 0, %0, c12, c12, 2"
|
||||
#define ICC_BPR0 "p15, 0, %0, c12, c8, 3"
|
||||
#define ICC_BPR1 "p15, 0, %0, c12, c12, 3"
|
||||
#define ICC_DIR "p15, 0, %0, c12, c11, 1"
|
||||
#define ICC_PMR "p15, 0, %0, c4, c6, 0"
|
||||
#define ICC_RPR "p15, 0, %0, c12, c11, 3"
|
||||
#define ICC_CTLR "p15, 0, %0, c12, c12, 4"
|
||||
#define ICC_MCTLR "p15, 6, %0, c12, c12, 4"
|
||||
#define ICC_SRE "p15, 0, %0, c12, c12, 5"
|
||||
#define ICC_HSRE "p15, 4, %0, c12, c9, 5"
|
||||
#define ICC_MSRE "p15, 6, %0, c12, c12, 5"
|
||||
#define ICC_IGRPEN0 "p15, 0, %0, c12, c12, 6"
|
||||
#define ICC_IGRPEN1 "p15, 0, %0, c12, c12, 7"
|
||||
#define ICC_MGRPEN1 "p15, 6, %0, c12, c12, 7"
|
||||
|
||||
#define __REG32(x) (*((volatile unsigned int*)((rt_uint32_t)x)))
|
||||
|
||||
#define ROUTED_TO_ALL (1)
|
||||
#define ROUTED_TO_SPEC (0)
|
||||
|
||||
/** Macro to access the Distributor Control Register (GICD_CTLR)
|
||||
*/
|
||||
#define GICD_CTLR_RWP (1<<31)
|
||||
#define GICD_CTLR_E1NWF (1<<7)
|
||||
#define GICD_CTLR_DS (1<<6)
|
||||
#define GICD_CTLR_ARE_NS (1<<5)
|
||||
#define GICD_CTLR_ARE_S (1<<4)
|
||||
#define GICD_CTLR_ENGRP1S (1<<2)
|
||||
#define GICD_CTLR_ENGRP1NS (1<<1)
|
||||
#define GICD_CTLR_ENGRP0 (1<<0)
|
||||
|
||||
/** Macro to access the Redistributor Control Register (GICR_CTLR)
|
||||
*/
|
||||
#define GICR_CTLR_UWP (1<<31)
|
||||
#define GICR_CTLR_DPG1S (1<<26)
|
||||
#define GICR_CTLR_DPG1NS (1<<25)
|
||||
#define GICR_CTLR_DPG0 (1<<24)
|
||||
#define GICR_CTLR_RWP (1<<3)
|
||||
#define GICR_CTLR_IR (1<<2)
|
||||
#define GICR_CTLR_CES (1<<1)
|
||||
#define GICR_CTLR_EnableLPI (1<<0)
|
||||
|
||||
/** Macro to access the Generic Interrupt Controller Interface (GICC)
|
||||
*/
|
||||
#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U)
|
||||
#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U)
|
||||
#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U)
|
||||
#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU)
|
||||
#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U)
|
||||
#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U)
|
||||
#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U)
|
||||
#define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU)
|
||||
|
||||
/** Macro to access the Generic Interrupt Controller Distributor (GICD)
|
||||
*/
|
||||
#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
|
||||
#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U)
|
||||
#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n)/16U) * 4U)
|
||||
#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U)
|
||||
#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U)
|
||||
#define GIC_DIST_IROUTER_LOW(hw_base, n) __REG32((hw_base) + 0x6000U + (n)*8U)
|
||||
#define GIC_DIST_IROUTER_HIGH(hw_base, n) __REG32((hw_base) + 0x6000U + (n)*8U + 4)
|
||||
|
||||
/* SGI base address is at 64K offset from Redistributor base address */
|
||||
#define GIC_RSGI_OFFSET 0x10000
|
||||
|
||||
/** Macro to access the Generic Interrupt Controller Redistributor (GICD)
|
||||
*/
|
||||
#define GIC_RDIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
|
||||
#define GIC_RDIST_IIDR(hw_base) __REG32((hw_base) + 0x004U)
|
||||
#define GIC_RDIST_TYPER(hw_base) __REG32((hw_base) + 0x008U)
|
||||
#define GIC_RDIST_TSTATUSR(hw_base) __REG32((hw_base) + 0x010U)
|
||||
#define GIC_RDIST_WAKER(hw_base) __REG32((hw_base) + 0x014U)
|
||||
#define GIC_RDIST_SETLPIR(hw_base) __REG32((hw_base) + 0x040U)
|
||||
#define GIC_RDIST_CLRLPIR(hw_base) __REG32((hw_base) + 0x048U)
|
||||
#define GIC_RDIST_PROPBASER(hw_base) __REG32((hw_base) + 0x070U)
|
||||
#define GIC_RDIST_PENDBASER(hw_base) __REG32((hw_base) + 0x078U)
|
||||
#define GIC_RDIST_INVLPIR(hw_base) __REG32((hw_base) + 0x0A0U)
|
||||
#define GIC_RDIST_INVALLR(hw_base) __REG32((hw_base) + 0x0B0U)
|
||||
#define GIC_RDIST_SYNCR(hw_base) __REG32((hw_base) + 0x0C0U)
|
||||
|
||||
#define GIC_RDISTSGI_IGROUPR0(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x080U + (n)*4U)
|
||||
#define GIC_RDISTSGI_ISENABLER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x100U)
|
||||
#define GIC_RDISTSGI_ICENABLER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x180U)
|
||||
#define GIC_RDISTSGI_ISPENDR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x200U)
|
||||
#define GIC_RDISTSGI_ICPENDR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x280U)
|
||||
#define GIC_RDISTSGI_ISACTIVER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x300U)
|
||||
#define GIC_RDISTSGI_ICACTIVER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x380U)
|
||||
#define GIC_RDISTSGI_IPRIORITYR(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x400U + ((n) / 4U) * 4U)
|
||||
#define GIC_RDISTSGI_ICFGR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xC00U)
|
||||
#define GIC_RDISTSGI_ICFGR1(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xC04U)
|
||||
#define GIC_RDISTSGI_IGRPMODR0(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xD00U + (n)*4)
|
||||
#define GIC_RDISTSGI_NSACR(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xE00U)
|
||||
|
||||
#define GIC_RSGI_AFF1_OFFSET 16
|
||||
#define GIC_RSGI_AFF2_OFFSET 32
|
||||
#define GIC_RSGI_AFF3_OFFSET 48
|
||||
|
||||
rt_uint32_t arm_gic_cpumask_to_affval(rt_uint32_t *cpu_mask, rt_uint32_t *cluster_id, rt_uint32_t *target_list);
|
||||
rt_uint64_t get_main_cpu_affval(void);
|
||||
int arm_gic_get_active_irq(rt_uint32_t index);
|
||||
void arm_gic_ack(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_mask(rt_uint32_t index, int irq);
|
||||
void arm_gic_umask(rt_uint32_t index, int irq);
|
||||
|
||||
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq);
|
||||
void arm_gic_set_pending_irq(rt_uint32_t index, int irq);
|
||||
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config);
|
||||
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_clear_active(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask);
|
||||
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority);
|
||||
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority);
|
||||
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index);
|
||||
|
||||
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point);
|
||||
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index);
|
||||
|
||||
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_send_affinity_sgi(rt_uint32_t index, int irq, rt_uint32_t cpu_mask, rt_uint32_t routing_mode);
|
||||
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index);
|
||||
|
||||
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index);
|
||||
|
||||
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group);
|
||||
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq);
|
||||
|
||||
int arm_gic_redist_address_set(rt_uint32_t index, rt_uint32_t redist_addr, rt_uint32_t cpu_id);
|
||||
int arm_gic_cpu_interface_address_set(rt_uint32_t index, rt_uint32_t interface_addr, rt_uint32_t cpu_id);
|
||||
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start);
|
||||
int arm_gic_cpu_init(rt_uint32_t index);
|
||||
int arm_gic_redist_init(rt_uint32_t index);
|
||||
|
||||
void arm_gic_dump_type(rt_uint32_t index);
|
||||
void arm_gic_dump(rt_uint32_t index);
|
||||
|
||||
void arm_gic_set_system_register_enable_mask(rt_uint32_t index, rt_uint32_t value);
|
||||
rt_uint32_t arm_gic_get_system_register_enable_mask(rt_uint32_t index);
|
||||
void arm_gic_secondary_cpu_init(void);
|
||||
#endif
|
||||
|
||||
331
rt-thread/libcpu/arm/cortex-a/interrupt.c
Normal file
331
rt-thread/libcpu/arm/cortex-a/interrupt.c
Normal file
@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-06 Bernard first version
|
||||
* 2018-11-22 Jesven add smp support
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include "interrupt.h"
|
||||
|
||||
#ifdef RT_USING_GIC_V2
|
||||
#include "gic.h"
|
||||
#else
|
||||
#include "gicv3.h"
|
||||
#endif
|
||||
|
||||
/* exception and interrupt handler table */
|
||||
struct rt_irq_desc isr_table[MAX_HANDLERS];
|
||||
|
||||
#ifndef RT_USING_SMP
|
||||
/* Those varibles will be accessed in ISR, so we need to share them. */
|
||||
rt_uint32_t rt_interrupt_from_thread = 0;
|
||||
rt_uint32_t rt_interrupt_to_thread = 0;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag = 0;
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
static void (*rt_interrupt_switch_hook)(void);
|
||||
|
||||
void rt_interrupt_switch_sethook(void (*hook)(void))
|
||||
{
|
||||
rt_interrupt_switch_hook = hook;
|
||||
}
|
||||
#endif
|
||||
|
||||
void rt_interrupt_hook(void)
|
||||
{
|
||||
RT_OBJECT_HOOK_CALL(rt_interrupt_switch_hook, ());
|
||||
}
|
||||
#endif
|
||||
|
||||
const unsigned int VECTOR_BASE = 0x00;
|
||||
extern void rt_cpu_vector_set_base(unsigned int addr);
|
||||
extern int system_vectors;
|
||||
|
||||
void rt_hw_vector_init(void)
|
||||
{
|
||||
rt_cpu_vector_set_base((unsigned int)&system_vectors);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_GIC_V2
|
||||
/**
|
||||
* This function will initialize hardware interrupt
|
||||
*/
|
||||
void rt_hw_interrupt_init(void)
|
||||
{
|
||||
rt_uint32_t gic_cpu_base;
|
||||
rt_uint32_t gic_dist_base;
|
||||
rt_uint32_t gic_irq_start;
|
||||
|
||||
/* initialize vector table */
|
||||
rt_hw_vector_init();
|
||||
|
||||
/* initialize exceptions table */
|
||||
rt_memset(isr_table, 0x00, sizeof(isr_table));
|
||||
|
||||
/* initialize ARM GIC */
|
||||
gic_dist_base = platform_get_gic_dist_base();
|
||||
gic_cpu_base = platform_get_gic_cpu_base();
|
||||
|
||||
gic_irq_start = GIC_IRQ_START;
|
||||
|
||||
arm_gic_dist_init(0, gic_dist_base, gic_irq_start);
|
||||
arm_gic_cpu_init(0, gic_cpu_base);
|
||||
}
|
||||
#else
|
||||
/**
|
||||
* This function will initialize hardware interrupt
|
||||
* Called by the primary cpu(cpu0)
|
||||
*/
|
||||
void rt_hw_interrupt_init(void)
|
||||
{
|
||||
rt_uint32_t gic_dist_base;
|
||||
rt_uint32_t gic_irq_start;
|
||||
|
||||
/* initialize vector table */
|
||||
rt_hw_vector_init();
|
||||
|
||||
/* initialize exceptions table */
|
||||
rt_memset(isr_table, 0x00, sizeof(isr_table));
|
||||
|
||||
/* initialize ARM GIC */
|
||||
gic_dist_base = platform_get_gic_dist_base();
|
||||
gic_irq_start = GIC_IRQ_START;
|
||||
|
||||
arm_gic_dist_init(0, gic_dist_base, gic_irq_start);
|
||||
|
||||
arm_gic_cpu_init(0);
|
||||
arm_gic_redist_init(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function will mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_mask(int vector)
|
||||
{
|
||||
arm_gic_mask(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will un-mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_umask(int vector)
|
||||
{
|
||||
arm_gic_umask(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the active interrupt number.
|
||||
* @param none
|
||||
*/
|
||||
int rt_hw_interrupt_get_irq(void)
|
||||
{
|
||||
return arm_gic_get_active_irq(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function acknowledges the interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_ack(int vector)
|
||||
{
|
||||
arm_gic_ack(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set interrupt CPU targets.
|
||||
* @param vector: the interrupt number
|
||||
* cpu_mask: target cpus mask, one bit for one core
|
||||
*/
|
||||
void rt_hw_interrupt_set_target_cpus(int vector, unsigned int cpu_mask)
|
||||
{
|
||||
arm_gic_set_cpu(0, vector, cpu_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get interrupt CPU targets.
|
||||
* @param vector: the interrupt number
|
||||
* @return target cpus mask, one bit for one core
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_target_cpus(int vector)
|
||||
{
|
||||
return arm_gic_get_target_cpu(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set interrupt triger mode.
|
||||
* @param vector: the interrupt number
|
||||
* mode: interrupt triger mode; 0: level triger, 1: edge triger
|
||||
*/
|
||||
void rt_hw_interrupt_set_triger_mode(int vector, unsigned int mode)
|
||||
{
|
||||
arm_gic_set_configuration(0, vector, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get interrupt triger mode.
|
||||
* @param vector: the interrupt number
|
||||
* @return interrupt triger mode; 0: level triger, 1: edge triger
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_triger_mode(int vector)
|
||||
{
|
||||
return arm_gic_get_configuration(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set interrupt pending flag.
|
||||
* @param vector: the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_set_pending(int vector)
|
||||
{
|
||||
arm_gic_set_pending_irq(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get interrupt pending flag.
|
||||
* @param vector: the interrupt number
|
||||
* @return interrupt pending flag, 0: not pending; 1: pending
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_pending(int vector)
|
||||
{
|
||||
return arm_gic_get_pending_irq(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function clear interrupt pending flag.
|
||||
* @param vector: the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_clear_pending(int vector)
|
||||
{
|
||||
arm_gic_clear_pending_irq(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set interrupt priority value.
|
||||
* @param vector: the interrupt number
|
||||
* priority: the priority of interrupt to set
|
||||
*/
|
||||
void rt_hw_interrupt_set_priority(int vector, unsigned int priority)
|
||||
{
|
||||
arm_gic_set_priority(0, vector, priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get interrupt priority.
|
||||
* @param vector: the interrupt number
|
||||
* @return interrupt priority value
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_priority(int vector)
|
||||
{
|
||||
return arm_gic_get_priority(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set priority masking threshold.
|
||||
* @param priority: priority masking threshold
|
||||
*/
|
||||
void rt_hw_interrupt_set_priority_mask(unsigned int priority)
|
||||
{
|
||||
arm_gic_set_interface_prior_mask(0, priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get priority masking threshold.
|
||||
* @param none
|
||||
* @return priority masking threshold
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_priority_mask(void)
|
||||
{
|
||||
return arm_gic_get_interface_prior_mask(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set priority grouping field split point.
|
||||
* @param bits: priority grouping field split point
|
||||
* @return 0: success; -1: failed
|
||||
*/
|
||||
int rt_hw_interrupt_set_prior_group_bits(unsigned int bits)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (bits < 8)
|
||||
{
|
||||
arm_gic_set_binary_point(0, (7 - bits));
|
||||
status = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = -1;
|
||||
}
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get priority grouping field split point.
|
||||
* @param none
|
||||
* @return priority grouping field split point
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_prior_group_bits(void)
|
||||
{
|
||||
unsigned int bp;
|
||||
|
||||
bp = arm_gic_get_binary_point(0) & 0x07;
|
||||
|
||||
return (7 - bp);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will install a interrupt service routine to a interrupt.
|
||||
* @param vector the interrupt number
|
||||
* @param new_handler the interrupt service routine to be installed
|
||||
* @param old_handler the old interrupt service routine
|
||||
*/
|
||||
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
|
||||
void *param, const char *name)
|
||||
{
|
||||
rt_isr_handler_t old_handler = RT_NULL;
|
||||
|
||||
if (vector < MAX_HANDLERS)
|
||||
{
|
||||
old_handler = isr_table[vector].handler;
|
||||
|
||||
if (handler != RT_NULL)
|
||||
{
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX);
|
||||
#endif /* RT_USING_INTERRUPT_INFO */
|
||||
isr_table[vector].handler = handler;
|
||||
isr_table[vector].param = param;
|
||||
}
|
||||
}
|
||||
|
||||
return old_handler;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask)
|
||||
{
|
||||
#ifdef RT_USING_GIC_V2
|
||||
arm_gic_send_sgi(0, ipi_vector, cpu_mask, 0);
|
||||
#else
|
||||
arm_gic_send_affinity_sgi(0, ipi_vector, cpu_mask, ROUTED_TO_SPEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler)
|
||||
{
|
||||
/* note: ipi_vector maybe different with irq_vector */
|
||||
rt_hw_interrupt_install(ipi_vector, ipi_isr_handler, 0, "IPI_HANDLER");
|
||||
}
|
||||
#endif
|
||||
|
||||
60
rt-thread/libcpu/arm/cortex-a/interrupt.h
Normal file
60
rt-thread/libcpu/arm/cortex-a/interrupt.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-06 Bernard first version
|
||||
*/
|
||||
|
||||
#ifndef __INTERRUPT_H__
|
||||
#define __INTERRUPT_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
#define INT_IRQ 0x00
|
||||
#define INT_FIQ 0x01
|
||||
|
||||
#define IRQ_MODE_TRIG_LEVEL (0x00) /* Trigger: level triggered interrupt */
|
||||
#define IRQ_MODE_TRIG_EDGE (0x01) /* Trigger: edge triggered interrupt */
|
||||
|
||||
void rt_hw_vector_init(void);
|
||||
|
||||
void rt_hw_interrupt_init(void);
|
||||
void rt_hw_interrupt_mask(int vector);
|
||||
void rt_hw_interrupt_umask(int vector);
|
||||
|
||||
int rt_hw_interrupt_get_irq(void);
|
||||
void rt_hw_interrupt_ack(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_target_cpus(int vector, unsigned int cpu_mask);
|
||||
unsigned int rt_hw_interrupt_get_target_cpus(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_triger_mode(int vector, unsigned int mode);
|
||||
unsigned int rt_hw_interrupt_get_triger_mode(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_pending(int vector);
|
||||
unsigned int rt_hw_interrupt_get_pending(int vector);
|
||||
void rt_hw_interrupt_clear_pending(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_priority(int vector, unsigned int priority);
|
||||
unsigned int rt_hw_interrupt_get_priority(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_priority_mask(unsigned int priority);
|
||||
unsigned int rt_hw_interrupt_get_priority_mask(void);
|
||||
|
||||
int rt_hw_interrupt_set_prior_group_bits(unsigned int bits);
|
||||
unsigned int rt_hw_interrupt_get_prior_group_bits(void);
|
||||
|
||||
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
|
||||
void *param, const char *name);
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask);
|
||||
void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
182
rt-thread/libcpu/arm/cortex-a/mmu.c
Normal file
182
rt-thread/libcpu/arm/cortex-a/mmu.c
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-01-10 bernard porting to AM1808
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
#include "cp15.h"
|
||||
#include "mmu.h"
|
||||
|
||||
/* dump 2nd level page table */
|
||||
void rt_hw_cpu_dump_page_table_2nd(rt_uint32_t *ptb)
|
||||
{
|
||||
int i;
|
||||
int fcnt = 0;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
rt_uint32_t pte2 = ptb[i];
|
||||
if ((pte2 & 0x3) == 0)
|
||||
{
|
||||
if (fcnt == 0)
|
||||
rt_kprintf(" ");
|
||||
rt_kprintf("%04x: ", i);
|
||||
fcnt++;
|
||||
if (fcnt == 16)
|
||||
{
|
||||
rt_kprintf("fault\n");
|
||||
fcnt = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (fcnt != 0)
|
||||
{
|
||||
rt_kprintf("fault\n");
|
||||
fcnt = 0;
|
||||
}
|
||||
|
||||
rt_kprintf(" %04x: %x: ", i, pte2);
|
||||
if ((pte2 & 0x3) == 0x1)
|
||||
{
|
||||
rt_kprintf("L,ap:%x,xn:%d,texcb:%02x\n",
|
||||
((pte2 >> 7) | (pte2 >> 4))& 0xf,
|
||||
(pte2 >> 15) & 0x1,
|
||||
((pte2 >> 10) | (pte2 >> 2)) & 0x1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("S,ap:%x,xn:%d,texcb:%02x\n",
|
||||
((pte2 >> 7) | (pte2 >> 4))& 0xf, pte2 & 0x1,
|
||||
((pte2 >> 4) | (pte2 >> 2)) & 0x1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dump_page_table(rt_uint32_t *ptb)
|
||||
{
|
||||
int i;
|
||||
int fcnt = 0;
|
||||
|
||||
rt_kprintf("page table@%p\n", ptb);
|
||||
for (i = 0; i < 1024*4; i++)
|
||||
{
|
||||
rt_uint32_t pte1 = ptb[i];
|
||||
if ((pte1 & 0x3) == 0)
|
||||
{
|
||||
rt_kprintf("%03x: ", i);
|
||||
fcnt++;
|
||||
if (fcnt == 16)
|
||||
{
|
||||
rt_kprintf("fault\n");
|
||||
fcnt = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (fcnt != 0)
|
||||
{
|
||||
rt_kprintf("fault\n");
|
||||
fcnt = 0;
|
||||
}
|
||||
|
||||
rt_kprintf("%03x: %08x: ", i, pte1);
|
||||
if ((pte1 & 0x3) == 0x3)
|
||||
{
|
||||
rt_kprintf("LPAE\n");
|
||||
}
|
||||
else if ((pte1 & 0x3) == 0x1)
|
||||
{
|
||||
rt_kprintf("pte,ns:%d,domain:%d\n",
|
||||
(pte1 >> 3) & 0x1, (pte1 >> 5) & 0xf);
|
||||
/*
|
||||
*rt_hw_cpu_dump_page_table_2nd((void*)((pte1 & 0xfffffc000)
|
||||
* - 0x80000000 + 0xC0000000));
|
||||
*/
|
||||
}
|
||||
else if (pte1 & (1 << 18))
|
||||
{
|
||||
rt_kprintf("super section,ns:%d,ap:%x,xn:%d,texcb:%02x\n",
|
||||
(pte1 >> 19) & 0x1,
|
||||
((pte1 >> 13) | (pte1 >> 10))& 0xf,
|
||||
(pte1 >> 4) & 0x1,
|
||||
((pte1 >> 10) | (pte1 >> 2)) & 0x1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("section,ns:%d,ap:%x,"
|
||||
"xn:%d,texcb:%02x,domain:%d\n",
|
||||
(pte1 >> 19) & 0x1,
|
||||
((pte1 >> 13) | (pte1 >> 10))& 0xf,
|
||||
(pte1 >> 4) & 0x1,
|
||||
(((pte1 & (0x7 << 12)) >> 10) |
|
||||
((pte1 & 0x0c) >> 2)) & 0x1f,
|
||||
(pte1 >> 5) & 0xf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* level1 page table, each entry for 1MB memory. */
|
||||
volatile static unsigned long MMUTable[4*1024] __attribute__((aligned(16*1024)));
|
||||
void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart,
|
||||
rt_uint32_t vaddrEnd,
|
||||
rt_uint32_t paddrStart,
|
||||
rt_uint32_t attr)
|
||||
{
|
||||
volatile rt_uint32_t *pTT;
|
||||
volatile int i, nSec;
|
||||
pTT = (rt_uint32_t *)MMUTable + (vaddrStart >> 20);
|
||||
nSec = (vaddrEnd >> 20) - (vaddrStart >> 20);
|
||||
for(i = 0; i <= nSec; i++)
|
||||
{
|
||||
*pTT = attr | (((paddrStart >> 20) + i) << 20);
|
||||
pTT++;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long rt_hw_set_domain_register(unsigned long domain_val)
|
||||
{
|
||||
unsigned long old_domain;
|
||||
|
||||
asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain));
|
||||
asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory");
|
||||
|
||||
return old_domain;
|
||||
}
|
||||
|
||||
void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size)
|
||||
{
|
||||
/* set page table */
|
||||
for(; size > 0; size--)
|
||||
{
|
||||
rt_hw_mmu_setmtt(mdesc->vaddr_start, mdesc->vaddr_end,
|
||||
mdesc->paddr_start, mdesc->attr);
|
||||
mdesc++;
|
||||
}
|
||||
}
|
||||
|
||||
void rt_hw_mmu_init(void)
|
||||
{
|
||||
rt_cpu_dcache_clean_flush();
|
||||
rt_cpu_icache_flush();
|
||||
rt_hw_cpu_dcache_disable();
|
||||
rt_hw_cpu_icache_disable();
|
||||
rt_cpu_mmu_disable();
|
||||
|
||||
/*rt_hw_cpu_dump_page_table(MMUTable);*/
|
||||
rt_hw_set_domain_register(0x55555555);
|
||||
|
||||
rt_cpu_tlb_set(MMUTable);
|
||||
|
||||
rt_cpu_mmu_enable();
|
||||
|
||||
rt_hw_cpu_icache_enable();
|
||||
rt_hw_cpu_dcache_enable();
|
||||
}
|
||||
|
||||
49
rt-thread/libcpu/arm/cortex-a/mmu.h
Normal file
49
rt-thread/libcpu/arm/cortex-a/mmu.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-03-25 quanzhao the first version
|
||||
*/
|
||||
#ifndef __MMU_H_
|
||||
#define __MMU_H_
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define DESC_SEC (0x2)
|
||||
#define MEMWBWA ((1<<12)|(3<<2)) /* write back, write allocate */
|
||||
#define MEMWB (3<<2) /* write back, no write allocate */
|
||||
#define MEMWT (2<<2) /* write through, no write allocate */
|
||||
#define SHAREDEVICE (1<<2) /* shared device */
|
||||
#define STRONGORDER (0<<2) /* strong ordered */
|
||||
#define XN (1<<4) /* eXecute Never */
|
||||
#define AP_RW (3<<10) /* supervisor=RW, user=RW */
|
||||
#define AP_RO (2<<10) /* supervisor=RW, user=RO */
|
||||
#define SHARED (1<<16) /* shareable */
|
||||
|
||||
#define DOMAIN_FAULT (0x0)
|
||||
#define DOMAIN_CHK (0x1)
|
||||
#define DOMAIN_NOTCHK (0x3)
|
||||
#define DOMAIN0 (0x0<<5)
|
||||
#define DOMAIN1 (0x1<<5)
|
||||
|
||||
#define DOMAIN0_ATTR (DOMAIN_CHK<<0)
|
||||
#define DOMAIN1_ATTR (DOMAIN_FAULT<<2)
|
||||
|
||||
/* device mapping type */
|
||||
#define DEVICE_MEM (SHARED|AP_RW|DOMAIN0|SHAREDEVICE|DESC_SEC|XN)
|
||||
/* normal memory mapping type */
|
||||
#define NORMAL_MEM (SHARED|AP_RW|DOMAIN0|MEMWBWA|DESC_SEC)
|
||||
|
||||
struct mem_desc
|
||||
{
|
||||
rt_uint32_t vaddr_start;
|
||||
rt_uint32_t vaddr_end;
|
||||
rt_uint32_t paddr_start;
|
||||
rt_uint32_t attr;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
71
rt-thread/libcpu/arm/cortex-a/stack.c
Normal file
71
rt-thread/libcpu/arm/cortex-a/stack.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-09-23 Bernard the first version
|
||||
* 2011-10-05 Bernard add thumb mode
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
#include <armv7.h>
|
||||
|
||||
/**
|
||||
* @addtogroup AM33xx
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
|
||||
rt_uint8_t *stack_addr, void *texit)
|
||||
{
|
||||
rt_uint32_t *stk;
|
||||
|
||||
stack_addr += sizeof(rt_uint32_t);
|
||||
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
|
||||
stk = (rt_uint32_t *)stack_addr;
|
||||
*(--stk) = (rt_uint32_t)tentry; /* entry point */
|
||||
*(--stk) = (rt_uint32_t)texit; /* lr */
|
||||
*(--stk) = 0xdeadbeef; /* r12 */
|
||||
*(--stk) = 0xdeadbeef; /* r11 */
|
||||
*(--stk) = 0xdeadbeef; /* r10 */
|
||||
*(--stk) = 0xdeadbeef; /* r9 */
|
||||
*(--stk) = 0xdeadbeef; /* r8 */
|
||||
*(--stk) = 0xdeadbeef; /* r7 */
|
||||
*(--stk) = 0xdeadbeef; /* r6 */
|
||||
*(--stk) = 0xdeadbeef; /* r5 */
|
||||
*(--stk) = 0xdeadbeef; /* r4 */
|
||||
*(--stk) = 0xdeadbeef; /* r3 */
|
||||
*(--stk) = 0xdeadbeef; /* r2 */
|
||||
*(--stk) = 0xdeadbeef; /* r1 */
|
||||
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
|
||||
/* cpsr */
|
||||
if ((rt_uint32_t)tentry & 0x01)
|
||||
*(--stk) = SVCMODE | 0x20; /* thumb mode */
|
||||
else
|
||||
*(--stk) = SVCMODE; /* arm mode */
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
*(--stk) = 0; /* user lr */
|
||||
*(--stk) = 0; /* user sp*/
|
||||
#endif
|
||||
#ifdef RT_USING_FPU
|
||||
*(--stk) = 0; /* not use fpu*/
|
||||
#endif
|
||||
|
||||
/* return task's current stack address */
|
||||
return (rt_uint8_t *)stk;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
487
rt-thread/libcpu/arm/cortex-a/start_gcc.S
Normal file
487
rt-thread/libcpu/arm/cortex-a/start_gcc.S
Normal file
@ -0,0 +1,487 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-05 Bernard the first version
|
||||
* 2018-11-22 Jesven in the interrupt context, use rt_scheduler_do_irq_switch checks
|
||||
* and switches to a new thread
|
||||
*/
|
||||
|
||||
#include "rtconfig.h"
|
||||
.equ Mode_USR, 0x10
|
||||
.equ Mode_FIQ, 0x11
|
||||
.equ Mode_IRQ, 0x12
|
||||
.equ Mode_SVC, 0x13
|
||||
.equ Mode_ABT, 0x17
|
||||
.equ Mode_UND, 0x1B
|
||||
.equ Mode_SYS, 0x1F
|
||||
|
||||
.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled
|
||||
.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled
|
||||
|
||||
.equ UND_Stack_Size, 0x00000400
|
||||
.equ SVC_Stack_Size, 0x00000400
|
||||
.equ ABT_Stack_Size, 0x00000400
|
||||
.equ RT_FIQ_STACK_PGSZ, 0x00000000
|
||||
.equ RT_IRQ_STACK_PGSZ, 0x00000800
|
||||
.equ USR_Stack_Size, 0x00000400
|
||||
|
||||
.equ SUB_UND_Stack_Size, 0x00000400
|
||||
.equ SUB_SVC_Stack_Size, 0x00000400
|
||||
.equ SUB_ABT_Stack_Size, 0x00000400
|
||||
.equ SUB_RT_FIQ_STACK_PGSZ, 0x00000000
|
||||
.equ SUB_RT_IRQ_STACK_PGSZ, 0x00000400
|
||||
.equ SUB_USR_Stack_Size, 0x00000400
|
||||
|
||||
#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
|
||||
RT_FIQ_STACK_PGSZ + RT_IRQ_STACK_PGSZ)
|
||||
|
||||
#define SUB_ISR_Stack_Size (SUB_UND_Stack_Size + SUB_SVC_Stack_Size + SUB_ABT_Stack_Size + \
|
||||
SUB_RT_FIQ_STACK_PGSZ + SUB_RT_IRQ_STACK_PGSZ)
|
||||
|
||||
.section .bss.share.isr
|
||||
/* stack */
|
||||
.globl stack_start
|
||||
.globl stack_top
|
||||
|
||||
.align 3
|
||||
stack_start:
|
||||
.rept ISR_Stack_Size
|
||||
.byte 0
|
||||
.endr
|
||||
stack_top:
|
||||
|
||||
.text
|
||||
/* reset entry */
|
||||
.globl _reset
|
||||
_reset:
|
||||
#ifdef ARCH_ARMV8
|
||||
/* Check for HYP mode */
|
||||
mrs r0, cpsr_all
|
||||
and r0, r0, #0x1F
|
||||
mov r8, #0x1A
|
||||
cmp r0, r8
|
||||
beq overHyped
|
||||
b continue
|
||||
|
||||
overHyped: /* Get out of HYP mode */
|
||||
adr r1, continue
|
||||
msr ELR_hyp, r1
|
||||
mrs r1, cpsr_all
|
||||
and r1, r1, #0x1f ;@ CPSR_MODE_MASK
|
||||
orr r1, r1, #0x13 ;@ CPSR_MODE_SUPERVISOR
|
||||
msr SPSR_hyp, r1
|
||||
eret
|
||||
|
||||
continue:
|
||||
#endif
|
||||
/* set the cpu to SVC32 mode and disable interrupt */
|
||||
cps #Mode_SVC
|
||||
|
||||
#ifdef RT_USING_FPU
|
||||
mov r4, #0xfffffff
|
||||
mcr p15, 0, r4, c1, c0, 2
|
||||
#endif
|
||||
|
||||
/* disable the data alignment check */
|
||||
mrc p15, 0, r1, c1, c0, 0
|
||||
bic r1, #(1<<0) /* Disable MMU */
|
||||
bic r1, #(1<<1) /* Disable Alignment fault checking */
|
||||
bic r1, #(1<<2) /* Disable data cache */
|
||||
bic r1, #(1<<11) /* Disable program flow prediction */
|
||||
bic r1, #(1<<12) /* Disable instruction cache */
|
||||
bic r1, #(3<<19) /* bit[20:19] must be zero */
|
||||
mcr p15, 0, r1, c1, c0, 0
|
||||
|
||||
@ get cpu id, and subtract the offset from the stacks base address
|
||||
bl rt_hw_cpu_id
|
||||
mov r5, r0
|
||||
|
||||
cmp r5, #0 @ cpu id == 0
|
||||
beq normal_setup
|
||||
|
||||
@ cpu id > 0, stop or wait
|
||||
#ifdef RT_SMP_AUTO_BOOT
|
||||
ldr r0, =secondary_cpu_entry
|
||||
mov r1, #0
|
||||
str r1, [r0] /* clean secondary_cpu_entry */
|
||||
#endif /* RT_SMP_AUTO_BOOT */
|
||||
|
||||
secondary_loop:
|
||||
@ cpu core 1 goes into sleep until core 0 wakeup it
|
||||
wfe
|
||||
#ifdef RT_SMP_AUTO_BOOT
|
||||
ldr r1, =secondary_cpu_entry
|
||||
ldr r0, [r1]
|
||||
cmp r0, #0
|
||||
blxne r0 /* if(secondary_cpu_entry) secondary_cpu_entry(); */
|
||||
#endif /* RT_SMP_AUTO_BOOT */
|
||||
b secondary_loop
|
||||
|
||||
normal_setup:
|
||||
/* setup stack */
|
||||
bl stack_setup
|
||||
|
||||
/* clear .bss */
|
||||
mov r0,#0 /* get a zero */
|
||||
ldr r1,=__bss_start /* bss start */
|
||||
ldr r2,=__bss_end /* bss end */
|
||||
|
||||
bss_loop:
|
||||
cmp r1,r2 /* check if data to clear */
|
||||
strlo r0,[r1],#4 /* clear 4 bytes */
|
||||
blo bss_loop /* loop until done */
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
mrc p15, 0, r1, c1, c0, 1
|
||||
mov r0, #(1<<6)
|
||||
orr r1, r0
|
||||
mcr p15, 0, r1, c1, c0, 1 //enable smp
|
||||
#endif
|
||||
|
||||
/* enable branch prediction */
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
orr r0, r0, #(1<<11)
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
/* initialize the mmu table and enable mmu */
|
||||
ldr r0, =platform_mem_desc
|
||||
ldr r1, =platform_mem_desc_size
|
||||
ldr r1, [r1]
|
||||
bl rt_hw_init_mmu_table
|
||||
bl rt_hw_mmu_init
|
||||
|
||||
/* start RT-Thread Kernel */
|
||||
ldr pc, _rtthread_startup
|
||||
_rtthread_startup:
|
||||
.word rtthread_startup
|
||||
|
||||
stack_setup:
|
||||
ldr r0, =stack_top
|
||||
|
||||
@ Set the startup stack for svc
|
||||
mov sp, r0
|
||||
sub r0, r0, #SVC_Stack_Size
|
||||
|
||||
@ Enter Undefined Instruction Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_UND|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #UND_Stack_Size
|
||||
|
||||
@ Enter Abort Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_ABT|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #ABT_Stack_Size
|
||||
|
||||
@ Enter FIQ Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #RT_FIQ_STACK_PGSZ
|
||||
|
||||
@ Enter IRQ Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #RT_IRQ_STACK_PGSZ
|
||||
|
||||
/* come back to SVC mode */
|
||||
msr cpsr_c, #Mode_SVC|I_Bit|F_Bit
|
||||
bx lr
|
||||
|
||||
/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */
|
||||
.section .text.isr, "ax"
|
||||
.align 5
|
||||
.globl vector_fiq
|
||||
vector_fiq:
|
||||
stmfd sp!,{r0-r7,lr}
|
||||
bl rt_hw_trap_fiq
|
||||
ldmfd sp!,{r0-r7,lr}
|
||||
subs pc, lr, #4
|
||||
|
||||
.globl rt_interrupt_enter
|
||||
.globl rt_interrupt_leave
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
|
||||
.globl rt_current_thread
|
||||
.globl vmm_thread
|
||||
.globl vmm_virq_check
|
||||
|
||||
.align 5
|
||||
.globl vector_irq
|
||||
vector_irq:
|
||||
#ifdef RT_USING_SMP
|
||||
clrex
|
||||
|
||||
stmfd sp!, {r0, r1}
|
||||
cps #Mode_SVC
|
||||
mov r0, sp /* svc_sp */
|
||||
mov r1, lr /* svc_lr */
|
||||
|
||||
cps #Mode_IRQ
|
||||
sub lr, #4
|
||||
stmfd r0!, {r1, lr} /* svc_lr, svc_pc */
|
||||
stmfd r0!, {r2 - r12}
|
||||
ldmfd sp!, {r1, r2} /* original r0, r1 */
|
||||
stmfd r0!, {r1 - r2}
|
||||
mrs r1, spsr /* original mode */
|
||||
stmfd r0!, {r1}
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
stmfd r0, {r13, r14}^ /* usr_sp, usr_lr */
|
||||
sub r0, #8
|
||||
#endif
|
||||
#ifdef RT_USING_FPU
|
||||
/* fpu context */
|
||||
vmrs r6, fpexc
|
||||
tst r6, #(1<<30)
|
||||
beq 1f
|
||||
vstmdb r0!, {d0-d15}
|
||||
vstmdb r0!, {d16-d31}
|
||||
vmrs r5, fpscr
|
||||
stmfd r0!, {r5}
|
||||
1:
|
||||
stmfd r0!, {r6}
|
||||
#endif
|
||||
|
||||
/* now irq stack is clean */
|
||||
/* r0 is task svc_sp */
|
||||
/* backup r0 -> r8 */
|
||||
mov r8, r0
|
||||
|
||||
bl rt_interrupt_enter
|
||||
bl rt_hw_trap_irq
|
||||
bl rt_interrupt_leave
|
||||
|
||||
cps #Mode_SVC
|
||||
mov sp, r8
|
||||
mov r0, r8
|
||||
bl rt_scheduler_do_irq_switch
|
||||
|
||||
b rt_hw_context_switch_exit
|
||||
|
||||
#else
|
||||
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
|
||||
|
||||
rt_hw_context_switch_interrupt_do:
|
||||
mov r1, #0 @ clear flag
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, sp @ r1 point to {r0-r3} in stack
|
||||
add sp, sp, #4*4
|
||||
ldmfd sp!, {r4-r12,lr}@ reload saved registers
|
||||
mrs r0, spsr @ get cpsr of interrupt thread
|
||||
sub r2, lr, #4 @ save old task's pc to r2
|
||||
|
||||
@ Switch to SVC mode with no interrupt. If the usr mode guest is
|
||||
@ interrupted, this will just switch to the stack of kernel space.
|
||||
@ save the registers in kernel space won't trigger data abort.
|
||||
msr cpsr_c, #I_Bit|F_Bit|Mode_SVC
|
||||
|
||||
stmfd sp!, {r2} @ push old task's pc
|
||||
stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4
|
||||
ldmfd r1, {r1-r4} @ restore r0-r3 of the interrupt thread
|
||||
stmfd sp!, {r1-r4} @ push old task's r0-r3
|
||||
stmfd sp!, {r0} @ push old task's cpsr
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
stmfd sp, {r13, r14}^ @push usr_sp, usr_lr
|
||||
sub sp, #8
|
||||
#endif
|
||||
#ifdef RT_USING_FPU
|
||||
/* fpu context */
|
||||
vmrs r6, fpexc
|
||||
tst r6, #(1<<30)
|
||||
beq 1f
|
||||
vstmdb sp!, {d0-d15}
|
||||
vstmdb sp!, {d16-d31}
|
||||
vmrs r5, fpscr
|
||||
stmfd sp!, {r5}
|
||||
1:
|
||||
stmfd sp!, {r6}
|
||||
#endif
|
||||
|
||||
ldr r4, =rt_interrupt_from_thread
|
||||
ldr r5, [r4]
|
||||
str sp, [r5] @ store sp in preempted tasks's TCB
|
||||
|
||||
ldr r6, =rt_interrupt_to_thread
|
||||
ldr r6, [r6]
|
||||
ldr sp, [r6] @ get new task's stack pointer
|
||||
|
||||
bl rt_interrupt_hook
|
||||
|
||||
#ifdef RT_USING_FPU
|
||||
/* fpu context */
|
||||
ldmfd sp!, {r6}
|
||||
vmsr fpexc, r6
|
||||
tst r6, #(1<<30)
|
||||
beq 1f
|
||||
ldmfd sp!, {r5}
|
||||
vmsr fpscr, r5
|
||||
vldmia sp!, {d16-d31}
|
||||
vldmia sp!, {d0-d15}
|
||||
1:
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
ldmfd sp, {r13, r14}^ @pop usr_sp, usr_lr
|
||||
add sp, #8
|
||||
#endif
|
||||
|
||||
ldmfd sp!, {r4} @ pop new task's cpsr to spsr
|
||||
msr spsr_cxsf, r4
|
||||
|
||||
ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr
|
||||
|
||||
#endif
|
||||
|
||||
.macro push_svc_reg
|
||||
sub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */
|
||||
stmia sp, {r0 - r12} @/* Calling r0-r12 */
|
||||
mov r0, sp
|
||||
mrs r6, spsr @/* Save CPSR */
|
||||
str lr, [r0, #15*4] @/* Push PC */
|
||||
str r6, [r0, #16*4] @/* Push CPSR */
|
||||
mrs r5, cpsr @/* Save CPSR */
|
||||
|
||||
and r4, r6, #0x1F
|
||||
cmp r4, #Mode_USR
|
||||
moveq r6, #Mode_SYS
|
||||
|
||||
orr r6, r6, #0x80 @/* Switch to previous mode, then save SP & PC */
|
||||
msr cpsr_c, r6
|
||||
str sp, [r0, #13*4] @/* Save calling SP */
|
||||
str lr, [r0, #14*4] @/* Save calling PC */
|
||||
|
||||
msr cpsr_c, r5 @/* Switch back to current mode */
|
||||
.endm
|
||||
|
||||
.align 5
|
||||
.weak vector_swi
|
||||
vector_swi:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_swi
|
||||
b .
|
||||
|
||||
.align 5
|
||||
.globl vector_undef
|
||||
vector_undef:
|
||||
push_svc_reg
|
||||
cps #Mode_UND
|
||||
bl rt_hw_trap_undef
|
||||
#ifdef RT_USING_FPU
|
||||
ldr lr, [sp, #15*4]
|
||||
ldmia sp, {r0 - r12}
|
||||
add sp, sp, #17 * 4
|
||||
movs pc, lr
|
||||
#endif
|
||||
b .
|
||||
|
||||
.align 5
|
||||
.globl vector_pabt
|
||||
vector_pabt:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_pabt
|
||||
b .
|
||||
|
||||
.align 5
|
||||
.globl vector_dabt
|
||||
vector_dabt:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_dabt
|
||||
b .
|
||||
|
||||
.align 5
|
||||
.globl vector_resv
|
||||
vector_resv:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_resv
|
||||
b .
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
.global secondary_cpu_start
|
||||
secondary_cpu_start:
|
||||
|
||||
#ifdef RT_USING_FPU
|
||||
mov r4, #0xfffffff
|
||||
mcr p15, 0, r4, c1, c0, 2
|
||||
#endif
|
||||
|
||||
mrc p15, 0, r1, c1, c0, 1
|
||||
mov r0, #(1<<6)
|
||||
orr r1, r0
|
||||
mcr p15, 0, r1, c1, c0, 1 //enable smp
|
||||
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
bic r0, #(1<<13)
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
/* enable branch prediction */
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
orr r0, r0, #(1<<11)
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
@ get cpu id, and subtract the offset from the stacks base address
|
||||
bl rt_hw_cpu_id
|
||||
sub r5, r0, #1
|
||||
|
||||
ldr r0, =SUB_ISR_Stack_Size
|
||||
mul r0, r0, r5 @r0 = SUB_ISR_Stack_Size * (cpuid - 1)
|
||||
ldr r1, =sub_stack_top
|
||||
sub r0, r1, r0 @r0 = sub_stack_top - (SUB_ISR_Stack_Size * (cpuid - 1))
|
||||
|
||||
cps #Mode_SVC
|
||||
mov sp, r0
|
||||
sub r0, r0, #SUB_SVC_Stack_Size
|
||||
|
||||
cps #Mode_UND
|
||||
mov sp, r0
|
||||
sub r0, r0, #SUB_UND_Stack_Size
|
||||
|
||||
cps #Mode_ABT
|
||||
mov sp, r0
|
||||
sub r0, r0, #SUB_ABT_Stack_Size
|
||||
|
||||
cps #Mode_FIQ
|
||||
mov sp, r0
|
||||
sub r0, r0, #SUB_RT_FIQ_STACK_PGSZ
|
||||
|
||||
cps #Mode_IRQ
|
||||
mov sp, r0
|
||||
sub r0, r0, #SUB_RT_IRQ_STACK_PGSZ
|
||||
|
||||
cps #Mode_SVC
|
||||
|
||||
/* initialize the mmu table and enable mmu */
|
||||
bl rt_hw_mmu_init
|
||||
|
||||
b secondary_cpu_c_start
|
||||
|
||||
.bss
|
||||
.align 2 //align to 2~2=4
|
||||
|
||||
.global sub_stack_top /* used for backtrace to calculate stack top of irq mode */
|
||||
|
||||
sub_stack_start:
|
||||
.space (SUB_ISR_Stack_Size * (RT_CPUS_NR-1))
|
||||
sub_stack_top:
|
||||
|
||||
#endif
|
||||
275
rt-thread/libcpu/arm/cortex-a/trap.c
Normal file
275
rt-thread/libcpu/arm/cortex-a/trap.c
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
#include "armv7.h"
|
||||
#include "interrupt.h"
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
|
||||
static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL;
|
||||
|
||||
/**
|
||||
* This function set the hook, which is invoked on fault exception handling.
|
||||
*
|
||||
* @param exception_handle the exception handling hook function.
|
||||
*/
|
||||
void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context))
|
||||
{
|
||||
rt_exception_hook = exception_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will show registers of CPU
|
||||
*
|
||||
* @param regs the registers point
|
||||
*/
|
||||
void rt_hw_show_register(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
rt_kprintf("Execption:\n");
|
||||
rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3);
|
||||
rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7);
|
||||
rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10);
|
||||
rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip);
|
||||
rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc);
|
||||
rt_kprintf("cpsr:0x%08x\n", regs->cpsr);
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(regs);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
}
|
||||
|
||||
void (*rt_trap_hook)(struct rt_hw_exp_stack *regs, const char *ex, unsigned int exception_type);
|
||||
|
||||
/**
|
||||
* This function will set a hook function to trap handler.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_hw_trap_set_hook(void (*hook)(struct rt_hw_exp_stack *regs, const char *ex, unsigned int exception_type))
|
||||
{
|
||||
rt_trap_hook = hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* When comes across an instruction which it cannot handle,
|
||||
* it takes the undefined instruction trap.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_undef(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
#ifdef RT_USING_FPU
|
||||
{
|
||||
uint32_t val;
|
||||
uint32_t addr;
|
||||
|
||||
if (regs->cpsr & (1 << 5))
|
||||
{
|
||||
/* thumb mode */
|
||||
addr = regs->pc - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = regs->pc - 4;
|
||||
}
|
||||
asm volatile ("vmrs %0, fpexc" : "=r"(val)::"memory");
|
||||
|
||||
if (!(val & 0x40000000))
|
||||
{
|
||||
/* float ins */
|
||||
val = (1U << 30);
|
||||
|
||||
asm volatile ("vmsr fpexc, %0"::"r"(val):"memory");
|
||||
regs->pc = addr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rt_trap_hook == RT_NULL)
|
||||
{
|
||||
rt_kprintf("undefined instruction:\n");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trap_hook(regs, "undefined instruction", UND_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The software interrupt instruction (SWI) is used for entering
|
||||
* Supervisor mode, usually to request a particular supervisor
|
||||
* function.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_swi(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
if (rt_trap_hook == RT_NULL)
|
||||
{
|
||||
rt_kprintf("software interrupt:\n");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trap_hook(regs, "software instruction", SWI_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An abort indicates that the current memory access cannot be completed,
|
||||
* which occurs during an instruction prefetch.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
if (rt_trap_hook == RT_NULL)
|
||||
{
|
||||
rt_kprintf("prefetch abort:\n");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trap_hook(regs, "prefetch abort", PABT_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An abort indicates that the current memory access cannot be completed,
|
||||
* which occurs during a data access.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
if (rt_trap_hook == RT_NULL)
|
||||
{
|
||||
rt_kprintf("data abort:");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trap_hook(regs, "data abort", DABT_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normally, system will never reach here
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_resv(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
if (rt_trap_hook == RT_NULL)
|
||||
{
|
||||
rt_kprintf("reserved trap:\n");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trap_hook(regs, "reserved trap", RESV_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
void rt_hw_trap_irq(void)
|
||||
{
|
||||
void *param;
|
||||
int int_ack;
|
||||
int ir;
|
||||
rt_isr_handler_t isr_func;
|
||||
extern struct rt_irq_desc isr_table[];
|
||||
|
||||
int_ack = rt_hw_interrupt_get_irq();
|
||||
|
||||
ir = int_ack & GIC_ACK_INTID_MASK;
|
||||
if (ir == 1023)
|
||||
{
|
||||
/* Spurious interrupt */
|
||||
return;
|
||||
}
|
||||
|
||||
/* get interrupt service routine */
|
||||
isr_func = isr_table[ir].handler;
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
isr_table[ir].counter++;
|
||||
#endif
|
||||
if (isr_func)
|
||||
{
|
||||
/* Interrupt for myself. */
|
||||
param = isr_table[ir].param;
|
||||
/* turn to interrupt service routine */
|
||||
isr_func(ir, param);
|
||||
}
|
||||
|
||||
/* end of interrupt */
|
||||
rt_hw_interrupt_ack(int_ack);
|
||||
}
|
||||
|
||||
void rt_hw_trap_fiq(void)
|
||||
{
|
||||
void *param;
|
||||
int ir;
|
||||
rt_isr_handler_t isr_func;
|
||||
extern struct rt_irq_desc isr_table[];
|
||||
|
||||
ir = rt_hw_interrupt_get_irq();
|
||||
|
||||
/* get interrupt service routine */
|
||||
isr_func = isr_table[ir].handler;
|
||||
param = isr_table[ir].param;
|
||||
|
||||
/* turn to interrupt service routine */
|
||||
isr_func(ir, param);
|
||||
|
||||
/* end of interrupt */
|
||||
rt_hw_interrupt_ack(ir);
|
||||
}
|
||||
|
||||
51
rt-thread/libcpu/arm/cortex-a/vector_gcc.S
Normal file
51
rt-thread/libcpu/arm/cortex-a/vector_gcc.S
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-05 Bernard the first version
|
||||
*/
|
||||
|
||||
.section .vectors, "ax"
|
||||
.code 32
|
||||
|
||||
.globl system_vectors
|
||||
system_vectors:
|
||||
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
|
||||
|
||||
.globl _reset
|
||||
.globl vector_undef
|
||||
.globl vector_swi
|
||||
.globl vector_pabt
|
||||
.globl vector_dabt
|
||||
.globl vector_resv
|
||||
.globl vector_irq
|
||||
.globl vector_fiq
|
||||
|
||||
_vector_reset:
|
||||
.word _reset
|
||||
_vector_undef:
|
||||
.word vector_undef
|
||||
_vector_swi:
|
||||
.word vector_swi
|
||||
_vector_pabt:
|
||||
.word vector_pabt
|
||||
_vector_dabt:
|
||||
.word vector_dabt
|
||||
_vector_resv:
|
||||
.word vector_resv
|
||||
_vector_irq:
|
||||
.word vector_irq
|
||||
_vector_fiq:
|
||||
.word vector_fiq
|
||||
|
||||
.balignl 16,0xdeadbeef
|
||||
214
rt-thread/libcpu/arm/cortex-m0/context_gcc.S
Normal file
214
rt-thread/libcpu/arm/cortex-m0/context_gcc.S
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-01-25 Bernard first version
|
||||
* 2012-06-01 aozima set pendsv priority to 0xFF.
|
||||
* 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
* 2013-02-20 aozima port to gcc.
|
||||
* 2013-06-18 aozima add restore MSP feature.
|
||||
* 2013-11-04 bright fixed hardfault bug for gcc.
|
||||
*/
|
||||
|
||||
.cpu cortex-m0
|
||||
.fpu softvfp
|
||||
.syntax unified
|
||||
.thumb
|
||||
.text
|
||||
|
||||
.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */
|
||||
.equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */
|
||||
.equ NVIC_SHPR3, 0xE000ED20 /* system priority register (3) */
|
||||
.equ NVIC_PENDSV_PRI, 0xFFFF0000 /* PendSV and SysTick priority value (lowest) */
|
||||
.equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.global rt_hw_interrupt_disable
|
||||
.type rt_hw_interrupt_disable, %function
|
||||
rt_hw_interrupt_disable:
|
||||
MRS R0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.global rt_hw_interrupt_enable
|
||||
.type rt_hw_interrupt_enable, %function
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, R0
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* R0 --> from
|
||||
* R1 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_interrupt
|
||||
.type rt_hw_context_switch_interrupt, %function
|
||||
.global rt_hw_context_switch
|
||||
.type rt_hw_context_switch, %function
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
/* set rt_thread_switch_interrupt_flag to 1 */
|
||||
LDR R2, =rt_thread_switch_interrupt_flag
|
||||
LDR R3, [R2]
|
||||
CMP R3, #1
|
||||
BEQ _reswitch
|
||||
MOVS R3, #1
|
||||
STR R3, [R2]
|
||||
|
||||
LDR R2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
|
||||
STR R0, [R2]
|
||||
|
||||
_reswitch:
|
||||
LDR R2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
|
||||
STR R1, [R2]
|
||||
|
||||
LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR R1, =NVIC_PENDSVSET
|
||||
STR R1, [R0]
|
||||
BX LR
|
||||
|
||||
/* R0 --> switch from thread stack
|
||||
* R1 --> switch to thread stack
|
||||
* psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack
|
||||
*/
|
||||
.global PendSV_Handler
|
||||
.type PendSV_Handler, %function
|
||||
PendSV_Handler:
|
||||
/* disable interrupt to protect context switch */
|
||||
MRS R2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
/* get rt_thread_switch_interrupt_flag */
|
||||
LDR R0, =rt_thread_switch_interrupt_flag
|
||||
LDR R1, [R0]
|
||||
CMP R1, #0x00
|
||||
BEQ pendsv_exit /* pendsv already handled */
|
||||
|
||||
/* clear rt_thread_switch_interrupt_flag to 0 */
|
||||
MOVS R1, #0
|
||||
STR R1, [R0]
|
||||
|
||||
LDR R0, =rt_interrupt_from_thread
|
||||
LDR R1, [R0]
|
||||
CMP R1, #0x00
|
||||
BEQ switch_to_thread /* skip register save at the first time */
|
||||
|
||||
MRS R1, PSP /* get from thread stack pointer */
|
||||
|
||||
SUBS R1, R1, #0x20 /* space for {R4 - R7} and {R8 - R11} */
|
||||
LDR R0, [R0]
|
||||
STR R1, [R0] /* update from thread stack pointer */
|
||||
|
||||
STMIA R1!, {R4 - R7} /* push thread {R4 - R7} register to thread stack */
|
||||
|
||||
MOV R4, R8 /* mov thread {R8 - R11} to {R4 - R7} */
|
||||
MOV R5, R9
|
||||
MOV R6, R10
|
||||
MOV R7, R11
|
||||
STMIA R1!, {R4 - R7} /* push thread {R8 - R11} high register to thread stack */
|
||||
switch_to_thread:
|
||||
LDR R1, =rt_interrupt_to_thread
|
||||
LDR R1, [R1]
|
||||
LDR R1, [R1] /* load thread stack pointer */
|
||||
|
||||
LDMIA R1!, {R4 - R7} /* pop thread {R4 - R7} register from thread stack */
|
||||
PUSH {R4 - R7} /* push {R4 - R7} to MSP for copy {R8 - R11} */
|
||||
|
||||
LDMIA R1!, {R4 - R7} /* pop thread {R8 - R11} high register from thread stack to {R4 - R7} */
|
||||
MOV R8, R4 /* mov {R4 - R7} to {R8 - R11} */
|
||||
MOV R9, R5
|
||||
MOV R10, R6
|
||||
MOV R11, R7
|
||||
|
||||
POP {R4 - R7} /* pop {R4 - R7} from MSP */
|
||||
|
||||
MSR PSP, R1 /* update stack pointer */
|
||||
|
||||
pendsv_exit:
|
||||
/* restore interrupt */
|
||||
MSR PRIMASK, R2
|
||||
|
||||
MOVS R0, #0x04
|
||||
RSBS R0, R0, #0x00
|
||||
BX R0
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* R0 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_to
|
||||
.type rt_hw_context_switch_to, %function
|
||||
rt_hw_context_switch_to:
|
||||
LDR R1, =rt_interrupt_to_thread
|
||||
STR R0, [R1]
|
||||
|
||||
/* set from thread to 0 */
|
||||
LDR R1, =rt_interrupt_from_thread
|
||||
MOVS R0, #0
|
||||
STR R0, [R1]
|
||||
|
||||
/* set interrupt flag to 1 */
|
||||
LDR R1, =rt_thread_switch_interrupt_flag
|
||||
MOVS R0, #1
|
||||
STR R0, [R1]
|
||||
|
||||
/* set the PendSV and SysTick exception priority */
|
||||
LDR R0, =NVIC_SHPR3
|
||||
LDR R1, =NVIC_PENDSV_PRI
|
||||
LDR R2, [R0,#0x00] /* read */
|
||||
ORRS R1, R1, R2 /* modify */
|
||||
STR R1, [R0] /* write-back */
|
||||
|
||||
LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR R1, =NVIC_PENDSVSET
|
||||
STR R1, [R0]
|
||||
NOP
|
||||
/* restore MSP */
|
||||
LDR R0, =SCB_VTOR
|
||||
LDR R0, [R0]
|
||||
LDR R0, [R0]
|
||||
NOP
|
||||
MSR MSP, R0
|
||||
|
||||
/* enable interrupts at processor level */
|
||||
CPSIE I
|
||||
|
||||
/* ensure PendSV exception taken place before subsequent operation */
|
||||
DSB
|
||||
ISB
|
||||
|
||||
/* never reach here! */
|
||||
|
||||
/* compatible with old version */
|
||||
.global rt_hw_interrupt_thread_switch
|
||||
.type rt_hw_interrupt_thread_switch, %function
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX LR
|
||||
NOP
|
||||
|
||||
.global HardFault_Handler
|
||||
.type HardFault_Handler, %function
|
||||
HardFault_Handler:
|
||||
/* get current context */
|
||||
MRS R0, PSP /* get fault thread stack pointer */
|
||||
PUSH {LR}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {PC}
|
||||
|
||||
|
||||
/*
|
||||
* rt_uint32_t rt_hw_interrupt_check(void);
|
||||
* R0 --> state
|
||||
*/
|
||||
.global rt_hw_interrupt_check
|
||||
.type rt_hw_interrupt_check, %function
|
||||
rt_hw_interrupt_check:
|
||||
MRS R0, IPSR
|
||||
BX LR
|
||||
210
rt-thread/libcpu/arm/cortex-m0/context_iar.S
Normal file
210
rt-thread/libcpu/arm/cortex-m0/context_iar.S
Normal file
@ -0,0 +1,210 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2010-01-25 Bernard first version
|
||||
; * 2012-06-01 aozima set pendsv priority to 0xFF.
|
||||
; * 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup CORTEX-M0
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SHPR3 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
SECTION .text:CODE(2)
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOVS r3, #0x1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
EXPORT PendSV_Handler
|
||||
PendSV_Handler:
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOVS r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
SUBS r1, r1, #0x20 ; space for {r4 - r7} and {r8 - r11}
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
STMIA r1!, {r4 - r7} ; push thread {r4 - r7} register to thread stack
|
||||
|
||||
MOV r4, r8 ; mov thread {r8 - r11} to {r4 - r7}
|
||||
MOV r5, r9
|
||||
MOV r6, r10
|
||||
MOV r7, r11
|
||||
STMIA r1!, {r4 - r7} ; push thread {r8 - r11} high register to thread stack
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r4 - r7} register from thread stack
|
||||
PUSH {r4 - r7} ; push {r4 - r7} to MSP for copy {r8 - r11}
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r8 - r11} high register from thread stack to {r4 - r7}
|
||||
MOV r8, r4 ; mov {r4 - r7} to {r8 - r11}
|
||||
MOV r9, r5
|
||||
MOV r10, r6
|
||||
MOV r11, r7
|
||||
|
||||
POP {r4 - r7} ; pop {r4 - r7} from MSP
|
||||
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
MOVS r0, #0x04
|
||||
RSBS r0, r0, #0x00
|
||||
BX r0
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOVS r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOVS r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SHPR3
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR r2, [r0,#0x00] ; read
|
||||
ORRS r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
NOP
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE I
|
||||
|
||||
; ensure PendSV exception taken place before subsequent operation
|
||||
DSB
|
||||
ISB
|
||||
|
||||
; never reach here!
|
||||
|
||||
; compatible with old version
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX lr
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler:
|
||||
|
||||
; get current context
|
||||
MRS r0, psp ; get fault thread stack pointer
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {pc}
|
||||
|
||||
END
|
||||
219
rt-thread/libcpu/arm/cortex-m0/context_rvds.S
Normal file
219
rt-thread/libcpu/arm/cortex-m0/context_rvds.S
Normal file
@ -0,0 +1,219 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2010-01-25 Bernard first version
|
||||
; * 2012-06-01 aozima set pendsv priority to 0xFF.
|
||||
; * 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup CORTEX-M0
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SHPR3 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable PROC
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch PROC
|
||||
EXPORT rt_hw_context_switch
|
||||
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOVS r3, #0x01
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOVS r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
SUBS r1, r1, #0x20 ; space for {r4 - r7} and {r8 - r11}
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
STMIA r1!, {r4 - r7} ; push thread {r4 - r7} register to thread stack
|
||||
|
||||
MOV r4, r8 ; mov thread {r8 - r11} to {r4 - r7}
|
||||
MOV r5, r9
|
||||
MOV r6, r10
|
||||
MOV r7, r11
|
||||
STMIA r1!, {r4 - r7} ; push thread {r8 - r11} high register to thread stack
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r4 - r7} register from thread stack
|
||||
PUSH {r4 - r7} ; push {r4 - r7} to MSP for copy {r8 - r11}
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r8 - r11} high register from thread stack to {r4 - r7}
|
||||
MOV r8, r4 ; mov {r4 - r7} to {r8 - r11}
|
||||
MOV r9, r5
|
||||
MOV r10, r6
|
||||
MOV r11, r7
|
||||
|
||||
POP {r4 - r7} ; pop {r4 - r7} from MSP
|
||||
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
MOVS r0, #0x04
|
||||
RSBS r0, r0, #0x00
|
||||
BX r0
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
rt_hw_context_switch_to PROC
|
||||
EXPORT rt_hw_context_switch_to
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOVS r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOVS r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SHPR3
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR r2, [r0,#0x00] ; read
|
||||
ORRS r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE I
|
||||
|
||||
; ensure PendSV exception taken place before subsequent operation
|
||||
DSB
|
||||
ISB
|
||||
|
||||
; never reach here!
|
||||
ENDP
|
||||
|
||||
; compatible with old version
|
||||
rt_hw_interrupt_thread_switch PROC
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
|
||||
HardFault_Handler PROC
|
||||
EXPORT HardFault_Handler
|
||||
|
||||
; get current context
|
||||
MRS r0, psp ; get fault thread stack pointer
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {pc}
|
||||
ENDP
|
||||
|
||||
ALIGN 4
|
||||
|
||||
END
|
||||
137
rt-thread/libcpu/arm/cortex-m0/cpuport.c
Normal file
137
rt-thread/libcpu/arm/cortex-m0/cpuport.c
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-01-25 Bernard first version
|
||||
* 2012-05-31 aozima Merge all of the C source code into cpuport.c
|
||||
* 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
* 2012-12-23 aozima stack addr align to 8byte.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
struct exception_stack_frame
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r12;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t psr;
|
||||
};
|
||||
|
||||
struct stack_frame
|
||||
{
|
||||
/* r4 ~ r7 low register */
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
|
||||
/* r8 ~ r11 high register */
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t r11;
|
||||
|
||||
struct exception_stack_frame exception_stack_frame;
|
||||
};
|
||||
|
||||
/* flag in interrupt handling */
|
||||
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
void *parameter,
|
||||
rt_uint8_t *stack_addr,
|
||||
void *texit)
|
||||
{
|
||||
struct stack_frame *stack_frame;
|
||||
rt_uint8_t *stk;
|
||||
unsigned long i;
|
||||
|
||||
stk = stack_addr + sizeof(rt_uint32_t);
|
||||
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
|
||||
stk -= sizeof(struct stack_frame);
|
||||
|
||||
stack_frame = (struct stack_frame *)stk;
|
||||
|
||||
/* init all register */
|
||||
for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
|
||||
{
|
||||
((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
|
||||
}
|
||||
|
||||
stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */
|
||||
stack_frame->exception_stack_frame.r1 = 0; /* r1 */
|
||||
stack_frame->exception_stack_frame.r2 = 0; /* r2 */
|
||||
stack_frame->exception_stack_frame.r3 = 0; /* r3 */
|
||||
stack_frame->exception_stack_frame.r12 = 0; /* r12 */
|
||||
stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */
|
||||
stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */
|
||||
stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */
|
||||
|
||||
/* return task's current stack address */
|
||||
return stk;
|
||||
}
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
extern rt_thread_t rt_current_thread;
|
||||
/**
|
||||
* fault exception handling
|
||||
*/
|
||||
void rt_hw_hard_fault_exception(struct exception_stack_frame *contex)
|
||||
{
|
||||
rt_kprintf("psr: 0x%08x\n", contex->psr);
|
||||
rt_kprintf(" pc: 0x%08x\n", contex->pc);
|
||||
rt_kprintf(" lr: 0x%08x\n", contex->lr);
|
||||
rt_kprintf("r12: 0x%08x\n", contex->r12);
|
||||
rt_kprintf("r03: 0x%08x\n", contex->r3);
|
||||
rt_kprintf("r02: 0x%08x\n", contex->r2);
|
||||
rt_kprintf("r01: 0x%08x\n", contex->r1);
|
||||
rt_kprintf("r00: 0x%08x\n", contex->r0);
|
||||
|
||||
rt_kprintf("hard fault on thread: %s\n", rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
|
||||
#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
|
||||
#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
|
||||
#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */
|
||||
#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED0C) /* Reset control Address Register */
|
||||
#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */
|
||||
|
||||
#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */
|
||||
#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */
|
||||
#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */
|
||||
|
||||
/**
|
||||
* reset CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset(void)
|
||||
{
|
||||
SCB_AIRCR = SCB_RESET_VALUE;//((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |SCB_AIRCR_SYSRESETREQ_Msk);
|
||||
}
|
||||
215
rt-thread/libcpu/arm/cortex-m23/context_gcc.S
Normal file
215
rt-thread/libcpu/arm/cortex-m23/context_gcc.S
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-01-25 Bernard first version
|
||||
* 2012-06-01 aozima set pendsv priority to 0xFF.
|
||||
* 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
* 2013-02-20 aozima port to gcc.
|
||||
* 2013-06-18 aozima add restore MSP feature.
|
||||
* 2013-11-04 bright fixed hardfault bug for gcc.
|
||||
* 2019-03-31 xuzhuoyi port to Cortex-M23.
|
||||
*/
|
||||
|
||||
.cpu cortex-m23
|
||||
.fpu softvfp
|
||||
.syntax unified
|
||||
.thumb
|
||||
.text
|
||||
|
||||
.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */
|
||||
.equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */
|
||||
.equ NVIC_SHPR3, 0xE000ED20 /* system priority register (3) */
|
||||
.equ NVIC_PENDSV_PRI, 0xFFFF0000 /* PendSV and SysTick priority value (lowest) */
|
||||
.equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.global rt_hw_interrupt_disable
|
||||
.type rt_hw_interrupt_disable, %function
|
||||
rt_hw_interrupt_disable:
|
||||
MRS R0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.global rt_hw_interrupt_enable
|
||||
.type rt_hw_interrupt_enable, %function
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, R0
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* R0 --> from
|
||||
* R1 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_interrupt
|
||||
.type rt_hw_context_switch_interrupt, %function
|
||||
.global rt_hw_context_switch
|
||||
.type rt_hw_context_switch, %function
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
/* set rt_thread_switch_interrupt_flag to 1 */
|
||||
LDR R2, =rt_thread_switch_interrupt_flag
|
||||
LDR R3, [R2]
|
||||
CMP R3, #1
|
||||
BEQ _reswitch
|
||||
MOVS R3, #1
|
||||
STR R3, [R2]
|
||||
|
||||
LDR R2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
|
||||
STR R0, [R2]
|
||||
|
||||
_reswitch:
|
||||
LDR R2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
|
||||
STR R1, [R2]
|
||||
|
||||
LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR R1, =NVIC_PENDSVSET
|
||||
STR R1, [R0]
|
||||
BX LR
|
||||
|
||||
/* R0 --> switch from thread stack
|
||||
* R1 --> switch to thread stack
|
||||
* psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack
|
||||
*/
|
||||
.global PendSV_Handler
|
||||
.type PendSV_Handler, %function
|
||||
PendSV_Handler:
|
||||
/* disable interrupt to protect context switch */
|
||||
MRS R2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
/* get rt_thread_switch_interrupt_flag */
|
||||
LDR R0, =rt_thread_switch_interrupt_flag
|
||||
LDR R1, [R0]
|
||||
CMP R1, #0x00
|
||||
BEQ pendsv_exit /* pendsv already handled */
|
||||
|
||||
/* clear rt_thread_switch_interrupt_flag to 0 */
|
||||
MOVS R1, #0
|
||||
STR R1, [R0]
|
||||
|
||||
LDR R0, =rt_interrupt_from_thread
|
||||
LDR R1, [R0]
|
||||
CMP R1, #0x00
|
||||
BEQ switch_to_thread /* skip register save at the first time */
|
||||
|
||||
MRS R1, PSP /* get from thread stack pointer */
|
||||
|
||||
SUBS R1, R1, #0x20 /* space for {R4 - R7} and {R8 - R11} */
|
||||
LDR R0, [R0]
|
||||
STR R1, [R0] /* update from thread stack pointer */
|
||||
|
||||
STMIA R1!, {R4 - R7} /* push thread {R4 - R7} register to thread stack */
|
||||
|
||||
MOV R4, R8 /* mov thread {R8 - R11} to {R4 - R7} */
|
||||
MOV R5, R9
|
||||
MOV R6, R10
|
||||
MOV R7, R11
|
||||
STMIA R1!, {R4 - R7} /* push thread {R8 - R11} high register to thread stack */
|
||||
switch_to_thread:
|
||||
LDR R1, =rt_interrupt_to_thread
|
||||
LDR R1, [R1]
|
||||
LDR R1, [R1] /* load thread stack pointer */
|
||||
|
||||
LDMIA R1!, {R4 - R7} /* pop thread {R4 - R7} register from thread stack */
|
||||
PUSH {R4 - R7} /* push {R4 - R7} to MSP for copy {R8 - R11} */
|
||||
|
||||
LDMIA R1!, {R4 - R7} /* pop thread {R8 - R11} high register from thread stack to {R4 - R7} */
|
||||
MOV R8, R4 /* mov {R4 - R7} to {R8 - R11} */
|
||||
MOV R9, R5
|
||||
MOV R10, R6
|
||||
MOV R11, R7
|
||||
|
||||
POP {R4 - R7} /* pop {R4 - R7} from MSP */
|
||||
|
||||
MSR PSP, R1 /* update stack pointer */
|
||||
|
||||
pendsv_exit:
|
||||
/* restore interrupt */
|
||||
MSR PRIMASK, R2
|
||||
|
||||
MOVS R0, #0x03
|
||||
RSBS R0, R0, #0x00
|
||||
BX R0
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* R0 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_to
|
||||
.type rt_hw_context_switch_to, %function
|
||||
rt_hw_context_switch_to:
|
||||
LDR R1, =rt_interrupt_to_thread
|
||||
STR R0, [R1]
|
||||
|
||||
/* set from thread to 0 */
|
||||
LDR R1, =rt_interrupt_from_thread
|
||||
MOVS R0, #0
|
||||
STR R0, [R1]
|
||||
|
||||
/* set interrupt flag to 1 */
|
||||
LDR R1, =rt_thread_switch_interrupt_flag
|
||||
MOVS R0, #1
|
||||
STR R0, [R1]
|
||||
|
||||
/* set the PendSV and SysTick exception priority */
|
||||
LDR R0, =NVIC_SHPR3
|
||||
LDR R1, =NVIC_PENDSV_PRI
|
||||
LDR R2, [R0,#0x00] /* read */
|
||||
ORRS R1, R1, R2 /* modify */
|
||||
STR R1, [R0] /* write-back */
|
||||
|
||||
LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR R1, =NVIC_PENDSVSET
|
||||
STR R1, [R0]
|
||||
NOP
|
||||
/* restore MSP */
|
||||
LDR R0, =SCB_VTOR
|
||||
LDR R0, [R0]
|
||||
LDR R0, [R0]
|
||||
NOP
|
||||
MSR MSP, R0
|
||||
|
||||
/* enable interrupts at processor level */
|
||||
CPSIE I
|
||||
|
||||
/* ensure PendSV exception taken place before subsequent operation */
|
||||
DSB
|
||||
ISB
|
||||
|
||||
/* never reach here! */
|
||||
|
||||
/* compatible with old version */
|
||||
.global rt_hw_interrupt_thread_switch
|
||||
.type rt_hw_interrupt_thread_switch, %function
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX LR
|
||||
NOP
|
||||
|
||||
.global HardFault_Handler
|
||||
.type HardFault_Handler, %function
|
||||
HardFault_Handler:
|
||||
/* get current context */
|
||||
MRS R0, PSP /* get fault thread stack pointer */
|
||||
PUSH {LR}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {PC}
|
||||
|
||||
|
||||
/*
|
||||
* rt_uint32_t rt_hw_interrupt_check(void);
|
||||
* R0 --> state
|
||||
*/
|
||||
.global rt_hw_interrupt_check
|
||||
.type rt_hw_interrupt_check, %function
|
||||
rt_hw_interrupt_check:
|
||||
MRS R0, IPSR
|
||||
BX LR
|
||||
211
rt-thread/libcpu/arm/cortex-m23/context_iar.S
Normal file
211
rt-thread/libcpu/arm/cortex-m23/context_iar.S
Normal file
@ -0,0 +1,211 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2010-01-25 Bernard first version
|
||||
; * 2012-06-01 aozima set pendsv priority to 0xFF.
|
||||
; * 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2019-03-31 xuzhuoyi port to Cortex-M23.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup CORTEX-M23
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SHPR3 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
SECTION .text:CODE(2)
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOVS r3, #0x1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
EXPORT PendSV_Handler
|
||||
PendSV_Handler:
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOVS r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
SUBS r1, r1, #0x20 ; space for {r4 - r7} and {r8 - r11}
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
STMIA r1!, {r4 - r7} ; push thread {r4 - r7} register to thread stack
|
||||
|
||||
MOV r4, r8 ; mov thread {r8 - r11} to {r4 - r7}
|
||||
MOV r5, r9
|
||||
MOV r6, r10
|
||||
MOV r7, r11
|
||||
STMIA r1!, {r4 - r7} ; push thread {r8 - r11} high register to thread stack
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r4 - r7} register from thread stack
|
||||
PUSH {r4 - r7} ; push {r4 - r7} to MSP for copy {r8 - r11}
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r8 - r11} high register from thread stack to {r4 - r7}
|
||||
MOV r8, r4 ; mov {r4 - r7} to {r8 - r11}
|
||||
MOV r9, r5
|
||||
MOV r10, r6
|
||||
MOV r11, r7
|
||||
|
||||
POP {r4 - r7} ; pop {r4 - r7} from MSP
|
||||
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
MOVS r0, #0x03
|
||||
RSBS r0, r0, #0x00
|
||||
BX r0
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOVS r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOVS r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SHPR3
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR r2, [r0,#0x00] ; read
|
||||
ORRS r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
NOP
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE I
|
||||
|
||||
; ensure PendSV exception taken place before subsequent operation
|
||||
DSB
|
||||
ISB
|
||||
|
||||
; never reach here!
|
||||
|
||||
; compatible with old version
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX lr
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler:
|
||||
|
||||
; get current context
|
||||
MRS r0, psp ; get fault thread stack pointer
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {pc}
|
||||
|
||||
END
|
||||
220
rt-thread/libcpu/arm/cortex-m23/context_rvds.S
Normal file
220
rt-thread/libcpu/arm/cortex-m23/context_rvds.S
Normal file
@ -0,0 +1,220 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2010-01-25 Bernard first version
|
||||
; * 2012-06-01 aozima set pendsv priority to 0xFF.
|
||||
; * 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2019-03-31 xuzhuoyi port to Cortex-M23.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup CORTEX-M23
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SHPR3 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable PROC
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch PROC
|
||||
EXPORT rt_hw_context_switch
|
||||
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOVS r3, #0x01
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOVS r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
SUBS r1, r1, #0x20 ; space for {r4 - r7} and {r8 - r11}
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
STMIA r1!, {r4 - r7} ; push thread {r4 - r7} register to thread stack
|
||||
|
||||
MOV r4, r8 ; mov thread {r8 - r11} to {r4 - r7}
|
||||
MOV r5, r9
|
||||
MOV r6, r10
|
||||
MOV r7, r11
|
||||
STMIA r1!, {r4 - r7} ; push thread {r8 - r11} high register to thread stack
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r4 - r7} register from thread stack
|
||||
PUSH {r4 - r7} ; push {r4 - r7} to MSP for copy {r8 - r11}
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r8 - r11} high register from thread stack to {r4 - r7}
|
||||
MOV r8, r4 ; mov {r4 - r7} to {r8 - r11}
|
||||
MOV r9, r5
|
||||
MOV r10, r6
|
||||
MOV r11, r7
|
||||
|
||||
POP {r4 - r7} ; pop {r4 - r7} from MSP
|
||||
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
MOVS r0, #0x03
|
||||
RSBS r0, r0, #0x00
|
||||
BX r0
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
rt_hw_context_switch_to PROC
|
||||
EXPORT rt_hw_context_switch_to
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOVS r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOVS r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SHPR3
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR r2, [r0,#0x00] ; read
|
||||
ORRS r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE I
|
||||
|
||||
; ensure PendSV exception taken place before subsequent operation
|
||||
DSB
|
||||
ISB
|
||||
|
||||
; never reach here!
|
||||
ENDP
|
||||
|
||||
; compatible with old version
|
||||
rt_hw_interrupt_thread_switch PROC
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
|
||||
HardFault_Handler PROC
|
||||
EXPORT HardFault_Handler
|
||||
|
||||
; get current context
|
||||
MRS r0, psp ; get fault thread stack pointer
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {pc}
|
||||
ENDP
|
||||
|
||||
ALIGN 4
|
||||
|
||||
END
|
||||
138
rt-thread/libcpu/arm/cortex-m23/cpuport.c
Normal file
138
rt-thread/libcpu/arm/cortex-m23/cpuport.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-01-25 Bernard first version
|
||||
* 2012-05-31 aozima Merge all of the C source code into cpuport.c
|
||||
* 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
* 2012-12-23 aozima stack addr align to 8byte.
|
||||
* 2019-03-31 xuzhuoyi port to Cortex-M23.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
struct exception_stack_frame
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r12;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t psr;
|
||||
};
|
||||
|
||||
struct stack_frame
|
||||
{
|
||||
/* r4 ~ r7 low register */
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
|
||||
/* r8 ~ r11 high register */
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t r11;
|
||||
|
||||
struct exception_stack_frame exception_stack_frame;
|
||||
};
|
||||
|
||||
/* flag in interrupt handling */
|
||||
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
void *parameter,
|
||||
rt_uint8_t *stack_addr,
|
||||
void *texit)
|
||||
{
|
||||
struct stack_frame *stack_frame;
|
||||
rt_uint8_t *stk;
|
||||
unsigned long i;
|
||||
|
||||
stk = stack_addr + sizeof(rt_uint32_t);
|
||||
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
|
||||
stk -= sizeof(struct stack_frame);
|
||||
|
||||
stack_frame = (struct stack_frame *)stk;
|
||||
|
||||
/* init all register */
|
||||
for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
|
||||
{
|
||||
((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
|
||||
}
|
||||
|
||||
stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */
|
||||
stack_frame->exception_stack_frame.r1 = 0; /* r1 */
|
||||
stack_frame->exception_stack_frame.r2 = 0; /* r2 */
|
||||
stack_frame->exception_stack_frame.r3 = 0; /* r3 */
|
||||
stack_frame->exception_stack_frame.r12 = 0; /* r12 */
|
||||
stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */
|
||||
stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */
|
||||
stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */
|
||||
|
||||
/* return task's current stack address */
|
||||
return stk;
|
||||
}
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
extern rt_thread_t rt_current_thread;
|
||||
/**
|
||||
* fault exception handling
|
||||
*/
|
||||
void rt_hw_hard_fault_exception(struct exception_stack_frame *contex)
|
||||
{
|
||||
rt_kprintf("psr: 0x%08x\n", contex->psr);
|
||||
rt_kprintf(" pc: 0x%08x\n", contex->pc);
|
||||
rt_kprintf(" lr: 0x%08x\n", contex->lr);
|
||||
rt_kprintf("r12: 0x%08x\n", contex->r12);
|
||||
rt_kprintf("r03: 0x%08x\n", contex->r3);
|
||||
rt_kprintf("r02: 0x%08x\n", contex->r2);
|
||||
rt_kprintf("r01: 0x%08x\n", contex->r1);
|
||||
rt_kprintf("r00: 0x%08x\n", contex->r0);
|
||||
|
||||
rt_kprintf("hard fault on thread: %s\n", rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
|
||||
#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
|
||||
#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
|
||||
#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */
|
||||
#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED00) /* Reset control Address Register */
|
||||
#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */
|
||||
|
||||
#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */
|
||||
#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */
|
||||
#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */
|
||||
|
||||
/**
|
||||
* reset CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset(void)
|
||||
{
|
||||
SCB_AIRCR = SCB_RESET_VALUE;//((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |SCB_AIRCR_SYSRESETREQ_Msk);
|
||||
}
|
||||
214
rt-thread/libcpu/arm/cortex-m3/context_gcc.S
Normal file
214
rt-thread/libcpu/arm/cortex-m3/context_gcc.S
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2009-10-11 Bernard First version
|
||||
* 2010-12-29 onelife Modify for EFM32
|
||||
* 2011-06-17 onelife Merge all of the assembly source code into context_gcc.S
|
||||
* 2011-07-12 onelife Add interrupt context check function
|
||||
* 2013-06-18 aozima add restore MSP feature.
|
||||
* 2013-07-09 aozima enhancement hard fault exception handler.
|
||||
*/
|
||||
|
||||
.cpu cortex-m3
|
||||
.fpu softvfp
|
||||
.syntax unified
|
||||
.thumb
|
||||
.text
|
||||
|
||||
.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */
|
||||
.equ ICSR, 0xE000ED04 /* interrupt control state register */
|
||||
.equ PENDSVSET_BIT, 0x10000000 /* value to trigger PendSV exception */
|
||||
|
||||
.equ SHPR3, 0xE000ED20 /* system priority register (3) */
|
||||
.equ PENDSV_PRI_LOWEST, 0xFFFF0000 /* PendSV and SysTick priority value (lowest) */
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.global rt_hw_interrupt_disable
|
||||
.type rt_hw_interrupt_disable, %function
|
||||
rt_hw_interrupt_disable:
|
||||
MRS R0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.global rt_hw_interrupt_enable
|
||||
.type rt_hw_interrupt_enable, %function
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, R0
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* R0 --> from
|
||||
* R1 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_interrupt
|
||||
.type rt_hw_context_switch_interrupt, %function
|
||||
.global rt_hw_context_switch
|
||||
.type rt_hw_context_switch, %function
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
/* set rt_thread_switch_interrupt_flag to 1 */
|
||||
LDR R2, =rt_thread_switch_interrupt_flag
|
||||
LDR R3, [R2]
|
||||
CMP R3, #1
|
||||
BEQ _reswitch
|
||||
MOV R3, #1
|
||||
STR R3, [R2]
|
||||
|
||||
LDR R2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
|
||||
STR R0, [R2]
|
||||
|
||||
_reswitch:
|
||||
LDR R2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
|
||||
STR R1, [R2]
|
||||
|
||||
LDR R0, =ICSR /* trigger the PendSV exception (causes context switch) */
|
||||
LDR R1, =PENDSVSET_BIT
|
||||
STR R1, [R0]
|
||||
BX LR
|
||||
|
||||
/* R0 --> switch from thread stack
|
||||
* R1 --> switch to thread stack
|
||||
* psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack
|
||||
*/
|
||||
.global PendSV_Handler
|
||||
.type PendSV_Handler, %function
|
||||
PendSV_Handler:
|
||||
/* disable interrupt to protect context switch */
|
||||
MRS R2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
/* get rt_thread_switch_interrupt_flag */
|
||||
LDR R0, =rt_thread_switch_interrupt_flag
|
||||
LDR R1, [R0]
|
||||
CBZ R1, pendsv_exit /* pendsv already handled */
|
||||
|
||||
/* clear rt_thread_switch_interrupt_flag to 0 */
|
||||
MOV R1, #0
|
||||
STR R1, [R0]
|
||||
|
||||
LDR R0, =rt_interrupt_from_thread
|
||||
LDR R1, [R0]
|
||||
CBZ R1, switch_to_thread /* skip register save at the first time */
|
||||
|
||||
MRS R1, PSP /* get from thread stack pointer */
|
||||
STMFD R1!, {R4 - R11} /* push R4 - R11 register */
|
||||
LDR R0, [R0]
|
||||
STR R1, [R0] /* update from thread stack pointer */
|
||||
|
||||
switch_to_thread:
|
||||
LDR R1, =rt_interrupt_to_thread
|
||||
LDR R1, [R1]
|
||||
LDR R1, [R1] /* load thread stack pointer */
|
||||
|
||||
LDMFD R1!, {R4 - R11} /* pop R4 - R11 register */
|
||||
MSR PSP, R1 /* update stack pointer */
|
||||
|
||||
pendsv_exit:
|
||||
/* restore interrupt */
|
||||
MSR PRIMASK, R2
|
||||
|
||||
ORR LR, LR, #0x04
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* R0 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_to
|
||||
.type rt_hw_context_switch_to, %function
|
||||
rt_hw_context_switch_to:
|
||||
LDR R1, =rt_interrupt_to_thread
|
||||
STR R0, [R1]
|
||||
|
||||
/* set from thread to 0 */
|
||||
LDR R1, =rt_interrupt_from_thread
|
||||
MOV R0, #0
|
||||
STR R0, [R1]
|
||||
|
||||
/* set interrupt flag to 1 */
|
||||
LDR R1, =rt_thread_switch_interrupt_flag
|
||||
MOV R0, #1
|
||||
STR R0, [R1]
|
||||
|
||||
/* set the PendSV and SysTick exception priority */
|
||||
LDR R0, =SHPR3
|
||||
LDR R1, =PENDSV_PRI_LOWEST
|
||||
LDR.W R2, [R0,#0] /* read */
|
||||
ORR R1, R1, R2 /* modify */
|
||||
STR R1, [R0] /* write-back */
|
||||
|
||||
LDR R0, =ICSR /* trigger the PendSV exception (causes context switch) */
|
||||
LDR R1, =PENDSVSET_BIT
|
||||
STR R1, [R0]
|
||||
|
||||
/* restore MSP */
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
/* enable interrupts at processor level */
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
/* ensure PendSV exception taken place before subsequent operation */
|
||||
DSB
|
||||
ISB
|
||||
|
||||
/* never reach here! */
|
||||
|
||||
/* compatible with old version */
|
||||
.global rt_hw_interrupt_thread_switch
|
||||
.type rt_hw_interrupt_thread_switch, %function
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX LR
|
||||
NOP
|
||||
|
||||
.global HardFault_Handler
|
||||
.type HardFault_Handler, %function
|
||||
HardFault_Handler:
|
||||
/* get current context */
|
||||
MRS r0, msp /* get fault context from handler. */
|
||||
TST lr, #0x04 /* if(!EXC_RETURN[2]) */
|
||||
BEQ _get_sp_done
|
||||
MRS r0, psp /* get fault context from thread. */
|
||||
_get_sp_done:
|
||||
|
||||
STMFD r0!, {r4 - r11} /* push r4 - r11 register */
|
||||
STMFD r0!, {lr} /* push exec_return register */
|
||||
|
||||
TST lr, #0x04 /* if(!EXC_RETURN[2]) */
|
||||
BEQ _update_msp
|
||||
MSR psp, r0 /* update stack pointer to PSP. */
|
||||
B _update_done
|
||||
_update_msp:
|
||||
MSR msp, r0 /* update stack pointer to MSP. */
|
||||
_update_done:
|
||||
|
||||
PUSH {LR}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {LR}
|
||||
|
||||
ORR LR, LR, #0x04
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* rt_uint32_t rt_hw_interrupt_check(void);
|
||||
* R0 --> state
|
||||
*/
|
||||
.global rt_hw_interrupt_check
|
||||
.type rt_hw_interrupt_check, %function
|
||||
rt_hw_interrupt_check:
|
||||
MRS R0, IPSR
|
||||
BX LR
|
||||
206
rt-thread/libcpu/arm/cortex-m3/context_iar.S
Normal file
206
rt-thread/libcpu/arm/cortex-m3/context_iar.S
Normal file
@ -0,0 +1,206 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2009-01-17 Bernard first version
|
||||
; * 2009-09-27 Bernard add protect when contex switch occurs
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2013-07-09 aozima enhancement hard fault exception handler.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup cortex-m3
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
SECTION .text:CODE(2)
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
EXPORT PendSV_Handler
|
||||
PendSV_Handler:
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CBZ r1, pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOV r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CBZ r1, switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
STMFD r1!, {r4 - r11} ; push r4 - r11 register
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
LDMFD r1!, {r4 - r11} ; pop r4 - r11 register
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] ; read
|
||||
ORR r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
; ensure PendSV exception taken place before subsequent operation
|
||||
DSB
|
||||
ISB
|
||||
|
||||
; never reach here!
|
||||
|
||||
; compatible with old version
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX lr
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler:
|
||||
|
||||
; get current context
|
||||
MRS r0, msp ; get fault context from handler.
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
BEQ _get_sp_done
|
||||
MRS r0, psp ; get fault context from thread.
|
||||
_get_sp_done
|
||||
|
||||
STMFD r0!, {r4 - r11} ; push r4 - r11 register
|
||||
;STMFD r0!, {lr} ; push exec_return register
|
||||
SUB r0, r0, #0x04
|
||||
STR lr, [r0]
|
||||
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
BEQ _update_msp
|
||||
MSR psp, r0 ; update stack pointer to PSP.
|
||||
B _update_done
|
||||
_update_msp
|
||||
MSR msp, r0 ; update stack pointer to MSP.
|
||||
_update_done
|
||||
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {lr}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
|
||||
END
|
||||
211
rt-thread/libcpu/arm/cortex-m3/context_rvds.S
Normal file
211
rt-thread/libcpu/arm/cortex-m3/context_rvds.S
Normal file
@ -0,0 +1,211 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2009-01-17 Bernard first version
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2013-07-09 aozima enhancement hard fault exception handler.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup CORTEX-M3
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable PROC
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch PROC
|
||||
EXPORT rt_hw_context_switch
|
||||
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CBZ r1, pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOV r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CBZ r1, switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
STMFD r1!, {r4 - r11} ; push r4 - r11 register
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
LDMFD r1!, {r4 - r11} ; pop r4 - r11 register
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
rt_hw_context_switch_to PROC
|
||||
EXPORT rt_hw_context_switch_to
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] ; read
|
||||
ORR r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
; ensure PendSV exception taken place before subsequent operation
|
||||
DSB
|
||||
ISB
|
||||
|
||||
; never reach here!
|
||||
ENDP
|
||||
|
||||
; compatible with old version
|
||||
rt_hw_interrupt_thread_switch PROC
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler PROC
|
||||
|
||||
; get current context
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
ITE EQ
|
||||
MRSEQ r0, msp ; [2]=0 ==> Z=1, get fault context from handler.
|
||||
MRSNE r0, psp ; [2]=1 ==> Z=0, get fault context from thread.
|
||||
|
||||
STMFD r0!, {r4 - r11} ; push r4 - r11 register
|
||||
STMFD r0!, {lr} ; push exec_return register
|
||||
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
ITE EQ
|
||||
MSREQ msp, r0 ; [2]=0 ==> Z=1, update stack pointer to MSP.
|
||||
MSRNE psp, r0 ; [2]=1 ==> Z=0, update stack pointer to PSP.
|
||||
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {lr}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
ALIGN 4
|
||||
|
||||
END
|
||||
424
rt-thread/libcpu/arm/cortex-m3/cpuport.c
Normal file
424
rt-thread/libcpu/arm/cortex-m3/cpuport.c
Normal file
@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2009-01-05 Bernard first version
|
||||
* 2011-02-14 onelife Modify for EFM32
|
||||
* 2011-06-17 onelife Merge all of the C source code into cpuport.c
|
||||
* 2012-12-23 aozima stack addr align to 8byte.
|
||||
* 2012-12-29 Bernard Add exception hook.
|
||||
* 2013-07-09 aozima enhancement hard fault exception handler.
|
||||
* 2019-07-03 yangjie add __rt_ffs() for armclang.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
struct exception_stack_frame
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r12;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t psr;
|
||||
};
|
||||
|
||||
struct stack_frame
|
||||
{
|
||||
/* r4 ~ r11 register */
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t r11;
|
||||
|
||||
struct exception_stack_frame exception_stack_frame;
|
||||
};
|
||||
|
||||
/* flag in interrupt handling */
|
||||
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
/* exception hook */
|
||||
static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL;
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
void *parameter,
|
||||
rt_uint8_t *stack_addr,
|
||||
void *texit)
|
||||
{
|
||||
struct stack_frame *stack_frame;
|
||||
rt_uint8_t *stk;
|
||||
unsigned long i;
|
||||
|
||||
stk = stack_addr + sizeof(rt_uint32_t);
|
||||
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
|
||||
stk -= sizeof(struct stack_frame);
|
||||
|
||||
stack_frame = (struct stack_frame *)stk;
|
||||
|
||||
/* init all register */
|
||||
for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
|
||||
{
|
||||
((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
|
||||
}
|
||||
|
||||
stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */
|
||||
stack_frame->exception_stack_frame.r1 = 0; /* r1 */
|
||||
stack_frame->exception_stack_frame.r2 = 0; /* r2 */
|
||||
stack_frame->exception_stack_frame.r3 = 0; /* r3 */
|
||||
stack_frame->exception_stack_frame.r12 = 0; /* r12 */
|
||||
stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */
|
||||
stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */
|
||||
stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */
|
||||
|
||||
/* return task's current stack address */
|
||||
return stk;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set the hook, which is invoked on fault exception handling.
|
||||
*
|
||||
* @param exception_handle the exception handling hook function.
|
||||
*/
|
||||
void rt_hw_exception_install(rt_err_t (*exception_handle)(void* context))
|
||||
{
|
||||
rt_exception_hook = exception_handle;
|
||||
}
|
||||
|
||||
#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
|
||||
#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
|
||||
#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
|
||||
#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */
|
||||
#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED0C) /* Reset control Address Register */
|
||||
#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */
|
||||
|
||||
#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */
|
||||
#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */
|
||||
#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
static void usage_fault_track(void)
|
||||
{
|
||||
rt_kprintf("usage fault:\n");
|
||||
rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR);
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<0))
|
||||
{
|
||||
/* [0]:UNDEFINSTR */
|
||||
rt_kprintf("UNDEFINSTR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<1))
|
||||
{
|
||||
/* [1]:INVSTATE */
|
||||
rt_kprintf("INVSTATE ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<2))
|
||||
{
|
||||
/* [2]:INVPC */
|
||||
rt_kprintf("INVPC ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<3))
|
||||
{
|
||||
/* [3]:NOCP */
|
||||
rt_kprintf("NOCP ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<8))
|
||||
{
|
||||
/* [8]:UNALIGNED */
|
||||
rt_kprintf("UNALIGNED ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<9))
|
||||
{
|
||||
/* [9]:DIVBYZERO */
|
||||
rt_kprintf("DIVBYZERO ");
|
||||
}
|
||||
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
static void bus_fault_track(void)
|
||||
{
|
||||
rt_kprintf("bus fault:\n");
|
||||
rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR);
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<0))
|
||||
{
|
||||
/* [0]:IBUSERR */
|
||||
rt_kprintf("IBUSERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<1))
|
||||
{
|
||||
/* [1]:PRECISERR */
|
||||
rt_kprintf("PRECISERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<2))
|
||||
{
|
||||
/* [2]:IMPRECISERR */
|
||||
rt_kprintf("IMPRECISERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<3))
|
||||
{
|
||||
/* [3]:UNSTKERR */
|
||||
rt_kprintf("UNSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<4))
|
||||
{
|
||||
/* [4]:STKERR */
|
||||
rt_kprintf("STKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<7))
|
||||
{
|
||||
rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void mem_manage_fault_track(void)
|
||||
{
|
||||
rt_kprintf("mem manage fault:\n");
|
||||
rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR);
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<0))
|
||||
{
|
||||
/* [0]:IACCVIOL */
|
||||
rt_kprintf("IACCVIOL ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<1))
|
||||
{
|
||||
/* [1]:DACCVIOL */
|
||||
rt_kprintf("DACCVIOL ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<3))
|
||||
{
|
||||
/* [3]:MUNSTKERR */
|
||||
rt_kprintf("MUNSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<4))
|
||||
{
|
||||
/* [4]:MSTKERR */
|
||||
rt_kprintf("MSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<7))
|
||||
{
|
||||
/* [7]:MMARVALID */
|
||||
rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void hard_fault_track(void)
|
||||
{
|
||||
if(SCB_HFSR & (1UL<<1))
|
||||
{
|
||||
/* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */
|
||||
rt_kprintf("failed vector fetch\n");
|
||||
}
|
||||
|
||||
if(SCB_HFSR & (1UL<<30))
|
||||
{
|
||||
/* [30]:FORCED, Indicates hard fault is taken because of bus fault,
|
||||
memory management fault, or usage fault. */
|
||||
if(SCB_CFSR_BFSR)
|
||||
{
|
||||
bus_fault_track();
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR)
|
||||
{
|
||||
mem_manage_fault_track();
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR)
|
||||
{
|
||||
usage_fault_track();
|
||||
}
|
||||
}
|
||||
|
||||
if(SCB_HFSR & (1UL<<31))
|
||||
{
|
||||
/* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */
|
||||
rt_kprintf("debug event\n");
|
||||
}
|
||||
}
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
struct exception_info
|
||||
{
|
||||
rt_uint32_t exc_return;
|
||||
struct stack_frame stack_frame;
|
||||
};
|
||||
|
||||
/*
|
||||
* fault exception handler
|
||||
*/
|
||||
void rt_hw_hard_fault_exception(struct exception_info * exception_info)
|
||||
{
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
struct stack_frame* context = &exception_info->stack_frame;
|
||||
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(exception_info);
|
||||
if (result == RT_EOK)
|
||||
return;
|
||||
}
|
||||
|
||||
rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr);
|
||||
|
||||
rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0);
|
||||
rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1);
|
||||
rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2);
|
||||
rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3);
|
||||
rt_kprintf("r04: 0x%08x\n", context->r4);
|
||||
rt_kprintf("r05: 0x%08x\n", context->r5);
|
||||
rt_kprintf("r06: 0x%08x\n", context->r6);
|
||||
rt_kprintf("r07: 0x%08x\n", context->r7);
|
||||
rt_kprintf("r08: 0x%08x\n", context->r8);
|
||||
rt_kprintf("r09: 0x%08x\n", context->r9);
|
||||
rt_kprintf("r10: 0x%08x\n", context->r10);
|
||||
rt_kprintf("r11: 0x%08x\n", context->r11);
|
||||
rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12);
|
||||
rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr);
|
||||
rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc);
|
||||
|
||||
if(exception_info->exc_return & (1 << 2) )
|
||||
{
|
||||
rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("hard fault on handler\r\n\r\n");
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
hard_fault_track();
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
/**
|
||||
* shutdown CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown(void)
|
||||
{
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset(void)
|
||||
{
|
||||
SCB_AIRCR = SCB_RESET_VALUE;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
/**
|
||||
* This function finds the first bit set (beginning with the least significant bit)
|
||||
* in value and return the index of that bit.
|
||||
*
|
||||
* Bits are numbered starting at 1 (the least significant bit). A return value of
|
||||
* zero from any of these functions means that the argument was zero.
|
||||
*
|
||||
* @return return the index of the first bit set. If value is 0, then this function
|
||||
* shall return 0.
|
||||
*/
|
||||
#if defined(__CC_ARM)
|
||||
__asm int __rt_ffs(int value)
|
||||
{
|
||||
CMP r0, #0x00
|
||||
BEQ exit
|
||||
|
||||
RBIT r0, r0
|
||||
CLZ r0, r0
|
||||
ADDS r0, r0, #0x01
|
||||
|
||||
exit
|
||||
BX lr
|
||||
}
|
||||
#elif defined(__clang__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
__asm volatile(
|
||||
"CMP %1, #0x00 \n"
|
||||
"BEQ 1f \n"
|
||||
|
||||
"RBIT %1, %1 \n"
|
||||
"CLZ %0, %1 \n"
|
||||
"ADDS %0, %0, #0x01 \n"
|
||||
|
||||
"1: \n"
|
||||
|
||||
: "=r"(value)
|
||||
: "r"(value)
|
||||
);
|
||||
return value;
|
||||
}
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
if (value == 0) return value;
|
||||
|
||||
asm("RBIT %0, %1" : "=r"(value) : "r"(value));
|
||||
asm("CLZ %0, %1" : "=r"(value) : "r"(value));
|
||||
asm("ADDS %0, %1, #0x01" : "=r"(value) : "r"(value));
|
||||
|
||||
return value;
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
return __builtin_ffs(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
299
rt-thread/libcpu/arm/cortex-m33/context_gcc.S
Normal file
299
rt-thread/libcpu/arm/cortex-m33/context_gcc.S
Normal file
@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2009-10-11 Bernard first version
|
||||
* 2012-01-01 aozima support context switch load/store FPU register.
|
||||
* 2013-06-18 aozima add restore MSP feature.
|
||||
* 2013-06-23 aozima support lazy stack optimized.
|
||||
* 2018-07-24 aozima enhancement hard fault exception handler.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup cortex-m4
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
.cpu cortex-m4
|
||||
.syntax unified
|
||||
.thumb
|
||||
.text
|
||||
|
||||
.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */
|
||||
.equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */
|
||||
.equ NVIC_SYSPRI2, 0xE000ED20 /* system priority register (2) */
|
||||
.equ NVIC_PENDSV_PRI, 0xFFFF0000 /* PendSV and SysTick priority value (lowest) */
|
||||
.equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.global rt_hw_interrupt_disable
|
||||
.type rt_hw_interrupt_disable, %function
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.global rt_hw_interrupt_enable
|
||||
.type rt_hw_interrupt_enable, %function
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_interrupt
|
||||
.type rt_hw_context_switch_interrupt, %function
|
||||
.global rt_hw_context_switch
|
||||
.type rt_hw_context_switch, %function
|
||||
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
/* set rt_thread_switch_interrupt_flag to 1 */
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch:
|
||||
LDR r2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
|
||||
/* r0 --> switch from thread stack
|
||||
* r1 --> switch to thread stack
|
||||
* psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
*/
|
||||
.global PendSV_Handler
|
||||
.type PendSV_Handler, %function
|
||||
PendSV_Handler:
|
||||
/* disable interrupt to protect context switch */
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
/* get rt_thread_switch_interrupt_flag */
|
||||
LDR r0, =rt_thread_switch_interrupt_flag /* r0 = &rt_thread_switch_interrupt_flag */
|
||||
LDR r1, [r0] /* r1 = *r1 */
|
||||
CMP r1, #0x00 /* compare r1 == 0x00 */
|
||||
BNE schedule
|
||||
MSR PRIMASK, r2 /* if r1 == 0x00, do msr PRIMASK, r2 */
|
||||
BX lr /* if r1 == 0x00, do bx lr */
|
||||
|
||||
schedule:
|
||||
PUSH {r2} /* store interrupt state */
|
||||
|
||||
/* clear rt_thread_switch_interrupt_flag to 0 */
|
||||
MOV r1, #0x00 /* r1 = 0x00 */
|
||||
STR r1, [r0] /* *r0 = r1 */
|
||||
|
||||
/* skip register save at the first time */
|
||||
LDR r0, =rt_interrupt_from_thread /* r0 = &rt_interrupt_from_thread */
|
||||
LDR r1, [r0] /* r1 = *r0 */
|
||||
CBZ r1, switch_to_thread /* if r1 == 0, goto switch_to_thread */
|
||||
|
||||
/* Whether TrustZone thread stack exists */
|
||||
LDR r1, =rt_trustzone_current_context /* r1 = &rt_secure_current_context */
|
||||
LDR r1, [r1] /* r1 = *r1 */
|
||||
CBZ r1, contex_ns_store /* if r1 == 0, goto contex_ns_store */
|
||||
|
||||
/*call TrustZone fun, Save TrustZone stack */
|
||||
STMFD sp!, {r0-r1, lr} /* push register */
|
||||
MOV r0, r1 /* r0 = rt_secure_current_context */
|
||||
BL rt_trustzone_context_store /* call TrustZone store fun */
|
||||
LDMFD sp!, {r0-r1, lr} /* pop register */
|
||||
|
||||
/* check break from TrustZone */
|
||||
MOV r2, lr /* r2 = lr */
|
||||
TST r2, #0x40 /* if EXC_RETURN[6] is 1, TrustZone stack was used */
|
||||
BEQ contex_ns_store /* if r2 & 0x40 == 0, goto contex_ns_store */
|
||||
|
||||
/* push PSPLIM CONTROL PSP LR current_context to stack */
|
||||
MRS r3, psplim /* r3 = psplim */
|
||||
MRS r4, control /* r4 = control */
|
||||
MRS r5, psp /* r5 = psp */
|
||||
STMFD r5!, {r1-r4} /* push to thread stack */
|
||||
|
||||
/* update from thread stack pointer */
|
||||
LDR r0, [r0] /* r0 = rt_thread_switch_interrupt_flag */
|
||||
STR r5, [r0] /* *r0 = r5 */
|
||||
b switch_to_thread /* goto switch_to_thread */
|
||||
|
||||
contex_ns_store:
|
||||
|
||||
MRS r1, psp /* get from thread stack pointer */
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
TST lr, #0x10 /* if(!EXC_RETURN[4]) */
|
||||
IT EQ
|
||||
VSTMDBEQ r1!, {d8 - d15} /* push FPU register s16~s31 */
|
||||
#endif
|
||||
|
||||
STMFD r1!, {r4 - r11} /* push r4 - r11 register */
|
||||
|
||||
LDR r2, =rt_trustzone_current_context /* r2 = &rt_secure_current_context */
|
||||
LDR r2, [r2] /* r2 = *r2 */
|
||||
MOV r3, lr /* r3 = lr */
|
||||
MRS r4, psplim /* r4 = psplim */
|
||||
MRS r5, control /* r5 = control */
|
||||
STMFD r1!, {r2-r5} /* push to thread stack */
|
||||
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] /* update from thread stack pointer */
|
||||
|
||||
switch_to_thread:
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] /* load thread stack pointer */
|
||||
|
||||
/* update current TrustZone context */
|
||||
LDMFD r1!, {r2-r5} /* pop thread stack */
|
||||
MSR psplim, r4 /* psplim = r4 */
|
||||
MSR control, r5 /* control = r5 */
|
||||
MOV lr, r3 /* lr = r3 */
|
||||
LDR r6, =rt_trustzone_current_context /* r6 = &rt_secure_current_context */
|
||||
STR r2, [r6] /* *r6 = r2 */
|
||||
MOV r0, r2 /* r0 = r2 */
|
||||
|
||||
/* Whether TrustZone thread stack exists */
|
||||
CBZ r0, contex_ns_load /* if r0 == 0, goto contex_ns_load */
|
||||
PUSH {r1, r3} /* push lr, thread_stack */
|
||||
BL rt_trustzone_context_load /* call TrustZone load fun */
|
||||
POP {r1, r3} /* pop lr, thread_stack */
|
||||
MOV lr, r3 /* lr = r1 */
|
||||
TST r3, #0x40 /* if EXC_RETURN[6] is 1, TrustZone stack was used */
|
||||
BEQ contex_ns_load /* if r1 & 0x40 == 0, goto contex_ns_load */
|
||||
B pendsv_exit
|
||||
|
||||
contex_ns_load:
|
||||
LDMFD r1!, {r4 - r11} /* pop r4 - r11 register */
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
TST lr, #0x10 /* if(!EXC_RETURN[4]) */
|
||||
IT EQ
|
||||
VLDMIAEQ r1!, {d8 - d15} /* pop FPU register s16~s31 */
|
||||
#endif
|
||||
|
||||
pendsv_exit:
|
||||
MSR psp, r1 /* update stack pointer */
|
||||
/* restore interrupt */
|
||||
POP {r2}
|
||||
MSR PRIMASK, r2
|
||||
|
||||
BX lr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* r0 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_to
|
||||
.type rt_hw_context_switch_to, %function
|
||||
rt_hw_context_switch_to:
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
/* CLEAR CONTROL.FPCA */
|
||||
MRS r2, CONTROL /* read */
|
||||
BIC r2, #0x04 /* modify */
|
||||
MSR CONTROL, r2 /* write-back */
|
||||
#endif
|
||||
|
||||
/* set from thread to 0 */
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
/* set interrupt flag to 1 */
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
/* set the PendSV and SysTick exception priority */
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] /* read */
|
||||
ORR r1,r1,r2 /* modify */
|
||||
STR r1, [r0] /* write-back */
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
/* restore MSP */
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
/* enable interrupts at processor level */
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
/* ensure PendSV exception taken place before subsequent operation */
|
||||
DSB
|
||||
ISB
|
||||
|
||||
/* never reach here! */
|
||||
|
||||
/* compatible with old version */
|
||||
.global rt_hw_interrupt_thread_switch
|
||||
.type rt_hw_interrupt_thread_switch, %function
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX lr
|
||||
NOP
|
||||
|
||||
.global HardFault_Handler
|
||||
.type HardFault_Handler, %function
|
||||
HardFault_Handler:
|
||||
/* get current context */
|
||||
MRS r0, msp /* get fault context from handler. */
|
||||
TST lr, #0x04 /* if(!EXC_RETURN[2]) */
|
||||
BEQ get_sp_done
|
||||
MRS r0, psp /* get fault context from thread. */
|
||||
get_sp_done:
|
||||
|
||||
STMFD r0!, {r4 - r11} /* push r4 - r11 register */
|
||||
|
||||
LDR r2, =rt_trustzone_current_context /* r2 = &rt_secure_current_context */
|
||||
LDR r2, [r2] /* r2 = *r2 */
|
||||
MOV r3, lr /* r3 = lr */
|
||||
MRS r4, psplim /* r4 = psplim */
|
||||
MRS r5, control /* r5 = control */
|
||||
STMFD r0!, {r2-r5} /* push to thread stack */
|
||||
|
||||
STMFD r0!, {lr} /* push exec_return register */
|
||||
|
||||
TST lr, #0x04 /* if(!EXC_RETURN[2]) */
|
||||
BEQ update_msp
|
||||
MSR psp, r0 /* update stack pointer to PSP. */
|
||||
B update_done
|
||||
update_msp:
|
||||
MSR msp, r0 /* update stack pointer to MSP. */
|
||||
update_done:
|
||||
|
||||
PUSH {LR}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {LR}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
304
rt-thread/libcpu/arm/cortex-m33/context_iar.S
Normal file
304
rt-thread/libcpu/arm/cortex-m33/context_iar.S
Normal file
@ -0,0 +1,304 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2009-01-17 Bernard first version
|
||||
; * 2009-09-27 Bernard add protect when contex switch occurs
|
||||
; * 2012-01-01 aozima support context switch load/store FPU register.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2013-06-23 aozima support lazy stack optimized.
|
||||
; * 2018-07-24 aozima enhancement hard fault exception handler.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup cortex-m33
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
SECTION .text:CODE(2)
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
IMPORT rt_trustzone_current_context
|
||||
IMPORT rt_trustzone_context_load
|
||||
IMPORT rt_trustzone_context_store
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
EXPORT PendSV_Handler
|
||||
PendSV_Handler:
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag ; r0 = &rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0] ; r1 = *r1
|
||||
CMP r1, #0x00 ; compare r1 == 0x00
|
||||
BNE schedule
|
||||
MSR PRIMASK, r2 ; if r1 == 0x00, do msr PRIMASK, r2
|
||||
BX lr ; if r1 == 0x00, do bx lr
|
||||
|
||||
schedule
|
||||
PUSH {r2} ; store interrupt state
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOV r1, #0x00 ; r1 = 0x00
|
||||
STR r1, [r0] ; *r0 = r1
|
||||
|
||||
; skip register save at the first time
|
||||
LDR r0, =rt_interrupt_from_thread ; r0 = &rt_interrupt_from_thread
|
||||
LDR r1, [r0] ; r1 = *r0
|
||||
CBZ r1, switch_to_thread ; if r1 == 0, goto switch_to_thread
|
||||
|
||||
; Whether TrustZone thread stack exists
|
||||
LDR r1, =rt_trustzone_current_context ; r1 = &rt_secure_current_context
|
||||
LDR r1, [r1] ; r1 = *r1
|
||||
CBZ r1, contex_ns_store ; if r1 == 0, goto contex_ns_store
|
||||
|
||||
;call TrustZone fun, Save TrustZone stack
|
||||
STMFD sp!, {r0-r1, lr} ; push register
|
||||
MOV r0, r1 ; r0 = rt_secure_current_context
|
||||
BL rt_trustzone_context_store ; call TrustZone store fun
|
||||
LDMFD sp!, {r0-r1, lr} ; pop register
|
||||
|
||||
; check break from TrustZone
|
||||
MOV r2, lr ; r2 = lr
|
||||
TST r2, #0x40 ; if EXC_RETURN[6] is 1, TrustZone stack was used
|
||||
BEQ contex_ns_store ; if r2 & 0x40 == 0, goto contex_ns_store
|
||||
|
||||
; push PSPLIM CONTROL PSP LR current_context to stack
|
||||
MRS r3, psplim ; r3 = psplim
|
||||
MRS r4, control ; r4 = control
|
||||
MRS r5, psp ; r5 = psp
|
||||
STMFD r5!, {r1-r4} ; push to thread stack
|
||||
|
||||
; update from thread stack pointer
|
||||
LDR r0, [r0] ; r0 = rt_thread_switch_interrupt_flag
|
||||
STR r5, [r0] ; *r0 = r5
|
||||
b switch_to_thread ; goto switch_to_thread
|
||||
|
||||
contex_ns_store
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
TST lr, #0x10 ; if(!EXC_RETURN[4])
|
||||
BNE skip_push_fpu
|
||||
VSTMDB r1!, {d8 - d15} ; push FPU register s16~s31
|
||||
skip_push_fpu
|
||||
#endif
|
||||
|
||||
STMFD r1!, {r4 - r11} ; push r4 - r11 register
|
||||
|
||||
LDR r2, =rt_trustzone_current_context ; r2 = &rt_secure_current_context
|
||||
LDR r2, [r2] ; r2 = *r2
|
||||
MOV r3, lr ; r3 = lr
|
||||
MRS r4, psplim ; r4 = psplim
|
||||
MRS r5, control ; r5 = control
|
||||
STMFD r1!, {r2-r5} ; push to thread stack
|
||||
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
switch_to_thread
|
||||
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
; update current TrustZone context
|
||||
LDMFD r1!, {r2-r5} ; pop thread stack
|
||||
MSR psplim, r4 ; psplim = r4
|
||||
MSR control, r5 ; control = r5
|
||||
MOV lr, r3 ; lr = r3
|
||||
LDR r6, =rt_trustzone_current_context ; r6 = &rt_secure_current_context
|
||||
STR r2, [r6] ; *r6 = r2
|
||||
MOV r0, r2 ; r0 = r2
|
||||
|
||||
; Whether TrustZone thread stack exists
|
||||
CBZ r0, contex_ns_load ; if r0 == 0, goto contex_ns_load
|
||||
PUSH {r1, r3} ; push lr, thread_stack
|
||||
BL rt_trustzone_context_load ; call TrustZone load fun
|
||||
POP {r1, r3} ; pop lr, thread_stack
|
||||
MOV lr, r3 ; lr = r1
|
||||
TST r3, #0x40 ; if EXC_RETURN[6] is 1, TrustZone stack was used
|
||||
BEQ contex_ns_load ; if r1 & 0x40 == 0, goto contex_ns_load
|
||||
B pendsv_exit
|
||||
|
||||
contex_ns_load
|
||||
LDMFD r1!, {r4 - r11} ; pop r4 - r11 register
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
TST lr, #0x10 ; if(!EXC_RETURN[4])
|
||||
BNE skip_pop_fpu
|
||||
VLDMIA r1!, {d8 - d15} ; pop FPU register s16~s31
|
||||
skip_pop_fpu
|
||||
#endif
|
||||
|
||||
pendsv_exit
|
||||
MSR psp, r1 ; update stack pointer
|
||||
; restore interrupt
|
||||
POP {r2}
|
||||
MSR PRIMASK, r2
|
||||
|
||||
BX lr
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
; CLEAR CONTROL.FPCA
|
||||
MRS r2, CONTROL ; read
|
||||
BIC r2, r2, #0x04 ; modify
|
||||
MSR CONTROL, r2 ; write-back
|
||||
#endif
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] ; read
|
||||
ORR r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
; ensure PendSV exception taken place before subsequent operation
|
||||
DSB
|
||||
ISB
|
||||
|
||||
; never reach here!
|
||||
|
||||
; compatible with old version
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX lr
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler:
|
||||
|
||||
; get current context
|
||||
MRS r0, msp ; get fault context from handler.
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
BEQ get_sp_done
|
||||
MRS r0, psp ; get fault context from thread.
|
||||
get_sp_done
|
||||
|
||||
STMFD r0!, {r4 - r11} ; push r4 - r11 register
|
||||
|
||||
LDR r2, =rt_trustzone_current_context ; r2 = &rt_secure_current_context
|
||||
LDR r2, [r2] ; r2 = *r2
|
||||
MOV r3, lr ; r3 = lr
|
||||
MRS r4, psplim ; r4 = psplim
|
||||
MRS r5, control ; r5 = control
|
||||
STMFD r0!, {r2-r5} ; push to thread stack
|
||||
|
||||
STMFD r0!, {lr} ; push exec_return register
|
||||
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
BEQ update_msp
|
||||
MSR psp, r0 ; update stack pointer to PSP.
|
||||
B update_done
|
||||
update_msp
|
||||
MSR msp, r0 ; update stack pointer to MSP.
|
||||
update_done
|
||||
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {lr}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
|
||||
END
|
||||
310
rt-thread/libcpu/arm/cortex-m33/context_rvds.S
Normal file
310
rt-thread/libcpu/arm/cortex-m33/context_rvds.S
Normal file
@ -0,0 +1,310 @@
|
||||
;/*
|
||||
;* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
;*
|
||||
;* SPDX-License-Identifier: Apache-2.0
|
||||
;*
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2009-01-17 Bernard first version.
|
||||
; * 2012-01-01 aozima support context switch load/store FPU register.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2013-06-23 aozima support lazy stack optimized.
|
||||
; * 2018-07-24 aozima enhancement hard fault exception handler.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup cortex-m33
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
IMPORT rt_trustzone_current_context
|
||||
IMPORT rt_trustzone_context_load
|
||||
IMPORT rt_trustzone_context_store
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable PROC
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch PROC
|
||||
EXPORT rt_hw_context_switch
|
||||
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK ; R2 = PRIMASK
|
||||
CPSID I ; disable all interrupt
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag ; r0 = &rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0] ; r1 = *r1
|
||||
CMP r1, #0x00 ; compare r1 == 0x00
|
||||
BNE schedule
|
||||
MSR PRIMASK, r2 ; if r1 == 0x00, do msr PRIMASK, r2
|
||||
BX lr ; if r1 == 0x00, do bx lr
|
||||
|
||||
schedule
|
||||
PUSH {r2} ; store interrupt state
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOV r1, #0x00 ; r1 = 0x00
|
||||
STR r1, [r0] ; *r0 = r1
|
||||
|
||||
; skip register save at the first time
|
||||
LDR r0, =rt_interrupt_from_thread ; r0 = &rt_interrupt_from_thread
|
||||
LDR r1, [r0] ; r1 = *r0
|
||||
CBZ r1, switch_to_thread ; if r1 == 0, goto switch_to_thread
|
||||
|
||||
; Whether TrustZone thread stack exists
|
||||
LDR r1, =rt_trustzone_current_context ; r1 = &rt_secure_current_context
|
||||
LDR r1, [r1] ; r1 = *r1
|
||||
CBZ r1, contex_ns_store ; if r1 == 0, goto contex_ns_store
|
||||
|
||||
;call TrustZone fun, Save TrustZone stack
|
||||
STMFD sp!, {r0-r1, lr} ; push register
|
||||
MOV r0, r1 ; r0 = rt_secure_current_context
|
||||
BL rt_trustzone_context_store ; call TrustZone store fun
|
||||
LDMFD sp!, {r0-r1, lr} ; pop register
|
||||
|
||||
; check break from TrustZone
|
||||
MOV r2, lr ; r2 = lr
|
||||
TST r2, #0x40 ; if EXC_RETURN[6] is 1, TrustZone stack was used
|
||||
BEQ contex_ns_store ; if r2 & 0x40 == 0, goto contex_ns_store
|
||||
|
||||
; push PSPLIM CONTROL PSP LR current_context to stack
|
||||
MRS r3, psplim ; r3 = psplim
|
||||
MRS r4, control ; r4 = control
|
||||
MRS r5, psp ; r5 = psp
|
||||
STMFD r5!, {r1-r4} ; push to thread stack
|
||||
|
||||
; update from thread stack pointer
|
||||
LDR r0, [r0] ; r0 = rt_thread_switch_interrupt_flag
|
||||
STR r5, [r0] ; *r0 = r5
|
||||
b switch_to_thread ; goto switch_to_thread
|
||||
|
||||
contex_ns_store
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
TST lr, #0x10 ; if(!EXC_RETURN[4])
|
||||
VSTMFDEQ r1!, {d8 - d15} ; push FPU register s16~s31
|
||||
ENDIF
|
||||
|
||||
STMFD r1!, {r4 - r11} ; push r4 - r11 register
|
||||
|
||||
LDR r2, =rt_trustzone_current_context ; r2 = &rt_secure_current_context
|
||||
LDR r2, [r2] ; r2 = *r2
|
||||
MOV r3, lr ; r3 = lr
|
||||
MRS r4, psplim ; r4 = psplim
|
||||
MRS r5, control ; r5 = control
|
||||
STMFD r1!, {r2-r5} ; push to thread stack
|
||||
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
; update current TrustZone context
|
||||
LDMFD r1!, {r2-r5} ; pop thread stack
|
||||
MSR psplim, r4 ; psplim = r4
|
||||
MSR control, r5 ; control = r5
|
||||
MOV lr, r3 ; lr = r3
|
||||
LDR r6, =rt_trustzone_current_context ; r6 = &rt_secure_current_context
|
||||
STR r2, [r6] ; *r6 = r2
|
||||
MOV r0, r2 ; r0 = r2
|
||||
|
||||
; Whether TrustZone thread stack exists
|
||||
CBZ r0, contex_ns_load ; if r0 == 0, goto contex_ns_load
|
||||
PUSH {r1, r3} ; push lr, thread_stack
|
||||
BL rt_trustzone_context_load ; call TrustZone load fun
|
||||
POP {r1, r3} ; pop lr, thread_stack
|
||||
MOV lr, r3 ; lr = r1
|
||||
TST r3, #0x40 ; if EXC_RETURN[6] is 1, TrustZone stack was used
|
||||
BEQ contex_ns_load ; if r1 & 0x40 == 0, goto contex_ns_load
|
||||
B pendsv_exit
|
||||
|
||||
contex_ns_load
|
||||
LDMFD r1!, {r4 - r11} ; pop r4 - r11 register
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
TST lr, #0x10 ; if(!EXC_RETURN[4])
|
||||
VLDMFDEQ r1!, {d8 - d15} ; pop FPU register s16~s31
|
||||
ENDIF
|
||||
|
||||
pendsv_exit
|
||||
MSR psp, r1 ; update stack pointer
|
||||
; restore interrupt
|
||||
POP {r2}
|
||||
MSR PRIMASK, r2
|
||||
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
rt_hw_context_switch_to PROC
|
||||
EXPORT rt_hw_context_switch_to
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
; CLEAR CONTROL.FPCA
|
||||
MRS r2, CONTROL ; read
|
||||
BIC r2, #0x04 ; modify
|
||||
MSR CONTROL, r2 ; write-back
|
||||
ENDIF
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] ; read
|
||||
ORR r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
; ensure PendSV exception taken place before subsequent operation
|
||||
DSB
|
||||
ISB
|
||||
|
||||
; never reach here!
|
||||
ENDP
|
||||
|
||||
; compatible with old version
|
||||
rt_hw_interrupt_thread_switch PROC
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler PROC
|
||||
|
||||
; get current context
|
||||
MRS r0, msp ;get fault context from handler
|
||||
TST lr, #0x04 ;if(!EXC_RETURN[2])
|
||||
BEQ get_sp_done
|
||||
MRS r0, psp ;get fault context from thread
|
||||
get_sp_done
|
||||
|
||||
STMFD r0!, {r4 - r11} ; push r4 - r11 register
|
||||
|
||||
LDR r2, =rt_trustzone_current_context ; r2 = &rt_secure_current_context
|
||||
LDR r2, [r2] ; r2 = *r2
|
||||
MOV r3, lr ; r3 = lr
|
||||
MRS r4, psplim ; r4 = psplim
|
||||
MRS r5, control ; r5 = control
|
||||
STMFD r0!, {r2-r5} ; push to thread stack
|
||||
|
||||
STMFD r0!, {lr} ; push exec_return register
|
||||
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
BEQ update_msp
|
||||
MSR psp, r0 ; update stack pointer to PSP
|
||||
B update_done
|
||||
update_msp
|
||||
MSR msp, r0 ; update stack pointer to MSP
|
||||
update_done
|
||||
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {lr}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
ALIGN 4
|
||||
|
||||
END
|
||||
559
rt-thread/libcpu/arm/cortex-m33/cpuport.c
Normal file
559
rt-thread/libcpu/arm/cortex-m33/cpuport.c
Normal file
@ -0,0 +1,559 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-10-21 Bernard the first version.
|
||||
* 2011-10-27 aozima update for cortex-M4 FPU.
|
||||
* 2011-12-31 aozima fixed stack align issues.
|
||||
* 2012-01-01 aozima support context switch load/store FPU register.
|
||||
* 2012-12-11 lgnq fixed the coding style.
|
||||
* 2012-12-23 aozima stack addr align to 8byte.
|
||||
* 2012-12-29 Bernard Add exception hook.
|
||||
* 2013-06-23 aozima support lazy stack optimized.
|
||||
* 2018-07-24 aozima enhancement hard fault exception handler.
|
||||
* 2019-07-03 yangjie add __rt_ffs() for armclang.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#if /* ARMCC */ ( (defined ( __CC_ARM ) && defined ( __TARGET_FPU_VFP )) \
|
||||
/* Clang */ || (defined ( __clang__ ) && defined ( __VFP_FP__ ) && !defined(__SOFTFP__)) \
|
||||
/* IAR */ || (defined ( __ICCARM__ ) && defined ( __ARMVFP__ )) \
|
||||
/* GNU */ || (defined ( __GNUC__ ) && defined ( __VFP_FP__ ) && !defined(__SOFTFP__)) )
|
||||
#define USE_FPU 1
|
||||
#else
|
||||
#define USE_FPU 0
|
||||
#endif
|
||||
|
||||
/* exception and interrupt handler table */
|
||||
rt_uint32_t rt_interrupt_from_thread;
|
||||
rt_uint32_t rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
|
||||
/* exception hook */
|
||||
static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL;
|
||||
|
||||
struct exception_stack_frame
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r12;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t psr;
|
||||
};
|
||||
|
||||
struct stack_frame
|
||||
{
|
||||
rt_uint32_t tz;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t psplim;
|
||||
rt_uint32_t control;
|
||||
|
||||
/* r4 ~ r11 register */
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t r11;
|
||||
|
||||
struct exception_stack_frame exception_stack_frame;
|
||||
};
|
||||
|
||||
struct exception_stack_frame_fpu
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r12;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t psr;
|
||||
|
||||
#if USE_FPU
|
||||
/* FPU register */
|
||||
rt_uint32_t S0;
|
||||
rt_uint32_t S1;
|
||||
rt_uint32_t S2;
|
||||
rt_uint32_t S3;
|
||||
rt_uint32_t S4;
|
||||
rt_uint32_t S5;
|
||||
rt_uint32_t S6;
|
||||
rt_uint32_t S7;
|
||||
rt_uint32_t S8;
|
||||
rt_uint32_t S9;
|
||||
rt_uint32_t S10;
|
||||
rt_uint32_t S11;
|
||||
rt_uint32_t S12;
|
||||
rt_uint32_t S13;
|
||||
rt_uint32_t S14;
|
||||
rt_uint32_t S15;
|
||||
rt_uint32_t FPSCR;
|
||||
rt_uint32_t NO_NAME;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stack_frame_fpu
|
||||
{
|
||||
rt_uint32_t flag;
|
||||
|
||||
/* r4 ~ r11 register */
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t r11;
|
||||
|
||||
#if USE_FPU
|
||||
/* FPU register s16 ~ s31 */
|
||||
rt_uint32_t s16;
|
||||
rt_uint32_t s17;
|
||||
rt_uint32_t s18;
|
||||
rt_uint32_t s19;
|
||||
rt_uint32_t s20;
|
||||
rt_uint32_t s21;
|
||||
rt_uint32_t s22;
|
||||
rt_uint32_t s23;
|
||||
rt_uint32_t s24;
|
||||
rt_uint32_t s25;
|
||||
rt_uint32_t s26;
|
||||
rt_uint32_t s27;
|
||||
rt_uint32_t s28;
|
||||
rt_uint32_t s29;
|
||||
rt_uint32_t s30;
|
||||
rt_uint32_t s31;
|
||||
#endif
|
||||
|
||||
struct exception_stack_frame_fpu exception_stack_frame;
|
||||
};
|
||||
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
void *parameter,
|
||||
rt_uint8_t *stack_addr,
|
||||
void *texit)
|
||||
{
|
||||
struct stack_frame *stack_frame;
|
||||
rt_uint8_t *stk;
|
||||
unsigned long i;
|
||||
|
||||
stk = stack_addr + sizeof(rt_uint32_t);
|
||||
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
|
||||
stk -= sizeof(struct stack_frame);
|
||||
|
||||
stack_frame = (struct stack_frame *)stk;
|
||||
|
||||
/* init all register */
|
||||
for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
|
||||
{
|
||||
((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
|
||||
}
|
||||
|
||||
stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */
|
||||
stack_frame->exception_stack_frame.r1 = 0; /* r1 */
|
||||
stack_frame->exception_stack_frame.r2 = 0; /* r2 */
|
||||
stack_frame->exception_stack_frame.r3 = 0; /* r3 */
|
||||
stack_frame->exception_stack_frame.r12 = 0; /* r12 */
|
||||
stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */
|
||||
stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */
|
||||
stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */
|
||||
|
||||
stack_frame->tz = 0x00; /* trustzone thread context */
|
||||
/*
|
||||
* Exception return behavior
|
||||
* +--------+---+---+------+-------+------+-------+---+----+
|
||||
* | PREFIX | - | S | DCRS | FType | Mode | SPSEL | - | ES |
|
||||
* +--------+---+---+------+-------+------+-------+---+----+
|
||||
* PREFIX [31:24] - Indicates that this is an EXC_RETURN value. This field reads as 0b11111111.
|
||||
* S [6] - Indicates whether registers have been pushed to a Secure or Non-secure stack.
|
||||
* 0: Non-secure stack used.
|
||||
* 1: Secure stack used.
|
||||
* DCRS [5] - Indicates whether the default stacking rules apply, or whether the callee registers are already on the stack.
|
||||
* 0: Stacking of the callee saved registers is skipped.
|
||||
* 1: Default rules for stacking the callee registers are followed.
|
||||
* FType [4] - In a PE with the Main and Floating-point Extensions:
|
||||
* 0: The PE allocated space on the stack for FP context.
|
||||
* 1: The PE did not allocate space on the stack for FP context.
|
||||
* In a PE without the Floating-point Extension, this bit is Reserved, RES1.
|
||||
* Mode [3] - Indicates the mode that was stacked from.
|
||||
* 0: Handler mode.
|
||||
* 1: Thread mode.
|
||||
* SPSEL [2] - Indicates which stack contains the exception stack frame.
|
||||
* 0: Main stack pointer.
|
||||
* 1: Process stack pointer.
|
||||
* ES [0] - Indicates the Security state the exception was taken to.
|
||||
* 0: Non-secure.
|
||||
* 1: Secure.
|
||||
*/
|
||||
stack_frame->lr = 0xfffffffdL;
|
||||
stack_frame->psplim = 0x00;
|
||||
/*
|
||||
* CONTROL register bit assignments
|
||||
* +---+------+------+-------+-------+
|
||||
* | - | SFPA | FPCA | SPSEL | nPRIV |
|
||||
* +---+------+------+-------+-------+
|
||||
* SFPA [3] - Indicates that the floating-point registers contain active state that belongs to the Secure state:
|
||||
* 0: The floating-point registers do not contain state that belongs to the Secure state.
|
||||
* 1: The floating-point registers contain state that belongs to the Secure state.
|
||||
* This bit is not banked between Security states and RAZ/WI from Non-secure state.
|
||||
* FPCA [2] - Indicates whether floating-point context is active:
|
||||
* 0: No floating-point context active.
|
||||
* 1: Floating-point context active.
|
||||
* This bit is used to determine whether to preserve floating-point state when processing an exception.
|
||||
* This bit is not banked between Security states.
|
||||
* SPSEL [1] - Defines the currently active stack pointer:
|
||||
* 0: MSP is the current stack pointer.
|
||||
* 1: PSP is the current stack pointer.
|
||||
* In Handler mode, this bit reads as zero and ignores writes. The CortexM33 core updates this bit automatically onexception return.
|
||||
* This bit is banked between Security states.
|
||||
* nPRIV [0] - Defines the Thread mode privilege level:
|
||||
* 0: Privileged.
|
||||
* 1: Unprivileged.
|
||||
* This bit is banked between Security states.
|
||||
*
|
||||
*/
|
||||
stack_frame->control = 0x00000000L;
|
||||
|
||||
/* return task's current stack address */
|
||||
return stk;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set the hook, which is invoked on fault exception handling.
|
||||
*
|
||||
* @param exception_handle the exception handling hook function.
|
||||
*/
|
||||
void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context))
|
||||
{
|
||||
rt_exception_hook = exception_handle;
|
||||
}
|
||||
|
||||
#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
|
||||
#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
|
||||
#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
|
||||
#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */
|
||||
#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED0C) /* Reset control Address Register */
|
||||
#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */
|
||||
|
||||
#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */
|
||||
#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */
|
||||
#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
static void usage_fault_track(void)
|
||||
{
|
||||
rt_kprintf("usage fault:\n");
|
||||
rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR);
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<0))
|
||||
{
|
||||
/* [0]:UNDEFINSTR */
|
||||
rt_kprintf("UNDEFINSTR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<1))
|
||||
{
|
||||
/* [1]:INVSTATE */
|
||||
rt_kprintf("INVSTATE ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<2))
|
||||
{
|
||||
/* [2]:INVPC */
|
||||
rt_kprintf("INVPC ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<3))
|
||||
{
|
||||
/* [3]:NOCP */
|
||||
rt_kprintf("NOCP ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<8))
|
||||
{
|
||||
/* [8]:UNALIGNED */
|
||||
rt_kprintf("UNALIGNED ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<9))
|
||||
{
|
||||
/* [9]:DIVBYZERO */
|
||||
rt_kprintf("DIVBYZERO ");
|
||||
}
|
||||
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
static void bus_fault_track(void)
|
||||
{
|
||||
rt_kprintf("bus fault:\n");
|
||||
rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR);
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<0))
|
||||
{
|
||||
/* [0]:IBUSERR */
|
||||
rt_kprintf("IBUSERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<1))
|
||||
{
|
||||
/* [1]:PRECISERR */
|
||||
rt_kprintf("PRECISERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<2))
|
||||
{
|
||||
/* [2]:IMPRECISERR */
|
||||
rt_kprintf("IMPRECISERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<3))
|
||||
{
|
||||
/* [3]:UNSTKERR */
|
||||
rt_kprintf("UNSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<4))
|
||||
{
|
||||
/* [4]:STKERR */
|
||||
rt_kprintf("STKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<7))
|
||||
{
|
||||
rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void mem_manage_fault_track(void)
|
||||
{
|
||||
rt_kprintf("mem manage fault:\n");
|
||||
rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR);
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<0))
|
||||
{
|
||||
/* [0]:IACCVIOL */
|
||||
rt_kprintf("IACCVIOL ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<1))
|
||||
{
|
||||
/* [1]:DACCVIOL */
|
||||
rt_kprintf("DACCVIOL ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<3))
|
||||
{
|
||||
/* [3]:MUNSTKERR */
|
||||
rt_kprintf("MUNSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<4))
|
||||
{
|
||||
/* [4]:MSTKERR */
|
||||
rt_kprintf("MSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<7))
|
||||
{
|
||||
/* [7]:MMARVALID */
|
||||
rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void hard_fault_track(void)
|
||||
{
|
||||
if(SCB_HFSR & (1UL<<1))
|
||||
{
|
||||
/* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */
|
||||
rt_kprintf("failed vector fetch\n");
|
||||
}
|
||||
|
||||
if(SCB_HFSR & (1UL<<30))
|
||||
{
|
||||
/* [30]:FORCED, Indicates hard fault is taken because of bus fault,
|
||||
memory management fault, or usage fault. */
|
||||
if(SCB_CFSR_BFSR)
|
||||
{
|
||||
bus_fault_track();
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR)
|
||||
{
|
||||
mem_manage_fault_track();
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR)
|
||||
{
|
||||
usage_fault_track();
|
||||
}
|
||||
}
|
||||
|
||||
if(SCB_HFSR & (1UL<<31))
|
||||
{
|
||||
/* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */
|
||||
rt_kprintf("debug event\n");
|
||||
}
|
||||
}
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
struct exception_info
|
||||
{
|
||||
rt_uint32_t exc_return;
|
||||
struct stack_frame stack_frame;
|
||||
};
|
||||
|
||||
void rt_hw_hard_fault_exception(struct exception_info *exception_info)
|
||||
{
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
struct exception_stack_frame *exception_stack = &exception_info->stack_frame.exception_stack_frame;
|
||||
struct stack_frame *context = &exception_info->stack_frame;
|
||||
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(exception_stack);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
|
||||
rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr);
|
||||
|
||||
rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0);
|
||||
rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1);
|
||||
rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2);
|
||||
rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3);
|
||||
rt_kprintf("r04: 0x%08x\n", context->r4);
|
||||
rt_kprintf("r05: 0x%08x\n", context->r5);
|
||||
rt_kprintf("r06: 0x%08x\n", context->r6);
|
||||
rt_kprintf("r07: 0x%08x\n", context->r7);
|
||||
rt_kprintf("r08: 0x%08x\n", context->r8);
|
||||
rt_kprintf("r09: 0x%08x\n", context->r9);
|
||||
rt_kprintf("r10: 0x%08x\n", context->r10);
|
||||
rt_kprintf("r11: 0x%08x\n", context->r11);
|
||||
rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12);
|
||||
rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr);
|
||||
rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc);
|
||||
|
||||
if (exception_info->exc_return & (1 << 2))
|
||||
{
|
||||
rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("hard fault on handler\r\n\r\n");
|
||||
}
|
||||
|
||||
if ( (exception_info->exc_return & 0x10) == 0)
|
||||
{
|
||||
rt_kprintf("FPU active!\r\n");
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
hard_fault_track();
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
/**
|
||||
* shutdown CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown(void)
|
||||
{
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset(void)
|
||||
{
|
||||
SCB_AIRCR = SCB_RESET_VALUE;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
/**
|
||||
* This function finds the first bit set (beginning with the least significant bit)
|
||||
* in value and return the index of that bit.
|
||||
*
|
||||
* Bits are numbered starting at 1 (the least significant bit). A return value of
|
||||
* zero from any of these functions means that the argument was zero.
|
||||
*
|
||||
* @return return the index of the first bit set. If value is 0, then this function
|
||||
* shall return 0.
|
||||
*/
|
||||
#if defined(__CC_ARM)
|
||||
__asm int __rt_ffs(int value)
|
||||
{
|
||||
CMP r0, #0x00
|
||||
BEQ exit
|
||||
|
||||
RBIT r0, r0
|
||||
CLZ r0, r0
|
||||
ADDS r0, r0, #0x01
|
||||
|
||||
exit
|
||||
BX lr
|
||||
}
|
||||
#elif defined(__clang__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
if (value == 0) return value;
|
||||
|
||||
__asm volatile(
|
||||
"RBIT r0, r0 \n"
|
||||
"CLZ r0, r0 \n"
|
||||
"ADDS r0, r0, #0x01 \n"
|
||||
|
||||
: "=r"(value)
|
||||
: "r"(value)
|
||||
);
|
||||
return value;
|
||||
}
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
if (value == 0) return value;
|
||||
|
||||
asm("RBIT %0, %1" : "=r"(value) : "r"(value));
|
||||
asm("CLZ %0, %1" : "=r"(value) : "r"(value));
|
||||
asm("ADDS %0, %1, #0x01" : "=r"(value) : "r"(value));
|
||||
|
||||
return value;
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
return __builtin_ffs(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
59
rt-thread/libcpu/arm/cortex-m33/syscall_gcc.S
Normal file
59
rt-thread/libcpu/arm/cortex-m33/syscall_gcc.S
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-10-25 tyx first version
|
||||
*/
|
||||
|
||||
.cpu cortex-m4
|
||||
.syntax unified
|
||||
.thumb
|
||||
.text
|
||||
|
||||
/*
|
||||
* int tzcall(int id, rt_ubase_t arg0, rt_ubase_t arg1, rt_ubase_t arg2);
|
||||
*/
|
||||
.global tzcall
|
||||
.type tzcall, %function
|
||||
tzcall:
|
||||
SVC 1 /* call SVC 1 */
|
||||
BX LR
|
||||
|
||||
tzcall_entry:
|
||||
PUSH {R1, R4, LR}
|
||||
MOV R4, R1 /* copy thread SP to R4 */
|
||||
LDMFD R4!, {r0 - r3} /* pop user stack, get input arg0, arg1, arg2 */
|
||||
STMFD R4!, {r0 - r3} /* push stack, user stack recovery */
|
||||
BL rt_secure_svc_handle /* call fun */
|
||||
POP {R1, R4, LR}
|
||||
STR R0, [R1] /* update return value */
|
||||
BX LR /* return to thread */
|
||||
|
||||
syscall_entry:
|
||||
BX LR /* return to user app */
|
||||
|
||||
.global SVC_Handler
|
||||
.type SVC_Handler, %function
|
||||
SVC_Handler:
|
||||
|
||||
/* get SP, save to R1 */
|
||||
MRS R1, MSP /* get fault context from handler. */
|
||||
TST LR, #0x04 /* if(!EXC_RETURN[2]) */
|
||||
BEQ get_sp_done
|
||||
MRS R1, PSP /* get fault context from thread. */
|
||||
get_sp_done:
|
||||
|
||||
/* get svc index */
|
||||
LDR R0, [R1, #24]
|
||||
LDRB R0, [R0, #-2]
|
||||
|
||||
/* if svc == 0, do system call */
|
||||
CMP R0, #0x0
|
||||
BEQ syscall_entry
|
||||
|
||||
/* if svc == 1, do TrustZone call */
|
||||
CMP R0, #0x1
|
||||
BEQ tzcall_entry
|
||||
67
rt-thread/libcpu/arm/cortex-m33/syscall_iar.S
Normal file
67
rt-thread/libcpu/arm/cortex-m33/syscall_iar.S
Normal file
@ -0,0 +1,67 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2019-10-25 tyx first version
|
||||
; * 2021-03-26 lxf modify bad instruction
|
||||
; */
|
||||
|
||||
;/*
|
||||
; * @addtogroup cortex-m33
|
||||
; */
|
||||
|
||||
|
||||
SECTION .text:CODE(2)
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_secure_svc_handle
|
||||
|
||||
;/*
|
||||
; * int tzcall(int id, rt_ubase_t arg0, rt_ubase_t arg1, rt_ubase_t arg2);
|
||||
; */
|
||||
EXPORT tzcall
|
||||
tzcall:
|
||||
SVC 1 ;/* call SVC 1 */
|
||||
BX LR
|
||||
|
||||
tzcall_entry:
|
||||
PUSH {R1, R4, LR}
|
||||
MOV R4, R1 ;/* copy thread SP to R4 */
|
||||
LDMFD R4!, {r0 - r3} ;/* pop user stack, get input arg0, arg1, arg2 */
|
||||
STMFD R4!, {r0 - r3} ;/* push stack, user stack recovery */
|
||||
BL rt_secure_svc_handle ;/* call fun */
|
||||
POP {R1, R4, LR}
|
||||
STR R0, [R1] ;/* update return value */
|
||||
BX LR ;/* return to thread */
|
||||
|
||||
syscall_entry:
|
||||
BX LR ;/* return to user app */
|
||||
|
||||
EXPORT SVC_Handler
|
||||
SVC_Handler:
|
||||
|
||||
;/* get SP, save to R1 */
|
||||
MRS R1, MSP ;/* get fault context from handler. */
|
||||
TST LR, #0x04 ;/* if(!EXC_RETURN[2]) */
|
||||
BEQ get_sp_done
|
||||
MRS R1, PSP ;/* get fault context from thread. */
|
||||
get_sp_done:
|
||||
|
||||
;/* get svc index */
|
||||
LDR R0, [R1, #24]
|
||||
LDRB R0, [R0, #-2]
|
||||
|
||||
;/* if svc == 0, do system call */
|
||||
CMP R0, #0x0
|
||||
BEQ syscall_entry
|
||||
|
||||
;/* if svc == 1, do TrustZone call */
|
||||
CMP R0, #0x1
|
||||
BEQ tzcall_entry
|
||||
|
||||
END
|
||||
74
rt-thread/libcpu/arm/cortex-m33/syscall_rvds.S
Normal file
74
rt-thread/libcpu/arm/cortex-m33/syscall_rvds.S
Normal file
@ -0,0 +1,74 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2019-10-25 tyx first version
|
||||
; */
|
||||
|
||||
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_secure_svc_handle
|
||||
|
||||
;/*
|
||||
; * int tzcall(int id, rt_ubase_t arg0, rt_ubase_t arg1, rt_ubase_t arg2);
|
||||
; */
|
||||
tzcall PROC
|
||||
EXPORT tzcall
|
||||
SVC 1 ;call SVC 1
|
||||
BX LR
|
||||
|
||||
ENDP
|
||||
|
||||
tzcall_entry PROC
|
||||
PUSH {R1, R4, LR}
|
||||
MOV R4, R1 ; copy thread SP to R4
|
||||
LDMFD R4!, {r0 - r3} ; pop user stack, get input arg0, arg1, arg2
|
||||
STMFD R4!, {r0 - r3} ; push stack, user stack recovery
|
||||
BL rt_secure_svc_handle ; call fun
|
||||
POP {R1, R4, LR}
|
||||
STR R0, [R1] ; update return value
|
||||
BX LR ; return to thread
|
||||
|
||||
ENDP
|
||||
|
||||
syscall_entry PROC
|
||||
BX LR ; return to user app
|
||||
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void SVC_Handler(void);
|
||||
; */
|
||||
SVC_Handler PROC
|
||||
EXPORT SVC_Handler
|
||||
|
||||
; get SP, save to R1
|
||||
MRS R1, MSP ;get fault context from handler
|
||||
TST LR, #0x04 ;if(!EXC_RETURN[2])
|
||||
BEQ get_sp_done
|
||||
MRS R1, PSP ;get fault context from thread
|
||||
get_sp_done
|
||||
|
||||
; get svc index
|
||||
LDR R0, [R1, #24]
|
||||
LDRB R0, [R0, #-2]
|
||||
|
||||
;if svc == 0, do system call
|
||||
CMP R0, #0x0
|
||||
BEQ syscall_entry
|
||||
|
||||
;if svc == 1, do TrustZone call
|
||||
CMP R0, #0x1
|
||||
BEQ tzcall_entry
|
||||
|
||||
ENDP
|
||||
|
||||
ALIGN
|
||||
|
||||
END
|
||||
98
rt-thread/libcpu/arm/cortex-m33/trustzone.c
Normal file
98
rt-thread/libcpu/arm/cortex-m33/trustzone.c
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-10-28 tyx the first version.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef ARM_CM33_ENABLE_TRUSTZONE
|
||||
extern void TZ_InitContextSystem_S(void);
|
||||
extern rt_uint32_t TZ_AllocModuleContext_S (rt_uint32_t module);
|
||||
extern rt_uint32_t TZ_FreeModuleContext_S(rt_uint32_t id);
|
||||
extern rt_uint32_t TZ_LoadContext_S(rt_uint32_t id);
|
||||
extern rt_uint32_t TZ_StoreContext_S(rt_uint32_t id);
|
||||
#else
|
||||
void TZ_InitContextSystem_S(void){}
|
||||
rt_uint32_t TZ_AllocModuleContext_S (rt_uint32_t module){return 0;}
|
||||
rt_uint32_t TZ_FreeModuleContext_S(rt_uint32_t id) {return 0;}
|
||||
rt_uint32_t TZ_LoadContext_S(rt_uint32_t id){return 0;};
|
||||
rt_uint32_t TZ_StoreContext_S(rt_uint32_t id){return 0;};
|
||||
#endif
|
||||
extern int tzcall(int id, rt_ubase_t arg0, rt_ubase_t arg1, rt_ubase_t arg2);
|
||||
|
||||
#define TZ_INIT_CONTEXT_ID (0x1001)
|
||||
#define TZ_ALLOC_CONTEXT_ID (0x1002)
|
||||
#define TZ_FREE_CONTEXT_ID (0x1003)
|
||||
|
||||
rt_ubase_t rt_trustzone_current_context;
|
||||
|
||||
void rt_trustzone_init(void)
|
||||
{
|
||||
static rt_uint8_t _init;
|
||||
|
||||
if (_init)
|
||||
return;
|
||||
tzcall(TZ_INIT_CONTEXT_ID, 0, 0, 0);
|
||||
_init = 1;
|
||||
}
|
||||
|
||||
rt_err_t rt_trustzone_enter(rt_ubase_t module)
|
||||
{
|
||||
rt_trustzone_init();
|
||||
if (tzcall(TZ_ALLOC_CONTEXT_ID, module, 0, 0))
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_err_t rt_trustzone_exit(void)
|
||||
{
|
||||
tzcall(TZ_FREE_CONTEXT_ID, 0, 0, 0);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
void rt_trustzone_context_store(rt_ubase_t context)
|
||||
{
|
||||
TZ_StoreContext_S(context);
|
||||
}
|
||||
|
||||
void rt_trustzone_context_load(rt_ubase_t context)
|
||||
{
|
||||
TZ_LoadContext_S(context);
|
||||
}
|
||||
|
||||
int rt_secure_svc_handle(int svc_id, rt_ubase_t arg0, rt_ubase_t arg1, rt_ubase_t arg2)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
switch (svc_id)
|
||||
{
|
||||
case TZ_INIT_CONTEXT_ID:
|
||||
TZ_InitContextSystem_S();
|
||||
break;
|
||||
case TZ_ALLOC_CONTEXT_ID:
|
||||
res = TZ_AllocModuleContext_S(arg0);
|
||||
if (res <= 0)
|
||||
{
|
||||
rt_kprintf("Alloc Context Failed\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trustzone_current_context = res;
|
||||
TZ_LoadContext_S(res);
|
||||
}
|
||||
break;
|
||||
case TZ_FREE_CONTEXT_ID:
|
||||
TZ_FreeModuleContext_S(rt_trustzone_current_context);
|
||||
rt_trustzone_current_context = 0;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
253
rt-thread/libcpu/arm/cortex-m4/context_gcc.S
Normal file
253
rt-thread/libcpu/arm/cortex-m4/context_gcc.S
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2009-10-11 Bernard first version
|
||||
* 2012-01-01 aozima support context switch load/store FPU register.
|
||||
* 2013-06-18 aozima add restore MSP feature.
|
||||
* 2013-06-23 aozima support lazy stack optimized.
|
||||
* 2018-07-24 aozima enhancement hard fault exception handler.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup cortex-m4
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
.cpu cortex-m4
|
||||
.syntax unified
|
||||
.thumb
|
||||
.text
|
||||
|
||||
.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */
|
||||
.equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */
|
||||
.equ NVIC_SYSPRI2, 0xE000ED20 /* system priority register (2) */
|
||||
.equ NVIC_PENDSV_PRI, 0xFFFF0000 /* PendSV and SysTick priority value (lowest) */
|
||||
.equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.global rt_hw_interrupt_disable
|
||||
.type rt_hw_interrupt_disable, %function
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.global rt_hw_interrupt_enable
|
||||
.type rt_hw_interrupt_enable, %function
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_interrupt
|
||||
.type rt_hw_context_switch_interrupt, %function
|
||||
.global rt_hw_context_switch
|
||||
.type rt_hw_context_switch, %function
|
||||
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
/* set rt_thread_switch_interrupt_flag to 1 */
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch:
|
||||
LDR r2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
|
||||
/* r0 --> switch from thread stack
|
||||
* r1 --> switch to thread stack
|
||||
* psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
*/
|
||||
.global PendSV_Handler
|
||||
.type PendSV_Handler, %function
|
||||
PendSV_Handler:
|
||||
/* disable interrupt to protect context switch */
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
/* get rt_thread_switch_interrupt_flag */
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CBZ r1, pendsv_exit /* pendsv already handled */
|
||||
|
||||
/* clear rt_thread_switch_interrupt_flag to 0 */
|
||||
MOV r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CBZ r1, switch_to_thread /* skip register save at the first time */
|
||||
|
||||
MRS r1, psp /* get from thread stack pointer */
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
TST lr, #0x10 /* if(!EXC_RETURN[4]) */
|
||||
IT EQ
|
||||
VSTMDBEQ r1!, {d8 - d15} /* push FPU register s16~s31 */
|
||||
#endif
|
||||
|
||||
STMFD r1!, {r4 - r11} /* push r4 - r11 register */
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
MOV r4, #0x00 /* flag = 0 */
|
||||
|
||||
TST lr, #0x10 /* if(!EXC_RETURN[4]) */
|
||||
IT EQ
|
||||
MOVEQ r4, #0x01 /* flag = 1 */
|
||||
|
||||
STMFD r1!, {r4} /* push flag */
|
||||
#endif
|
||||
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] /* update from thread stack pointer */
|
||||
|
||||
switch_to_thread:
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] /* load thread stack pointer */
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
LDMFD r1!, {r3} /* pop flag */
|
||||
#endif
|
||||
|
||||
LDMFD r1!, {r4 - r11} /* pop r4 - r11 register */
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
CMP r3, #0 /* if(flag_r3 != 0) */
|
||||
IT NE
|
||||
VLDMIANE r1!, {d8 - d15} /* pop FPU register s16~s31 */
|
||||
#endif
|
||||
|
||||
MSR psp, r1 /* update stack pointer */
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
ORR lr, lr, #0x10 /* lr |= (1 << 4), clean FPCA. */
|
||||
CMP r3, #0 /* if(flag_r3 != 0) */
|
||||
IT NE
|
||||
BICNE lr, lr, #0x10 /* lr &= ~(1 << 4), set FPCA. */
|
||||
#endif
|
||||
|
||||
pendsv_exit:
|
||||
/* restore interrupt */
|
||||
MSR PRIMASK, r2
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* r0 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_to
|
||||
.type rt_hw_context_switch_to, %function
|
||||
rt_hw_context_switch_to:
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
/* CLEAR CONTROL.FPCA */
|
||||
MRS r2, CONTROL /* read */
|
||||
BIC r2, #0x04 /* modify */
|
||||
MSR CONTROL, r2 /* write-back */
|
||||
#endif
|
||||
|
||||
/* set from thread to 0 */
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
/* set interrupt flag to 1 */
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
/* set the PendSV and SysTick exception priority */
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] /* read */
|
||||
ORR r1,r1,r2 /* modify */
|
||||
STR r1, [r0] /* write-back */
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
/* restore MSP */
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
/* enable interrupts at processor level */
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
/* ensure PendSV exception taken place before subsequent operation */
|
||||
DSB
|
||||
ISB
|
||||
|
||||
/* never reach here! */
|
||||
|
||||
/* compatible with old version */
|
||||
.global rt_hw_interrupt_thread_switch
|
||||
.type rt_hw_interrupt_thread_switch, %function
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX lr
|
||||
NOP
|
||||
|
||||
.global HardFault_Handler
|
||||
.type HardFault_Handler, %function
|
||||
HardFault_Handler:
|
||||
/* get current context */
|
||||
MRS r0, msp /* get fault context from handler. */
|
||||
TST lr, #0x04 /* if(!EXC_RETURN[2]) */
|
||||
BEQ _get_sp_done
|
||||
MRS r0, psp /* get fault context from thread. */
|
||||
_get_sp_done:
|
||||
|
||||
STMFD r0!, {r4 - r11} /* push r4 - r11 register */
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
STMFD r0!, {lr} /* push dummy for flag */
|
||||
#endif
|
||||
STMFD r0!, {lr} /* push exec_return register */
|
||||
|
||||
TST lr, #0x04 /* if(!EXC_RETURN[2]) */
|
||||
BEQ _update_msp
|
||||
MSR psp, r0 /* update stack pointer to PSP. */
|
||||
B _update_done
|
||||
_update_msp:
|
||||
MSR msp, r0 /* update stack pointer to MSP. */
|
||||
_update_done:
|
||||
|
||||
PUSH {LR}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {LR}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
257
rt-thread/libcpu/arm/cortex-m4/context_iar.S
Normal file
257
rt-thread/libcpu/arm/cortex-m4/context_iar.S
Normal file
@ -0,0 +1,257 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2009-01-17 Bernard first version
|
||||
; * 2009-09-27 Bernard add protect when contex switch occurs
|
||||
; * 2012-01-01 aozima support context switch load/store FPU register.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2013-06-23 aozima support lazy stack optimized.
|
||||
; * 2018-07-24 aozima enhancement hard fault exception handler.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup cortex-m4
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
SECTION .text:CODE(2)
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
EXPORT PendSV_Handler
|
||||
PendSV_Handler:
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CBZ r1, pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOV r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CBZ r1, switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
TST lr, #0x10 ; if(!EXC_RETURN[4])
|
||||
BNE skip_push_fpu
|
||||
VSTMDB r1!, {d8 - d15} ; push FPU register s16~s31
|
||||
skip_push_fpu
|
||||
#endif
|
||||
|
||||
STMFD r1!, {r4 - r11} ; push r4 - r11 register
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
MOV r4, #0x00 ; flag = 0
|
||||
TST lr, #0x10 ; if(!EXC_RETURN[4])
|
||||
BNE push_flag
|
||||
MOV r4, #0x01 ; flag = 1
|
||||
push_flag
|
||||
;STMFD r1!, {r4} ; push flag
|
||||
SUB r1, r1, #0x04
|
||||
STR r4, [r1]
|
||||
#endif
|
||||
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
LDMFD r1!, {r3} ; pop flag
|
||||
#endif
|
||||
|
||||
LDMFD r1!, {r4 - r11} ; pop r4 - r11 register
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
CBZ r3, skip_pop_fpu
|
||||
VLDMIA r1!, {d8 - d15} ; pop FPU register s16~s31
|
||||
skip_pop_fpu
|
||||
#endif
|
||||
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
ORR lr, lr, #0x10 ; lr |= (1 << 4), clean FPCA.
|
||||
CBZ r3, return_without_fpu ; if(flag_r3 != 0)
|
||||
BIC lr, lr, #0x10 ; lr &= ~(1 << 4), set FPCA.
|
||||
return_without_fpu
|
||||
#endif
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
; CLEAR CONTROL.FPCA
|
||||
MRS r2, CONTROL ; read
|
||||
BIC r2, r2, #0x04 ; modify
|
||||
MSR CONTROL, r2 ; write-back
|
||||
#endif
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] ; read
|
||||
ORR r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
; ensure PendSV exception taken place before subsequent operation
|
||||
DSB
|
||||
ISB
|
||||
|
||||
; never reach here!
|
||||
|
||||
; compatible with old version
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX lr
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler:
|
||||
|
||||
; get current context
|
||||
MRS r0, msp ; get fault context from handler.
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
BEQ _get_sp_done
|
||||
MRS r0, psp ; get fault context from thread.
|
||||
_get_sp_done
|
||||
|
||||
STMFD r0!, {r4 - r11} ; push r4 - r11 register
|
||||
;STMFD r0!, {lr} ; push exec_return register
|
||||
#if defined ( __ARMVFP__ )
|
||||
SUB r0, r0, #0x04 ; push dummy for flag
|
||||
STR lr, [r0]
|
||||
#endif
|
||||
SUB r0, r0, #0x04
|
||||
STR lr, [r0]
|
||||
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
BEQ _update_msp
|
||||
MSR psp, r0 ; update stack pointer to PSP.
|
||||
B _update_done
|
||||
_update_msp
|
||||
MSR msp, r0 ; update stack pointer to MSP.
|
||||
_update_done
|
||||
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {lr}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
|
||||
END
|
||||
255
rt-thread/libcpu/arm/cortex-m4/context_rvds.S
Normal file
255
rt-thread/libcpu/arm/cortex-m4/context_rvds.S
Normal file
@ -0,0 +1,255 @@
|
||||
;/*
|
||||
;* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
;*
|
||||
;* SPDX-License-Identifier: Apache-2.0
|
||||
;*
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2009-01-17 Bernard first version.
|
||||
; * 2012-01-01 aozima support context switch load/store FPU register.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2013-06-23 aozima support lazy stack optimized.
|
||||
; * 2018-07-24 aozima enhancement hard fault exception handler.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup cortex-m4
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable PROC
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch PROC
|
||||
EXPORT rt_hw_context_switch
|
||||
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CBZ r1, pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOV r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CBZ r1, switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
TST lr, #0x10 ; if(!EXC_RETURN[4])
|
||||
VSTMFDEQ r1!, {d8 - d15} ; push FPU register s16~s31
|
||||
ENDIF
|
||||
|
||||
STMFD r1!, {r4 - r11} ; push r4 - r11 register
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
MOV r4, #0x00 ; flag = 0
|
||||
|
||||
TST lr, #0x10 ; if(!EXC_RETURN[4])
|
||||
MOVEQ r4, #0x01 ; flag = 1
|
||||
|
||||
STMFD r1!, {r4} ; push flag
|
||||
ENDIF
|
||||
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
LDMFD r1!, {r3} ; pop flag
|
||||
ENDIF
|
||||
|
||||
LDMFD r1!, {r4 - r11} ; pop r4 - r11 register
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
CMP r3, #0 ; if(flag_r3 != 0)
|
||||
VLDMFDNE r1!, {d8 - d15} ; pop FPU register s16~s31
|
||||
ENDIF
|
||||
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
ORR lr, lr, #0x10 ; lr |= (1 << 4), clean FPCA.
|
||||
CMP r3, #0 ; if(flag_r3 != 0)
|
||||
BICNE lr, lr, #0x10 ; lr &= ~(1 << 4), set FPCA.
|
||||
ENDIF
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
rt_hw_context_switch_to PROC
|
||||
EXPORT rt_hw_context_switch_to
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
; CLEAR CONTROL.FPCA
|
||||
MRS r2, CONTROL ; read
|
||||
BIC r2, #0x04 ; modify
|
||||
MSR CONTROL, r2 ; write-back
|
||||
ENDIF
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] ; read
|
||||
ORR r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
; ensure PendSV exception taken place before subsequent operation
|
||||
DSB
|
||||
ISB
|
||||
|
||||
; never reach here!
|
||||
ENDP
|
||||
|
||||
; compatible with old version
|
||||
rt_hw_interrupt_thread_switch PROC
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler PROC
|
||||
|
||||
; get current context
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
ITE EQ
|
||||
MRSEQ r0, msp ; [2]=0 ==> Z=1, get fault context from handler.
|
||||
MRSNE r0, psp ; [2]=1 ==> Z=0, get fault context from thread.
|
||||
|
||||
STMFD r0!, {r4 - r11} ; push r4 - r11 register
|
||||
IF {FPU} != "SoftVFP"
|
||||
STMFD r0!, {lr} ; push dummy for flag
|
||||
ENDIF
|
||||
STMFD r0!, {lr} ; push exec_return register
|
||||
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
ITE EQ
|
||||
MSREQ msp, r0 ; [2]=0 ==> Z=1, update stack pointer to MSP.
|
||||
MSRNE psp, r0 ; [2]=1 ==> Z=0, update stack pointer to PSP.
|
||||
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {lr}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
ALIGN 4
|
||||
|
||||
END
|
||||
509
rt-thread/libcpu/arm/cortex-m4/cpuport.c
Normal file
509
rt-thread/libcpu/arm/cortex-m4/cpuport.c
Normal file
@ -0,0 +1,509 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-10-21 Bernard the first version.
|
||||
* 2011-10-27 aozima update for cortex-M4 FPU.
|
||||
* 2011-12-31 aozima fixed stack align issues.
|
||||
* 2012-01-01 aozima support context switch load/store FPU register.
|
||||
* 2012-12-11 lgnq fixed the coding style.
|
||||
* 2012-12-23 aozima stack addr align to 8byte.
|
||||
* 2012-12-29 Bernard Add exception hook.
|
||||
* 2013-06-23 aozima support lazy stack optimized.
|
||||
* 2018-07-24 aozima enhancement hard fault exception handler.
|
||||
* 2019-07-03 yangjie add __rt_ffs() for armclang.
|
||||
* 2022-06-12 jonas fixed __rt_ffs() for armclang.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#if /* ARMCC */ ( (defined ( __CC_ARM ) && defined ( __TARGET_FPU_VFP )) \
|
||||
/* Clang */ || (defined ( __clang__ ) && defined ( __VFP_FP__ ) && !defined(__SOFTFP__)) \
|
||||
/* IAR */ || (defined ( __ICCARM__ ) && defined ( __ARMVFP__ )) \
|
||||
/* GNU */ || (defined ( __GNUC__ ) && defined ( __VFP_FP__ ) && !defined(__SOFTFP__)) )
|
||||
#define USE_FPU 1
|
||||
#else
|
||||
#define USE_FPU 0
|
||||
#endif
|
||||
|
||||
/* exception and interrupt handler table */
|
||||
rt_uint32_t rt_interrupt_from_thread;
|
||||
rt_uint32_t rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
/* exception hook */
|
||||
static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL;
|
||||
|
||||
struct exception_stack_frame
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r12;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t psr;
|
||||
};
|
||||
|
||||
struct stack_frame
|
||||
{
|
||||
#if USE_FPU
|
||||
rt_uint32_t flag;
|
||||
#endif /* USE_FPU */
|
||||
|
||||
/* r4 ~ r11 register */
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t r11;
|
||||
|
||||
struct exception_stack_frame exception_stack_frame;
|
||||
};
|
||||
|
||||
struct exception_stack_frame_fpu
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r12;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t psr;
|
||||
|
||||
#if USE_FPU
|
||||
/* FPU register */
|
||||
rt_uint32_t S0;
|
||||
rt_uint32_t S1;
|
||||
rt_uint32_t S2;
|
||||
rt_uint32_t S3;
|
||||
rt_uint32_t S4;
|
||||
rt_uint32_t S5;
|
||||
rt_uint32_t S6;
|
||||
rt_uint32_t S7;
|
||||
rt_uint32_t S8;
|
||||
rt_uint32_t S9;
|
||||
rt_uint32_t S10;
|
||||
rt_uint32_t S11;
|
||||
rt_uint32_t S12;
|
||||
rt_uint32_t S13;
|
||||
rt_uint32_t S14;
|
||||
rt_uint32_t S15;
|
||||
rt_uint32_t FPSCR;
|
||||
rt_uint32_t NO_NAME;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stack_frame_fpu
|
||||
{
|
||||
rt_uint32_t flag;
|
||||
|
||||
/* r4 ~ r11 register */
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t r11;
|
||||
|
||||
#if USE_FPU
|
||||
/* FPU register s16 ~ s31 */
|
||||
rt_uint32_t s16;
|
||||
rt_uint32_t s17;
|
||||
rt_uint32_t s18;
|
||||
rt_uint32_t s19;
|
||||
rt_uint32_t s20;
|
||||
rt_uint32_t s21;
|
||||
rt_uint32_t s22;
|
||||
rt_uint32_t s23;
|
||||
rt_uint32_t s24;
|
||||
rt_uint32_t s25;
|
||||
rt_uint32_t s26;
|
||||
rt_uint32_t s27;
|
||||
rt_uint32_t s28;
|
||||
rt_uint32_t s29;
|
||||
rt_uint32_t s30;
|
||||
rt_uint32_t s31;
|
||||
#endif
|
||||
|
||||
struct exception_stack_frame_fpu exception_stack_frame;
|
||||
};
|
||||
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
void *parameter,
|
||||
rt_uint8_t *stack_addr,
|
||||
void *texit)
|
||||
{
|
||||
struct stack_frame *stack_frame;
|
||||
rt_uint8_t *stk;
|
||||
unsigned long i;
|
||||
|
||||
stk = stack_addr + sizeof(rt_uint32_t);
|
||||
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
|
||||
stk -= sizeof(struct stack_frame);
|
||||
|
||||
stack_frame = (struct stack_frame *)stk;
|
||||
|
||||
/* init all register */
|
||||
for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
|
||||
{
|
||||
((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
|
||||
}
|
||||
|
||||
stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */
|
||||
stack_frame->exception_stack_frame.r1 = 0; /* r1 */
|
||||
stack_frame->exception_stack_frame.r2 = 0; /* r2 */
|
||||
stack_frame->exception_stack_frame.r3 = 0; /* r3 */
|
||||
stack_frame->exception_stack_frame.r12 = 0; /* r12 */
|
||||
stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */
|
||||
stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */
|
||||
stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */
|
||||
|
||||
#if USE_FPU
|
||||
stack_frame->flag = 0;
|
||||
#endif /* USE_FPU */
|
||||
|
||||
/* return task's current stack address */
|
||||
return stk;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set the hook, which is invoked on fault exception handling.
|
||||
*
|
||||
* @param exception_handle the exception handling hook function.
|
||||
*/
|
||||
void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context))
|
||||
{
|
||||
rt_exception_hook = exception_handle;
|
||||
}
|
||||
|
||||
#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
|
||||
#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
|
||||
#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
|
||||
#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */
|
||||
#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED0C) /* Reset control Address Register */
|
||||
#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */
|
||||
|
||||
#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */
|
||||
#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */
|
||||
#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
static void usage_fault_track(void)
|
||||
{
|
||||
rt_kprintf("usage fault:\n");
|
||||
rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR);
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<0))
|
||||
{
|
||||
/* [0]:UNDEFINSTR */
|
||||
rt_kprintf("UNDEFINSTR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<1))
|
||||
{
|
||||
/* [1]:INVSTATE */
|
||||
rt_kprintf("INVSTATE ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<2))
|
||||
{
|
||||
/* [2]:INVPC */
|
||||
rt_kprintf("INVPC ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<3))
|
||||
{
|
||||
/* [3]:NOCP */
|
||||
rt_kprintf("NOCP ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<8))
|
||||
{
|
||||
/* [8]:UNALIGNED */
|
||||
rt_kprintf("UNALIGNED ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<9))
|
||||
{
|
||||
/* [9]:DIVBYZERO */
|
||||
rt_kprintf("DIVBYZERO ");
|
||||
}
|
||||
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
static void bus_fault_track(void)
|
||||
{
|
||||
rt_kprintf("bus fault:\n");
|
||||
rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR);
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<0))
|
||||
{
|
||||
/* [0]:IBUSERR */
|
||||
rt_kprintf("IBUSERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<1))
|
||||
{
|
||||
/* [1]:PRECISERR */
|
||||
rt_kprintf("PRECISERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<2))
|
||||
{
|
||||
/* [2]:IMPRECISERR */
|
||||
rt_kprintf("IMPRECISERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<3))
|
||||
{
|
||||
/* [3]:UNSTKERR */
|
||||
rt_kprintf("UNSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<4))
|
||||
{
|
||||
/* [4]:STKERR */
|
||||
rt_kprintf("STKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<7))
|
||||
{
|
||||
rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void mem_manage_fault_track(void)
|
||||
{
|
||||
rt_kprintf("mem manage fault:\n");
|
||||
rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR);
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<0))
|
||||
{
|
||||
/* [0]:IACCVIOL */
|
||||
rt_kprintf("IACCVIOL ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<1))
|
||||
{
|
||||
/* [1]:DACCVIOL */
|
||||
rt_kprintf("DACCVIOL ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<3))
|
||||
{
|
||||
/* [3]:MUNSTKERR */
|
||||
rt_kprintf("MUNSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<4))
|
||||
{
|
||||
/* [4]:MSTKERR */
|
||||
rt_kprintf("MSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<7))
|
||||
{
|
||||
/* [7]:MMARVALID */
|
||||
rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void hard_fault_track(void)
|
||||
{
|
||||
if(SCB_HFSR & (1UL<<1))
|
||||
{
|
||||
/* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */
|
||||
rt_kprintf("failed vector fetch\n");
|
||||
}
|
||||
|
||||
if(SCB_HFSR & (1UL<<30))
|
||||
{
|
||||
/* [30]:FORCED, Indicates hard fault is taken because of bus fault,
|
||||
memory management fault, or usage fault. */
|
||||
if(SCB_CFSR_BFSR)
|
||||
{
|
||||
bus_fault_track();
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR)
|
||||
{
|
||||
mem_manage_fault_track();
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR)
|
||||
{
|
||||
usage_fault_track();
|
||||
}
|
||||
}
|
||||
|
||||
if(SCB_HFSR & (1UL<<31))
|
||||
{
|
||||
/* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */
|
||||
rt_kprintf("debug event\n");
|
||||
}
|
||||
}
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
struct exception_info
|
||||
{
|
||||
rt_uint32_t exc_return;
|
||||
struct stack_frame stack_frame;
|
||||
};
|
||||
|
||||
void rt_hw_hard_fault_exception(struct exception_info *exception_info)
|
||||
{
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
struct exception_stack_frame *exception_stack = &exception_info->stack_frame.exception_stack_frame;
|
||||
struct stack_frame *context = &exception_info->stack_frame;
|
||||
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(exception_stack);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
|
||||
rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr);
|
||||
|
||||
rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0);
|
||||
rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1);
|
||||
rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2);
|
||||
rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3);
|
||||
rt_kprintf("r04: 0x%08x\n", context->r4);
|
||||
rt_kprintf("r05: 0x%08x\n", context->r5);
|
||||
rt_kprintf("r06: 0x%08x\n", context->r6);
|
||||
rt_kprintf("r07: 0x%08x\n", context->r7);
|
||||
rt_kprintf("r08: 0x%08x\n", context->r8);
|
||||
rt_kprintf("r09: 0x%08x\n", context->r9);
|
||||
rt_kprintf("r10: 0x%08x\n", context->r10);
|
||||
rt_kprintf("r11: 0x%08x\n", context->r11);
|
||||
rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12);
|
||||
rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr);
|
||||
rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc);
|
||||
|
||||
if (exception_info->exc_return & (1 << 2))
|
||||
{
|
||||
rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("hard fault on handler\r\n\r\n");
|
||||
}
|
||||
|
||||
if ( (exception_info->exc_return & 0x10) == 0)
|
||||
{
|
||||
rt_kprintf("FPU active!\r\n");
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
hard_fault_track();
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
/**
|
||||
* shutdown CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown(void)
|
||||
{
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset(void)
|
||||
{
|
||||
SCB_AIRCR = SCB_RESET_VALUE;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
/**
|
||||
* This function finds the first bit set (beginning with the least significant bit)
|
||||
* in value and return the index of that bit.
|
||||
*
|
||||
* Bits are numbered starting at 1 (the least significant bit). A return value of
|
||||
* zero from any of these functions means that the argument was zero.
|
||||
*
|
||||
* @return return the index of the first bit set. If value is 0, then this function
|
||||
* shall return 0.
|
||||
*/
|
||||
#if defined(__CC_ARM)
|
||||
__asm int __rt_ffs(int value)
|
||||
{
|
||||
CMP r0, #0x00
|
||||
BEQ exit
|
||||
|
||||
RBIT r0, r0
|
||||
CLZ r0, r0
|
||||
ADDS r0, r0, #0x01
|
||||
|
||||
exit
|
||||
BX lr
|
||||
}
|
||||
#elif defined(__clang__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
__asm volatile(
|
||||
"CMP %1, #0x00 \n"
|
||||
"BEQ 1f \n"
|
||||
|
||||
"RBIT %1, %1 \n"
|
||||
"CLZ %0, %1 \n"
|
||||
"ADDS %0, %0, #0x01 \n"
|
||||
|
||||
"1: \n"
|
||||
|
||||
: "=r"(value)
|
||||
: "r"(value)
|
||||
);
|
||||
return value;
|
||||
}
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
if (value == 0) return value;
|
||||
|
||||
asm("RBIT %0, %1" : "=r"(value) : "r"(value));
|
||||
asm("CLZ %0, %1" : "=r"(value) : "r"(value));
|
||||
asm("ADDS %0, %1, #0x01" : "=r"(value) : "r"(value));
|
||||
|
||||
return value;
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
return __builtin_ffs(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
253
rt-thread/libcpu/arm/cortex-m7/context_gcc.S
Normal file
253
rt-thread/libcpu/arm/cortex-m7/context_gcc.S
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2009-10-11 Bernard first version
|
||||
* 2012-01-01 aozima support context switch load/store FPU register.
|
||||
* 2013-06-18 aozima add restore MSP feature.
|
||||
* 2013-06-23 aozima support lazy stack optimized.
|
||||
* 2018-07-24 aozima enhancement hard fault exception handler.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup cortex-m4
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
.cpu cortex-m4
|
||||
.syntax unified
|
||||
.thumb
|
||||
.text
|
||||
|
||||
.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */
|
||||
.equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */
|
||||
.equ NVIC_SYSPRI2, 0xE000ED20 /* system priority register (2) */
|
||||
.equ NVIC_PENDSV_PRI, 0xFFFF0000 /* PendSV and SysTick priority value (lowest) */
|
||||
.equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.global rt_hw_interrupt_disable
|
||||
.type rt_hw_interrupt_disable, %function
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.global rt_hw_interrupt_enable
|
||||
.type rt_hw_interrupt_enable, %function
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_interrupt
|
||||
.type rt_hw_context_switch_interrupt, %function
|
||||
.global rt_hw_context_switch
|
||||
.type rt_hw_context_switch, %function
|
||||
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
/* set rt_thread_switch_interrupt_flag to 1 */
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch:
|
||||
LDR r2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
|
||||
/* r0 --> switch from thread stack
|
||||
* r1 --> switch to thread stack
|
||||
* psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
*/
|
||||
.global PendSV_Handler
|
||||
.type PendSV_Handler, %function
|
||||
PendSV_Handler:
|
||||
/* disable interrupt to protect context switch */
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
/* get rt_thread_switch_interrupt_flag */
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CBZ r1, pendsv_exit /* pendsv already handled */
|
||||
|
||||
/* clear rt_thread_switch_interrupt_flag to 0 */
|
||||
MOV r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CBZ r1, switch_to_thread /* skip register save at the first time */
|
||||
|
||||
MRS r1, psp /* get from thread stack pointer */
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
TST lr, #0x10 /* if(!EXC_RETURN[4]) */
|
||||
IT EQ
|
||||
VSTMDBEQ r1!, {d8 - d15} /* push FPU register s16~s31 */
|
||||
#endif
|
||||
|
||||
STMFD r1!, {r4 - r11} /* push r4 - r11 register */
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
MOV r4, #0x00 /* flag = 0 */
|
||||
|
||||
TST lr, #0x10 /* if(!EXC_RETURN[4]) */
|
||||
IT EQ
|
||||
MOVEQ r4, #0x01 /* flag = 1 */
|
||||
|
||||
STMFD r1!, {r4} /* push flag */
|
||||
#endif
|
||||
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] /* update from thread stack pointer */
|
||||
|
||||
switch_to_thread:
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] /* load thread stack pointer */
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
LDMFD r1!, {r3} /* pop flag */
|
||||
#endif
|
||||
|
||||
LDMFD r1!, {r4 - r11} /* pop r4 - r11 register */
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
CMP r3, #0 /* if(flag_r3 != 0) */
|
||||
IT NE
|
||||
VLDMIANE r1!, {d8 - d15} /* pop FPU register s16~s31 */
|
||||
#endif
|
||||
|
||||
MSR psp, r1 /* update stack pointer */
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
ORR lr, lr, #0x10 /* lr |= (1 << 4), clean FPCA. */
|
||||
CMP r3, #0 /* if(flag_r3 != 0) */
|
||||
IT NE
|
||||
BICNE lr, lr, #0x10 /* lr &= ~(1 << 4), set FPCA. */
|
||||
#endif
|
||||
|
||||
pendsv_exit:
|
||||
/* restore interrupt */
|
||||
MSR PRIMASK, r2
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* r0 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_to
|
||||
.type rt_hw_context_switch_to, %function
|
||||
rt_hw_context_switch_to:
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
/* CLEAR CONTROL.FPCA */
|
||||
MRS r2, CONTROL /* read */
|
||||
BIC r2, #0x04 /* modify */
|
||||
MSR CONTROL, r2 /* write-back */
|
||||
#endif
|
||||
|
||||
/* set from thread to 0 */
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
/* set interrupt flag to 1 */
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
/* set the PendSV and SysTick exception priority */
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] /* read */
|
||||
ORR r1,r1,r2 /* modify */
|
||||
STR r1, [r0] /* write-back */
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
/* restore MSP */
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
/* enable interrupts at processor level */
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
/* ensure PendSV exception taken place before subsequent operation */
|
||||
DSB
|
||||
ISB
|
||||
|
||||
/* never reach here! */
|
||||
|
||||
/* compatible with old version */
|
||||
.global rt_hw_interrupt_thread_switch
|
||||
.type rt_hw_interrupt_thread_switch, %function
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX lr
|
||||
NOP
|
||||
|
||||
.global HardFault_Handler
|
||||
.type HardFault_Handler, %function
|
||||
HardFault_Handler:
|
||||
/* get current context */
|
||||
MRS r0, msp /* get fault context from handler. */
|
||||
TST lr, #0x04 /* if(!EXC_RETURN[2]) */
|
||||
BEQ _get_sp_done
|
||||
MRS r0, psp /* get fault context from thread. */
|
||||
_get_sp_done:
|
||||
|
||||
STMFD r0!, {r4 - r11} /* push r4 - r11 register */
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
|
||||
STMFD r0!, {lr} /* push dummy for flag */
|
||||
#endif
|
||||
STMFD r0!, {lr} /* push exec_return register */
|
||||
|
||||
TST lr, #0x04 /* if(!EXC_RETURN[2]) */
|
||||
BEQ _update_msp
|
||||
MSR psp, r0 /* update stack pointer to PSP. */
|
||||
B _update_done
|
||||
_update_msp:
|
||||
MSR msp, r0 /* update stack pointer to MSP. */
|
||||
_update_done:
|
||||
|
||||
PUSH {LR}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {LR}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
257
rt-thread/libcpu/arm/cortex-m7/context_iar.S
Normal file
257
rt-thread/libcpu/arm/cortex-m7/context_iar.S
Normal file
@ -0,0 +1,257 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2009-01-17 Bernard first version
|
||||
; * 2009-09-27 Bernard add protect when contex switch occurs
|
||||
; * 2012-01-01 aozima support context switch load/store FPU register.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2013-06-23 aozima support lazy stack optimized.
|
||||
; * 2018-07-24 aozima enhancement hard fault exception handler.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup cortex-m4
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
SECTION .text:CODE(2)
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
EXPORT PendSV_Handler
|
||||
PendSV_Handler:
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CBZ r1, pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOV r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CBZ r1, switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
TST lr, #0x10 ; if(!EXC_RETURN[4])
|
||||
BNE skip_push_fpu
|
||||
VSTMDB r1!, {d8 - d15} ; push FPU register s16~s31
|
||||
skip_push_fpu
|
||||
#endif
|
||||
|
||||
STMFD r1!, {r4 - r11} ; push r4 - r11 register
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
MOV r4, #0x00 ; flag = 0
|
||||
TST lr, #0x10 ; if(!EXC_RETURN[4])
|
||||
BNE push_flag
|
||||
MOV r4, #0x01 ; flag = 1
|
||||
push_flag
|
||||
;STMFD r1!, {r4} ; push flag
|
||||
SUB r1, r1, #0x04
|
||||
STR r4, [r1]
|
||||
#endif
|
||||
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
LDMFD r1!, {r3} ; pop flag
|
||||
#endif
|
||||
|
||||
LDMFD r1!, {r4 - r11} ; pop r4 - r11 register
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
CBZ r3, skip_pop_fpu
|
||||
VLDMIA r1!, {d8 - d15} ; pop FPU register s16~s31
|
||||
skip_pop_fpu
|
||||
#endif
|
||||
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
ORR lr, lr, #0x10 ; lr |= (1 << 4), clean FPCA.
|
||||
CBZ r3, return_without_fpu ; if(flag_r3 != 0)
|
||||
BIC lr, lr, #0x10 ; lr &= ~(1 << 4), set FPCA.
|
||||
return_without_fpu
|
||||
#endif
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
#if defined ( __ARMVFP__ )
|
||||
; CLEAR CONTROL.FPCA
|
||||
MRS r2, CONTROL ; read
|
||||
BIC r2, r2, #0x04 ; modify
|
||||
MSR CONTROL, r2 ; write-back
|
||||
#endif
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] ; read
|
||||
ORR r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
; ensure PendSV exception taken place before subsequent operation
|
||||
DSB
|
||||
ISB
|
||||
|
||||
; never reach here!
|
||||
|
||||
; compatible with old version
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX lr
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler:
|
||||
|
||||
; get current context
|
||||
MRS r0, msp ; get fault context from handler.
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
BEQ _get_sp_done
|
||||
MRS r0, psp ; get fault context from thread.
|
||||
_get_sp_done
|
||||
|
||||
STMFD r0!, {r4 - r11} ; push r4 - r11 register
|
||||
;STMFD r0!, {lr} ; push exec_return register
|
||||
#if defined ( __ARMVFP__ )
|
||||
SUB r0, r0, #0x04 ; push dummy for flag
|
||||
STR lr, [r0]
|
||||
#endif
|
||||
SUB r0, r0, #0x04
|
||||
STR lr, [r0]
|
||||
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
BEQ _update_msp
|
||||
MSR psp, r0 ; update stack pointer to PSP.
|
||||
B _update_done
|
||||
_update_msp
|
||||
MSR msp, r0 ; update stack pointer to MSP.
|
||||
_update_done
|
||||
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {lr}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
|
||||
END
|
||||
257
rt-thread/libcpu/arm/cortex-m7/context_rvds.S
Normal file
257
rt-thread/libcpu/arm/cortex-m7/context_rvds.S
Normal file
@ -0,0 +1,257 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2009-01-17 Bernard first version.
|
||||
; * 2012-01-01 aozima support context switch load/store FPU register.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2013-06-23 aozima support lazy stack optimized.
|
||||
; * 2018-07-24 aozima enhancement hard fault exception handler.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup cortex-m4
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable PROC
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch PROC
|
||||
EXPORT rt_hw_context_switch
|
||||
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CBZ r1, pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOV r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CBZ r1, switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
TST lr, #0x10 ; if(!EXC_RETURN[4])
|
||||
VSTMFDEQ r1!, {d8 - d15} ; push FPU register s16~s31
|
||||
ENDIF
|
||||
|
||||
STMFD r1!, {r4 - r11} ; push r4 - r11 register
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
MOV r4, #0x00 ; flag = 0
|
||||
|
||||
TST lr, #0x10 ; if(!EXC_RETURN[4])
|
||||
MOVEQ r4, #0x01 ; flag = 1
|
||||
|
||||
STMFD r1!, {r4} ; push flag
|
||||
ENDIF
|
||||
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
LDMFD r1!, {r3} ; pop flag
|
||||
ENDIF
|
||||
|
||||
LDMFD r1!, {r4 - r11} ; pop r4 - r11 register
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
CMP r3, #0 ; if(flag_r3 != 0)
|
||||
VLDMFDNE r1!, {d8 - d15} ; pop FPU register s16~s31
|
||||
ENDIF
|
||||
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
ORR lr, lr, #0x10 ; lr |= (1 << 4), clean FPCA.
|
||||
CMP r3, #0 ; if(flag_r3 != 0)
|
||||
BICNE lr, lr, #0x10 ; lr &= ~(1 << 4), set FPCA.
|
||||
ENDIF
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
rt_hw_context_switch_to PROC
|
||||
EXPORT rt_hw_context_switch_to
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
IF {FPU} != "SoftVFP"
|
||||
; CLEAR CONTROL.FPCA
|
||||
MRS r2, CONTROL ; read
|
||||
BIC r2, #0x04 ; modify
|
||||
MSR CONTROL, r2 ; write-back
|
||||
ENDIF
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] ; read
|
||||
ORR r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
; ensure PendSV exception taken place before subsequent operation
|
||||
DSB
|
||||
ISB
|
||||
|
||||
; never reach here!
|
||||
ENDP
|
||||
|
||||
; compatible with old version
|
||||
rt_hw_interrupt_thread_switch PROC
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
EXPORT MemManage_Handler
|
||||
HardFault_Handler PROC
|
||||
MemManage_Handler
|
||||
|
||||
; get current context
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
ITE EQ
|
||||
MRSEQ r0, msp ; [2]=0 ==> Z=1, get fault context from handler.
|
||||
MRSNE r0, psp ; [2]=1 ==> Z=0, get fault context from thread.
|
||||
|
||||
STMFD r0!, {r4 - r11} ; push r4 - r11 register
|
||||
IF {FPU} != "SoftVFP"
|
||||
STMFD r0!, {lr} ; push dummy for flag
|
||||
ENDIF
|
||||
STMFD r0!, {lr} ; push exec_return register
|
||||
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
ITE EQ
|
||||
MSREQ msp, r0 ; [2]=0 ==> Z=1, update stack pointer to MSP.
|
||||
MSRNE psp, r0 ; [2]=1 ==> Z=0, update stack pointer to PSP.
|
||||
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {lr}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
ALIGN 4
|
||||
|
||||
END
|
||||
90
rt-thread/libcpu/arm/cortex-m7/cpu_cache.c
Normal file
90
rt-thread/libcpu/arm/cortex-m7/cpu_cache.c
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-04-02 tanek first implementation
|
||||
* 2019-04-27 misonyo update to cortex-m7 series
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdef.h>
|
||||
#include <board.h>
|
||||
|
||||
/* The L1-caches on all Cortex®-M7s are divided into lines of 32 bytes. */
|
||||
#define L1CACHE_LINESIZE_BYTE (32)
|
||||
|
||||
void rt_hw_cpu_icache_enable(void)
|
||||
{
|
||||
SCB_EnableICache();
|
||||
}
|
||||
|
||||
void rt_hw_cpu_icache_disable(void)
|
||||
{
|
||||
SCB_DisableICache();
|
||||
}
|
||||
|
||||
rt_base_t rt_hw_cpu_icache_status(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rt_hw_cpu_icache_ops(int ops, void* addr, int size)
|
||||
{
|
||||
rt_uint32_t address = (rt_uint32_t)addr & (rt_uint32_t) ~(L1CACHE_LINESIZE_BYTE - 1);
|
||||
rt_int32_t size_byte = size + address - (rt_uint32_t)addr;
|
||||
rt_uint32_t linesize = 32U;
|
||||
if (ops & RT_HW_CACHE_INVALIDATE)
|
||||
{
|
||||
__DSB();
|
||||
while (size_byte > 0)
|
||||
{
|
||||
SCB->ICIMVAU = address;
|
||||
address += linesize;
|
||||
size_byte -= linesize;
|
||||
}
|
||||
__DSB();
|
||||
__ISB();
|
||||
}
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_enable(void)
|
||||
{
|
||||
SCB_EnableDCache();
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_disable(void)
|
||||
{
|
||||
SCB_DisableDCache();
|
||||
}
|
||||
|
||||
rt_base_t rt_hw_cpu_dcache_status(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_ops(int ops, void* addr, int size)
|
||||
{
|
||||
rt_uint32_t startAddr = (rt_uint32_t)addr & (rt_uint32_t)~(L1CACHE_LINESIZE_BYTE - 1);
|
||||
rt_uint32_t size_byte = size + (rt_uint32_t)addr - startAddr;
|
||||
rt_uint32_t clean_invalid = RT_HW_CACHE_FLUSH | RT_HW_CACHE_INVALIDATE;
|
||||
|
||||
if ((ops & clean_invalid) == clean_invalid)
|
||||
{
|
||||
SCB_CleanInvalidateDCache_by_Addr((uint32_t *)startAddr, size_byte);
|
||||
}
|
||||
else if (ops & RT_HW_CACHE_FLUSH)
|
||||
{
|
||||
SCB_CleanDCache_by_Addr((uint32_t *)startAddr, size_byte);
|
||||
}
|
||||
else if (ops & RT_HW_CACHE_INVALIDATE)
|
||||
{
|
||||
SCB_InvalidateDCache_by_Addr((uint32_t *)startAddr, size_byte);
|
||||
}
|
||||
else
|
||||
{
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
}
|
||||
508
rt-thread/libcpu/arm/cortex-m7/cpuport.c
Normal file
508
rt-thread/libcpu/arm/cortex-m7/cpuport.c
Normal file
@ -0,0 +1,508 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-10-21 Bernard the first version.
|
||||
* 2011-10-27 aozima update for cortex-M4 FPU.
|
||||
* 2011-12-31 aozima fixed stack align issues.
|
||||
* 2012-01-01 aozima support context switch load/store FPU register.
|
||||
* 2012-12-11 lgnq fixed the coding style.
|
||||
* 2012-12-23 aozima stack addr align to 8byte.
|
||||
* 2012-12-29 Bernard Add exception hook.
|
||||
* 2013-06-23 aozima support lazy stack optimized.
|
||||
* 2018-07-24 aozima enhancement hard fault exception handler.
|
||||
* 2019-07-03 yangjie add __rt_ffs() for armclang.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#if /* ARMCC */ ( (defined ( __CC_ARM ) && defined ( __TARGET_FPU_VFP )) \
|
||||
/* Clang */ || (defined ( __clang__ ) && defined ( __VFP_FP__ ) && !defined(__SOFTFP__)) \
|
||||
/* IAR */ || (defined ( __ICCARM__ ) && defined ( __ARMVFP__ )) \
|
||||
/* GNU */ || (defined ( __GNUC__ ) && defined ( __VFP_FP__ ) && !defined(__SOFTFP__)) )
|
||||
#define USE_FPU 1
|
||||
#else
|
||||
#define USE_FPU 0
|
||||
#endif
|
||||
|
||||
/* exception and interrupt handler table */
|
||||
rt_uint32_t rt_interrupt_from_thread;
|
||||
rt_uint32_t rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
/* exception hook */
|
||||
static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL;
|
||||
|
||||
struct exception_stack_frame
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r12;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t psr;
|
||||
};
|
||||
|
||||
struct stack_frame
|
||||
{
|
||||
#if USE_FPU
|
||||
rt_uint32_t flag;
|
||||
#endif /* USE_FPU */
|
||||
|
||||
/* r4 ~ r11 register */
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t r11;
|
||||
|
||||
struct exception_stack_frame exception_stack_frame;
|
||||
};
|
||||
|
||||
struct exception_stack_frame_fpu
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r12;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t psr;
|
||||
|
||||
#if USE_FPU
|
||||
/* FPU register */
|
||||
rt_uint32_t S0;
|
||||
rt_uint32_t S1;
|
||||
rt_uint32_t S2;
|
||||
rt_uint32_t S3;
|
||||
rt_uint32_t S4;
|
||||
rt_uint32_t S5;
|
||||
rt_uint32_t S6;
|
||||
rt_uint32_t S7;
|
||||
rt_uint32_t S8;
|
||||
rt_uint32_t S9;
|
||||
rt_uint32_t S10;
|
||||
rt_uint32_t S11;
|
||||
rt_uint32_t S12;
|
||||
rt_uint32_t S13;
|
||||
rt_uint32_t S14;
|
||||
rt_uint32_t S15;
|
||||
rt_uint32_t FPSCR;
|
||||
rt_uint32_t NO_NAME;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stack_frame_fpu
|
||||
{
|
||||
rt_uint32_t flag;
|
||||
|
||||
/* r4 ~ r11 register */
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t r11;
|
||||
|
||||
#if USE_FPU
|
||||
/* FPU register s16 ~ s31 */
|
||||
rt_uint32_t s16;
|
||||
rt_uint32_t s17;
|
||||
rt_uint32_t s18;
|
||||
rt_uint32_t s19;
|
||||
rt_uint32_t s20;
|
||||
rt_uint32_t s21;
|
||||
rt_uint32_t s22;
|
||||
rt_uint32_t s23;
|
||||
rt_uint32_t s24;
|
||||
rt_uint32_t s25;
|
||||
rt_uint32_t s26;
|
||||
rt_uint32_t s27;
|
||||
rt_uint32_t s28;
|
||||
rt_uint32_t s29;
|
||||
rt_uint32_t s30;
|
||||
rt_uint32_t s31;
|
||||
#endif
|
||||
|
||||
struct exception_stack_frame_fpu exception_stack_frame;
|
||||
};
|
||||
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
void *parameter,
|
||||
rt_uint8_t *stack_addr,
|
||||
void *texit)
|
||||
{
|
||||
struct stack_frame *stack_frame;
|
||||
rt_uint8_t *stk;
|
||||
unsigned long i;
|
||||
|
||||
stk = stack_addr + sizeof(rt_uint32_t);
|
||||
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
|
||||
stk -= sizeof(struct stack_frame);
|
||||
|
||||
stack_frame = (struct stack_frame *)stk;
|
||||
|
||||
/* init all register */
|
||||
for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
|
||||
{
|
||||
((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
|
||||
}
|
||||
|
||||
stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */
|
||||
stack_frame->exception_stack_frame.r1 = 0; /* r1 */
|
||||
stack_frame->exception_stack_frame.r2 = 0; /* r2 */
|
||||
stack_frame->exception_stack_frame.r3 = 0; /* r3 */
|
||||
stack_frame->exception_stack_frame.r12 = 0; /* r12 */
|
||||
stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */
|
||||
stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */
|
||||
stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */
|
||||
|
||||
#if USE_FPU
|
||||
stack_frame->flag = 0;
|
||||
#endif /* USE_FPU */
|
||||
|
||||
/* return task's current stack address */
|
||||
return stk;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set the hook, which is invoked on fault exception handling.
|
||||
*
|
||||
* @param exception_handle the exception handling hook function.
|
||||
*/
|
||||
void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context))
|
||||
{
|
||||
rt_exception_hook = exception_handle;
|
||||
}
|
||||
|
||||
#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
|
||||
#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
|
||||
#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
|
||||
#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */
|
||||
#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED0C) /* Reset control Address Register */
|
||||
#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */
|
||||
|
||||
#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */
|
||||
#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */
|
||||
#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
static void usage_fault_track(void)
|
||||
{
|
||||
rt_kprintf("usage fault:\n");
|
||||
rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR);
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<0))
|
||||
{
|
||||
/* [0]:UNDEFINSTR */
|
||||
rt_kprintf("UNDEFINSTR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<1))
|
||||
{
|
||||
/* [1]:INVSTATE */
|
||||
rt_kprintf("INVSTATE ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<2))
|
||||
{
|
||||
/* [2]:INVPC */
|
||||
rt_kprintf("INVPC ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<3))
|
||||
{
|
||||
/* [3]:NOCP */
|
||||
rt_kprintf("NOCP ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<8))
|
||||
{
|
||||
/* [8]:UNALIGNED */
|
||||
rt_kprintf("UNALIGNED ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<9))
|
||||
{
|
||||
/* [9]:DIVBYZERO */
|
||||
rt_kprintf("DIVBYZERO ");
|
||||
}
|
||||
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
static void bus_fault_track(void)
|
||||
{
|
||||
rt_kprintf("bus fault:\n");
|
||||
rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR);
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<0))
|
||||
{
|
||||
/* [0]:IBUSERR */
|
||||
rt_kprintf("IBUSERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<1))
|
||||
{
|
||||
/* [1]:PRECISERR */
|
||||
rt_kprintf("PRECISERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<2))
|
||||
{
|
||||
/* [2]:IMPRECISERR */
|
||||
rt_kprintf("IMPRECISERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<3))
|
||||
{
|
||||
/* [3]:UNSTKERR */
|
||||
rt_kprintf("UNSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<4))
|
||||
{
|
||||
/* [4]:STKERR */
|
||||
rt_kprintf("STKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<7))
|
||||
{
|
||||
rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void mem_manage_fault_track(void)
|
||||
{
|
||||
rt_kprintf("mem manage fault:\n");
|
||||
rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR);
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<0))
|
||||
{
|
||||
/* [0]:IACCVIOL */
|
||||
rt_kprintf("IACCVIOL ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<1))
|
||||
{
|
||||
/* [1]:DACCVIOL */
|
||||
rt_kprintf("DACCVIOL ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<3))
|
||||
{
|
||||
/* [3]:MUNSTKERR */
|
||||
rt_kprintf("MUNSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<4))
|
||||
{
|
||||
/* [4]:MSTKERR */
|
||||
rt_kprintf("MSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<7))
|
||||
{
|
||||
/* [7]:MMARVALID */
|
||||
rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void hard_fault_track(void)
|
||||
{
|
||||
if(SCB_HFSR & (1UL<<1))
|
||||
{
|
||||
/* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */
|
||||
rt_kprintf("failed vector fetch\n");
|
||||
}
|
||||
|
||||
if(SCB_HFSR & (1UL<<30))
|
||||
{
|
||||
/* [30]:FORCED, Indicates hard fault is taken because of bus fault,
|
||||
memory management fault, or usage fault. */
|
||||
if(SCB_CFSR_BFSR)
|
||||
{
|
||||
bus_fault_track();
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR)
|
||||
{
|
||||
mem_manage_fault_track();
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR)
|
||||
{
|
||||
usage_fault_track();
|
||||
}
|
||||
}
|
||||
|
||||
if(SCB_HFSR & (1UL<<31))
|
||||
{
|
||||
/* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */
|
||||
rt_kprintf("debug event\n");
|
||||
}
|
||||
}
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
struct exception_info
|
||||
{
|
||||
rt_uint32_t exc_return;
|
||||
struct stack_frame stack_frame;
|
||||
};
|
||||
|
||||
void rt_hw_hard_fault_exception(struct exception_info *exception_info)
|
||||
{
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
struct exception_stack_frame *exception_stack = &exception_info->stack_frame.exception_stack_frame;
|
||||
struct stack_frame *context = &exception_info->stack_frame;
|
||||
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(exception_stack);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
|
||||
rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr);
|
||||
|
||||
rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0);
|
||||
rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1);
|
||||
rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2);
|
||||
rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3);
|
||||
rt_kprintf("r04: 0x%08x\n", context->r4);
|
||||
rt_kprintf("r05: 0x%08x\n", context->r5);
|
||||
rt_kprintf("r06: 0x%08x\n", context->r6);
|
||||
rt_kprintf("r07: 0x%08x\n", context->r7);
|
||||
rt_kprintf("r08: 0x%08x\n", context->r8);
|
||||
rt_kprintf("r09: 0x%08x\n", context->r9);
|
||||
rt_kprintf("r10: 0x%08x\n", context->r10);
|
||||
rt_kprintf("r11: 0x%08x\n", context->r11);
|
||||
rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12);
|
||||
rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr);
|
||||
rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc);
|
||||
|
||||
if (exception_info->exc_return & (1 << 2))
|
||||
{
|
||||
rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("hard fault on handler\r\n\r\n");
|
||||
}
|
||||
|
||||
if ( (exception_info->exc_return & 0x10) == 0)
|
||||
{
|
||||
rt_kprintf("FPU active!\r\n");
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
hard_fault_track();
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
/**
|
||||
* shutdown CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown(void)
|
||||
{
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset(void)
|
||||
{
|
||||
SCB_AIRCR = SCB_RESET_VALUE;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
/**
|
||||
* This function finds the first bit set (beginning with the least significant bit)
|
||||
* in value and return the index of that bit.
|
||||
*
|
||||
* Bits are numbered starting at 1 (the least significant bit). A return value of
|
||||
* zero from any of these functions means that the argument was zero.
|
||||
*
|
||||
* @return return the index of the first bit set. If value is 0, then this function
|
||||
* shall return 0.
|
||||
*/
|
||||
#if defined(__CC_ARM)
|
||||
__asm int __rt_ffs(int value)
|
||||
{
|
||||
CMP r0, #0x00
|
||||
BEQ exit
|
||||
|
||||
RBIT r0, r0
|
||||
CLZ r0, r0
|
||||
ADDS r0, r0, #0x01
|
||||
|
||||
exit
|
||||
BX lr
|
||||
}
|
||||
#elif defined(__clang__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
__asm volatile(
|
||||
"CMP %1, #0x00 \n"
|
||||
"BEQ 1f \n"
|
||||
|
||||
"RBIT %1, %1 \n"
|
||||
"CLZ %0, %1 \n"
|
||||
"ADDS %0, %0, #0x01 \n"
|
||||
|
||||
"1: \n"
|
||||
|
||||
: "=r"(value)
|
||||
: "r"(value)
|
||||
);
|
||||
return value;
|
||||
}
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
if (value == 0) return value;
|
||||
|
||||
asm("RBIT %0, %1" : "=r"(value) : "r"(value));
|
||||
asm("CLZ %0, %1" : "=r"(value) : "r"(value));
|
||||
asm("ADDS %0, %1, #0x01" : "=r"(value) : "r"(value));
|
||||
|
||||
return value;
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
return __builtin_ffs(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
56
rt-thread/libcpu/arm/cortex-r4/armv7.h
Normal file
56
rt-thread/libcpu/arm/cortex-r4/armv7.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
#ifndef __ARMV7_H__
|
||||
#define __ARMV7_H__
|
||||
|
||||
#ifndef VFP_DATA_NR
|
||||
#define VFP_DATA_NR 32
|
||||
#endif
|
||||
|
||||
/* the exception stack without VFP registers */
|
||||
struct rt_hw_exp_stack
|
||||
{
|
||||
unsigned long r0;
|
||||
unsigned long r1;
|
||||
unsigned long r2;
|
||||
unsigned long r3;
|
||||
unsigned long r4;
|
||||
unsigned long r5;
|
||||
unsigned long r6;
|
||||
unsigned long r7;
|
||||
unsigned long r8;
|
||||
unsigned long r9;
|
||||
unsigned long r10;
|
||||
unsigned long fp;
|
||||
unsigned long ip;
|
||||
unsigned long sp;
|
||||
unsigned long lr;
|
||||
unsigned long pc;
|
||||
unsigned long cpsr;
|
||||
};
|
||||
|
||||
#define USERMODE 0x10
|
||||
#define FIQMODE 0x11
|
||||
#define IRQMODE 0x12
|
||||
#define SVCMODE 0x13
|
||||
#define MONITORMODE 0x16
|
||||
#define ABORTMODE 0x17
|
||||
#define HYPMODE 0x1b
|
||||
#define UNDEFMODE 0x1b
|
||||
#define MODEMASK 0x1f
|
||||
#define NOINT 0xc0
|
||||
|
||||
#define T_Bit (1<<5)
|
||||
#define F_Bit (1<<6)
|
||||
#define I_Bit (1<<7)
|
||||
#define A_Bit (1<<8)
|
||||
#define E_Bit (1<<9)
|
||||
#define J_Bit (1<<24)
|
||||
|
||||
#endif
|
||||
260
rt-thread/libcpu/arm/cortex-r4/context_ccs.asm
Normal file
260
rt-thread/libcpu/arm/cortex-r4/context_ccs.asm
Normal file
@ -0,0 +1,260 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2009-01-20 Bernard first version
|
||||
; * 2011-07-22 Bernard added thumb mode porting
|
||||
; * 2013-05-24 Grissiom port to CCS
|
||||
; * 2013-05-26 Grissiom optimize for ARMv7
|
||||
; */
|
||||
|
||||
.text
|
||||
.arm
|
||||
.ref rt_thread_switch_interrupt_flag
|
||||
.ref rt_interrupt_from_thread
|
||||
.ref rt_interrupt_to_thread
|
||||
.ref rt_interrupt_enter
|
||||
.ref rt_interrupt_leave
|
||||
.ref rt_hw_trap_irq
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
.def rt_hw_interrupt_disable
|
||||
.asmfunc
|
||||
rt_hw_interrupt_disable
|
||||
MRS r0, cpsr
|
||||
CPSID IF
|
||||
BX lr
|
||||
.endasmfunc
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
.def rt_hw_interrupt_enable
|
||||
.asmfunc
|
||||
rt_hw_interrupt_enable
|
||||
MSR cpsr_c, r0
|
||||
BX lr
|
||||
.endasmfunc
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
.def rt_hw_context_switch
|
||||
.asmfunc
|
||||
rt_hw_context_switch
|
||||
STMDB sp!, {lr} ; push pc (lr should be pushed in place of PC)
|
||||
STMDB sp!, {r0-r12, lr} ; push lr & register file
|
||||
|
||||
MRS r4, cpsr
|
||||
TST lr, #0x01
|
||||
ORRNE r4, r4, #0x20 ; it's thumb code
|
||||
|
||||
STMDB sp!, {r4} ; push cpsr
|
||||
|
||||
.if (__TI_VFP_SUPPORT__)
|
||||
VMRS r4, fpexc
|
||||
TST r4, #0x40000000
|
||||
BEQ __no_vfp_frame1
|
||||
VSTMDB sp!, {d0-d15}
|
||||
VMRS r5, fpscr
|
||||
; TODO: add support for Common VFPv3.
|
||||
; Save registers like FPINST, FPINST2
|
||||
STMDB sp!, {r5}
|
||||
__no_vfp_frame1
|
||||
STMDB sp!, {r4}
|
||||
.endif
|
||||
|
||||
STR sp, [r0] ; store sp in preempted tasks TCB
|
||||
LDR sp, [r1] ; get new task stack pointer
|
||||
|
||||
.if (__TI_VFP_SUPPORT__)
|
||||
LDMIA sp!, {r0} ; get fpexc
|
||||
VMSR fpexc, r0 ; restore fpexc
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame2
|
||||
LDMIA sp!, {r1} ; get fpscr
|
||||
VMSR fpscr, r1
|
||||
VLDMIA sp!, {d0-d15}
|
||||
__no_vfp_frame2
|
||||
.endif
|
||||
|
||||
LDMIA sp!, {r4} ; pop new task cpsr to spsr
|
||||
MSR spsr_cxsf, r4
|
||||
|
||||
LDMIA sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr
|
||||
.endasmfunc
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; */
|
||||
.def rt_hw_context_switch_to
|
||||
.asmfunc
|
||||
rt_hw_context_switch_to
|
||||
LDR sp, [r0] ; get new task stack pointer
|
||||
|
||||
.if (__TI_VFP_SUPPORT__)
|
||||
LDMIA sp!, {r0} ; get fpexc
|
||||
VMSR fpexc, r0
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame_to
|
||||
LDMIA sp!, {r1} ; get fpscr
|
||||
VMSR fpscr, r1
|
||||
VLDMIA sp!, {d0-d15}
|
||||
__no_vfp_frame_to
|
||||
.endif
|
||||
|
||||
LDMIA sp!, {r4} ; pop new task cpsr to spsr
|
||||
MSR spsr_cxsf, r4
|
||||
|
||||
LDMIA sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr
|
||||
.endasmfunc
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
; */
|
||||
|
||||
.def rt_hw_context_switch_interrupt
|
||||
.asmfunc
|
||||
rt_hw_context_switch_interrupt
|
||||
LDR r2, pintflag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 1
|
||||
STR r3, [r2]
|
||||
LDR r2, pfromthread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
_reswitch
|
||||
LDR r2, ptothread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
BX lr
|
||||
.endasmfunc
|
||||
|
||||
.def IRQ_Handler
|
||||
IRQ_Handler
|
||||
STMDB sp!, {r0-r12,lr}
|
||||
|
||||
.if (__TI_VFP_SUPPORT__)
|
||||
VMRS r0, fpexc
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame_str_irq
|
||||
VSTMDB sp!, {d0-d15}
|
||||
VMRS r1, fpscr
|
||||
; TODO: add support for Common VFPv3.
|
||||
; Save registers like FPINST, FPINST2
|
||||
STMDB sp!, {r1}
|
||||
__no_vfp_frame_str_irq
|
||||
STMDB sp!, {r0}
|
||||
.endif
|
||||
|
||||
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, pintflag
|
||||
LDR r1, [r0]
|
||||
CMP r1, #1
|
||||
BEQ rt_hw_context_switch_interrupt_do
|
||||
|
||||
.if (__TI_VFP_SUPPORT__)
|
||||
LDMIA sp!, {r0} ; get fpexc
|
||||
VMSR fpexc, r0
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame_ldr_irq
|
||||
LDMIA sp!, {r1} ; get fpscr
|
||||
VMSR fpscr, r1
|
||||
VLDMIA sp!, {d0-d15}
|
||||
__no_vfp_frame_ldr_irq
|
||||
.endif
|
||||
|
||||
LDMIA sp!, {r0-r12,lr}
|
||||
SUBS pc, lr, #4
|
||||
|
||||
; /*
|
||||
; * void rt_hw_context_switch_interrupt_do(rt_base_t flag)
|
||||
; */
|
||||
.def rt_hw_context_switch_interrupt_do
|
||||
rt_hw_context_switch_interrupt_do
|
||||
MOV r1, #0 ; clear flag
|
||||
STR r1, [r0]
|
||||
|
||||
.if (__TI_VFP_SUPPORT__)
|
||||
LDMIA sp!, {r0} ; get fpexc
|
||||
VMSR fpexc, r0
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame_do1
|
||||
LDMIA sp!, {r1} ; get fpscr
|
||||
VMSR fpscr, r1
|
||||
VLDMIA sp!, {d0-d15}
|
||||
__no_vfp_frame_do1
|
||||
.endif
|
||||
|
||||
LDMIA sp!, {r0-r12,lr} ; reload saved registers
|
||||
STMDB sp, {r0-r3} ; save r0-r3. We will restore r0-r3 in the SVC
|
||||
; mode so there is no need to update SP.
|
||||
SUB r1, sp, #16 ; save the right SP value in r1, so we could restore r0-r3.
|
||||
SUB r2, lr, #4 ; save old task's pc to r2
|
||||
|
||||
MRS r3, spsr ; get cpsr of interrupt thread
|
||||
|
||||
; switch to SVC mode and no interrupt
|
||||
CPSID IF, #0x13
|
||||
|
||||
STMDB sp!, {r2} ; push old task's pc
|
||||
STMDB sp!, {r4-r12,lr} ; push old task's lr,r12-r4
|
||||
LDMIA r1!, {r4-r7} ; restore r0-r3 of the interrupted thread
|
||||
STMDB sp!, {r4-r7} ; push old task's r3-r0. We don't need to push/pop them to
|
||||
; r0-r3 because we just want to transfer the data and don't
|
||||
; use them here.
|
||||
STMDB sp!, {r3} ; push old task's cpsr
|
||||
|
||||
.if (__TI_VFP_SUPPORT__)
|
||||
VMRS r0, fpexc
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame_do2
|
||||
VSTMDB sp!, {d0-d15}
|
||||
VMRS r1, fpscr
|
||||
; TODO: add support for Common VFPv3.
|
||||
; Save registers like FPINST, FPINST2
|
||||
STMDB sp!, {r1}
|
||||
__no_vfp_frame_do2
|
||||
STMDB sp!, {r0}
|
||||
.endif
|
||||
|
||||
LDR r4, pfromthread
|
||||
LDR r5, [r4]
|
||||
STR sp, [r5] ; store sp in preempted tasks's TCB
|
||||
|
||||
LDR r6, ptothread
|
||||
LDR r6, [r6]
|
||||
LDR sp, [r6] ; get new task's stack pointer
|
||||
|
||||
.if (__TI_VFP_SUPPORT__)
|
||||
LDMIA sp!, {r0} ; get fpexc
|
||||
VMSR fpexc, r0
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame_do3
|
||||
LDMIA sp!, {r1} ; get fpscr
|
||||
VMSR fpscr, r1
|
||||
VLDMIA sp!, {d0-d15}
|
||||
__no_vfp_frame_do3
|
||||
.endif
|
||||
|
||||
LDMIA sp!, {r4} ; pop new task's cpsr to spsr
|
||||
MSR spsr_cxsf, r4
|
||||
|
||||
LDMIA sp!, {r0-r12,lr,pc}^ ; pop new task's r0-r12,lr & pc, copy spsr to cpsr
|
||||
|
||||
pintflag .word rt_thread_switch_interrupt_flag
|
||||
pfromthread .word rt_interrupt_from_thread
|
||||
ptothread .word rt_interrupt_to_thread
|
||||
251
rt-thread/libcpu/arm/cortex-r4/context_gcc.S
Normal file
251
rt-thread/libcpu/arm/cortex-r4/context_gcc.S
Normal file
@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2009-01-20 Bernard first version
|
||||
* 2011-07-22 Bernard added thumb mode porting
|
||||
* 2013-05-24 Grissiom port to CCS
|
||||
* 2013-05-26 Grissiom optimize for ARMv7
|
||||
* 2013-10-20 Grissiom port to GCC
|
||||
*/
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
.text
|
||||
.arm
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
.globl rt_interrupt_enter
|
||||
.globl rt_interrupt_leave
|
||||
.globl rt_hw_trap_irq
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable()
|
||||
*/
|
||||
.globl rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, cpsr
|
||||
CPSID IF
|
||||
BX lr
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level)
|
||||
*/
|
||||
.globl rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR cpsr_c, r0
|
||||
BX lr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to)
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
STMDB sp!, {lr} @ push pc (lr should be pushed in place of PC)
|
||||
STMDB sp!, {r0-r12, lr} @ push lr & register file
|
||||
|
||||
MRS r4, cpsr
|
||||
TST lr, #0x01
|
||||
ORRNE r4, r4, #0x20 @ it's thumb code
|
||||
|
||||
STMDB sp!, {r4} @ push cpsr
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING)
|
||||
VMRS r4, fpexc
|
||||
TST r4, #0x40000000
|
||||
BEQ __no_vfp_frame1
|
||||
VSTMDB sp!, {d0-d15}
|
||||
VMRS r5, fpscr
|
||||
@ TODO: add support for Common VFPv3.
|
||||
@ Save registers like FPINST, FPINST2
|
||||
STMDB sp!, {r5}
|
||||
__no_vfp_frame1:
|
||||
STMDB sp!, {r4}
|
||||
#endif
|
||||
|
||||
STR sp, [r0] @ store sp in preempted tasks TCB
|
||||
LDR sp, [r1] @ get new task stack pointer
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING)
|
||||
LDMIA sp!, {r0} @ get fpexc
|
||||
VMSR fpexc, r0 @ restore fpexc
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame2
|
||||
LDMIA sp!, {r1} @ get fpscr
|
||||
VMSR fpscr, r1
|
||||
VLDMIA sp!, {d0-d15}
|
||||
__no_vfp_frame2:
|
||||
#endif
|
||||
|
||||
LDMIA sp!, {r4} @ pop new task cpsr to spsr
|
||||
MSR spsr_cxsf, r4
|
||||
|
||||
LDMIA sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to)
|
||||
* r0 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
LDR sp, [r0] @ get new task stack pointer
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING)
|
||||
LDMIA sp!, {r0} @ get fpexc
|
||||
VMSR fpexc, r0
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame_to
|
||||
LDMIA sp!, {r1} @ get fpscr
|
||||
VMSR fpscr, r1
|
||||
VLDMIA sp!, {d0-d15}
|
||||
__no_vfp_frame_to:
|
||||
#endif
|
||||
|
||||
LDMIA sp!, {r4} @ pop new task cpsr to spsr
|
||||
MSR spsr_cxsf, r4
|
||||
|
||||
LDMIA sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to)@
|
||||
*/
|
||||
|
||||
.globl rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch_interrupt:
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1 @ set rt_thread_switch_interrupt_flag to 1
|
||||
STR r3, [r2]
|
||||
LDR r2, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
|
||||
|
||||
STR r0, [r2]
|
||||
_reswitch:
|
||||
LDR r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
BX lr
|
||||
|
||||
.globl IRQ_Handler
|
||||
IRQ_Handler:
|
||||
STMDB sp!, {r0-r12,lr}
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING)
|
||||
VMRS r0, fpexc
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame_str_irq
|
||||
VSTMDB sp!, {d0-d15}
|
||||
VMRS r1, fpscr
|
||||
@ TODO: add support for Common VFPv3.
|
||||
@ Save registers like FPINST, FPINST2
|
||||
STMDB sp!, {r1}
|
||||
__no_vfp_frame_str_irq:
|
||||
STMDB sp!, {r0}
|
||||
#endif
|
||||
|
||||
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
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING)
|
||||
LDMIA sp!, {r0} @ get fpexc
|
||||
VMSR fpexc, r0
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame_ldr_irq
|
||||
LDMIA sp!, {r1} @ get fpscr
|
||||
VMSR fpscr, r1
|
||||
VLDMIA sp!, {d0-d15}
|
||||
__no_vfp_frame_ldr_irq:
|
||||
#endif
|
||||
|
||||
LDMIA sp!, {r0-r12,lr}
|
||||
SUBS pc, lr, #4
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt_do(rt_base_t flag)
|
||||
*/
|
||||
.globl rt_hw_context_switch_interrupt_do
|
||||
rt_hw_context_switch_interrupt_do:
|
||||
MOV r1, #0 @ clear flag
|
||||
STR r1, [r0]
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING)
|
||||
LDMIA sp!, {r0} @ get fpexc
|
||||
VMSR fpexc, r0
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame_do1
|
||||
LDMIA sp!, {r1} @ get fpscr
|
||||
VMSR fpscr, r1
|
||||
VLDMIA sp!, {d0-d15}
|
||||
__no_vfp_frame_do1:
|
||||
#endif
|
||||
|
||||
LDMIA sp!, {r0-r12,lr} @ reload saved registers
|
||||
STMDB sp, {r0-r3} @ save r0-r3. We will restore r0-r3 in the SVC
|
||||
@ mode so there is no need to update SP.
|
||||
SUB r1, sp, #16 @ save the right SP value in r1, so we could restore r0-r3.
|
||||
SUB r2, lr, #4 @ save old task's pc to r2
|
||||
|
||||
MRS r3, spsr @ get cpsr of interrupt thread
|
||||
|
||||
@ switch to SVC mode and no interrupt
|
||||
CPSID IF, #0x13
|
||||
|
||||
STMDB sp!, {r2} @ push old task's pc
|
||||
STMDB sp!, {r4-r12,lr} @ push old task's lr,r12-r4
|
||||
LDMIA r1!, {r4-r7} @ restore r0-r3 of the interrupted thread
|
||||
STMDB sp!, {r4-r7} @ push old task's r3-r0. We don't need to push/pop them to
|
||||
@ r0-r3 because we just want to transfer the data and don't
|
||||
@ use them here.
|
||||
STMDB sp!, {r3} @ push old task's cpsr
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING)
|
||||
VMRS r0, fpexc
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame_do2
|
||||
VSTMDB sp!, {d0-d15}
|
||||
VMRS r1, fpscr
|
||||
@ TODO: add support for Common VFPv3.
|
||||
@ Save registers like FPINST, FPINST2
|
||||
STMDB sp!, {r1}
|
||||
__no_vfp_frame_do2:
|
||||
STMDB sp!, {r0}
|
||||
#endif
|
||||
|
||||
LDR r4, =rt_interrupt_from_thread
|
||||
LDR r5, [r4]
|
||||
STR sp, [r5] @ store sp in preempted tasks's TCB
|
||||
|
||||
LDR r6, =rt_interrupt_to_thread
|
||||
LDR r6, [r6]
|
||||
LDR sp, [r6] @ get new task's stack pointer
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING)
|
||||
LDMIA sp!, {r0} @ get fpexc
|
||||
VMSR fpexc, r0
|
||||
TST r0, #0x40000000
|
||||
BEQ __no_vfp_frame_do3
|
||||
LDMIA sp!, {r1} @ get fpscr
|
||||
VMSR fpscr, r1
|
||||
VLDMIA sp!, {d0-d15}
|
||||
__no_vfp_frame_do3:
|
||||
#endif
|
||||
|
||||
LDMIA sp!, {r4} @ pop new task's cpsr to spsr
|
||||
MSR spsr_cxsf, r4
|
||||
|
||||
LDMIA sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr
|
||||
|
||||
97
rt-thread/libcpu/arm/cortex-r4/cpu.c
Normal file
97
rt-thread/libcpu/arm/cortex-r4/cpu.c
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2008-12-11 XuXinming first version
|
||||
* 2013-05-24 Grissiom port to RM48x50
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
/**
|
||||
* @addtogroup RM48x50
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* this function will reset CPU
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will shutdown CPU
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown()
|
||||
{
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
#ifdef __TI_COMPILER_VERSION__
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
if (value == 0)
|
||||
return value;
|
||||
|
||||
__asm(" rsb r1, r0, #0");
|
||||
__asm(" and r1, r1, r0");
|
||||
__asm(" clz r1, r1");
|
||||
__asm(" rsb r0, r1, #32");
|
||||
}
|
||||
#endif
|
||||
|
||||
void rt_hw_cpu_icache_enable()
|
||||
{
|
||||
__asm(" MRC p15, #0, r1, c1, c0, #0 ; Read SCTLR configuration data");
|
||||
__asm(" ORR r1, r1, #0x1 <<12 ; instruction cache enable");
|
||||
__asm(" MCR p15, #0, r0, c7, c5, #0 ; Invalidate entire instruction cache, r0 is ignored");
|
||||
__asm(" MCR p15, #0, r1, c1, c0, #0 ; enabled instruction cache");
|
||||
__asm(" ISB");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_icache_disable()
|
||||
{
|
||||
__asm(" MRC p15, #0, r1, c1, c0, #0 ; Read SCTLR configuration data");
|
||||
__asm(" BIC r1, r1, #0x1 <<12 ; instruction cache enable");
|
||||
__asm(" MCR p15, #0, r1, c1, c0, #0 ; disabled instruction cache");
|
||||
__asm(" ISB");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_enable()
|
||||
{
|
||||
__asm(" MRC p15, #0, R1, c1, c0, #0 ; Read SCTLR configuration data");
|
||||
__asm(" ORR R1, R1, #0x1 <<2");
|
||||
__asm(" DSB");
|
||||
__asm(" MCR p15, #0, r0, c15, c5, #0 ; Invalidate entire data cache");
|
||||
__asm(" MCR p15, #0, R1, c1, c0, #0 ; enabled data cache");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_disable()
|
||||
{
|
||||
/* FIXME: Clean entire data cache. This routine depends on the data cache
|
||||
* size. It can be omitted if it is known that the data cache has no dirty
|
||||
* data. */
|
||||
__asm(" MRC p15, #0, r1, c1, c0, #0 ; Read SCTLR configuration data");
|
||||
__asm(" BIC r1, r1, #0x1 <<2");
|
||||
__asm(" DSB");
|
||||
__asm(" MCR p15, #0, r1, c1, c0, #0 ; disabled data cache");
|
||||
}
|
||||
|
||||
#elif __GNUC__
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
return __builtin_ffs(value);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
/*@}*/
|
||||
106
rt-thread/libcpu/arm/cortex-r4/interrupt.c
Normal file
106
rt-thread/libcpu/arm/cortex-r4/interrupt.c
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2008-12-11 XuXinming first version
|
||||
* 2013-03-29 aozima Modify the interrupt interface implementations.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
#include <sys_vim.h>
|
||||
#include <system.h>
|
||||
|
||||
#include "armv7.h"
|
||||
|
||||
#define MAX_HANDLERS 96
|
||||
|
||||
/* exception and interrupt handler table */
|
||||
struct rt_irq_desc irq_desc[MAX_HANDLERS];
|
||||
|
||||
extern volatile rt_uint8_t rt_interrupt_nest;
|
||||
|
||||
/* exception and interrupt handler table */
|
||||
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
|
||||
/**
|
||||
* @addtogroup RM48x50
|
||||
*/
|
||||
|
||||
/*@{*/
|
||||
|
||||
static void rt_hw_int_not_handle(int vector, void *param)
|
||||
{
|
||||
rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
|
||||
}
|
||||
|
||||
#define vimRAM (0xFFF82000U)
|
||||
|
||||
void rt_hw_interrupt_init(void)
|
||||
{
|
||||
register int i;
|
||||
|
||||
rt_uint32_t *vect_addr;
|
||||
|
||||
/* the initialization is done in sys_startup.c */
|
||||
|
||||
/* init exceptions table */
|
||||
rt_memset(irq_desc, 0x00, sizeof(irq_desc));
|
||||
for(i=0; i < MAX_HANDLERS; i++)
|
||||
{
|
||||
irq_desc[i].handler = rt_hw_int_not_handle;
|
||||
|
||||
vect_addr = (rt_uint32_t *)(vimRAM + i*4);
|
||||
*vect_addr = (rt_uint32_t)&irq_desc[i];
|
||||
}
|
||||
|
||||
/* init interrupt nest, and context in thread sp */
|
||||
rt_interrupt_nest = 0;
|
||||
rt_interrupt_from_thread = 0;
|
||||
rt_interrupt_to_thread = 0;
|
||||
rt_thread_switch_interrupt_flag = 0;
|
||||
}
|
||||
|
||||
void rt_hw_interrupt_mask(int vector)
|
||||
{
|
||||
vimDisableInterrupt(vector);
|
||||
}
|
||||
|
||||
void rt_hw_interrupt_umask(int vector)
|
||||
{
|
||||
vimEnableInterrupt(vector, SYS_IRQ);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will install a interrupt service routine to a interrupt.
|
||||
* @param vector the interrupt number
|
||||
* @param handler the interrupt service routine to be installed
|
||||
* @param param the parameter for interrupt service routine
|
||||
* @name unused.
|
||||
*
|
||||
* @return the old handler
|
||||
*/
|
||||
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
|
||||
void *param, const char *name)
|
||||
{
|
||||
rt_isr_handler_t old_handler = RT_NULL;
|
||||
|
||||
if(vector >= 0 && vector < MAX_HANDLERS)
|
||||
{
|
||||
old_handler = irq_desc[vector].handler;
|
||||
if (handler != RT_NULL)
|
||||
{
|
||||
irq_desc[vector].handler = handler;
|
||||
irq_desc[vector].param = param;
|
||||
}
|
||||
}
|
||||
|
||||
return old_handler;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
83
rt-thread/libcpu/arm/cortex-r4/stack.c
Normal file
83
rt-thread/libcpu/arm/cortex-r4/stack.c
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2008-12-11 XuXinming first version
|
||||
* 2013-05-24 Grissiom port to RM48x50
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "armv7.h"
|
||||
/**
|
||||
* @addtogroup RM48x50
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
|
||||
rt_uint8_t *stack_addr, void *texit)
|
||||
{
|
||||
rt_uint32_t *stk;
|
||||
|
||||
stack_addr += sizeof(rt_uint32_t);
|
||||
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
|
||||
stk = (rt_uint32_t *)stack_addr;
|
||||
*(--stk) = (rt_uint32_t)tentry; /* entry point */
|
||||
*(--stk) = (rt_uint32_t)texit; /* lr */
|
||||
*(--stk) = 0xdeadbeef; /* r12 */
|
||||
*(--stk) = 0xdeadbeef; /* r11 */
|
||||
*(--stk) = 0xdeadbeef; /* r10 */
|
||||
*(--stk) = 0xdeadbeef; /* r9 */
|
||||
*(--stk) = 0xdeadbeef; /* r8 */
|
||||
*(--stk) = 0xdeadbeef; /* r7 */
|
||||
*(--stk) = 0xdeadbeef; /* r6 */
|
||||
*(--stk) = 0xdeadbeef; /* r5 */
|
||||
*(--stk) = 0xdeadbeef; /* r4 */
|
||||
*(--stk) = 0xdeadbeef; /* r3 */
|
||||
*(--stk) = 0xdeadbeef; /* r2 */
|
||||
*(--stk) = 0xdeadbeef; /* r1 */
|
||||
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
|
||||
|
||||
/* cpsr */
|
||||
if ((rt_uint32_t)tentry & 0x01)
|
||||
*(--stk) = SVCMODE | 0x20; /* thumb mode */
|
||||
else
|
||||
*(--stk) = SVCMODE; /* arm mode */
|
||||
|
||||
#if defined(__TI_VFP_SUPPORT__) || (defined (__VFP_FP__) && !defined(__SOFTFP__))
|
||||
#ifndef RT_VFP_LAZY_STACKING
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < VFP_DATA_NR; i++)
|
||||
{
|
||||
*(--stk) = 0;
|
||||
}
|
||||
/* FPSCR TODO: do we need to set the values other than 0? */
|
||||
*(--stk) = 0;
|
||||
/* FPEXC. Enable the FVP if no lazy stacking. */
|
||||
*(--stk) = 0x40000000;
|
||||
}
|
||||
#else
|
||||
/* FPEXC. Disable the FVP by default. */
|
||||
*(--stk) = 0x00000000;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* return task's current stack address */
|
||||
return (rt_uint8_t *)stk;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
552
rt-thread/libcpu/arm/cortex-r4/start_ccs.asm
Normal file
552
rt-thread/libcpu/arm/cortex-r4/start_ccs.asm
Normal file
@ -0,0 +1,552 @@
|
||||
;-------------------------------------------------------------------------------
|
||||
; sys_core.asm
|
||||
;
|
||||
; (c) Texas Instruments 2009-2013, All rights reserved.
|
||||
;
|
||||
|
||||
.text
|
||||
.arm
|
||||
|
||||
.ref _c_int00
|
||||
|
||||
.def _reset
|
||||
.asmfunc
|
||||
_reset
|
||||
;-------------------------------------------------------------------------------
|
||||
; Initialize CPU Registers
|
||||
; After reset, the CPU is in the Supervisor mode (M = 10011)
|
||||
mov r0, lr
|
||||
mov r1, #0x0000
|
||||
mov r2, #0x0000
|
||||
mov r3, #0x0000
|
||||
mov r4, #0x0000
|
||||
mov r5, #0x0000
|
||||
mov r6, #0x0000
|
||||
mov r7, #0x0000
|
||||
mov r8, #0x0000
|
||||
mov r9, #0x0000
|
||||
mov r10, #0x0000
|
||||
mov r11, #0x0000
|
||||
mov r12, #0x0000
|
||||
mov r13, #0x0000
|
||||
mrs r1, cpsr
|
||||
msr spsr_cxsf, r1
|
||||
; Switch to FIQ mode (M = 10001)
|
||||
cps #17
|
||||
mov lr, r0
|
||||
mov r8, #0x0000
|
||||
mov r9, #0x0000
|
||||
mov r10, #0x0000
|
||||
mov r11, #0x0000
|
||||
mov r12, #0x0000
|
||||
mrs r1, cpsr
|
||||
msr spsr_cxsf, r1
|
||||
; Switch to IRQ mode (M = 10010)
|
||||
cps #18
|
||||
mov lr, r0
|
||||
mrs r1,cpsr
|
||||
msr spsr_cxsf, r1
|
||||
; Switch to Abort mode (M = 10111)
|
||||
cps #23
|
||||
mov lr, r0
|
||||
mrs r1,cpsr
|
||||
msr spsr_cxsf, r1
|
||||
; Switch to Undefined Instruction Mode (M = 11011)
|
||||
cps #27
|
||||
mov lr, r0
|
||||
mrs r1,cpsr
|
||||
msr spsr_cxsf, r1
|
||||
; Switch to System Mode ( Shares User Mode registers ) (M = 11111)
|
||||
cps #31
|
||||
mov lr, r0
|
||||
mrs r1,cpsr
|
||||
msr spsr_cxsf, r1
|
||||
; Switch back to Supervisor Mode (M = 10011)
|
||||
cps #19
|
||||
|
||||
; Turn on FPV coprocessor
|
||||
mrc p15, #0x00, r2, c1, c0, #0x02
|
||||
orr r2, r2, #0xF00000
|
||||
mcr p15, #0x00, r2, c1, c0, #0x02
|
||||
|
||||
.if (RT_VFP_LAZY_STACKING) = 0
|
||||
fmrx r2, fpexc
|
||||
orr r2, r2, #0x40000000
|
||||
fmxr fpexc, r2
|
||||
|
||||
fmdrr d0, r1, r1
|
||||
fmdrr d1, r1, r1
|
||||
fmdrr d2, r1, r1
|
||||
fmdrr d3, r1, r1
|
||||
fmdrr d4, r1, r1
|
||||
fmdrr d5, r1, r1
|
||||
fmdrr d6, r1, r1
|
||||
fmdrr d7, r1, r1
|
||||
fmdrr d8, r1, r1
|
||||
fmdrr d9, r1, r1
|
||||
fmdrr d10, r1, r1
|
||||
fmdrr d11, r1, r1
|
||||
fmdrr d12, r1, r1
|
||||
fmdrr d13, r1, r1
|
||||
fmdrr d14, r1, r1
|
||||
fmdrr d15, r1, r1
|
||||
.endif
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Initialize Stack Pointers
|
||||
cps #17
|
||||
ldr sp, fiqSp
|
||||
cps #18
|
||||
ldr sp, irqSp
|
||||
cps #23
|
||||
ldr sp, abortSp
|
||||
cps #27
|
||||
ldr sp, undefSp
|
||||
cps #31
|
||||
ldr sp, userSp
|
||||
cps #19
|
||||
ldr sp, svcSp
|
||||
|
||||
bl next1
|
||||
next1
|
||||
bl next2
|
||||
next2
|
||||
bl next3
|
||||
next3
|
||||
bl next4
|
||||
next4
|
||||
ldr lr, int00ad
|
||||
bx lr
|
||||
|
||||
int00ad .word _c_int00
|
||||
userSp .word 0x08000000+0x00001000
|
||||
svcSp .word 0x08000000+0x00001000+0x00000100
|
||||
fiqSp .word 0x08000000+0x00001000+0x00000100+0x00000100
|
||||
irqSp .word 0x08000000+0x00001000+0x00000100+0x00000100+0x00000100
|
||||
abortSp .word 0x08000000+0x00001000+0x00000100+0x00000100+0x00000100+0x00000100
|
||||
undefSp .word 0x08000000+0x00001000+0x00000100+0x00000100+0x00000100+0x00000100+0x00000100
|
||||
|
||||
.endasmfunc
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Enable RAM ECC Support
|
||||
|
||||
.def _coreEnableRamEcc_
|
||||
.asmfunc
|
||||
|
||||
_coreEnableRamEcc_
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mrc p15, #0x00, r0, c1, c0, #0x01
|
||||
orr r0, r0, #0x0C000000
|
||||
mcr p15, #0x00, r0, c1, c0, #0x01
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Disable RAM ECC Support
|
||||
|
||||
.def _coreDisableRamEcc_
|
||||
.asmfunc
|
||||
|
||||
_coreDisableRamEcc_
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mrc p15, #0x00, r0, c1, c0, #0x01
|
||||
bic r0, r0, #0x0C000000
|
||||
mcr p15, #0x00, r0, c1, c0, #0x01
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Enable Flash ECC Support
|
||||
|
||||
.def _coreEnableFlashEcc_
|
||||
.asmfunc
|
||||
|
||||
_coreEnableFlashEcc_
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mrc p15, #0x00, r0, c1, c0, #0x01
|
||||
orr r0, r0, #0x02000000
|
||||
dmb
|
||||
mcr p15, #0x00, r0, c1, c0, #0x01
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Disable Flash ECC Support
|
||||
|
||||
.def _coreDisableFlashEcc_
|
||||
.asmfunc
|
||||
|
||||
_coreDisableFlashEcc_
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mrc p15, #0x00, r0, c1, c0, #0x01
|
||||
bic r0, r0, #0x02000000
|
||||
mcr p15, #0x00, r0, c1, c0, #0x01
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Get data fault status register
|
||||
|
||||
.def _coreGetDataFault_
|
||||
.asmfunc
|
||||
|
||||
_coreGetDataFault_
|
||||
|
||||
mrc p15, #0, r0, c5, c0, #0
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Clear data fault status register
|
||||
|
||||
.def _coreClearDataFault_
|
||||
.asmfunc
|
||||
|
||||
_coreClearDataFault_
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mov r0, #0
|
||||
mcr p15, #0, r0, c5, c0, #0
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Get instruction fault status register
|
||||
|
||||
.def _coreGetInstructionFault_
|
||||
.asmfunc
|
||||
|
||||
_coreGetInstructionFault_
|
||||
|
||||
mrc p15, #0, r0, c5, c0, #1
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Clear instruction fault status register
|
||||
|
||||
.def _coreClearInstructionFault_
|
||||
.asmfunc
|
||||
|
||||
_coreClearInstructionFault_
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mov r0, #0
|
||||
mcr p15, #0, r0, c5, c0, #1
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Get data fault address register
|
||||
|
||||
.def _coreGetDataFaultAddress_
|
||||
.asmfunc
|
||||
|
||||
_coreGetDataFaultAddress_
|
||||
|
||||
mrc p15, #0, r0, c6, c0, #0
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Clear data fault address register
|
||||
|
||||
.def _coreClearDataFaultAddress_
|
||||
.asmfunc
|
||||
|
||||
_coreClearDataFaultAddress_
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mov r0, #0
|
||||
mcr p15, #0, r0, c6, c0, #0
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Get instruction fault address register
|
||||
|
||||
.def _coreGetInstructionFaultAddress_
|
||||
.asmfunc
|
||||
|
||||
_coreGetInstructionFaultAddress_
|
||||
|
||||
mrc p15, #0, r0, c6, c0, #2
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Clear instruction fault address register
|
||||
|
||||
.def _coreClearInstructionFaultAddress_
|
||||
.asmfunc
|
||||
|
||||
_coreClearInstructionFaultAddress_
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mov r0, #0
|
||||
mcr p15, #0, r0, c6, c0, #2
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Get auxiliary data fault status register
|
||||
|
||||
.def _coreGetAuxiliaryDataFault_
|
||||
.asmfunc
|
||||
|
||||
_coreGetAuxiliaryDataFault_
|
||||
|
||||
mrc p15, #0, r0, c5, c1, #0
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Clear auxiliary data fault status register
|
||||
|
||||
.def _coreClearAuxiliaryDataFault_
|
||||
.asmfunc
|
||||
|
||||
_coreClearAuxiliaryDataFault_
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mov r0, #0
|
||||
mcr p15, #0, r0, c5, c1, #0
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Get auxiliary instruction fault status register
|
||||
|
||||
.def _coreGetAuxiliaryInstructionFault_
|
||||
.asmfunc
|
||||
|
||||
_coreGetAuxiliaryInstructionFault_
|
||||
|
||||
mrc p15, #0, r0, c5, c1, #1
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Clear auxiliary instruction fault status register
|
||||
|
||||
.def _coreClearAuxiliaryInstructionFault_
|
||||
.asmfunc
|
||||
|
||||
_coreClearAuxiliaryInstructionFault_
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mov r0, #0
|
||||
mrc p15, #0, r0, c5, c1, #1
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
.endasmfunc
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Clear ESM CCM errorss
|
||||
|
||||
.def _esmCcmErrorsClear_
|
||||
.asmfunc
|
||||
|
||||
_esmCcmErrorsClear_
|
||||
|
||||
stmfd sp!, {r0-r2}
|
||||
ldr r0, ESMSR1_REG ; load the ESMSR1 status register address
|
||||
ldr r2, ESMSR1_ERR_CLR
|
||||
str r2, [r0] ; clear the ESMSR1 register
|
||||
|
||||
ldr r0, ESMSR2_REG ; load the ESMSR2 status register address
|
||||
ldr r2, ESMSR2_ERR_CLR
|
||||
str r2, [r0] ; clear the ESMSR2 register
|
||||
|
||||
ldr r0, ESMSSR2_REG ; load the ESMSSR2 status register address
|
||||
ldr r2, ESMSSR2_ERR_CLR
|
||||
str r2, [r0] ; clear the ESMSSR2 register
|
||||
|
||||
ldr r0, ESMKEY_REG ; load the ESMKEY register address
|
||||
mov r2, #0x5 ; load R2 with 0x5
|
||||
str r2, [r0] ; clear the ESMKEY register
|
||||
|
||||
ldr r0, VIM_INTREQ ; load the INTREQ register address
|
||||
ldr r2, VIM_INT_CLR
|
||||
str r2, [r0] ; clear the INTREQ register
|
||||
ldr r0, CCMR4_STAT_REG ; load the CCMR4 status register address
|
||||
ldr r2, CCMR4_ERR_CLR
|
||||
str r2, [r0] ; clear the CCMR4 status register
|
||||
ldmfd sp!, {r0-r2}
|
||||
bx lr
|
||||
|
||||
ESMSR1_REG .word 0xFFFFF518
|
||||
ESMSR2_REG .word 0xFFFFF51C
|
||||
ESMSR3_REG .word 0xFFFFF520
|
||||
ESMKEY_REG .word 0xFFFFF538
|
||||
ESMSSR2_REG .word 0xFFFFF53C
|
||||
CCMR4_STAT_REG .word 0xFFFFF600
|
||||
ERR_CLR_WRD .word 0xFFFFFFFF
|
||||
CCMR4_ERR_CLR .word 0x00010000
|
||||
ESMSR1_ERR_CLR .word 0x80000000
|
||||
ESMSR2_ERR_CLR .word 0x00000004
|
||||
ESMSSR2_ERR_CLR .word 0x00000004
|
||||
VIM_INT_CLR .word 0x00000001
|
||||
VIM_INTREQ .word 0xFFFFFE20
|
||||
|
||||
.endasmfunc
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Work Around for Errata CORTEX-R4#57:
|
||||
;
|
||||
; Errata Description:
|
||||
; Conditional VMRS APSR_Nzcv, FPSCR May Evaluate With Incorrect Flags
|
||||
; Workaround:
|
||||
; Disable out-of-order single-precision floating point
|
||||
; multiply-accumulate instruction completion
|
||||
|
||||
.def _errata_CORTEXR4_57_
|
||||
.asmfunc
|
||||
|
||||
_errata_CORTEXR4_57_
|
||||
|
||||
push {r0}
|
||||
mrc p15, #0, r0, c15, c0, #0 ; Read Secondary Auxiliary Control Register
|
||||
orr r0, r0, #0x10000 ; Set BIT 16 (Set DOOFMACS)
|
||||
mcr p15, #0, r0, c15, c0, #0 ; Write Secondary Auxiliary Control Register
|
||||
pop {r0}
|
||||
bx lr
|
||||
.endasmfunc
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; Work Around for Errata CORTEX-R4#66:
|
||||
;
|
||||
; Errata Description:
|
||||
; Register Corruption During A Load-Multiple Instruction At
|
||||
; an Exception Vector
|
||||
; Workaround:
|
||||
; Disable out-of-order completion for divide instructions in
|
||||
; Auxiliary Control register
|
||||
|
||||
.def _errata_CORTEXR4_66_
|
||||
.asmfunc
|
||||
|
||||
_errata_CORTEXR4_66_
|
||||
|
||||
push {r0}
|
||||
mrc p15, #0, r0, c1, c0, #1 ; Read Auxiliary Control register
|
||||
orr r0, r0, #0x80 ; Set BIT 7 (Disable out-of-order completion
|
||||
; for divide instructions.)
|
||||
mcr p15, #0, r0, c1, c0, #1 ; Write Auxiliary Control register
|
||||
pop {r0}
|
||||
bx lr
|
||||
.endasmfunc
|
||||
|
||||
.def turnon_VFP
|
||||
.asmfunc
|
||||
turnon_VFP
|
||||
; Enable FPV
|
||||
STMDB sp!, {r0}
|
||||
fmrx r0, fpexc
|
||||
orr r0, r0, #0x40000000
|
||||
fmxr fpexc, r0
|
||||
LDMIA sp!, {r0}
|
||||
subs pc, lr, #4
|
||||
.endasmfunc
|
||||
|
||||
_push_svc_reg .macro
|
||||
sub sp, sp, #17 * 4 ;/* Sizeof(struct rt_hw_exp_stack) */
|
||||
stmia sp, {r0 - r12} ;/* Calling r0-r12 */
|
||||
mov r0, sp
|
||||
mrs r6, spsr ;/* Save CPSR */
|
||||
str lr, [r0, #15*4] ;/* Push PC */
|
||||
str r6, [r0, #16*4] ;/* Push CPSR */
|
||||
cps #0x13
|
||||
str sp, [r0, #13*4] ;/* Save calling SP */
|
||||
str lr, [r0, #14*4] ;/* Save calling PC */
|
||||
.endm
|
||||
|
||||
.ref rt_hw_trap_svc
|
||||
.def vector_svc
|
||||
.asmfunc
|
||||
vector_svc:
|
||||
_push_svc_reg
|
||||
bl rt_hw_trap_svc
|
||||
sub pc, pc, #-4
|
||||
.endasmfunc
|
||||
|
||||
.ref rt_hw_trap_pabt
|
||||
.def vector_pabort
|
||||
.asmfunc
|
||||
vector_pabort:
|
||||
_push_svc_reg
|
||||
bl rt_hw_trap_pabt
|
||||
sub pc, pc, #-4
|
||||
.endasmfunc
|
||||
|
||||
.ref rt_hw_trap_dabt
|
||||
.def vector_dabort
|
||||
.asmfunc
|
||||
vector_dabort:
|
||||
_push_svc_reg
|
||||
bl rt_hw_trap_dabt
|
||||
sub pc, pc, #-4
|
||||
.endasmfunc
|
||||
|
||||
.ref rt_hw_trap_resv
|
||||
.def vector_resv
|
||||
.asmfunc
|
||||
vector_resv:
|
||||
_push_svc_reg
|
||||
bl rt_hw_trap_resv
|
||||
sub pc, pc, #-4
|
||||
.endasmfunc
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; C++ construct table pointers
|
||||
|
||||
.def __TI_PINIT_Base, __TI_PINIT_Limit
|
||||
.weak SHT$$INIT_ARRAY$$Base, SHT$$INIT_ARRAY$$Limit
|
||||
|
||||
__TI_PINIT_Base .long SHT$$INIT_ARRAY$$Base
|
||||
__TI_PINIT_Limit .long SHT$$INIT_ARRAY$$Limit
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
504
rt-thread/libcpu/arm/cortex-r4/start_gcc.S
Normal file
504
rt-thread/libcpu/arm/cortex-r4/start_gcc.S
Normal file
@ -0,0 +1,504 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
@-------------------------------------------------------------------------------
|
||||
@ sys_core.asm
|
||||
@
|
||||
@ (c) Texas Instruments 2009-2013, All rights reserved.
|
||||
@
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
.equ Mode_USR, 0x10
|
||||
.equ Mode_FIQ, 0x11
|
||||
.equ Mode_IRQ, 0x12
|
||||
.equ Mode_SVC, 0x13
|
||||
.equ Mode_ABT, 0x17
|
||||
.equ Mode_UND, 0x1B
|
||||
.equ Mode_SYS, 0x1F
|
||||
|
||||
.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled
|
||||
.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled
|
||||
|
||||
.equ UND_Stack_Size, 0x00000000
|
||||
.equ SVC_Stack_Size, 0x00000000
|
||||
.equ ABT_Stack_Size, 0x00000000
|
||||
.equ FIQ_Stack_Size, 0x00001000
|
||||
.equ IRQ_Stack_Size, 0x00001000
|
||||
|
||||
.section .bss.noinit
|
||||
/* stack */
|
||||
.globl stack_start
|
||||
.globl stack_top
|
||||
|
||||
.align 3
|
||||
stack_start:
|
||||
.rept (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + FIQ_Stack_Size + IRQ_Stack_Size)
|
||||
.byte 0
|
||||
.endr
|
||||
stack_top:
|
||||
|
||||
.section .text, "ax"
|
||||
.text
|
||||
.arm
|
||||
|
||||
.globl _c_int00
|
||||
|
||||
.globl _reset
|
||||
_reset:
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Initialize CPU Registers
|
||||
@ After reset, the CPU is in the Supervisor mode (M = 10011)
|
||||
mov r0, #0x0000
|
||||
mov r1, #0x0000
|
||||
mov r2, #0x0000
|
||||
mov r3, #0x0000
|
||||
mov r4, #0x0000
|
||||
mov r5, #0x0000
|
||||
mov r6, #0x0000
|
||||
mov r7, #0x0000
|
||||
mov r8, #0x0000
|
||||
mov r9, #0x0000
|
||||
mov r10, #0x0000
|
||||
mov r11, #0x0000
|
||||
mov r12, #0x0000
|
||||
mov r13, #0x0000
|
||||
mrs r1, cpsr
|
||||
msr spsr_cxsf, r1
|
||||
|
||||
cpsid if, #19
|
||||
|
||||
#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING)
|
||||
@ Turn on FPV coprocessor
|
||||
mrc p15, #0x00, r2, c1, c0, #0x02
|
||||
orr r2, r2, #0xF00000
|
||||
mcr p15, #0x00, r2, c1, c0, #0x02
|
||||
|
||||
fmrx r2, fpexc
|
||||
orr r2, r2, #0x40000000
|
||||
fmxr fpexc, r2
|
||||
#endif
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Initialize Stack Pointers
|
||||
ldr r0, =stack_top
|
||||
|
||||
@ Set the startup stack for svc
|
||||
mov sp, r0
|
||||
|
||||
@ Enter Undefined Instruction Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_UND|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #UND_Stack_Size
|
||||
|
||||
@ Enter Abort Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_ABT|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #ABT_Stack_Size
|
||||
|
||||
@ Enter FIQ Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #FIQ_Stack_Size
|
||||
|
||||
@ Enter IRQ Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #IRQ_Stack_Size
|
||||
|
||||
@ Switch back to SVC
|
||||
msr cpsr_c, #Mode_SVC|I_Bit|F_Bit
|
||||
|
||||
bl next1
|
||||
next1:
|
||||
bl next2
|
||||
next2:
|
||||
bl next3
|
||||
next3:
|
||||
bl next4
|
||||
next4:
|
||||
ldr lr, =_c_int00
|
||||
bx lr
|
||||
|
||||
.globl data_init
|
||||
data_init:
|
||||
/* copy .data to SRAM */
|
||||
ldr r1, =_sidata /* .data start in image */
|
||||
ldr r2, =_edata /* .data end in image */
|
||||
ldr r3, =_sdata /* sram data start */
|
||||
data_loop:
|
||||
ldr r0, [r1, #0]
|
||||
str r0, [r3]
|
||||
|
||||
add r1, r1, #4
|
||||
add r3, r3, #4
|
||||
|
||||
cmp r3, r2 /* check if data to clear */
|
||||
blo data_loop /* loop until done */
|
||||
|
||||
/* clear .bss */
|
||||
mov r0,#0 /* get a zero */
|
||||
ldr r1,=__bss_start /* bss start */
|
||||
ldr r2,=__bss_end /* bss end */
|
||||
|
||||
bss_loop:
|
||||
cmp r1,r2 /* check if data to clear */
|
||||
strlo r0,[r1],#4 /* clear 4 bytes */
|
||||
blo bss_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-r3, ip, lr}
|
||||
mov lr, pc
|
||||
bx r2
|
||||
ldmfd sp!, {r0-r3, ip, lr}
|
||||
b ctor_loop
|
||||
ctor_end:
|
||||
bx lr
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Enable RAM ECC Support
|
||||
|
||||
.globl _coreEnableRamEcc_
|
||||
_coreEnableRamEcc_:
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mrc p15, #0x00, r0, c1, c0, #0x01
|
||||
orr r0, r0, #0x0C000000
|
||||
mcr p15, #0x00, r0, c1, c0, #0x01
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Disable RAM ECC Support
|
||||
|
||||
.globl _coreDisableRamEcc_
|
||||
_coreDisableRamEcc_:
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mrc p15, #0x00, r0, c1, c0, #0x01
|
||||
bic r0, r0, #0x0C000000
|
||||
mcr p15, #0x00, r0, c1, c0, #0x01
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Enable Flash ECC Support
|
||||
|
||||
.globl _coreEnableFlashEcc_
|
||||
_coreEnableFlashEcc_:
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mrc p15, #0x00, r0, c1, c0, #0x01
|
||||
orr r0, r0, #0x02000000
|
||||
dmb
|
||||
mcr p15, #0x00, r0, c1, c0, #0x01
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Disable Flash ECC Support
|
||||
|
||||
.globl _coreDisableFlashEcc_
|
||||
_coreDisableFlashEcc_:
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mrc p15, #0x00, r0, c1, c0, #0x01
|
||||
bic r0, r0, #0x02000000
|
||||
mcr p15, #0x00, r0, c1, c0, #0x01
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Get data fault status register
|
||||
|
||||
.globl _coreGetDataFault_
|
||||
_coreGetDataFault_:
|
||||
|
||||
mrc p15, #0, r0, c5, c0, #0
|
||||
bx lr
|
||||
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Clear data fault status register
|
||||
|
||||
.globl _coreClearDataFault_
|
||||
_coreClearDataFault_:
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mov r0, #0
|
||||
mcr p15, #0, r0, c5, c0, #0
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Get instruction fault status register
|
||||
|
||||
.globl _coreGetInstructionFault_
|
||||
_coreGetInstructionFault_:
|
||||
|
||||
mrc p15, #0, r0, c5, c0, #1
|
||||
bx lr
|
||||
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Clear instruction fault status register
|
||||
|
||||
.globl _coreClearInstructionFault_
|
||||
_coreClearInstructionFault_:
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mov r0, #0
|
||||
mcr p15, #0, r0, c5, c0, #1
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Get data fault address register
|
||||
|
||||
.globl _coreGetDataFaultAddress_
|
||||
_coreGetDataFaultAddress_:
|
||||
|
||||
mrc p15, #0, r0, c6, c0, #0
|
||||
bx lr
|
||||
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Clear data fault address register
|
||||
|
||||
.globl _coreClearDataFaultAddress_
|
||||
_coreClearDataFaultAddress_:
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mov r0, #0
|
||||
mcr p15, #0, r0, c6, c0, #0
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Get instruction fault address register
|
||||
|
||||
.globl _coreGetInstructionFaultAddress_
|
||||
_coreGetInstructionFaultAddress_:
|
||||
|
||||
mrc p15, #0, r0, c6, c0, #2
|
||||
bx lr
|
||||
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Clear instruction fault address register
|
||||
|
||||
.globl _coreClearInstructionFaultAddress_
|
||||
_coreClearInstructionFaultAddress_:
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mov r0, #0
|
||||
mcr p15, #0, r0, c6, c0, #2
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Get auxiliary data fault status register
|
||||
|
||||
.globl _coreGetAuxiliaryDataFault_
|
||||
_coreGetAuxiliaryDataFault_:
|
||||
|
||||
mrc p15, #0, r0, c5, c1, #0
|
||||
bx lr
|
||||
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Clear auxiliary data fault status register
|
||||
|
||||
.globl _coreClearAuxiliaryDataFault_
|
||||
_coreClearAuxiliaryDataFault_:
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mov r0, #0
|
||||
mcr p15, #0, r0, c5, c1, #0
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Get auxiliary instruction fault status register
|
||||
|
||||
.globl _coreGetAuxiliaryInstructionFault_
|
||||
_coreGetAuxiliaryInstructionFault_:
|
||||
|
||||
mrc p15, #0, r0, c5, c1, #1
|
||||
bx lr
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Clear auxiliary instruction fault status register
|
||||
|
||||
.globl _coreClearAuxiliaryInstructionFault_
|
||||
_coreClearAuxiliaryInstructionFault_:
|
||||
|
||||
stmfd sp!, {r0}
|
||||
mov r0, #0
|
||||
mrc p15, #0, r0, c5, c1, #1
|
||||
ldmfd sp!, {r0}
|
||||
bx lr
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Clear ESM CCM errorss
|
||||
|
||||
.globl _esmCcmErrorsClear_
|
||||
_esmCcmErrorsClear_:
|
||||
|
||||
stmfd sp!, {r0-r2}
|
||||
ldr r0, ESMSR1_REG @ load the ESMSR1 status register address
|
||||
ldr r2, ESMSR1_ERR_CLR
|
||||
str r2, [r0] @ clear the ESMSR1 register
|
||||
|
||||
ldr r0, ESMSR2_REG @ load the ESMSR2 status register address
|
||||
ldr r2, ESMSR2_ERR_CLR
|
||||
str r2, [r0] @ clear the ESMSR2 register
|
||||
|
||||
ldr r0, ESMSSR2_REG @ load the ESMSSR2 status register address
|
||||
ldr r2, ESMSSR2_ERR_CLR
|
||||
str r2, [r0] @ clear the ESMSSR2 register
|
||||
|
||||
ldr r0, ESMKEY_REG @ load the ESMKEY register address
|
||||
mov r2, #0x5 @ load R2 with 0x5
|
||||
str r2, [r0] @ clear the ESMKEY register
|
||||
|
||||
ldr r0, VIM_INTREQ @ load the INTREQ register address
|
||||
ldr r2, VIM_INT_CLR
|
||||
str r2, [r0] @ clear the INTREQ register
|
||||
ldr r0, CCMR4_STAT_REG @ load the CCMR4 status register address
|
||||
ldr r2, CCMR4_ERR_CLR
|
||||
str r2, [r0] @ clear the CCMR4 status register
|
||||
ldmfd sp!, {r0-r2}
|
||||
bx lr
|
||||
|
||||
ESMSR1_REG: .word 0xFFFFF518
|
||||
ESMSR2_REG: .word 0xFFFFF51C
|
||||
ESMSR3_REG: .word 0xFFFFF520
|
||||
ESMKEY_REG: .word 0xFFFFF538
|
||||
ESMSSR2_REG: .word 0xFFFFF53C
|
||||
CCMR4_STAT_REG: .word 0xFFFFF600
|
||||
ERR_CLR_WRD: .word 0xFFFFFFFF
|
||||
CCMR4_ERR_CLR: .word 0x00010000
|
||||
ESMSR1_ERR_CLR: .word 0x80000000
|
||||
ESMSR2_ERR_CLR: .word 0x00000004
|
||||
ESMSSR2_ERR_CLR: .word 0x00000004
|
||||
VIM_INT_CLR: .word 0x00000001
|
||||
VIM_INTREQ: .word 0xFFFFFE20
|
||||
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Work Around for Errata CORTEX-R4#57:
|
||||
@
|
||||
@ Errata Description:
|
||||
@ Conditional VMRS APSR_Nzcv, FPSCR May Evaluate With Incorrect Flags
|
||||
@ Workaround:
|
||||
@ Disable out-of-order single-precision floating point
|
||||
@ multiply-accumulate instruction completion
|
||||
|
||||
.globl _errata_CORTEXR4_57_
|
||||
_errata_CORTEXR4_57_:
|
||||
|
||||
push {r0}
|
||||
mrc p15, #0, r0, c15, c0, #0 @ Read Secondary Auxiliary Control Register
|
||||
orr r0, r0, #0x10000 @ Set BIT 16 (Set DOOFMACS)
|
||||
mcr p15, #0, r0, c15, c0, #0 @ Write Secondary Auxiliary Control Register
|
||||
pop {r0}
|
||||
bx lr
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ Work Around for Errata CORTEX-R4#66:
|
||||
@
|
||||
@ Errata Description:
|
||||
@ Register Corruption During A Load-Multiple Instruction At
|
||||
@ an Exception Vector
|
||||
@ Workaround:
|
||||
@ Disable out-of-order completion for divide instructions in
|
||||
@ Auxiliary Control register
|
||||
|
||||
.globl _errata_CORTEXR4_66_
|
||||
_errata_CORTEXR4_66_:
|
||||
|
||||
push {r0}
|
||||
mrc p15, #0, r0, c1, c0, #1 @ Read Auxiliary Control register
|
||||
orr r0, r0, #0x80 @ Set BIT 7 (Disable out-of-order completion
|
||||
@ for divide instructions.)
|
||||
mcr p15, #0, r0, c1, c0, #1 @ Write Auxiliary Control register
|
||||
pop {r0}
|
||||
bx lr
|
||||
|
||||
.globl turnon_VFP
|
||||
turnon_VFP:
|
||||
@ Enable FPV
|
||||
STMDB sp!, {r0}
|
||||
fmrx r0, fpexc
|
||||
orr r0, r0, #0x40000000
|
||||
fmxr fpexc, r0
|
||||
LDMIA sp!, {r0}
|
||||
subs pc, lr, #4
|
||||
|
||||
.macro push_svc_reg
|
||||
sub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */
|
||||
stmia sp, {r0 - r12} @/* Calling r0-r12 */
|
||||
mov r0, sp
|
||||
mrs r6, spsr @/* Save CPSR */
|
||||
str lr, [r0, #15*4] @/* Push PC */
|
||||
str r6, [r0, #16*4] @/* Push CPSR */
|
||||
cps #Mode_SVC
|
||||
str sp, [r0, #13*4] @/* Save calling SP */
|
||||
str lr, [r0, #14*4] @/* Save calling PC */
|
||||
.endm
|
||||
|
||||
.globl vector_svc
|
||||
vector_svc:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_svc
|
||||
b .
|
||||
|
||||
.globl vector_pabort
|
||||
vector_pabort:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_pabt
|
||||
b .
|
||||
|
||||
.globl vector_dabort
|
||||
vector_dabort:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_dabt
|
||||
b .
|
||||
|
||||
.globl vector_resv
|
||||
vector_resv:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_resv
|
||||
b .
|
||||
148
rt-thread/libcpu/arm/cortex-r4/trap.c
Normal file
148
rt-thread/libcpu/arm/cortex-r4/trap.c
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2008-12-11 XuXinming first version
|
||||
* 2013-05-24 Grissiom port to RM48x50
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
#include <sys_vim.h>
|
||||
|
||||
#include "armv7.h"
|
||||
|
||||
/**
|
||||
* @addtogroup RM48x50
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* this function will show registers of CPU
|
||||
*
|
||||
* @param regs the registers point
|
||||
*/
|
||||
void rt_hw_show_register (struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
rt_kprintf("Execption:\n");
|
||||
rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3);
|
||||
rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7);
|
||||
rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10);
|
||||
rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip);
|
||||
rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc);
|
||||
rt_kprintf("cpsr:0x%08x\n", regs->cpsr);
|
||||
}
|
||||
|
||||
/**
|
||||
* When comes across an instruction which it cannot handle,
|
||||
* it takes the undefined instruction trap.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_udef(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
rt_kprintf("undefined instruction\n");
|
||||
rt_hw_show_register(regs);
|
||||
if (rt_thread_self() != RT_NULL)
|
||||
rt_kprintf("Current Thread: %s\n", rt_thread_self()->name);
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* The software interrupt instruction (SWI) is used for entering
|
||||
* Supervisor mode, usually to request a particular supervisor
|
||||
* function.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_svc(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
rt_kprintf("software interrupt\n");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* An abort indicates that the current memory access cannot be completed,
|
||||
* which occurs during an instruction prefetch.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
rt_kprintf("prefetch abort\n");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* An abort indicates that the current memory access cannot be completed,
|
||||
* which occurs during a data access.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
rt_kprintf("Data Abort ");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Normally, system will never reach here
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_resv(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
rt_kprintf("Reserved trap\n");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
extern rt_isr_handler_t isr_table[];
|
||||
void rt_hw_trap_irq(void)
|
||||
{
|
||||
int irqno;
|
||||
struct rt_irq_desc* irq;
|
||||
extern struct rt_irq_desc irq_desc[];
|
||||
|
||||
irq = (struct rt_irq_desc*) vimREG->IRQVECREG;
|
||||
irqno = ((rt_uint32_t) irq - (rt_uint32_t) &irq_desc[0])/sizeof(struct rt_irq_desc);
|
||||
|
||||
/* invoke isr */
|
||||
irq->handler(irqno, irq->param);
|
||||
}
|
||||
|
||||
void rt_hw_trap_fiq(void)
|
||||
{
|
||||
rt_kprintf("fast interrupt request\n");
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
34
rt-thread/libcpu/arm/cortex-r4/vector_ccs.asm
Normal file
34
rt-thread/libcpu/arm/cortex-r4/vector_ccs.asm
Normal file
@ -0,0 +1,34 @@
|
||||
;-------------------------------------------------------------------------------
|
||||
; sys_intvecs.asm
|
||||
;
|
||||
; (c) Texas Instruments 2009-2013, All rights reserved.
|
||||
;
|
||||
|
||||
.sect ".intvecs"
|
||||
.arm
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; import reference for interrupt routines
|
||||
|
||||
.ref _reset
|
||||
.ref turnon_VFP
|
||||
.ref vector_svc
|
||||
.ref vector_pabort
|
||||
.ref vector_dabort
|
||||
.ref vector_resv
|
||||
.ref IRQ_Handler
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; interrupt vectors
|
||||
.def resetEntry
|
||||
resetEntry
|
||||
b _reset
|
||||
b turnon_VFP
|
||||
b vector_svc
|
||||
b vector_pabort
|
||||
b vector_dabort
|
||||
b vector_resv
|
||||
b IRQ_Handler
|
||||
ldr pc,[pc,#-0x1b0]
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
39
rt-thread/libcpu/arm/cortex-r4/vector_gcc.S
Normal file
39
rt-thread/libcpu/arm/cortex-r4/vector_gcc.S
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
@-------------------------------------------------------------------------------
|
||||
@ sys_intvecs.asm
|
||||
@
|
||||
@ (c) Texas Instruments 2009-2013, All rights reserved.
|
||||
@
|
||||
|
||||
.section .vectors, "ax"
|
||||
.code 32
|
||||
|
||||
@-------------------------------------------------------------------------------
|
||||
@ import reference for interrupt routines
|
||||
|
||||
.globl _reset
|
||||
.globl turnon_VFP
|
||||
.globl vector_svc
|
||||
.globl vector_pabort
|
||||
.globl vector_dabort
|
||||
.globl vector_resv
|
||||
.globl IRQ_Handler
|
||||
|
||||
|
||||
.globl system_vectors
|
||||
system_vectors:
|
||||
b _reset
|
||||
b turnon_VFP
|
||||
b vector_svc
|
||||
b vector_pabort
|
||||
b vector_dabort
|
||||
b vector_resv
|
||||
b IRQ_Handler
|
||||
ldr pc,[pc,#-0x1b0]
|
||||
Reference in New Issue
Block a user