创建
This commit is contained in:
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(®s, 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
|
||||
Reference in new issue
Block a user