This commit is contained in:
sc committed 2026-02-14 19:03:02 +08:00
commit da43152a7e
3380 files changed
+1128754

No files matched your search

@@ -0,0 +1,23 @@
# RT-Thread building script for component
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')
CPPPATH = [cwd]
if rtconfig.PLATFORM in ['armcc', 'armclang']:
src += Glob('*_rvds.S')
if rtconfig.PLATFORM in ['gcc']:
src += Glob('*_init.S')
src += Glob('*_gcc.S')
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef __ARMV8_H__
#define __ARMV8_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
void rt_hw_show_register(struct rt_hw_exp_stack *regs);
#endif
@@ -0,0 +1,545 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-29 Jesven the first version
*/
#ifndef __ICCARM__
#ifndef __CHECKER__
#if !defined (__ARM_EABI__)
#warning Your compiler does not have EABI support.
#warning ARM unwind is known to compile only with EABI compilers.
#warning Change compiler or disable ARM_UNWIND option.
#elif (__GNUC__ == 4 && __GNUC_MINOR__ <= 2) && !defined(__clang__)
#warning Your compiler is too buggy; it is known to not compile ARM unwind support.
#warning Change compiler or disable ARM_UNWIND option.
#endif
#endif /* __CHECKER__ */
#include <rtthread.h>
#include <rthw.h>
#include <backtrace.h>
#define DBG_TAG "BACKTRACE"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#ifdef RT_USING_SMART
#include <lwp.h>
#include <lwp_user_mm.h>
#include <lwp_arch.h>
#endif
rt_inline void arm_get_current_stackframe(struct pt_regs *regs, struct stackframe *frame)
{
frame->fp = frame_pointer(regs);
frame->sp = regs->ARM_sp;
frame->lr = regs->ARM_lr;
frame->pc = regs->ARM_pc;
}
struct unwind_ctrl_block {
unsigned long vrs[16]; /* virtual register set */
const unsigned long *insn; /* pointer to the current instructions word */
unsigned long sp_high; /* highest value of sp allowed */
/*
* 1 : check for stack overflow for each register pop.
* 0 : save overhead if there is plenty of stack remaining.
*/
int check_each_pop;
int entries; /* number of entries left to interpret */
int byte; /* current byte number in the instructions word */
};
enum regs
{
#ifdef CONFIG_THUMB2_KERNEL
FP = 7,
#else
FP = 11,
#endif
SP = 13,
LR = 14,
PC = 15
};
static int core_kernel_text(unsigned long addr)
{
return 1;
}
/* Convert a prel31 symbol to an absolute address */
#define prel31_to_addr(ptr) \
({ \
/* sign-extend to 32 bits */ \
long offset = (((long)*(ptr)) << 1) >> 1; \
(unsigned long)(ptr) + offset; \
})
/*
* Binary search in the unwind index. The entries are
* guaranteed to be sorted in ascending order by the linker.
*
* start = first entry
* origin = first entry with positive offset (or stop if there is no such entry)
* stop - 1 = last entry
*/
static const struct unwind_idx *search_index(unsigned long addr,
const struct unwind_idx *start,
const struct unwind_idx *origin,
const struct unwind_idx *stop)
{
unsigned long addr_prel31;
LOG_D("%s(%08lx, %x, %x, %x)",
__func__, addr, start, origin, stop);
/*
* only search in the section with the matching sign. This way the
* prel31 numbers can be compared as unsigned longs.
*/
if (addr < (unsigned long)start)
/* negative offsets: [start; origin) */
stop = origin;
else
/* positive offsets: [origin; stop) */
start = origin;
/* prel31 for address relavive to start */
addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
while (start < stop - 1)
{
const struct unwind_idx *mid = start + ((stop - start) >> 1);
/*
* As addr_prel31 is relative to start an offset is needed to
* make it relative to mid.
*/
if (addr_prel31 - ((unsigned long)mid - (unsigned long)start) <
mid->addr_offset)
stop = mid;
else
{
/* keep addr_prel31 relative to start */
addr_prel31 -= ((unsigned long)mid -
(unsigned long)start);
start = mid;
}
}
if (start->addr_offset <= addr_prel31)
return start;
else
{
LOG_W("unwind: Unknown symbol address %08lx", addr);
return RT_NULL;
}
}
static const struct unwind_idx *unwind_find_origin(
const struct unwind_idx *start, const struct unwind_idx *stop)
{
LOG_D("%s(%x, %x)", __func__, start, stop);
while (start < stop)
{
const struct unwind_idx *mid = start + ((stop - start) >> 1);
if (mid->addr_offset >= 0x40000000)
/* negative offset */
start = mid + 1;
else
/* positive offset */
stop = mid;
}
LOG_D("%s -> %x", __func__, stop);
return stop;
}
static const struct unwind_idx *unwind_find_idx(unsigned long addr, const struct unwind_idx **origin_idx, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[])
{
const struct unwind_idx *idx = RT_NULL;
LOG_D("%s(%08lx)", __func__, addr);
if (core_kernel_text(addr))
{
if (!*origin_idx)
*origin_idx =
unwind_find_origin(exidx_start,
exidx_end);
/* main unwind table */
idx = search_index(addr, exidx_start,
*origin_idx,
exidx_end);
}
LOG_D("%s: idx = %x", __func__, idx);
return idx;
}
static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl)
{
unsigned long ret;
if (ctrl->entries <= 0)
{
LOG_W("unwind: Corrupt unwind table");
return 0;
}
ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
if (ctrl->byte == 0)
{
ctrl->insn++;
ctrl->entries--;
ctrl->byte = 3;
}
else
ctrl->byte--;
return ret;
}
/* Before poping a register check whether it is feasible or not */
static int unwind_pop_register(struct unwind_ctrl_block *ctrl,
unsigned long **vsp, unsigned int reg)
{
if (ctrl->check_each_pop)
if (*vsp >= (unsigned long *)ctrl->sp_high)
return -URC_FAILURE;
ctrl->vrs[reg] = *(*vsp)++;
return URC_OK;
}
/* Helper functions to execute the instructions */
static int unwind_exec_pop_subset_r4_to_r13(struct unwind_ctrl_block *ctrl,
unsigned long mask)
{
unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
int load_sp, reg = 4;
load_sp = mask & (1 << (13 - 4));
while (mask)
{
if (mask & 1)
if (unwind_pop_register(ctrl, &vsp, reg))
return -URC_FAILURE;
mask >>= 1;
reg++;
}
if (!load_sp)
ctrl->vrs[SP] = (unsigned long)vsp;
return URC_OK;
}
static int unwind_exec_pop_r4_to_rN(struct unwind_ctrl_block *ctrl,
unsigned long insn)
{
unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
int reg;
/* pop R4-R[4+bbb] */
for (reg = 4; reg <= 4 + (insn & 7); reg++)
if (unwind_pop_register(ctrl, &vsp, reg))
return -URC_FAILURE;
if (insn & 0x8)
if (unwind_pop_register(ctrl, &vsp, 14))
return -URC_FAILURE;
ctrl->vrs[SP] = (unsigned long)vsp;
return URC_OK;
}
static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_block *ctrl,
unsigned long mask)
{
unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
int reg = 0;
/* pop R0-R3 according to mask */
while (mask)
{
if (mask & 1)
if (unwind_pop_register(ctrl, &vsp, reg))
return -URC_FAILURE;
mask >>= 1;
reg++;
}
ctrl->vrs[SP] = (unsigned long)vsp;
return URC_OK;
}
/*
* Execute the current unwind instruction.
*/
static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
{
unsigned long insn = unwind_get_byte(ctrl);
int ret = URC_OK;
LOG_D("%s: insn = %08lx", __func__, insn);
if ((insn & 0xc0) == 0x00)
ctrl->vrs[SP] += ((insn & 0x3f) << 2) + 4;
else if ((insn & 0xc0) == 0x40)
ctrl->vrs[SP] -= ((insn & 0x3f) << 2) + 4;
else if ((insn & 0xf0) == 0x80)
{
unsigned long mask;
insn = (insn << 8) | unwind_get_byte(ctrl);
mask = insn & 0x0fff;
if (mask == 0)
{
LOG_W("unwind: 'Refuse to unwind' instruction %04lx",
insn);
return -URC_FAILURE;
}
ret = unwind_exec_pop_subset_r4_to_r13(ctrl, mask);
if (ret)
goto error;
}
else if ((insn & 0xf0) == 0x90 &&
(insn & 0x0d) != 0x0d)
ctrl->vrs[SP] = ctrl->vrs[insn & 0x0f];
else if ((insn & 0xf0) == 0xa0)
{
ret = unwind_exec_pop_r4_to_rN(ctrl, insn);
if (ret)
goto error;
}
else if (insn == 0xb0)
{
if (ctrl->vrs[PC] == 0)
ctrl->vrs[PC] = ctrl->vrs[LR];
/* no further processing */
ctrl->entries = 0;
}
else if (insn == 0xb1)
{
unsigned long mask = unwind_get_byte(ctrl);
if (mask == 0 || mask & 0xf0)
{
LOG_W("unwind: Spare encoding %04lx",
(insn << 8) | mask);
return -URC_FAILURE;
}
ret = unwind_exec_pop_subset_r0_to_r3(ctrl, mask);
if (ret)
goto error;
}
else if (insn == 0xb2)
{
unsigned long uleb128 = unwind_get_byte(ctrl);
ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
}
else
{
LOG_W("unwind: Unhandled instruction %02lx", insn);
return -URC_FAILURE;
}
LOG_D("%s: fp = %08lx sp = %08lx lr = %08lx pc = %08lx", __func__,
ctrl->vrs[FP], ctrl->vrs[SP], ctrl->vrs[LR], ctrl->vrs[PC]);
error:
return ret;
}
#ifdef RT_BACKTRACE_FUNCTION_NAME
static char *unwind_get_function_name(void *address)
{
uint32_t flag_word = *(uint32_t *)((char*)address - 4);
if ((flag_word & 0xff000000) == 0xff000000)
{
return (char *)((char*)address - 4 - (flag_word & 0x00ffffff));
}
return RT_NULL;
}
#endif
/*
* Unwind a single frame starting with *sp for the symbol at *pc. It
* updates the *pc and *sp with the new values.
*/
int unwind_frame(struct stackframe *frame, const struct unwind_idx **origin_idx, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[])
{
unsigned long low;
const struct unwind_idx *idx;
struct unwind_ctrl_block ctrl;
struct rt_thread *rt_c_thread;
/* store the highest address on the stack to avoid crossing it*/
low = frame->sp;
rt_c_thread = rt_thread_self();
ctrl.sp_high = (unsigned long)((char*)rt_c_thread->stack_addr + rt_c_thread->stack_size);
LOG_D("%s(pc = %08lx lr = %08lx sp = %08lx)", __func__,
frame->pc, frame->lr, frame->sp);
idx = unwind_find_idx(frame->pc, origin_idx, exidx_start, exidx_end);
if (!idx)
{
LOG_W("unwind: Index not found %08lx", frame->pc);
return -URC_FAILURE;
}
#ifdef RT_BACKTRACE_FUNCTION_NAME
{
char *fun_name;
fun_name = unwind_get_function_name((void *)prel31_to_addr(&idx->addr_offset));
if (fun_name)
{
rt_kprintf("0x%08x @ %s\n", frame->pc, fun_name);
}
}
#endif
ctrl.vrs[FP] = frame->fp;
ctrl.vrs[SP] = frame->sp;
ctrl.vrs[LR] = frame->lr;
ctrl.vrs[PC] = 0;
if (idx->insn == 1)
/* can't unwind */
return -URC_FAILURE;
else if ((idx->insn & 0x80000000) == 0)
/* prel31 to the unwind table */
ctrl.insn = (unsigned long *)prel31_to_addr(&idx->insn);
else if ((idx->insn & 0xff000000) == 0x80000000)
/* only personality routine 0 supported in the index */
ctrl.insn = &idx->insn;
else
{
LOG_W("unwind: Unsupported personality routine %08lx in the index at %x",
idx->insn, idx);
return -URC_FAILURE;
}
/* check the personality routine */
if ((*ctrl.insn & 0xff000000) == 0x80000000)
{
ctrl.byte = 2;
ctrl.entries = 1;
}
else if ((*ctrl.insn & 0xff000000) == 0x81000000)
{
ctrl.byte = 1;
ctrl.entries = 1 + ((*ctrl.insn & 0x00ff0000) >> 16);
}
else
{
LOG_W("unwind: Unsupported personality routine %08lx at %x",
*ctrl.insn, ctrl.insn);
return -URC_FAILURE;
}
ctrl.check_each_pop = 0;
while (ctrl.entries > 0)
{
int urc;
if ((ctrl.sp_high - ctrl.vrs[SP]) < sizeof(ctrl.vrs))
ctrl.check_each_pop = 1;
urc = unwind_exec_insn(&ctrl);
if (urc < 0)
return urc;
if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= ctrl.sp_high)
return -URC_FAILURE;
}
if (ctrl.vrs[PC] == 0)
ctrl.vrs[PC] = ctrl.vrs[LR];
/* check for infinite loop */
if (frame->pc == ctrl.vrs[PC])
return -URC_FAILURE;
frame->fp = ctrl.vrs[FP];
frame->sp = ctrl.vrs[SP];
frame->lr = ctrl.vrs[LR];
frame->pc = ctrl.vrs[PC];
return URC_OK;
}
void unwind_backtrace(struct pt_regs *regs, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[])
{
struct stackframe frame;
const struct unwind_idx *origin_idx = RT_NULL;
LOG_D("%s(regs = %x)", __func__, regs);
arm_get_current_stackframe(regs, &frame);
#ifndef RT_BACKTRACE_FUNCTION_NAME
rt_kprintf("please use: addr2line -e rtthread.elf -a -f %08x\n", frame.pc);
#endif
LOG_D("pc = %08x, sp = %08x", frame.pc, frame.sp);
while (1)
{
int urc;
urc = unwind_frame(&frame, &origin_idx, exidx_start, exidx_end);
if (urc < 0)
break;
//dump_backtrace_entry(where, frame.pc, frame.sp - 4);
#ifndef RT_BACKTRACE_FUNCTION_NAME
rt_kprintf(" %08x", frame.pc);
#endif
LOG_D("from: pc = %08x, frame = %08x", frame.pc, frame.sp - 4);
}
rt_kprintf("\n");
}
extern const struct unwind_idx __exidx_start[];
extern const struct unwind_idx __exidx_end[];
void rt_unwind(struct rt_hw_exp_stack *regs, unsigned int pc_adj)
{
struct pt_regs e_regs;
e_regs.ARM_fp = regs->fp;
e_regs.ARM_sp = regs->sp;
e_regs.ARM_lr = regs->lr;
e_regs.ARM_pc = regs->pc - pc_adj;
#ifdef RT_USING_SMART
if (!lwp_user_accessable((void *)e_regs.ARM_pc, sizeof (void *)))
{
e_regs.ARM_pc = regs->lr - sizeof(void *);
}
#endif
rt_kprintf("backtrace:\n");
unwind_backtrace(&e_regs, __exidx_start, __exidx_end);
}
rt_err_t rt_backtrace(void)
{
struct rt_hw_exp_stack regs;
__asm volatile ("mov %0, fp":"=r"(regs.fp));
__asm volatile ("mov %0, sp":"=r"(regs.sp));
__asm volatile ("mov %0, lr":"=r"(regs.lr));
__asm volatile ("mov %0, pc":"=r"(regs.pc));
rt_unwind(&regs, 8);
return RT_EOK;
}
#endif // (__ICCARM__) undefined
@@ -0,0 +1,83 @@
#ifndef __BACKTRACE_H
#define __BACKTRACE_H
#ifndef __ASSEMBLY__
#include <cpuport.h>
/* Unwind reason code according the the ARM EABI documents */
enum unwind_reason_code
{
URC_OK = 0, /* operation completed successfully */
URC_CONTINUE_UNWIND = 8,
URC_FAILURE = 9 /* unspecified failure of some kind */
};
struct unwind_idx
{
unsigned long addr_offset;
unsigned long insn;
};
struct unwind_table
{
const struct unwind_idx *start;
const struct unwind_idx *origin;
const struct unwind_idx *stop;
unsigned long begin_addr;
unsigned long end_addr;
};
struct stackframe
{
/*
* FP member should hold R7 when CONFIG_THUMB2_KERNEL is enabled
* and R11 otherwise.
*/
unsigned long fp;
unsigned long sp;
unsigned long lr;
unsigned long pc;
};
struct pt_regs
{
unsigned long uregs[18];
};
#define ARM_cpsr uregs[16]
#define ARM_pc uregs[15]
#define ARM_lr uregs[14]
#define ARM_sp uregs[13]
#define ARM_ip uregs[12]
#define ARM_fp uregs[11]
#define ARM_r10 uregs[10]
#define ARM_r9 uregs[9]
#define ARM_r8 uregs[8]
#define ARM_r7 uregs[7]
#define ARM_r6 uregs[6]
#define ARM_r5 uregs[5]
#define ARM_r4 uregs[4]
#define ARM_r3 uregs[3]
#define ARM_r2 uregs[2]
#define ARM_r1 uregs[1]
#define ARM_r0 uregs[0]
#define ARM_ORIG_r0 uregs[17]
#define instruction_pointer(regs) (regs)->ARM_pc
#ifdef CONFIG_THUMB2_KERNEL
#define frame_pointer(regs) (regs)->ARM_r7
#else
#define frame_pointer(regs) (regs)->ARM_fp
#endif
int unwind_frame(struct stackframe *frame, const struct unwind_idx **origin_idx, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[]);
void unwind_backtrace(struct pt_regs *regs, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[]);
void rt_unwind(struct rt_hw_exp_stack *regs, unsigned int pc_adj);
rt_err_t rt_backtrace(void);
#endif /* !__ASSEMBLY__ */
#endif /* __BACKTRACE_H */
@@ -0,0 +1,249 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-03-01 Wangyuqiang first version
*/
.syntax unified
.text
.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 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(rt_uint32 from, rt_uint32 to)
* r0 --> from
* r1 --> to
*/
.globl rt_hw_context_switch
rt_hw_context_switch:
clrex
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_FPU
/* fpu context */
vmrs r6, fpexc
tst r6, #(1<<30)
beq __no_vfp_frame1
vstmdb sp!, {d0-d15}
vstmdb sp!, {d16-d31}
vmrs r5, fpscr
stmfd sp!, {r5}
__no_vfp_frame1:
stmfd sp!, {r6}
#endif
str sp, [r0] @ store sp in preempted tasks TCB
ldr sp, [r1] @ get new task stack pointer
#ifdef RT_USING_FPU
/* fpu context */
ldmfd sp!, {r6}
vmsr fpexc, r6
tst r6, #(1<<30)
beq __no_vfp_frame2
ldmfd sp!, {r5}
vmsr fpscr, r5
vldmia sp!, {d16-d31}
vldmia sp!, {d0-d15}
__no_vfp_frame2:
#endif
ldmfd sp!, {r1}
msr spsr_cxsf, r1 /* original mode */
ldmfd sp!, {r0-r12,lr,pc}^ /* irq return */
/*
* 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
#ifdef RT_USING_FPU
ldmfd sp!, {r6}
vmsr fpexc, r6
tst r6, #(1<<30)
beq __no_vfp_frame_to
ldmfd sp!, {r5}
vmsr fpscr, r5
vldmia sp!, {d0-d15}
__no_vfp_frame_to:
#endif
LDMIA sp!, {r4} @ pop new task cpsr to spsr
MSR spsr_cxsf, r4
ldmfd sp!, {r0-r12,lr,pc}^ /* irq return */
/*
* 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}
#ifdef RT_USING_FPU
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
#ifdef RT_USING_FPU
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]
#ifdef RT_USING_FPU
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
#ifdef RT_USING_FPU
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
#ifdef RT_USING_FPU
ldmfd sp!, {r6}
vmsr fpexc, r6
tst r6, #(1<<30)
beq __no_vfp_frame_do3
ldmfd sp!, {r5}
vmsr fpscr, r5
vldmia sp!, {d0-d15}
__no_vfp_frame_do3:
#endif
LDMIA sp!, {r4} @ pop new task's cpsr to spsr
MSR spsr_cxsf, r4
ldmfd sp!, {r0-r12,lr,pc}^ /* irq return */
@@ -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
; * 2013-10-20 Grissiom port to GCC
; * 2024-03-11 Wangyuqiang rzn2l adapt
; */
SECTION .text:CODE(2)
ARM
IMPORT rt_thread_switch_interrupt_flag
IMPORT rt_interrupt_from_thread
IMPORT rt_interrupt_to_thread
IMPORT rt_interrupt_enter
IMPORT rt_interrupt_leave
IMPORT rt_hw_trap_irq
;/*
; * rt_base_t rt_hw_interrupt_disable();
; */
EXPORT rt_hw_interrupt_disable
rt_hw_interrupt_disable:
MRS r0, CPSR
CPSID I
BX lr
;/*
; * void rt_hw_interrupt_enable(rt_base_t level);
; */
EXPORT 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
; */
EXPORT 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
CMP r4, #0
BNE ne_label
ne_label:
ORR r4, r4, #0x20
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
MOV lr, pc
STMIA sp!, {lr}
;/*
; * void rt_hw_context_switch_to(rt_uint32 to)
; * r0 --> to
; */
EXPORT 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}^
;/*
; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to)@
; */
EXPORT 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
EXPORT 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)
; */
EXPORT 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
MOV lr, pc
STMIA sp!, {r0-r12, lr}
STR pc, [sp]
END
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2011-2024, Shanghai Real-Thread Electronic Technology Co.,Ltd
*
* Change Logs:
* Date Author Notes
* 2022-08-29 RT-Thread 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" )
#endif
@@ -0,0 +1,167 @@
/*
* Copyright (c) 2011-2022, Shanghai Real-Thread Electronic Technology Co.,Ltd
*
* Change Logs:
* Date Author Notes
* 2022-08-29 RT-Thread first version
*/
.globl rt_cpu_get_smp_id
rt_cpu_get_smp_id:
mrc p15, #0, r0, c0, c0, #5
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:
stmfd sp!, {r0-r12, lr}
bl v7_flush_dcache_all
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
dsb
isb
ldmfd sp!, {r0-r12, lr}
mov pc, lr
v7_flush_dcache_all:
dmb @ ensure ordering with previous memory accesses
mrc p15, 1, r0, c0, c0, 1 @ read clidr
ands r3, r0, #0x7000000 @ extract loc from clidr
mov r3, r3, lsr #23 @ left align loc bit field
beq finished @ if loc is 0, then no need to clean
mov r10, #0 @ start clean at cache level 0
loop1:
add r2, r10, r10, lsr #1 @ work out 3x current cache level
mov r1, r0, lsr r2 @ extract cache type bits from clidr
and r1, r1, #7 @ mask of the bits for current cache only
cmp r1, #2 @ see what cache we have at this level
blt skip @ skip if no cache, or just i-cache
mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
isb @ isb to sych the new cssr&csidr
mrc p15, 1, r1, c0, c0, 0 @ read the new csidr
and r2, r1, #7 @ extract the length of the cache lines
add r2, r2, #4 @ add 4 (line length offset)
ldr r4, =0x3ff
ands r4, r4, r1, lsr #3 @ find maximum number on the way size
clz r5, r4 @ find bit position of way size increment
ldr r7, =0x7fff
ands r7, r7, r1, lsr #13 @ extract max number of the index size
loop2:
mov r9, r4 @ create working copy of max way size
loop3:
orr r11, r10, r9, lsl r5 @ factor way and cache number into r11
orr r11, r11, r7, lsl r2 @ factor index number into r11
mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way
subs r9, r9, #1 @ decrement the way
bge loop3
subs r7, r7, #1 @ decrement the index
bge loop2
skip:
add r10, r10, #2 @ increment cache number
cmp r3, r10
bgt loop1
finished:
mov r10, #0 @ swith back to cache level 0
mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
dsb
isb
mov pc, lr
#if 0
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
#endif
.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
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2011-2024, Shanghai Real-Thread Electronic Technology Co.,Ltd
*
* Change Logs:
* Date Author Notes
* 2022-08-29 RT-Thread first version
*/
#include <rthw.h>
#include <rtthread.h>
int rt_hw_cpu_id(void)
{
int cpu_id;
__asm volatile (
"mrc p15, 0, %0, c0, c0, 5"
:"=r"(cpu_id)
);
cpu_id &= 0xf;
return cpu_id;
}
/**
* @addtogroup ARM CPU
*/
/*@{*/
/** shutdown CPU */
void rt_hw_cpu_shutdown()
{
rt_uint32_t level;
rt_kprintf("shutdown...\n");
level = rt_hw_interrupt_disable();
while (level)
{
RT_ASSERT(0);
}
}
/*@}*/
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2011-2024, Shanghai Real-Thread Electronic Technology Co.,Ltd
*
* Change Logs:
* Date Author Notes
* 2022-08-29 RT-Thread first version
*/
#ifndef CPUPORT_H__
#define CPUPORT_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)
// rt_inline void rt_hw_isb(void)
// {
// __asm volatile ("isb":::"memory");
// }
// rt_inline void rt_hw_dmb(void)
// {
// __asm volatile ("dmb":::"memory");
// }
// rt_inline void rt_hw_dsb(void)
// {
// __asm volatile ("dsb":::"memory");
// }
#endif /*CPUPORT_H__*/
@@ -0,0 +1,682 @@
/*
* Copyright (c) 2006-2024, 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 >= 0);
__DSB();
__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 >= 0);
if (irq < 32)
{
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 < 32)
{
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 >= 16)
{
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 >= 16)
{
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);
__ISB();
// __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);
}
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);
// 一直执行,直到GIC_RDIST_WAKER(base)的值的第2位(从0开始计数)为0
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);
/* The Priority Mask sets the minimum priority an
* interrupt must have in order to be forwarded to the PE.
*/
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);
/* The Binary Point register is used
* for priority grouping and preemption.
*/
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;
}
@@ -0,0 +1,197 @@
/*
* Copyright (c) 2006-2024, 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 ((unsigned int)1<<31)
#define GICD_CTLR_E1NWF (1<<7)
#define GICD_CTLR_DS (1<<6) // 当两种安全模式被同时支持时,可以通过GICD_CTLR.DS==1关闭其中一个,只支持non-secure模式
#define GICD_CTLR_ARE_NS (1<<5)
#define GICD_CTLR_ARE_S (1<<4)
#define GICD_CTLR_ENGRP1S (1<<2) // secure group 1
#define GICD_CTLR_ENGRP1NS (1<<1) // non-secure group 1
#define GICD_CTLR_ENGRP0 (1<<0) // group 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);
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);
void assemb_dsb_func();
void assemb_isb_func();
#endif
@@ -0,0 +1,282 @@
/*
* Copyright (c) 2006-2024, 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"
#include "gicv3.h"
/* 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);
}
/**
* 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);
}
/**
* 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;
}
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2006-2024, 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>
#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);
#endif
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2011-2024, Shanghai Real-Thread Electronic Technology Co.,Ltd
*
* Change Logs:
* Date Author Notes
* 2022-08-29 RT-Thread first version
*/
#include "armv8.h"
#include <rtthread.h>
//#include <board.h>
/**
* 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_OSA
*(--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;
}
/*@}*/
@@ -0,0 +1,514 @@
/*
* 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.
@
.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 entry
.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, =entry
bx lr
.globl data_init
data_init:
/* copy .data to SRAM */
ldr r1, =_mdata /* .data start in image */
ldr r2, =_data_end /* .data end in image */
ldr r3, =_data_start /* 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 SWI_Handler
SWI_Handler:
push_svc_reg
bl rt_hw_trap_swi
b .
.globl Undefined_Handler
Undefined_Handler:
push_svc_reg
bl rt_hw_trap_undef
b .
.globl SVC_Handler
SVC_Handler:
push_svc_reg
b rt_hw_trap_svc
b .
.globl Prefetch_Handler
Prefetch_Handler:
push_svc_reg
b rt_hw_trap_pabt
b .
.globl Abort_Handler
Abort_Handler:
push_svc_reg
b rt_hw_trap_dabt
b .
.globl Reserved_Handler
Reserved_Handler:
push_svc_reg
b rt_hw_trap_resv
b .
@@ -0,0 +1,348 @@
;/*
; * Copyright (c) 2006-2022, RT-Thread Development Team
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Change Logs:
; * Date Author Notes
; * 2024-03-11 Wangyuqiang first version
; */
;@-------------------------------------------------------------------------------
;@ sys_core.asm
;@
;@ (c) Texas Instruments 2009-2013, All rights reserved.
;@
; Constants
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
I_Bit EQU 0x80
F_Bit EQU 0x40
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000000
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00001000
IRQ_Stack_Size EQU 0x00001000
IMPORT entry
IMPORT rt_hw_trap_svc
IMPORT rt_hw_trap_pabt
IMPORT rt_hw_trap_dabt
IMPORT rt_hw_trap_resv
IMPORT rt_hw_trap_swi
IMPORT rt_hw_trap_undef
IMPORT system_init
IMPORT __iar_program_start
; Define sections
SECTION .text:CODE:REORDER:NOROOT(2)
; Define stack start and top
EXPORT stack_start
EXPORT stack_top
; Align stack start to a 4-byte boundary (32-bit word)
ALIGNRAM 5
stack_start:
; Reserve stack memory
REPT (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + FIQ_Stack_Size + IRQ_Stack_Size)
DCB 0 ; Define a byte of data and clear it to zero
ENDR
; Define stack top label
stack_top:
; Define code section
SECTION .text:CODE:REORDER:NOROOT(2)
; Specify ARM mode
THUMB
;@-------------------------------------------------------------------------------
;@ Enable RAM ECC Support
EXPORT _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
EXPORT _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
EXPORT _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
EXPORT _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
EXPORT _coreGetDataFault_
_coreGetDataFault_:
mrc p15, #0, r0, c5, c0, #0
bx lr
;@-------------------------------------------------------------------------------
;@ Clear data fault status register
EXPORT _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
EXPORT _coreGetInstructionFault_
_coreGetInstructionFault_:
mrc p15, #0, r0, c5, c0, #1
bx lr
;@-------------------------------------------------------------------------------
;@ Clear instruction fault status register
EXPORT _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
EXPORT _coreGetDataFaultAddress_
_coreGetDataFaultAddress_:
mrc p15, #0, r0, c6, c0, #0
bx lr
;@-------------------------------------------------------------------------------
;@ Clear data fault address register
EXPORT _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
EXPORT _coreGetInstructionFaultAddress_
_coreGetInstructionFaultAddress_:
mrc p15, #0, r0, c6, c0, #2
bx lr
;@-------------------------------------------------------------------------------
;@ Clear instruction fault address register
EXPORT _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
EXPORT _coreGetAuxiliaryDataFault_
_coreGetAuxiliaryDataFault_:
mrc p15, #0, r0, c5, c1, #0
bx lr
;@-------------------------------------------------------------------------------
;@ Clear auxiliary data fault status register
EXPORT _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
EXPORT _coreGetAuxiliaryInstructionFault_
_coreGetAuxiliaryInstructionFault_:
mrc p15, #0, r0, c5, c1, #1
bx lr
;@-------------------------------------------------------------------------------
;@ Clear auxiliary instruction fault status register
EXPORT _coreClearAuxiliaryInstructionFault_
_coreClearAuxiliaryInstructionFault_:
stmfd sp!, {r0}
mov r0, #0
mrc p15, #0, r0, c5, c1, #1
ldmfd sp!, {r0}
bx lr
;@-------------------------------------------------------------------------------
;@ 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
EXPORT _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
EXPORT _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
EXPORT 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
EXPORT SWI_Handler
SWI_Handler:
push_svc_reg
bl rt_hw_trap_swi
b .
EXPORT Undefined_Handler
Undefined_Handler:
push_svc_reg
bl rt_hw_trap_undef
b .
EXPORT SVC_Handler
SVC_Handler:
push_svc_reg
bl rt_hw_trap_svc
b .
EXPORT Prefetch_Handler
Prefetch_Handler:
push_svc_reg
bl rt_hw_trap_pabt
b .
EXPORT Abort_Handler
Abort_Handler:
push_svc_reg
bl rt_hw_trap_dabt
b .
EXPORT Reserved_Handler
Reserved_Handler:
push_svc_reg
bl rt_hw_trap_resv
b .
END
@@ -0,0 +1,318 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
*/
#include <armv8.h>
#include <gicv3.h>
#include <rtthread.h>
#include <rthw.h>
//#include <board.h>
#include "interrupt.h"
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
extern long list_thread(void);
#endif
/**
* 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();
}
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;
volatile 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;
}
#ifdef SOC_SERIES_R9A07G0
extern fsp_vector_t g_vector_table[BSP_ICU_VECTOR_MAX_ENTRIES];
bsp_common_interrupt_handler((uint32_t)ir);
if (ir < MAX_HANDLERS)
{
/* get interrupt service routine */
isr_table[ir].handler = (rt_isr_handler_t)g_vector_table[ir];
isr_table[ir].param = RT_NULL;
}
#endif
/* 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();
#ifdef SOC_SERIES_R9A07G0
extern fsp_vector_t g_vector_table[BSP_ICU_VECTOR_MAX_ENTRIES];
bsp_common_interrupt_handler((uint32_t)ir);
if (ir < MAX_HANDLERS)
{
/* get interrupt service routine */
isr_table[ir].handler = (rt_isr_handler_t)g_vector_table[ir];
isr_table[ir].param = RT_NULL;
}
#endif
/* 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);
}
@@ -0,0 +1,42 @@
/*
* 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_Handler
.globl Undefined_Handler
.globl SWI_Handler
.globl SVC_Handler
.globl Prefetch_Handler
.globl Abort_Handler
.globl Reserved_Handler
.globl IRQ_Handler
.globl FIQ_Handler
.globl system_vector
system_vector:
b Reset_Handler
b Undefined_Handler
b SWI_Handler
b SVC_Handler
b Prefetch_Handler
b Abort_Handler
b Reserved_Handler
b IRQ_Handler
b FIQ_Handler
@@ -0,0 +1,46 @@
;/*
; * Copyright (c) 2006-2018, RT-Thread Development Team
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Change Logs:
; * Date Author Notes
; * 2024-03-11 Wangyuqiang first version
; */
;@-------------------------------------------------------------------------------
;@ sys_intvecs.asm
;@
;@ (c) Texas Instruments 2009-2013, All rights reserved.
;@
;SECTION .vectors:"ax"
;@-------------------------------------------------------------------------------
;@ import reference for interrupt routines
IMPORT Reset_Handler
IMPORT Undefined_Handler
IMPORT SWI_Handler
IMPORT SVC_Handler
IMPORT Prefetch_Handler
IMPORT Abort_Handler
IMPORT Reserved_Handler
IMPORT IRQ_Handler
IMPORT FIQ_Handler
;/*
; * int system_vectors(void);
; */
EXPORT system_vectors
SECTION .intvec:CODE:NOROOT(2)
system_vectors:
b Reset_Handler
b Undefined_Handler
b SWI_Handler
b SVC_Handler
b Prefetch_Handler
b Abort_Handler
b Reserved_Handler
b IRQ_Handler
b FIQ_Handler
END